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();