Permalink
Browse files

Merge pull request #40 from abayer/jenkins-39244

[FIXED JENKINS-39244, FIXED JENKINS-39245] Add env and tools to stages
  • Loading branch information...
rsandell committed Oct 28, 2016
2 parents 869ab82 + 8f93d6f commit 83a83f675427cbc2eb6f4ba4bf8e487c1654fbf0
@@ -42,7 +42,7 @@ These are sections that are specified directly within the `pipeline` argument cl
* *Description*: A sequence of `key = value` pairs, which will be passed to the `withEnv` step the build will be
executed within.
* *Required*: No
* *Allowed In*: Top-level `pipeline` closure only.
* *Allowed In*: Top-level `pipeline` or `stage` closures only.
* *Parameters*: None
* *Takes a Closure*: Yes
* *Closure Contents*: One or more lines with `foo = 'bar'` variable name/value pairs.
@@ -146,10 +146,10 @@ stages {
```
### tools
* *Description*: A top-level section defining tools to auto-install and put on the PATH. This is ignored if `image none`
* *Description*: A section defining tools to auto-install and put on the PATH. This is ignored if `image none`
is specified.
* *Required*: No
* *Allowed In*: Top-level `pipeline` closure only.
* *Allowed In*: Top-level `pipeline` or `stage` closures only.
* *Parameters*: None
* *Takes a Closure*: Yes
* *Closure Contents*: Names and versions of tools configured in Jenkins to install.
@@ -18,6 +18,8 @@
private ModelASTAgent agent;
private List<ModelASTBranch> branches = new ArrayList<ModelASTBranch>();
private ModelASTPostStage post;
private ModelASTTools tools;
private ModelASTEnvironment environment;
public ModelASTStage(Object sourceLocation) {
super(sourceLocation);
@@ -40,6 +42,14 @@ public JSONObject toJSON() {
o.accumulate("post", post.toJSON());
}
if (tools != null) {
o.accumulate("tools", tools.toJSON());
}
if (environment != null) {
o.accumulate("environment", environment.toJSON());
}
return o;
}
@@ -55,6 +65,12 @@ public void validate(final ModelValidator validator) {
if (post != null) {
post.validate(validator);
}
if (tools != null) {
tools.validate(validator);
}
if (environment != null) {
environment.validate(validator);
}
}
@Override
@@ -65,7 +81,12 @@ public String toGroovy() {
if (agent != null) {
result.append(agent.toGroovy());
}
if (tools != null) {
result.append(tools.toGroovy());
}
if (environment != null) {
result.append(environment.toGroovy());
}
result.append("steps {\n");
if (branches.size() > 1) {
result.append("parallel(");
@@ -107,6 +128,12 @@ public void removeSourceLocation() {
if (post != null) {
post.removeSourceLocation();
}
if (tools != null) {
tools.removeSourceLocation();
}
if (environment != null) {
environment.removeSourceLocation();
}
}
public String getName() {
@@ -141,13 +168,31 @@ public void setPost(ModelASTPostStage post) {
this.post = post;
}
public ModelASTTools getTools() {
return tools;
}
public void setTools(ModelASTTools tools) {
this.tools = tools;
}
public ModelASTEnvironment getEnvironment() {
return environment;
}
public void setEnvironment(ModelASTEnvironment environment) {
this.environment = environment;
}
@Override
public String toString() {
return "ModelASTStage{" +
"name='" + name + '\'' +
", agent=" + agent +
", branches=" + branches +
", post=" + post +
", tools=" + tools +
", environment=" + environment +
"}";
}
@@ -174,6 +219,12 @@ public boolean equals(Object o) {
if (getPost() != null ? !getPost().equals(that.getPost()) : that.getPost() != null) {
return false;
}
if (getTools() != null ? !getTools().equals(that.getTools()) : that.getTools() != null) {
return false;
}
if (getEnvironment() != null ? !getEnvironment().equals(that.getEnvironment()) : that.getEnvironment() != null) {
return false;
}
return getBranches() != null ? getBranches().equals(that.getBranches()) : that.getBranches() == null;
}
@@ -184,6 +235,9 @@ public int hashCode() {
result = 31 * result + (getName() != null ? getName().hashCode() : 0);
result = 31 * result + (getAgent() != null ? getAgent().hashCode() : 0);
result = 31 * result + (getBranches() != null ? getBranches().hashCode() : 0);
result = 31 * result + (getPost() != null ? getPost().hashCode() : 0);
result = 31 * result + (getTools() != null ? getTools().hashCode() : 0);
result = 31 * result + (getEnvironment() != null ? getEnvironment().hashCode() : 0);
return result;
}
}
@@ -50,6 +50,10 @@ public class Stage implements NestedModel, Serializable {
@Whitelisted
PostStage post
Tools tools
Environment environment
@Whitelisted
Stage name(String n) {
this.name = n
@@ -80,6 +84,29 @@ public class Stage implements NestedModel, Serializable {
return this
}
Stage tools(Tools tools) {
this.tools = tools
return this
}
Stage environment(Environment environment) {
this.environment = environment
return this
}
/**
* Helper method for translating the key/value pairs in the {@link Environment} into a list of "key=value" strings
* suitable for use with the withEnv step.
*
* @return a list of "key=value" strings.
*/
List<String> getEnvVars() {
return environment.collect { k, v ->
"${k}=${v}"
}
}
@Override
@Whitelisted
public void modelFromMap(Map<String,Object> m) {
@@ -180,18 +180,25 @@ class JSONParser {
stage.branches.add(parseBranch(o))
}
if (j.has("environment")) {
stage.environment = parseEnvironment(j.getJSONArray("environment"))
}
if (j.has("tools")) {
stage.tools = parseTools(j.getJSONArray("tools"))
}
if (j.has("post")) {
def object = j.getJSONObject("post")
if (!object.isNullObject()) {
stage.post = parsePostStage(object)
}
}
return stage
}
public @CheckForNull ModelASTBranch parseBranch(JSONObject j) {
ModelASTBranch branch = new ModelASTBranch(j)
branch.name = j.getString("name")
@@ -329,6 +329,12 @@ class ModelParser {
case 'post':
stage.post = parsePostStage(s)
break;
case 'tools':
stage.tools = parseTools(s)
break
case 'environment':
stage.environment = parseEnvironment(s)
break
default:
errorCollector.error(stage, "Unknown stage section '${name}'")
}
@@ -322,6 +322,12 @@
"post": {
"$ref": "#/definitions/notifications"
},
"tools": {
"$ref": "#/definitions/tools"
},
"environment": {
"$ref": "#/definitions/environment"
},
"branches": {
"type": "array",
"items": {
@@ -28,6 +28,7 @@ import hudson.FilePath
import hudson.Launcher
import hudson.model.Result
import org.jenkinsci.plugins.pipeline.modeldefinition.model.Agent
import org.jenkinsci.plugins.pipeline.modeldefinition.model.Environment
import org.jenkinsci.plugins.pipeline.modeldefinition.model.Root
import org.jenkinsci.plugins.pipeline.modeldefinition.model.Stage
import org.jenkinsci.plugins.pipeline.modeldefinition.model.Tools
@@ -76,7 +77,7 @@ public class ModelInterpreter implements Serializable {
}
// Entire build, including notifications, runs in the withEnv.
script.withEnv(root.getEnvVars()) {
withEnvBlock(root.getEnvVars()) {
// Stage execution and post-build actions run in try/catch blocks, so we still run post-build actions
// even if the build fails, and we still send notifications if the build and/or post-build actions fail.
// We save the caught error, if any, for throwing at the end of the build.
@@ -91,41 +92,46 @@ public class ModelInterpreter implements Serializable {
Stage thisStage = root.stages.getStages().get(i)
script.stage(thisStage.name) {
if (firstError == null) {
nodeOrDockerOrNone(thisStage.agent) {
try {
catchRequiredContextForNode(root.agent) {
setUpDelegate(thisStage.steps.closure).call()
}.call()
} catch (Exception e) {
script.echo "Error in stages execution: ${e.getMessage()}"
script.getProperty("currentBuild").result = Result.FAILURE
if (firstError == null) {
firstError = e
}
} finally {
// And finally, run the post stage steps.
List<Closure> postClosures = thisStage.satisfiedPostStageConditions(root, script.getProperty("currentBuild"))
withEnvBlock(thisStage.getEnvVars()) {
if (firstError == null) {
nodeOrDockerOrNone(thisStage.agent) {
toolsBlock(thisStage.agent ?: root.agent, thisStage.tools) {
try {
catchRequiredContextForNode(root.agent) {
setUpDelegate(thisStage.steps.closure).call()
}.call()
} catch (Exception e) {
script.echo "Error in stages execution: ${e.getMessage()}"
script.getProperty("currentBuild").result = Result.FAILURE
if (firstError == null) {
firstError = e
}
} finally {
// And finally, run the post stage steps.
List<Closure> postClosures = thisStage.satisfiedPostStageConditions(root, script.getProperty("currentBuild"))
catchRequiredContextForNode(thisStage.agent != null ? thisStage.agent : root.agent, false) {
if (postClosures.size() > 0) {
script.echo("Post stage") //TODO should this be a nested stage instead?
try {
for (int ni = 0; ni < postClosures.size(); ni++) {
setUpDelegate(postClosures.get(ni)).call()
}
} catch (Exception e) {
script.echo "Error in stage post: ${e.getMessage()}"
script.getProperty("currentBuild").result = Result.FAILURE
if (firstError == null) {
firstError = e
catchRequiredContextForNode(thisStage.agent != null ? thisStage.agent : root.agent, false) {
if (postClosures.size() > 0) {
script.echo("Post stage")
//TODO should this be a nested stage instead?
try {
for (int ni = 0; ni < postClosures.size(); ni++) {
setUpDelegate(postClosures.get(ni)).call()
}
} catch (Exception e) {
script.echo "Error in stage post: ${e.getMessage()}"
script.getProperty("currentBuild").result = Result.FAILURE
if (firstError == null) {
firstError = e
}
}
}
}
}.call()
}
}.call()
}
}.call()
}
}.call()
}
}.call()
}
}
@@ -170,7 +176,7 @@ public class ModelInterpreter implements Serializable {
firstError = e
}
}
}
}.call()
if (firstError != null) {
throw firstError
}
@@ -204,6 +210,20 @@ public class ModelInterpreter implements Serializable {
}
}
def withEnvBlock(List<String> envVars, Closure body) {
if (envVars != null && !envVars.isEmpty()) {
return {
script.withEnv(envVars) {
body.call()
}
}
} else {
return {
body.call()
}
}
}
def toolsBlock(Agent agent, Tools tools, Closure body) {
// If there's no agent, don't install tools in the first place.
if (agent.hasAgent() && tools != null) {
@@ -118,6 +118,8 @@ public void setUp() throws Exception {
"simpleJobProperties",
"simpleTriggers",
"simpleParameters",
"toolsInStage",
"environmentInStage",
"stringsNeedingEscapeLogic"
);
@@ -54,6 +54,16 @@ public void simpleEnvironment() throws Exception {
j.assertLogContains("FOO is BAR", b);
}
@Test
public void environmentInStage() throws Exception {
prepRepoWithJenkinsfile("environmentInStage");
WorkflowRun b = getAndStartBuild();
j.assertBuildStatusSuccess(j.waitForCompletion(b));
j.assertLogContains("[Pipeline] { (foo)", b);
j.assertLogContains("FOO is BAR", b);
}
@Test
public void nonLiteralEnvironment() throws Exception {
prepRepoWithJenkinsfile("nonLiteralEnvironment");
Oops, something went wrong.

0 comments on commit 83a83f6

Please sign in to comment.