diff --git a/pipeline-model-definition/src/main/resources/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy b/pipeline-model-definition/src/main/resources/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy index 7fd7aee5b..a8f62ea1c 100644 --- a/pipeline-model-definition/src/main/resources/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy +++ b/pipeline-model-definition/src/main/resources/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy @@ -31,6 +31,7 @@ import hudson.Launcher import hudson.model.Result import org.jenkinsci.plugins.pipeline.StageStatus import org.jenkinsci.plugins.pipeline.modeldefinition.Messages +import org.jenkinsci.plugins.pipeline.modeldefinition.agent.DeclarativeAgentScript2 import org.jenkinsci.plugins.pipeline.modeldefinition.model.* import org.jenkinsci.plugins.pipeline.modeldefinition.options.DeclarativeOption import org.jenkinsci.plugins.pipeline.modeldefinition.steps.CredentialWrapper @@ -82,7 +83,7 @@ class ModelInterpreter implements Serializable { // the whole pipeline and don't want firstError to be set. firstError = null toolsBlock(root.tools, root.agent, null) { - firstError = evaluateSequentialStages(root, root.stages, firstError, null, restartedStage, null).call() + firstError = evaluateSequentialStages(root, root.stages, firstError, null, restartedStage, null) // Execute post-build actions now that we've finished all parallel. try { @@ -148,50 +149,47 @@ class ModelInterpreter implements Serializable { * @param restartedStageName the name of the stage we're restarting at. Null if this is not a restarted build or this is * called from a nested stage. * @param skippedReason Possibly null reason the container for the stages was skipped. - * @return A closure to execute */ def evaluateSequentialStages(Root root, Stages stages, Throwable firstError, Stage parent, String restartedStageName, SkippedStageReason skippedReason) { - return { - try { - boolean skippedForRestart = restartedStageName != null - stages.stages.each { thisStage -> - if (skippedForRestart) { - // Check if we're skipping for restart but are now on the stage we're supposed to restart on. - if (thisStage.name == restartedStageName) { - // If so, set skippedForRestart to false, and if the skippedReason is for restart, wipe that out too. - skippedForRestart = false - if (skippedReason instanceof SkippedStageReason.Restart) { - skippedReason = null - } - } else { - // If we skipped for restart and this isn't the restarted name, create a new reason. - skippedReason = new SkippedStageReason.Restart(thisStage.name, restartedStageName) - } - } - try { - evaluateStage(root, thisStage.agent ?: root.agent, thisStage, firstError, parent, skippedReason).call() - } catch (Throwable e) { - Utils.markStageFailedAndContinued(thisStage.name) - if (firstError == null) { - firstError = e + try { + boolean skippedForRestart = restartedStageName != null + stages.stages.each { thisStage -> + if (skippedForRestart) { + // Check if we're skipping for restart but are now on the stage we're supposed to restart on. + if (thisStage.name == restartedStageName) { + // If so, set skippedForRestart to false, and if the skippedReason is for restart, wipe that out too. + skippedForRestart = false + if (skippedReason instanceof SkippedStageReason.Restart) { + skippedReason = null } + } else { + // If we skipped for restart and this isn't the restarted name, create a new reason. + skippedReason = new SkippedStageReason.Restart(thisStage.name, restartedStageName) } - if (skippedForRestart) { - Utils.markStartAndEndNodesInStageAsNotExecuted(thisStage.name) + } + try { + evaluateStage(root, thisStage.agent ?: root.agent, thisStage, firstError, parent, skippedReason) + } catch (Throwable e) { + Utils.markStageFailedAndContinued(thisStage.name) + if (firstError == null) { + firstError = e } } - } finally { - // And finally, run the post stage steps if this was a parallel parent. - if (skippedReason == null && parent != null && - root.hasSatisfiedConditions(parent.post, script.getProperty("currentBuild"), parent, firstError)) { - Utils.logToTaskListener("Post stage") - firstError = runPostConditions(parent.post, parent.agent ?: root.agent, firstError, parent.name) + if (skippedForRestart) { + Utils.markStartAndEndNodesInStageAsNotExecuted(thisStage.name) } } - - return firstError + } finally { + // And finally, run the post stage steps if this was a parallel parent. + if (skippedReason == null && parent != null && + root.hasSatisfiedConditions(parent.post, script.getProperty("currentBuild"), parent, firstError)) { + Utils.logToTaskListener("Post stage") + firstError = runPostConditions(parent.post, parent.agent ?: root.agent, firstError, parent.name) + } } + + return firstError } /** @@ -208,11 +206,13 @@ class ModelInterpreter implements Serializable { def parallelStages = [:] thisStage?.parallel?.stages?.each { content -> if (skippedReason != null) { - parallelStages.put(content.name, - evaluateStage(root, parentAgent, content, firstError, thisStage, skippedReason.cloneWithNewStage(content.name))) + parallelStages.put(content.name, { + evaluateStage(root, parentAgent, content, firstError, thisStage, skippedReason.cloneWithNewStage(content.name)) + }) } else { - parallelStages.put(content.name, - evaluateStage(root, thisStage.agent ?: parentAgent, content, firstError, thisStage, null)) + parallelStages.put(content.name, { + evaluateStage(root, thisStage.agent ?: parentAgent, content, firstError, thisStage, null) + }) } } if (!parallelStages.isEmpty() && ( thisStage.failFast || root.options?.options?.get("parallelsAlwaysFailFast") != null) ) { @@ -238,61 +238,58 @@ class ModelInterpreter implements Serializable { * @param firstError An error that's already occurred earlier in the build. Can be null. * @param parent The possible parent stage, defaults to null. * @param skippedReason Possibly null reason this stage's parent, and therefore itself, is skipped. - * @return */ def evaluateStage(Root root, Agent parentAgent, Stage thisStage, Throwable firstError, Stage parent, SkippedStageReason skippedReason) { - return { - script.stage(thisStage.name) { - try { - if (skippedReason != null) { - skipStage(root, parentAgent, thisStage, firstError, skippedReason, parent).call() - } else if (firstError != null) { - skippedReason = new SkippedStageReason.Failure(thisStage.name) - skipStage(root, parentAgent, thisStage, firstError, skippedReason, parent).call() - } else if (skipUnstable(root.options)) { - skippedReason = new SkippedStageReason.Unstable(thisStage.name) - skipStage(root, parentAgent, thisStage, firstError, skippedReason, parent).call() - } else { - // if this a is a matrix generated stage, evaluate the matrix axis values first - // These are literals that guaranteed not to depend on other variables - // Users will expect them to be available at all times in a particular cell in a matrix. - withEnvBlock(thisStage.getMatrixCellEnvVars(script)) { - - def whenEvaluator = new WhenEvaluator(thisStage.when) - - if (whenEvaluator.passedOrNotEvaluatedBeforeOptions()) { - inWrappers(thisStage.options?.wrappers) { - if (whenEvaluator.passedOrNotEvaluatedBeforeInput()) { - stageInput(thisStage.input) { - if (thisStage?.parallel != null) { - if (whenEvaluator.passedOrNotEvaluated()) { - withCredentialsBlock(thisStage.environment) { - withEnvBlock(thisStage.getEnvVars(script)) { - script.parallel(getParallelStages(root, parentAgent, thisStage, firstError, null)) - } + script.stage(thisStage.name) { + try { + if (skippedReason != null) { + skipStage(root, parentAgent, thisStage, firstError, skippedReason, parent) + } else if (firstError != null) { + skippedReason = new SkippedStageReason.Failure(thisStage.name) + skipStage(root, parentAgent, thisStage, firstError, skippedReason, parent) + } else if (skipUnstable(root.options)) { + skippedReason = new SkippedStageReason.Unstable(thisStage.name) + skipStage(root, parentAgent, thisStage, firstError, skippedReason, parent) + } else { + // if this a is a matrix generated stage, evaluate the matrix axis values first + // These are literals that guaranteed not to depend on other variables + // Users will expect them to be available at all times in a particular cell in a matrix. + withEnvBlock(thisStage.getMatrixCellEnvVars(script)) { + + def whenEvaluator = new WhenEvaluator(thisStage.when) + + if (whenEvaluator.passedOrNotEvaluatedBeforeOptions()) { + inWrappers(thisStage.options?.wrappers) { + if (whenEvaluator.passedOrNotEvaluatedBeforeInput()) { + stageInput(thisStage.input) { + if (thisStage?.parallel != null) { + if (whenEvaluator.passedOrNotEvaluated()) { + withCredentialsBlock(thisStage.environment) { + withEnvBlock(thisStage.getEnvVars(script)) { + script.parallel(getParallelStages(root, parentAgent, thisStage, firstError, null)) } } - } else { - if (whenEvaluator.passedOrNotEvaluatedBeforeAgent()) { - inDeclarativeAgent(thisStage, root, thisStage.agent) { - if (whenEvaluator.passedOrNotEvaluated()) { - withCredentialsBlock(thisStage.environment) { - withEnvBlock(thisStage.getEnvVars(script)) { - toolsBlock(thisStage.tools, thisStage.agent ?: root.agent, parent?.tools ?: root.tools) { - if (thisStage?.stages) { - def nestedError = evaluateSequentialStages(root, thisStage.stages, firstError, - thisStage, null, null).call() - - // Propagate any possible error from the sequential stages - // as if it were an error thrown directly. - if (nestedError != null) { - throw nestedError - } - } else { - // Execute the actual stage and potential post-stage actions - executeSingleStage(root, thisStage, parentAgent) + } + } else { + if (whenEvaluator.passedOrNotEvaluatedBeforeAgent()) { + inDeclarativeAgent(thisStage, root, thisStage.agent) { + if (whenEvaluator.passedOrNotEvaluated()) { + withCredentialsBlock(thisStage.environment) { + withEnvBlock(thisStage.getEnvVars(script)) { + toolsBlock(thisStage.tools, thisStage.agent ?: root.agent, parent?.tools ?: root.tools) { + if (thisStage?.stages) { + def nestedError = evaluateSequentialStages(root, thisStage.stages, firstError, + thisStage, null, null) + + // Propagate any possible error from the sequential stages + // as if it were an error thrown directly. + if (nestedError != null) { + throw nestedError } + } else { + // Execute the actual stage and potential post-stage actions + executeSingleStage(root, thisStage, parentAgent) } } } @@ -304,85 +301,77 @@ class ModelInterpreter implements Serializable { } } } - if (!whenEvaluator.passed) { - skippedReason = new SkippedStageReason.When(thisStage.name) - skipStage(root, parentAgent, thisStage, firstError, skippedReason, parent).call() - } } - } - } catch (Throwable e) { - Utils.markStageFailedAndContinued(thisStage.name) - if (firstError == null) { - firstError = e - } - } finally { - // And finally, run the post stage steps if this was a parallel parent. - if (skippedReason == null && - root.hasSatisfiedConditions(thisStage.post, script.getProperty("currentBuild"), thisStage, firstError) && - thisStage?.parallel != null) { - Utils.logToTaskListener("Post stage") - firstError = runPostConditions(thisStage.post, thisStage.agent ?: parentAgent, firstError, thisStage.name) + if (!whenEvaluator.passed) { + skippedReason = new SkippedStageReason.When(thisStage.name) + skipStage(root, parentAgent, thisStage, firstError, skippedReason, parent) + } } } - - if (firstError != null) { - throw firstError + } catch (Throwable e) { + Utils.markStageFailedAndContinued(thisStage.name) + if (firstError == null) { + firstError = e + } + } finally { + // And finally, run the post stage steps if this was a parallel parent. + if (skippedReason == null && + root.hasSatisfiedConditions(thisStage.post, script.getProperty("currentBuild"), thisStage, firstError) && + thisStage?.parallel != null) { + Utils.logToTaskListener("Post stage") + firstError = runPostConditions(thisStage.post, thisStage.agent ?: parentAgent, firstError, thisStage.name) } } + + if (firstError != null) { + throw firstError + } } } def stageInput(StageInput input, Closure body) { if (input != null) { - return { - def submitted = script.input(message: input.message, id: input.id, ok: input.ok, submitter: input.submitter, - submitterParameter: input.submitterParameter, parameters: input.parameters) - if (input.parameters.isEmpty() && input.submitterParameter == null) { - // No parameters, so just proceed - body.call() - } else { - def inputEnv = [] - if (submitted instanceof Map) { - // Multiple parameters! - inputEnv = submitted.collect { k, v -> "${k}=${v}" } - } else if (input.submitterParameter != null) { - // Single parameter, it's the submitter. - inputEnv = ["${input.submitterParameter}=${submitted}"] - } else if (input.parameters.size() == 1) { - // One defined parameter, so we know its name. - inputEnv = ["${input.parameters.first().name}=${submitted}"] - } - script.withEnv(inputEnv) { - body.call() - } + def submitted = script.input(message: input.message, id: input.id, ok: input.ok, submitter: input.submitter, + submitterParameter: input.submitterParameter, parameters: input.parameters) + if (input.parameters.isEmpty() && input.submitterParameter == null) { + // No parameters, so just proceed + body.call() + } else { + def inputEnv = [] + if (submitted instanceof Map) { + // Multiple parameters! + inputEnv = submitted.collect { k, v -> "${k}=${v}" } + } else if (input.submitterParameter != null) { + // Single parameter, it's the submitter. + inputEnv = ["${input.submitterParameter}=${submitted}"] + } else if (input.parameters.size() == 1) { + // One defined parameter, so we know its name. + inputEnv = ["${input.parameters.first().name}=${submitted}"] } - }.call() + script.withEnv(inputEnv, body) + } } else { - return { - body.call() - }.call() + body.call() } } def skipStage(Root root, Agent parentAgent, Stage thisStage, Throwable firstError, SkippedStageReason reason, Stage parentStage) { - return { - Utils.logToTaskListener(reason.message) - def stepContextFlowNodeId = getFlowNodeId(); - Utils.markStageWithTag(thisStage.name, stepContextFlowNodeId, StageStatus.TAG_NAME, reason.stageStatus) - if (thisStage?.parallel != null) { - Map parallelToSkip = getParallelStages(root, parentAgent, thisStage, firstError, reason) - script.parallel(parallelToSkip) - if (reason instanceof SkippedStageReason.Restart) { - parallelToSkip.keySet().each { k -> Utils.markStartAndEndNodesInStageAsNotExecuted(k) } - } - } else if (thisStage?.stages != null) { - String restartedStage = null - if (reason instanceof SkippedStageReason.Restart) { - restartedStage = reason.restartedStage - } - evaluateSequentialStages(root, thisStage.stages, firstError, thisStage, restartedStage, reason).call() + Utils.logToTaskListener(reason.message) + def stepContextFlowNodeId = getFlowNodeId(); + Utils.markStageWithTag(thisStage.name, stepContextFlowNodeId, StageStatus.TAG_NAME, reason.stageStatus) + if (thisStage?.parallel != null) { + Map parallelToSkip = getParallelStages(root, parentAgent, thisStage, firstError, reason) + script.parallel(parallelToSkip) + if (reason instanceof SkippedStageReason.Restart) { + parallelToSkip.keySet().each { k -> Utils.markStartAndEndNodesInStageAsNotExecuted(k) } + } + } else if (thisStage?.stages != null) { + String restartedStage = null + if (reason instanceof SkippedStageReason.Restart) { + restartedStage = reason.restartedStage } + evaluateSequentialStages(root, thisStage.stages, firstError, thisStage, restartedStage, reason) } } @@ -397,21 +386,19 @@ class ModelInterpreter implements Serializable { * @throws Exception */ def catchRequiredContextForNode(Agent agent, Closure body) throws Exception { - return { - try { - body.call() - } catch (MissingContextVariableException e) { - if (FilePath.class == e.type || Launcher.class == e.type) { - if (!agent.hasAgent()) { - script.error(Messages.ModelInterpreter_NoNodeContext()) - } else { - throw e - } + try { + body.call() + } catch (MissingContextVariableException e) { + if (FilePath.class == e.type || Launcher.class == e.type) { + if (!agent.hasAgent()) { + script.error(Messages.ModelInterpreter_NoNodeContext()) } else { throw e } + } else { + throw e } - }.call() + } } @Deprecated @@ -440,15 +427,9 @@ class ModelInterpreter implements Serializable { throw new IllegalArgumentException( Messages.ModelInterpreter_EnvironmentVariableFailed(k) ) } }.findAll { it != null} - return { - script.withEnv(evaledEnv) { - body.call() - } - }.call() + script.withEnv(evaledEnv, body) } else { - return { - body.call() - }.call() + body.call() } } @@ -478,15 +459,9 @@ class ModelInterpreter implements Serializable { if (!creds.isEmpty()) { List> parameters = createWithCredentialsParameters(creds) - return { - script.withCredentials(parameters) { - body.call() - } - }.call() + script.withCredentials(parameters, body) } else { - return { - body.call() - }.call() + body.call() } } @@ -541,15 +516,9 @@ class ModelInterpreter implements Serializable { toolEnv = actualToolsInstall(toolsList) } - return { - script.withEnv(toolEnv) { - body.call() - } - }.call() + script.withEnv(toolEnv, body) } else { - return { - body.call() - }.call() + body.call() } } @@ -589,18 +558,19 @@ class ModelInterpreter implements Serializable { } } if (agent == null) { - return { - body.call() - }.call() + body.call() } else { def declarativeAgent = agent.getDeclarativeAgent(root, context) if (declarativeAgent == null) { script.error 'Unrecognized agent type' return null } - return declarativeAgent.getScript(script).run { - body.call() - }.call() + def script = declarativeAgent.getScript(script) + if (script instanceof DeclarativeAgentScript2) { + script.run(body) + } else { + script.run(body).call() + } } } @@ -617,13 +587,9 @@ class ModelInterpreter implements Serializable { */ def inWrappers(Map wrappers, Closure body) { if (wrappers != null) { - return { - recursiveWrappers(wrappers.keySet().toList(), wrappers, body) - }.call() + recursiveWrappers(wrappers.keySet().toList(), wrappers, body) } else { - return { - body.call() - }.call() + body.call() } } @@ -636,25 +602,19 @@ class ModelInterpreter implements Serializable { */ def recursiveWrappers(List wrapperNames, Map wrappers, Closure body) { if (wrapperNames.isEmpty()) { - return { - body.call() - }.call() + body.call() } else { def thisWrapper = wrapperNames.remove(0) def wrapperArgs = wrappers.get(thisWrapper) if (wrapperArgs != null) { - return { - script."${thisWrapper}"(wrapperArgs) { - recursiveWrappers(wrapperNames, wrappers, body) - } - }.call() + script."${thisWrapper}"(wrapperArgs) { + recursiveWrappers(wrapperNames, wrappers, body) + } } else { - return { - script."${thisWrapper}"() { - recursiveWrappers(wrapperNames, wrappers, body) - } - }.call() + script."${thisWrapper}"() { + recursiveWrappers(wrapperNames, wrappers, body) + } } } } diff --git a/pipeline-model-definition/src/main/resources/org/jenkinsci/plugins/pipeline/modeldefinition/agent/impl/AnyScript.groovy b/pipeline-model-definition/src/main/resources/org/jenkinsci/plugins/pipeline/modeldefinition/agent/impl/AnyScript.groovy index a67ccf2f9..64ea27edf 100644 --- a/pipeline-model-definition/src/main/resources/org/jenkinsci/plugins/pipeline/modeldefinition/agent/impl/AnyScript.groovy +++ b/pipeline-model-definition/src/main/resources/org/jenkinsci/plugins/pipeline/modeldefinition/agent/impl/AnyScript.groovy @@ -26,21 +26,19 @@ package org.jenkinsci.plugins.pipeline.modeldefinition.agent.impl import org.jenkinsci.plugins.pipeline.modeldefinition.agent.CheckoutScript -import org.jenkinsci.plugins.pipeline.modeldefinition.agent.DeclarativeAgentScript +import org.jenkinsci.plugins.pipeline.modeldefinition.agent.DeclarativeAgentScript2 import org.jenkinsci.plugins.workflow.cps.CpsScript -class AnyScript extends DeclarativeAgentScript { +class AnyScript extends DeclarativeAgentScript2 { AnyScript(CpsScript s, Any a) { super(s, a) } @Override - Closure run(Closure body) { - return { - script.node { - CheckoutScript.doCheckout(script, describable, null, body).call() - } + void run(Closure body) { + script.node { + CheckoutScript.doCheckout2(script, describable, null, body) } } } diff --git a/pipeline-model-definition/src/main/resources/org/jenkinsci/plugins/pipeline/modeldefinition/agent/impl/LabelScript.groovy b/pipeline-model-definition/src/main/resources/org/jenkinsci/plugins/pipeline/modeldefinition/agent/impl/LabelScript.groovy index 745b6021d..e18277c07 100644 --- a/pipeline-model-definition/src/main/resources/org/jenkinsci/plugins/pipeline/modeldefinition/agent/impl/LabelScript.groovy +++ b/pipeline-model-definition/src/main/resources/org/jenkinsci/plugins/pipeline/modeldefinition/agent/impl/LabelScript.groovy @@ -27,30 +27,27 @@ package org.jenkinsci.plugins.pipeline.modeldefinition.agent.impl import org.jenkinsci.plugins.pipeline.modeldefinition.agent.CheckoutScript -import org.jenkinsci.plugins.pipeline.modeldefinition.agent.DeclarativeAgentScript +import org.jenkinsci.plugins.pipeline.modeldefinition.agent.DeclarativeAgentScript2 import org.jenkinsci.plugins.workflow.cps.CpsScript -class LabelScript extends DeclarativeAgentScript