diff --git a/Jenkinsfile b/Jenkinsfile index 70e42115..c5d64b97 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,6 +1,5 @@ buildPlugin(useAci: true, configurations: [ [platform: 'linux', jdk: '8'], [platform: 'windows', jdk: '8'], - [platform: 'linux', jdk: '11'], - [platform: 'windows', jdk: '11'] + [platform: 'linux', jdk: '11'] ]) diff --git a/pom.xml b/pom.xml index f98eab59..2834b44a 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ org.jenkins-ci.plugins plugin - 3.54 + 4.6 org.jenkins-ci.plugins.workflow @@ -64,49 +64,51 @@ 2.36 -SNAPSHOT - 2.176.1 + 2.248 8 true - 2.20 - 3.3 + + + + io.jenkins.tools.bom + bom-2.235.x + 11 + import + pom + + + org.jenkins-ci.plugins.workflow workflow-step-api - ${workflow-step-api-plugin.version} org.jenkins-ci.plugins durable-task - 1.33 org.jenkins-ci.plugins.workflow workflow-api - 2.33 org.jenkins-ci.plugins.workflow workflow-support - ${workflow-support-plugin.version} org.jenkins-ci.plugins.workflow workflow-cps - 2.70 test org.jenkins-ci.plugins.workflow workflow-job - 2.31 test org.jenkins-ci.plugins.workflow workflow-basic-steps - 2.14 test @@ -118,43 +120,42 @@ org.jenkins-ci.plugins.workflow workflow-step-api - ${workflow-step-api-plugin.version} tests test org.jenkins-ci.plugins.workflow workflow-support - ${workflow-support-plugin.version} tests test org.jenkins-ci.plugins credentials-binding - 1.17 test org.jenkins-ci.plugins.workflow workflow-scm-step - 2.7 test org.jenkins-ci.plugins script-security - 1.58 org.jenkins-ci.plugins structs - 1.18 org.jenkins-ci.plugins scm-api - 2.2.6 + + + io.jenkins.plugins + generic-environment-filters + 1.2 + test diff --git a/src/main/java/org/jenkinsci/plugins/workflow/steps/durable_task/DurableTaskStep.java b/src/main/java/org/jenkinsci/plugins/workflow/steps/durable_task/DurableTaskStep.java index 061b1bac..b33d543e 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/steps/durable_task/DurableTaskStep.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/steps/durable_task/DurableTaskStep.java @@ -35,6 +35,7 @@ import hudson.init.Terminator; import hudson.model.Node; import hudson.model.Result; +import hudson.model.Run; import hudson.model.TaskListener; import hudson.remoting.Channel; import hudson.remoting.ChannelClosedException; @@ -61,6 +62,7 @@ import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import jenkins.model.Jenkins; +import jenkins.tasks.filters.EnvVarsFilterableBuilder; import jenkins.util.Timer; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; @@ -96,7 +98,7 @@ * When the process exits, the status code is also written to a file and ultimately results in the step passing or failing. *

Tasks can also be run on the master node, which differs only in that there is no possibility of a network failure. */ -public abstract class DurableTaskStep extends Step { +public abstract class DurableTaskStep extends Step implements EnvVarsFilterableBuilder { private static final Logger LOGGER = Logger.getLogger(DurableTaskStep.class.getName()); @@ -312,6 +314,7 @@ static final class Execution extends AbstractStepExecutionImpl implements Runnab durableTask.defaultCharset(); } Launcher launcher = context.get(Launcher.class); + launcher.prepareFilterRules(context.get(Run.class), step); LOGGER.log(Level.FINE, "launching task against {0} using {1}", new Object[] {ws.getChannel(), launcher}); try { controller = durableTask.launch(context.get(EnvVars.class), ws, launcher, listener); diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/ExecutorStepExecution.java b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/ExecutorStepExecution.java index 39268967..885b96b2 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/ExecutorStepExecution.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/ExecutorStepExecution.java @@ -836,8 +836,9 @@ private final class PlaceholderExecutable implements ContinuableExecutable, Acce FilePath workspace = lease.path; // Cf. AbstractBuild.getEnvironment: env.put("WORKSPACE", workspace.getRemote()); - if (workspace.getParent() != null) { - env.put("WORKSPACE_TMP", WorkspaceList.tempDir(workspace).getRemote()); // JENKINS-60634 + final FilePath tempDir = WorkspaceList.tempDir(workspace); + if (tempDir != null) { + env.put("WORKSPACE_TMP", tempDir.getRemote()); // JENKINS-60634 } FlowNode flowNode = context.get(FlowNode.class); if (flowNode != null) { diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/WorkspaceStepExecution.java b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/WorkspaceStepExecution.java index ccfdf10c..2d2ca789 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/WorkspaceStepExecution.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/WorkspaceStepExecution.java @@ -62,8 +62,9 @@ public boolean start() throws Exception { getContext().get(TaskListener.class).getLogger().println("Running in " + workspace); Map env = new HashMap<>(); env.put("WORKSPACE", workspace.getRemote()); - if (workspace.getParent() != null) { - env.put("WORKSPACE_TMP", WorkspaceList.tempDir(workspace).getRemote()); + final FilePath tempDir = WorkspaceList.tempDir(workspace); + if (tempDir != null) { + env.put("WORKSPACE_TMP", tempDir.getRemote()); } getContext().newBodyInvoker() .withContexts( diff --git a/src/test/java/org/jenkinsci/plugins/workflow/steps/durable_task/ShellStepTest.java b/src/test/java/org/jenkinsci/plugins/workflow/steps/durable_task/ShellStepTest.java index c0e54af5..7f30fcfa 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/steps/durable_task/ShellStepTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/steps/durable_task/ShellStepTest.java @@ -19,6 +19,7 @@ import hudson.model.BooleanParameterDefinition; import hudson.model.BooleanParameterValue; import hudson.model.BuildListener; +import hudson.model.Descriptor; import hudson.model.FreeStyleProject; import hudson.model.Node; import hudson.model.ParametersAction; @@ -32,6 +33,9 @@ import hudson.slaves.EnvironmentVariablesNodeProperty; import hudson.tasks.BatchFile; import hudson.tasks.Shell; +import io.jenkins.plugins.environment_filter_utils.util.BuilderUtil; +import io.jenkins.plugins.generic_environment_filters.RemoveSpecificVariablesFilter; +import io.jenkins.plugins.generic_environment_filters.VariableContributingFilter; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; @@ -54,10 +58,13 @@ import java.util.logging.Level; import java.util.logging.LogRecord; import javax.annotation.CheckForNull; +import jenkins.tasks.filters.EnvVarsFilterGlobalConfiguration; import jenkins.util.JenkinsJVM; import org.apache.commons.lang.StringUtils; import static org.hamcrest.Matchers.*; + +import org.hamcrest.MatcherAssert; import org.jenkinsci.plugins.durabletask.FileMonitoringTask; import org.jenkinsci.plugins.workflow.actions.ArgumentsAction; @@ -192,6 +199,10 @@ public void abort() throws Exception { b.getExecutor().interrupt(); + // It can take a while for the process to exit on Windows (see JENKINS-59152), so we wait for the build to + // complete and confirm that the process is no longer running after the build has already completed. + j.assertBuildStatus(Result.ABORTED, j.waitForCompletion(b)); + // touching should have stopped final long refTimestamp = Files.getLastModifiedTime(tmp).toMillis(); ensureForWhile(5000, tmp, tmpFile -> { @@ -201,8 +212,6 @@ public void abort() throws Exception { throw new UncheckedIOException(e); } }); - - j.assertBuildStatus(Result.ABORTED, j.waitForCompletion(b)); } @Issue("JENKINS-41339") @@ -724,6 +733,36 @@ private static final class HelloNote extends ConsoleNote> { j.waitForMessage("Timeout has been exceeded", b); // TODO assertLogContains fails unless a sleep is introduced; possible race condition in waitForCompletion } + @Issue("JENKINS-62014") + @Test public void envVarFilters() throws Exception { + EnvVarsFilterGlobalConfiguration.getAllActivatedGlobalRules().add(new RemoveSpecificVariablesFilter("FOO")); + EnvVarsFilterGlobalConfiguration.getAllActivatedGlobalRules().add(new VariableContributingFilter("BAZ", "QUX")); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition(new CpsFlowDefinition( + "node() {\n" + + " withEnv(['FOO=BAR']) {\n" + + " if (isUnix()) {\n" + + " sh('echo FOO=$FOO and BAZ=$BAZ')\n" + + " } else {\n" + + " bat('ECHO FOO=%FOO% and BAZ=%BAZ%')\n" + + " }\n" + + " }\n" + + "}", true)); + WorkflowRun b = j.buildAndAssertSuccess(p); + j.assertLogContains("FOO=", b); + j.assertLogNotContains("FOO=BAR", b); + j.assertLogContains("BAZ=QUX", b); + } + + @Issue("JENKINS-62014") + @Test public void ensureTypes() throws Exception { + final List descriptors = BuilderUtil.allDescriptors(); + + MatcherAssert.assertThat(descriptors , containsInAnyOrder( + j.jenkins.getDescriptor(Shell.class), j.jenkins.getDescriptor(BatchFile.class), + j.jenkins.getDescriptor(BatchScriptStep.class), j.jenkins.getDescriptor(PowershellScriptStep.class), j.jenkins.getDescriptor(ShellStep.class), j.jenkins.getDescriptor(PowerShellCoreScriptStep.class))); + } + /** * Asserts that the predicate remains true up to the given timeout. */ diff --git a/src/test/java/org/jenkinsci/plugins/workflow/support/steps/ExecutorStepTest.java b/src/test/java/org/jenkinsci/plugins/workflow/support/steps/ExecutorStepTest.java index 06538bab..5dc01db9 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/support/steps/ExecutorStepTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/support/steps/ExecutorStepTest.java @@ -339,13 +339,14 @@ private void startJnlpProc() throws Exception { new FileOutputStream(f1).close(); p.setDefinition(new CpsFlowDefinition( "node('dumbo') {\n" + - " sh 'touch \"" + f2 + "\"; while [ -f \"" + f1 + "\" ]; do sleep 1; done; echo finished waiting; rm \"" + f2 + "\"'\n" + + " sh 'touch \"" + f2 + "\"; while [ -f \"" + f1 + "\" ]; do echo waiting; sleep 1; done; echo finished waiting; rm \"" + f2 + "\"'\n" + " echo 'OK, done'\n" + "}", true)); WorkflowRun b = p.scheduleBuild2(0).waitForStart(); while (!f2.isFile()) { Thread.sleep(100); } + story.j.waitForMessage("waiting", b); assertTrue(b.isBuilding()); Computer c = s.toComputer(); assertNotNull(c); @@ -392,7 +393,7 @@ public void evaluate() throws Throwable { new FileOutputStream(f1).close(); p.setDefinition(new CpsFlowDefinition( "node('dumbo') {\n" + - " sh 'touch \"" + f2 + "\"; while [ -f \"" + f1 + "\" ]; do sleep 1; done; echo finished waiting; rm \"" + f2 + "\"'\n" + + " sh 'touch \"" + f2 + "\"; while [ -f \"" + f1 + "\" ]; do echo waiting; sleep 1; done; echo finished waiting; rm \"" + f2 + "\"'\n" + " sh 'echo Back again'\n" + " echo 'OK, done'\n" + "}", true)); @@ -401,6 +402,7 @@ public void evaluate() throws Throwable { while (!f2.isFile()) { Thread.sleep(100); } + story.j.waitForMessage("waiting", b); LOGGER.info("f2 created, first sh running"); assertTrue(b.isBuilding()); Computer computer = s.toComputer();