Skip to content

Commit

Permalink
Merge pull request #35 from abayer/jenkins-24141
Browse files Browse the repository at this point in the history
[JENKINS-24141] Implement RunWithSCMMixIn.RunWithSCM
  • Loading branch information
jglick committed May 16, 2017
2 parents 666a710 + a970443 commit 70f444c
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 17 deletions.
2 changes: 1 addition & 1 deletion Jenkinsfile
@@ -1 +1 @@
buildPlugin(jenkinsVersions: [null, '2.32.3'])
buildPlugin()
22 changes: 14 additions & 8 deletions pom.xml
Expand Up @@ -28,7 +28,7 @@
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>2.25</version>
<version>2.27</version>
<relativePath />
</parent>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
Expand Down Expand Up @@ -62,10 +62,10 @@
</pluginRepository>
</pluginRepositories>
<properties>
<jenkins.version>1.642.3</jenkins.version>
<jenkins-test-harness.version>2.19</jenkins-test-harness.version>
<jenkins.version>2.60</jenkins.version>
<java.level>8</java.level>
<no-test-jar>false</no-test-jar>
<workflow-support-plugin.version>2.2</workflow-support-plugin.version>
<workflow-support-plugin.version>2.14</workflow-support-plugin.version>
<scm-api-plugin.version>2.1.1</scm-api-plugin.version>
<git-plugin.version>3.2.0</git-plugin.version>
</properties>
Expand All @@ -83,13 +83,19 @@
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-cps</artifactId>
<version>1.15</version>
<version>2.29</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>structs</artifactId>
<version>1.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-basic-steps</artifactId>
<version>1.15</version>
<version>2.4</version>
<scope>test</scope>
</dependency>
<dependency>
Expand All @@ -102,13 +108,13 @@
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-scm-step</artifactId>
<version>2.2</version>
<version>2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-durable-task-step</artifactId>
<version>2.0</version>
<version>2.11</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down
47 changes: 40 additions & 7 deletions src/main/java/org/jenkinsci/plugins/workflow/job/WorkflowRun.java
Expand Up @@ -28,6 +28,7 @@
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
Expand All @@ -49,10 +50,10 @@
import hudson.model.Run;
import hudson.model.StreamBuildListener;
import hudson.model.TaskListener;
import hudson.model.User;
import hudson.model.listeners.RunListener;
import hudson.model.listeners.SCMListener;
import hudson.scm.ChangeLogSet;
import hudson.scm.RepositoryBrowser;
import hudson.scm.SCM;
import hudson.scm.SCMRevisionState;
import hudson.security.ACL;
Expand All @@ -72,10 +73,12 @@
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
Expand All @@ -94,6 +97,7 @@
import jenkins.model.lazy.BuildReference;
import jenkins.model.lazy.LazyBuildMixIn;
import jenkins.model.queue.AsynchronousExecution;
import jenkins.scm.RunWithSCM;
import jenkins.security.NotReallyRoleSensitiveCallable;
import jenkins.util.Timer;
import org.jenkinsci.plugins.workflow.FilePathUtils;
Expand Down Expand Up @@ -124,7 +128,7 @@

@SuppressWarnings("SynchronizeOnNonFinalField")
@SuppressFBWarnings(value="JLM_JSR166_UTILCONCURRENT_MONITORENTER", justification="completed is an unusual usage")
public final class WorkflowRun extends Run<WorkflowJob,WorkflowRun> implements FlowExecutionOwner.Executable, LazyBuildMixIn.LazyLoadingRun<WorkflowJob,WorkflowRun> {
public final class WorkflowRun extends Run<WorkflowJob,WorkflowRun> implements FlowExecutionOwner.Executable, LazyBuildMixIn.LazyLoadingRun<WorkflowJob,WorkflowRun>, RunWithSCM<WorkflowJob,WorkflowRun> {

private static final Logger LOGGER = Logger.getLogger(WorkflowRun.class.getName());

Expand Down Expand Up @@ -155,6 +159,19 @@ public String url() {

private transient boolean allowKill;

/**
* Cumulative list of people who contributed to the build problem.
*
* <p>
* This is a list of {@link User#getId() user ids} who made a change
* since the last non-broken build. Can be null (which should be
* treated like empty set), because of the compatibility.
*
* <p>
* This field is semi-final --- once set the value will never be modified.
*/
private volatile Set<String> culprits;

/**
* Flag for whether or not the build has completed somehow.
* Non-null soon after the build starts or is reloaded from disk.
Expand Down Expand Up @@ -716,6 +733,7 @@ public boolean hasntStartedYet() {
return checkouts;
}

@Override
@Exported
public synchronized List<ChangeLogSet<? extends ChangeLogSet.Entry>> getChangeSets() {
if (changeSets == null) {
Expand All @@ -724,7 +742,7 @@ public synchronized List<ChangeLogSet<? extends ChangeLogSet.Entry>> getChangeSe
if (co.changelogFile != null && co.changelogFile.isFile()) {
try {
ChangeLogSet<? extends ChangeLogSet.Entry> changeLogSet =
co.scm.createChangeLogParser().parse(this, getEffectiveBrowser(co.scm), co.changelogFile);
co.scm.createChangeLogParser().parse(this, co.scm.getEffectiveBrowser(), co.changelogFile);
if (!changeLogSet.isEmptySet()) {
changeSets.add(changeLogSet);
}
Expand All @@ -737,10 +755,25 @@ public synchronized List<ChangeLogSet<? extends ChangeLogSet.Entry>> getChangeSe
return changeSets;
}

/** Replacement for {@link SCM#getEffectiveBrowser} to work around JENKINS-35098. TODO 2.7.3+ delete */
private static RepositoryBrowser<?> getEffectiveBrowser(SCM scm) {
RepositoryBrowser<?> b = scm.getBrowser();
return b != null ? b : scm.guessBrowser();
@Override
@CheckForNull public Set<String> getCulpritIds() {
if (shouldCalculateCulprits()) {
HashSet<String> tempCulpritIds = new HashSet<>();
for (User u : getCulprits()) {
tempCulpritIds.add(u.getId());
}
if (isBuilding()) {
return ImmutableSortedSet.copyOf(tempCulpritIds);
} else {
culprits = ImmutableSortedSet.copyOf(tempCulpritIds);
}
}
return culprits;
}

@Override
public boolean shouldCalculateCulprits() {
return isBuilding() || culprits == null;
}

@RequirePOST
Expand Down
Expand Up @@ -24,6 +24,8 @@

package org.jenkinsci.plugins.workflow.job;

import com.google.common.collect.ImmutableSet;
import hudson.AbortException;
import hudson.model.BallColor;
import hudson.model.Executor;
import hudson.model.Item;
Expand Down Expand Up @@ -107,7 +109,7 @@ public class WorkflowRunTest {

@Test public void funnyParameters() throws Exception {
WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition("echo \"a.b=${binding['a.b']}\"", true));
p.setDefinition(new CpsFlowDefinition("echo \"a.b=${params['a.b']}\"", true));
p.addProperty(new ParametersDefinitionProperty(new StringParameterDefinition("a.b", null)));
WorkflowRun b = r.assertBuildStatusSuccess(p.scheduleBuild2(0, new ParametersAction(new StringParameterValue("a.b", "v"))));
r.assertLogContains("a.b=v", b);
Expand Down Expand Up @@ -372,4 +374,57 @@ public void globalNodePropertiesInEnv() throws Exception {
r.assertLogContains("KEY is " + envProp.getEnvVars().get("KEY"), b);
}

@Test
@Issue("JENKINS-24141")
public void culprits() throws Exception {
WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition("import org.jvnet.hudson.test.FakeChangeLogSCM\n" +
"semaphore 'waitFirst'\n" +
"def testScm = new FakeChangeLogSCM()\n" +
"testScm.addChange().withAuthor(/alice$BUILD_NUMBER/)\n" +
"node {\n" +
" checkout(testScm)\n" +
" semaphore 'waitSecond'\n" +
" def secondScm = new FakeChangeLogSCM()\n" +
" secondScm.addChange().withAuthor(/bob$BUILD_NUMBER/)\n" +
" checkout(secondScm)\n" +
" semaphore 'waitThird'\n" +
" def thirdScm = new FakeChangeLogSCM()\n" +
" thirdScm.addChange().withAuthor(/charlie$BUILD_NUMBER/)\n" +
" checkout(thirdScm)\n" +
"}\n", false));

WorkflowRun b1 = p.scheduleBuild2(0).waitForStart();

SemaphoreStep.waitForStart("waitFirst/1", b1);
assertTrue(b1.getCulpritIds().isEmpty());
SemaphoreStep.success("waitFirst/1", null);

SemaphoreStep.waitForStart("waitSecond/1", b1);
assertEquals(ImmutableSet.of("alice1"), b1.getCulpritIds());
SemaphoreStep.success("waitSecond/1", null);

SemaphoreStep.waitForStart("waitThird/1", b1);
assertEquals(ImmutableSet.of("alice1", "bob1"), b1.getCulpritIds());
SemaphoreStep.failure("waitThird/1", new AbortException());

r.assertBuildStatus(Result.FAILURE, r.waitForCompletion(b1));

WorkflowRun b2 = p.scheduleBuild2(0).waitForStart();

SemaphoreStep.waitForStart("waitFirst/2", b2);
assertEquals(ImmutableSet.of("alice1", "bob1"), b2.getCulpritIds());
SemaphoreStep.success("waitFirst/2", null);

SemaphoreStep.waitForStart("waitSecond/2", b2);
assertEquals(ImmutableSet.of("alice1", "bob1", "alice2"), b2.getCulpritIds());
SemaphoreStep.success("waitSecond/2", null);

SemaphoreStep.waitForStart("waitThird/2", b2);
assertEquals(ImmutableSet.of("alice1", "bob1", "alice2", "bob2"), b2.getCulpritIds());
SemaphoreStep.success("waitThird/2", b2);

r.assertBuildStatusSuccess(r.waitForCompletion(b2));
assertEquals(ImmutableSet.of("alice1", "bob1", "alice2", "bob2", "charlie2"), b2.getCulpritIds());
}
}

0 comments on commit 70f444c

Please sign in to comment.