Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fixes to JENKINS-50784 to ensure we hard-fetch FlowExecutions when we…
… need to
  • Loading branch information
svanoort committed Apr 19, 2018
1 parent 564a12c commit 64848b1
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 8 deletions.
3 changes: 2 additions & 1 deletion pom.xml
Expand Up @@ -141,7 +141,8 @@
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-job</artifactId>
<version>2.18</version>
<!-- Temp SNAPSHOT from https://github.com/jenkinsci/workflow-job-plugin/pull/95 -->
<version>2.20-20180419.201134-1</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down
Expand Up @@ -1776,7 +1776,7 @@ public void autopersist(@Nonnull FlowNode n) throws IOException {
if (run instanceof FlowExecutionOwner.Executable) {
FlowExecutionOwner owner = ((FlowExecutionOwner.Executable) run).asFlowExecutionOwner();
if (owner != null) {
FlowExecution exec = owner.getOrNull();
FlowExecution exec = owner.get();
if (exec instanceof CpsFlowExecution) {
Map<String, Long> timings = ((CpsFlowExecution) exec).timings;
if (timings != null) {
Expand Down
Expand Up @@ -106,7 +106,8 @@ private ReplayAction(Run run) {
return isEnabled() || isRebuildEnabled() ? "replay" : null;
}

private @CheckForNull CpsFlowExecution getExecution() {
/** Poke for an execution without blocking - may be null if run is very fresh or has not lazy-loaded yet. */
private @CheckForNull CpsFlowExecution getExecutionLazy() {
FlowExecutionOwner owner = ((FlowExecutionOwner.Executable) run).asFlowExecutionOwner();
if (owner == null) {
return null;
Expand All @@ -115,6 +116,21 @@ private ReplayAction(Run run) {
return exec instanceof CpsFlowExecution ? (CpsFlowExecution) exec : null;
}

/** Fetches execution, blocking if needed while we wait for some of the loading process. */
private @CheckForNull CpsFlowExecution getExecutionBlocking() {
FlowExecutionOwner owner = ((FlowExecutionOwner.Executable) run).asFlowExecutionOwner();
if (owner == null) {
return null;
}
try {
FlowExecution exec = owner.get();
return exec instanceof CpsFlowExecution ? (CpsFlowExecution) exec : null;
} catch (IOException ioe) {
LOGGER.log(Level.WARNING, "Error fetching execution for replay", ioe);
}
return null;
}

/* accessible to Jelly */ public boolean isRebuildEnabled() {
if (!run.hasPermission(Item.BUILD)) {
return false;
Expand All @@ -123,7 +139,7 @@ private ReplayAction(Run run) {
return false;
}

return getExecution() != null;
return getExecutionLazy() != null;
}

/* accessible to Jelly */ public boolean isEnabled() {
Expand All @@ -135,7 +151,7 @@ private ReplayAction(Run run) {
return false;
}

CpsFlowExecution exec = getExecution();
CpsFlowExecution exec = getExecutionLazy();
if (exec == null) {
return false;
}
Expand All @@ -149,13 +165,13 @@ private ReplayAction(Run run) {

/** @see CpsFlowExecution#getScript */
/* accessible to Jelly */ public String getOriginalScript() {
CpsFlowExecution execution = getExecution();
CpsFlowExecution execution = getExecutionBlocking();
return execution != null ? execution.getScript() : "???";
}

/** @see CpsFlowExecution#getLoadedScripts */
/* accessible to Jelly */ public Map<String,String> getOriginalLoadedScripts() {
CpsFlowExecution execution = getExecution();
CpsFlowExecution execution = getExecutionBlocking();
if (execution == null) { // ?
return Collections.<String,String>emptyMap();
}
Expand Down Expand Up @@ -228,7 +244,7 @@ public void doRebuild(StaplerRequest req, StaplerResponse rsp) throws ServletExc
*/
public @CheckForNull Queue.Item run2(@Nonnull String replacementMainScript, @Nonnull Map<String,String> replacementLoadedScripts) {
List<Action> actions = new ArrayList<Action>();
CpsFlowExecution execution = getExecution();
CpsFlowExecution execution = getExecutionBlocking();
if (execution == null) {
return null;
}
Expand Down
Expand Up @@ -53,10 +53,13 @@
import org.hamcrest.Matchers;
import static org.hamcrest.Matchers.*;
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
import org.jenkinsci.plugins.workflow.flow.FlowExecution;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
import org.jenkinsci.plugins.workflow.test.steps.SemaphoreStep;
import static org.junit.Assert.*;

import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Rule;
Expand Down Expand Up @@ -133,6 +136,34 @@ public class ReplayActionTest {
});
}

@Issue("JENKINS-50784")
@Test public void lazyLoadExecutionStillReplayable() throws Exception {
story.then( r-> {
WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition("echo 'I did a thing'", false));
// Start off with a simple run of the first script.
r.buildAndAssertSuccess(p);

r.jenkins.setSecurityRealm(r.createDummySecurityRealm());
GlobalMatrixAuthorizationStrategy gmas = new GlobalMatrixAuthorizationStrategy();
gmas.add(Jenkins.ADMINISTER, "admin");
});
story.then( r-> {
WorkflowJob job = r.jenkins.getItemByFullName("p", WorkflowJob.class);
WorkflowRun run = job.getLastBuild();
JenkinsRule.WebClient wc = r.createWebClient();
Assert.assertNull(run.asFlowExecutionOwner().getOrNull());
canReplay(run, "admin");
canRebuild(run, "admin");
Assert.assertNull(run.asFlowExecutionOwner().getOrNull());

FlowExecution exec = run.getExecution();
Assert.assertNotNull(run.asFlowExecutionOwner().getOrNull());
canReplay(run, "admin");
canRebuild(run, "admin");
});
}

@Initializer(after=InitMilestone.EXTENSIONS_AUGMENTED, before=InitMilestone.JOB_LOADED) // same time as Jenkins global config is loaded (e.g., AuthorizationStrategy)
public static void assertPermissionId() {
String thePermissionId = "hudson.model.Run.Replay";
Expand Down

0 comments on commit 64848b1

Please sign in to comment.