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"; + } + }; + } + }