diff --git a/pom.xml b/pom.xml
index 5eba6292..fcf86b06 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,8 +28,8 @@
org.jenkins-ci.plugins
plugin
- 2.5
-
+ 2.11
+
org.jenkins-ci.plugins.workflow
workflow-support
@@ -52,23 +52,24 @@
repo.jenkins-ci.org
- http://repo.jenkins-ci.org/public/
+ https://repo.jenkins-ci.org/public/
repo.jenkins-ci.org
- http://repo.jenkins-ci.org/public/
+ https://repo.jenkins-ci.org/public/
1.642.3
+ 2.11
${project.groupId}
workflow-step-api
- 1.15
+ 2.2
${project.groupId}
@@ -78,7 +79,7 @@
org.jenkins-ci.plugins
script-security
- 1.16
+ 1.21
org.jboss.marshalling
@@ -88,7 +89,7 @@
${project.groupId}
workflow-step-api
- 1.15
+ 2.2
tests
test
@@ -113,7 +114,19 @@
org.jenkins-ci.plugins.workflow
workflow-cps
- 1.15
+ 2.9
+ test
+
+
+ org.jenkins-ci.plugins.workflow
+ workflow-scm-step
+ 2.2
+ test
+
+
+ org.jenkins-ci.plugins.workflow
+ workflow-durable-task-step
+ 2.3
test
@@ -128,6 +141,26 @@
1.15
test
+
+ org.jenkins-ci.plugins
+ git
+ 2.5.0
+ test
+
+
+ org.jenkins-ci.plugins
+ git
+ 2.5.0
+ tests
+ test
+
+
+ org.jenkins-ci.plugins.workflow
+ workflow-scm-step
+ 2.2
+ tests
+ test
+
diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/build/RunWrapper.java b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/build/RunWrapper.java
index 8c068f18..71f0fc41 100644
--- a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/build/RunWrapper.java
+++ b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/build/RunWrapper.java
@@ -28,10 +28,12 @@
import hudson.model.AbstractBuild;
import hudson.model.Result;
import hudson.model.Run;
+import hudson.scm.ChangeLogSet;
import hudson.security.ACL;
import java.io.IOException;
import java.io.Serializable;
import java.util.Collections;
+import java.util.List;
import java.util.Map;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -182,4 +184,14 @@ public String getId() throws AbortException {
return build().getAbsoluteUrl();
}
+ @Whitelisted
+ public List> getChangeSets() throws Exception {
+ Run,?> build = build();
+ try { // TODO JENKINS-24141 should not need to use reflection here
+ return (List) build.getClass().getMethod("getChangeSets").invoke(build);
+ } catch (NoSuchMethodException x) {
+ return Collections.emptyList();
+ }
+ }
+
}
diff --git a/src/test/java/org/jenkinsci/plugins/workflow/support/steps/build/RunWrapperTest.java b/src/test/java/org/jenkinsci/plugins/workflow/support/steps/build/RunWrapperTest.java
index 9e7c3707..21327522 100644
--- a/src/test/java/org/jenkinsci/plugins/workflow/support/steps/build/RunWrapperTest.java
+++ b/src/test/java/org/jenkinsci/plugins/workflow/support/steps/build/RunWrapperTest.java
@@ -25,6 +25,10 @@
package org.jenkinsci.plugins.workflow.support.steps.build;
import hudson.model.Result;
+import java.util.regex.Pattern;
+import jenkins.plugins.git.GitSampleRepoRule;
+import org.hamcrest.Matcher;
+import org.hamcrest.core.SubstringMatcher;
import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval;
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
@@ -37,6 +41,7 @@
import org.junit.runners.model.Statement;
import org.jvnet.hudson.test.BuildWatcher;
import org.jvnet.hudson.test.Issue;
+import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.RestartableJenkinsRule;
@Issue("JENKINS-26834")
@@ -44,6 +49,8 @@ public class RunWrapperTest {
@ClassRule public static BuildWatcher buildWatcher = new BuildWatcher();
@Rule public RestartableJenkinsRule r = new RestartableJenkinsRule();
+ @Rule public GitSampleRepoRule sampleRepo1 = new GitSampleRepoRule();
+ @Rule public GitSampleRepoRule sampleRepo2 = new GitSampleRepoRule();
@Test public void historyAndPickling() {
r.addStep(new Statement() {
@@ -99,4 +106,58 @@ public class RunWrapperTest {
});
}
+ @Issue("JENKINS-30412")
+ @Test public void getChangeSets() {
+ r.addStep(new Statement() {
+ @Override public void evaluate() throws Throwable {
+ sampleRepo1.init();
+ sampleRepo2.init();
+ WorkflowJob p = r.j.jenkins.createProject(WorkflowJob.class, "p");
+ p.setDefinition(new CpsFlowDefinition(
+ "node {dir('1') {git($/" + sampleRepo1 + "/$)}; dir('2') {git($/" + sampleRepo2 + "/$)}}\n" +
+ "echo(/changeSets: ${summarize currentBuild}/)\n" +
+ "@NonCPS def summarize(b) {\n" +
+ " b.changeSets.collect {cs ->\n" +
+ " /kind=${cs.kind}; entries=/ + cs.collect {entry ->\n" +
+ " /${entry.commitId} by ${entry.author.id} ~ ${entry.author.fullName} on ${new Date(entry.timestamp)}: ${entry.msg}: / + entry.affectedFiles.collect {file ->\n" +
+ " /${file.editType.name} ${file.path}/\n" +
+ " }.join('; ')\n" +
+ " }.join(', ')\n" +
+ " }.join(' & ')\n" +
+ "}", true));
+ r.j.assertLogContains("changeSets: ", r.j.assertBuildStatusSuccess(p.scheduleBuild2(0)));
+ sampleRepo1.write("onefile", "stuff");
+ sampleRepo1.git("add", "onefile");
+ sampleRepo1.git("commit", "--message=stuff");
+ assertThat(JenkinsRule.getLog(r.j.assertBuildStatusSuccess(p.scheduleBuild2(0))), containsRegexp(
+ "changeSets: kind=git; entries=[a-f0-9]{40} by .+ ~ .+ on .+: stuff: add onefile"));
+ sampleRepo1.write("onefile", "more stuff");
+ sampleRepo1.write("anotherfile", "stuff");
+ sampleRepo1.git("add", "onefile", "anotherfile");
+ sampleRepo1.git("commit", "--message=more stuff");
+ sampleRepo1.write("onefile", "amended");
+ sampleRepo1.git("add", "onefile");
+ sampleRepo1.git("commit", "--message=amended");
+ sampleRepo2.write("elsewhere", "stuff");
+ sampleRepo2.git("add", "elsewhere");
+ sampleRepo2.git("commit", "--message=second repo");
+ assertThat(JenkinsRule.getLog(r.j.assertBuildStatusSuccess(p.scheduleBuild2(0))), containsRegexp(
+ "changeSets: kind=git; entries=[a-f0-9]{40} by .+ ~ .+ on .+: more stuff: (edit onefile; add anotherfile|add anotherfile; edit onefile), " +
+ "[a-f0-9]{40} by .+ ~ .+ on .+: amended: edit onefile & " +
+ "kind=git; entries=[a-f0-9]{40} by .+ ~ .+ on .+: second repo: add elsewhere"));
+ }
+ });
+ }
+ // Like org.hamcrest.text.MatchesPattern.matchesPattern(String) but doing a substring, not whole-string, match:
+ private static Matcher containsRegexp(final String rx) {
+ return new SubstringMatcher(rx) {
+ @Override protected boolean evalSubstringOf(String string) {
+ return Pattern.compile(rx).matcher(string).find();
+ }
+ @Override protected String relationship() {
+ return "containing the regexp";
+ }
+ };
+ }
+
}