Skip to content

Commit 62e3034

Browse files
authored
Merge branch 'master' into FlowExecutionList-JENKINS-67164
2 parents 0ab4515 + 71dd22b commit 62e3034

File tree

2 files changed

+53
-2
lines changed

2 files changed

+53
-2
lines changed

src/main/java/org/jenkinsci/plugins/workflow/cps/EnvActionImpl.java

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
package org.jenkinsci.plugins.workflow.cps;
2626

27+
import com.google.common.util.concurrent.Futures;
28+
import com.google.common.util.concurrent.ListenableFuture;
2729
import groovy.lang.GroovyObjectSupport;
2830
import hudson.EnvVars;
2931
import hudson.Extension;
@@ -32,28 +34,30 @@
3234
import hudson.model.TaskListener;
3335
import hudson.util.LogTaskListener;
3436
import java.io.IOException;
35-
import java.io.Serializable;
3637
import java.util.Collection;
3738
import java.util.Collections;
3839
import java.util.Map;
3940
import java.util.TreeMap;
4041
import java.util.logging.Level;
4142
import java.util.logging.Logger;
4243
import edu.umd.cs.findbugs.annotations.NonNull;
44+
import hudson.model.Queue;
4345
import jenkins.model.RunAction2;
4446
import org.jenkinsci.plugins.workflow.flow.FlowCopier;
4547
import org.jenkinsci.plugins.workflow.flow.FlowExecution;
4648
import org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner;
4749
import org.jenkinsci.plugins.workflow.graph.FlowNode;
50+
import org.jenkinsci.plugins.workflow.pickles.Pickle;
4851
import org.jenkinsci.plugins.workflow.steps.EnvironmentExpander;
4952
import org.jenkinsci.plugins.workflow.support.actions.EnvironmentAction;
53+
import org.jenkinsci.plugins.workflow.support.pickles.SingleTypedPickleFactory;
5054
import org.kohsuke.accmod.Restricted;
5155
import org.kohsuke.accmod.restrictions.DoNotUse;
5256
import org.kohsuke.stapler.export.Exported;
5357
import org.kohsuke.stapler.export.ExportedBean;
5458

5559
@ExportedBean
56-
public class EnvActionImpl extends GroovyObjectSupport implements EnvironmentAction.IncludingOverrides, Serializable, RunAction2 {
60+
public class EnvActionImpl extends GroovyObjectSupport implements EnvironmentAction.IncludingOverrides, RunAction2 {
5761

5862
private static final Logger LOGGER = Logger.getLogger(EnvActionImpl.class.getName());
5963
private static final long serialVersionUID = 1;
@@ -199,4 +203,30 @@ public Collection<EnvironmentContributor> getEnvironmentContributors() {
199203

200204
}
201205

206+
@Extension public static class EnvActionImplPickleFactory extends SingleTypedPickleFactory<EnvActionImpl> {
207+
@Override
208+
protected Pickle pickle(EnvActionImpl object) {
209+
return new EnvActionImplPickle();
210+
}
211+
}
212+
213+
/**
214+
* Prevents multiple instances of {@link EnvActionImpl} from existing for a single Pipeline after a Jenkins restart
215+
* in case {@code env} is serialized into the program.
216+
*/
217+
private static class EnvActionImplPickle extends Pickle {
218+
@Override
219+
public ListenableFuture<?> rehydrate(FlowExecutionOwner owner) {
220+
try {
221+
Queue.Executable executable = owner.getExecutable();
222+
if (executable instanceof Run) {
223+
return Futures.immediateFuture(EnvActionImpl.forRun((Run)executable));
224+
} else {
225+
return Futures.immediateFailedFuture(new IllegalStateException("Invalid executable: " + executable));
226+
}
227+
} catch (IOException e) {
228+
return Futures.immediateFailedFuture(e);
229+
}
230+
}
231+
}
202232
}

src/test/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecutionTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
import org.jenkinsci.plugins.workflow.test.steps.SemaphoreStep;
6464
import static org.hamcrest.MatcherAssert.assertThat;
6565
import static org.hamcrest.Matchers.containsString;
66+
import static org.hamcrest.Matchers.equalTo;
6667
import static org.hamcrest.Matchers.hasItem;
6768
import static org.junit.Assert.assertEquals;
6869
import static org.junit.Assert.assertFalse;
@@ -527,4 +528,24 @@ public boolean isAllowed(String groovyResourceUrl) {
527528
return groovyResourceUrl.endsWith("/trusted/foo.groovy");
528529
}
529530
}
531+
532+
@Issue("JENKINS-45327")
533+
@Test public void envActionImplPickle() throws Throwable {
534+
sessions.then(r -> {
535+
WorkflowJob p = r.createProject(WorkflowJob.class, "p");
536+
p.setDefinition(new CpsFlowDefinition(
537+
"def e = env\n" +
538+
"semaphore('wait')\n" + // An instance of EnvActionImpl is part of the program's state at this point.
539+
"e.foo = 'bar'\n", true)); // Without EnvActionImplPickle, this throws an NPE in EnvActionImpl.setProperty because owner is null.
540+
WorkflowRun b = p.scheduleBuild2(0).waitForStart();
541+
SemaphoreStep.waitForStart("wait/1", b);
542+
});
543+
sessions.then(r -> {
544+
WorkflowJob p = r.jenkins.getItemByFullName("p", WorkflowJob.class);
545+
WorkflowRun b = p.getLastBuild();
546+
SemaphoreStep.success("wait/1", null);
547+
r.assertBuildStatus(Result.SUCCESS, r.waitForCompletion(b));
548+
assertThat(EnvActionImpl.forRun(b).getEnvironment().get("foo"), equalTo("bar"));
549+
});
550+
}
530551
}

0 commit comments

Comments
 (0)