Skip to content

Commit

Permalink
Merge pull request #273 from kmanning/issue_272
Browse files Browse the repository at this point in the history
Issue #272: refactor parameters into a plugin
  • Loading branch information
kmanning committed Aug 2, 2020
2 parents eb814f9 + 17aafe3 commit 9b4fc27
Show file tree
Hide file tree
Showing 16 changed files with 774 additions and 34 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ The example above gives you a bare-bones pipeline, and there may be Jenkinsfile
* [ConfirmApplyPlugin](./docs/ConfirmApplyPlugin.md): pause and review the plan, before applying any changes.
* [ConditionalApplyPlugin](./docs/ConditionalApplyPlugin.md): only allow apply on master branch.
* [DefaultEnvironmentPlugin](./docs/DefaultEnvironmentPlugin.md): automatically set `TF_VAR_environment` variable.
* [BuildWithParametersPlugin](./docs/BuildWithParametersPlugin.md): use this plugin to manage the "Build with Parameters" feature of pipelines.
* [TerraformPlugin](./docs/TerraformPlugin.md): apply version-specific terraform behavior based on the version of terraform in use.
### Credentials and Configuration Management
* [CredentialsPlugin](./docs/CredentialsPlugin.md): Inject Jenkins credentials into your stages.
Expand Down
36 changes: 36 additions & 0 deletions docs/BuildWithParametersPlugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
## [BuildWithParametersPlugin](../src/BuildWithParametersPlugin.groovy)

This plugin is enabled by default.

Pipelines can prompt the user for parameters at build-time, with the Jenkinsfile "Build With Parameters" feature. This plugin lets you enable this feature, and prompt the user for parameters. If no parameters are configured, this plugin does nothing.

Eg:

```
@Library(['terraform-pipeline@v5.1']) _
Jenkinsfile.init(this)
BuildWithParametersPlugin.withBooleanParameter([
name: 'PIPELINE_PREFERENCE',
description: 'Do you like pipelines?',
defaultValue: true
])
BuildWithParametersPlugin.withStringParameter([
name: 'PIPELINE_THOUGHTS',
description: 'What do you think about pipelines?',
defaultValue: 'They make deployments so easy'
])
def validate = new TerraformValidateStage()
def deployQa = new TerraformEnvironmentStage('qa')
def deployUat = new TerraformEnvironmentStage('uat')
def deployProd = new TerraformEnvironmentStage('prod')
// At the start of the pipeline, the user with a checkbox and a string input
// The user's responses are available in the environment variables
// PIPELINE_PREFERENCE and PIPELINE_THOUGHTS
validate.then(deployQa)
.then(deployUat)
.then(deployProd)
.build()
```
2 changes: 1 addition & 1 deletion src/BuildStage.groovy
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import static TerraformEnvironmentStage.ALL

class BuildStage implements Stage, TerraformEnvironmentStagePlugin {
class BuildStage implements Stage, DecoratableStage, TerraformEnvironmentStagePlugin {
private final String ARTIFACT_STASH_KEY = 'buildArtifact'

public String buildCommand
Expand Down
89 changes: 89 additions & 0 deletions src/BuildWithParametersPlugin.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
public class BuildWithParametersPlugin implements BuildStagePlugin,
TerraformValidateStagePlugin,
TerraformEnvironmentStagePlugin,
RegressionStagePlugin {

private static globalBuildParameters = []
private static appliedOnce = false

public static void init() {
def plugin = new BuildWithParametersPlugin()

BuildStage.addPlugin(plugin)
TerraformValidateStage.addPlugin(plugin)
TerraformEnvironmentStage.addPlugin(plugin)
RegressionStage.addPlugin(plugin)
}

@Override
public void apply(BuildStage stage) {
applyToAllStages(stage)
}

@Override
public void apply(TerraformValidateStage stage) {
applyToAllStages(stage)
}

@Override
public void apply(TerraformEnvironmentStage stage) {
applyToAllStages(stage)
}

@Override
public void apply(RegressionStage stage) {
applyToAllStages(stage)
}

private void applyToAllStages(DecoratableStage stage) {
stage.decorate(addParameterToFirstStageOnly())
}

public Closure addParameterToFirstStageOnly() {
return { innerClosure ->
if (hasParameters() && !appliedOnce) {
properties([
parameters(getBuildParameters())
])
appliedOnce = true
}

innerClosure()
}
}

public static withBooleanParameter(Map options) {
def optionDefaults = [
defaultValue: false,
$class: 'hudson.model.BooleanParameterDefinition'
]

globalBuildParameters << (optionDefaults + options)
}

public static withStringParameter(Map options) {
def optionDefaults = [
defaultValue: '',
$class: 'hudson.model.StringParameterDefinition'
]

globalBuildParameters << (optionDefaults + options)
}

public static withParameter(Map options) {
globalBuildParameters << options
}

public boolean hasParameters() {
return !globalBuildParameters.isEmpty()
}

public List getBuildParameters() {
return globalBuildParameters
}

public static reset() {
globalBuildParameters = []
appliedOnce = false
}
}
4 changes: 4 additions & 0 deletions src/DecoratableStage.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// This is temporary, and should be pushed into Stage interface. See Issue #152
interface DecoratableStage {
public void decorate(Closure closure)
}
25 changes: 4 additions & 21 deletions src/Jenkinsfile.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ class Jenkinsfile {
public static instance = new Jenkinsfile()
public static declarative = false
public static pipelineTemplate
public static List params = []

def String getStandardizedRepoSlug() {
if (repoSlug != null) {
Expand Down Expand Up @@ -68,6 +67,7 @@ class Jenkinsfile {

def static void initializeDefaultPlugins() {
TerraformPlugin.init()
BuildWithParametersPlugin.init()
}

def static String getNodeName() {
Expand All @@ -79,13 +79,6 @@ class Jenkinsfile {
}

public static void build(List<Stage> stages) {
// Decorate the first stage with the list of parameters
// The stage must have the decorate() method available
if (stages.size() > 0 && stages[0].metaClass.respondsTo(stages[0], 'decorate', String, Closure)) {
Stage first_stage = stages[0]
first_stage.decorate(TerraformEnvironmentStage.ALL, createParamClosure())
}

if (!declarative) {
stages.each { Stage stage -> stage.build() }
} else {
Expand All @@ -97,14 +90,6 @@ class Jenkinsfile {
}
}

private static Closure createParamClosure() {
return { ->
properties([
parameters(params)
])
}
}

public static getPipelineTemplate(List<Stage> stages) {
switch (stages.size()) {
case 2:
Expand Down Expand Up @@ -145,14 +130,12 @@ class Jenkinsfile {
this.instance = newInstance
}

public static addParam(newParam) {
params << newParam
}

public static reset() {
instance = new Jenkinsfile()
original = null
params = []
defaultNodeName = null
docker = null
pipelineTemplate = null
declarative = false
}
}
4 changes: 1 addition & 3 deletions src/PlanOnlyPlugin.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@ class PlanOnlyPlugin implements TerraformEnvironmentStagePlugin, TerraformPlanCo
public static void init() {
PlanOnlyPlugin plugin = new PlanOnlyPlugin()

Jenkinsfile.instance.addParam([
$class: 'hudson.model.BooleanParameterDefinition',
BuildWithParametersPlugin.withBooleanParameter([
name: "FAIL_PLAN_ON_CHANGES",
defaultValue: false,
description: 'Plan run with -detailed-exitcode; ANY CHANGES will cause failure'
])

Expand Down
2 changes: 1 addition & 1 deletion src/RegressionStage.groovy
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class RegressionStage implements Stage {
class RegressionStage implements Stage, DecoratableStage {

public String testCommand
public List automationRepoList = []
Expand Down
4 changes: 1 addition & 3 deletions src/TargetPlugin.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ class TargetPlugin implements TerraformPlanCommandPlugin, TerraformApplyCommandP
public static void init() {
TargetPlugin plugin = new TargetPlugin()

Jenkinsfile.instance.addParam([
$class: 'hudson.model.StringParameterDefinition',
BuildWithParametersPlugin.withStringParameter([
name: "RESOURCE_TARGETS",
defaultValue: '',
description: 'comma-separated list of resource addresses to pass to plan and apply "-target=" parameters'
])

Expand Down
2 changes: 1 addition & 1 deletion src/TerraformEnvironmentStage.groovy
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class TerraformEnvironmentStage implements Stage {
class TerraformEnvironmentStage implements Stage, DecoratableStage {
private Jenkinsfile jenkinsfile
private String environment
private StageDecorations decorations
Expand Down
4 changes: 2 additions & 2 deletions src/TerraformValidateStage.groovy
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class TerraformValidateStage implements Stage {
class TerraformValidateStage implements Stage, DecoratableStage {
private Jenkinsfile jenkinsfile
private StageDecorations decorations

Expand Down Expand Up @@ -41,7 +41,7 @@ class TerraformValidateStage implements Stage {
}
}

public decorate(Closure decoration) {
public void decorate(Closure decoration) {
decorations.add(ALL, decoration)
}

Expand Down
Loading

0 comments on commit 9b4fc27

Please sign in to comment.