diff --git a/src/main/java/hudson/plugins/git/GitSCM.java b/src/main/java/hudson/plugins/git/GitSCM.java index 085c0f5670..aa72551f11 100644 --- a/src/main/java/hudson/plugins/git/GitSCM.java +++ b/src/main/java/hudson/plugins/git/GitSCM.java @@ -1163,7 +1163,13 @@ public EnvVars getEnvironment() { for (GitSCMExtension ext : extensions) { rev = ext.decorateRevisionToBuild(this,build,git,listener,marked,rev); } - Build revToBuild = new Build(marked, rev, build.getNumber(), null); + + Revision revToDisplay = rev; + for (GitSCMExtension ext : extensions) { + revToDisplay = ext.decorateRevisionToDisplay(revToDisplay, marked); + } + + Build revToBuild = new Build(marked, rev, build.getNumber(), null, revToDisplay); buildData.saveBuild(revToBuild); if (buildData.getBuildsByBranchName().size() >= 100) { diff --git a/src/main/java/hudson/plugins/git/UserMergeOptions.java b/src/main/java/hudson/plugins/git/UserMergeOptions.java index e4ff9915a2..628a9e8b35 100644 --- a/src/main/java/hudson/plugins/git/UserMergeOptions.java +++ b/src/main/java/hudson/plugins/git/UserMergeOptions.java @@ -28,6 +28,7 @@ public class UserMergeOptions extends AbstractDescribableImpl private final String mergeTarget; private String mergeStrategy; private MergeCommand.GitPluginFastForwardMode fastForwardMode; + private DisplayRevision displayRevision; /** * @deprecated use the new constructor that allows to set the fast forward mode. @@ -40,6 +41,11 @@ public UserMergeOptions(String mergeRemote, String mergeTarget, String mergeStra this(mergeRemote, mergeTarget, mergeStrategy, MergeCommand.GitPluginFastForwardMode.FF); } + public UserMergeOptions(String mergeRemote, String mergeTarget, String mergeStrategy, + MergeCommand.GitPluginFastForwardMode fastForwardMode) { + this(mergeRemote, mergeTarget, mergeStrategy, MergeCommand.GitPluginFastForwardMode.FF, DisplayRevision.MERGED); + } + /** * @param mergeRemote remote name used for merge * @param mergeTarget remote branch to be merged into current branch @@ -47,11 +53,12 @@ public UserMergeOptions(String mergeRemote, String mergeTarget, String mergeStra * @param fastForwardMode fast forward mode */ public UserMergeOptions(String mergeRemote, String mergeTarget, String mergeStrategy, - MergeCommand.GitPluginFastForwardMode fastForwardMode) { + MergeCommand.GitPluginFastForwardMode fastForwardMode, DisplayRevision displayRevision) { this.mergeRemote = mergeRemote; this.mergeTarget = mergeTarget; this.mergeStrategy = mergeStrategy; this.fastForwardMode = fastForwardMode; + this.displayRevision = displayRevision; } @DataBoundConstructor @@ -124,6 +131,18 @@ public void setFastForwardMode(MergeCommand.GitPluginFastForwardMode fastForward this.fastForwardMode = fastForwardMode; } + public DisplayRevision getDisplayRevision() { + for (DisplayRevision revision : DisplayRevision.values()) + if (revision.equals(displayRevision)) + return revision; + return DisplayRevision.MERGED; + } + + @DataBoundSetter + public void setDisplayRevision(DisplayRevision displayRevision) { + this.displayRevision = displayRevision; + } + @Override public String toString() { return "UserMergeOptions{" + @@ -131,6 +150,7 @@ public String toString() { ", mergeTarget='" + mergeTarget + '\'' + ", mergeStrategy='" + getMergeStrategy().name() + '\'' + ", fastForwardMode='" + getFastForwardMode().name() + '\'' + + ", displayRevision='" + getDisplayRevision().name() + '\'' + '}'; } @@ -148,12 +168,13 @@ public boolean equals(Object o) { return Objects.equals(mergeRemote, that.mergeRemote) && Objects.equals(mergeTarget, that.mergeTarget) && Objects.equals(mergeStrategy, that.mergeStrategy) - && Objects.equals(fastForwardMode, that.fastForwardMode); + && Objects.equals(fastForwardMode, that.fastForwardMode) + && Objects.equals(displayRevision, that.displayRevision); } @Override public int hashCode() { - return Objects.hash(mergeRemote, mergeTarget, mergeStrategy, fastForwardMode); + return Objects.hash(mergeRemote, mergeTarget, mergeStrategy, fastForwardMode, displayRevision); } @Extension @@ -175,5 +196,15 @@ public Map customInstantiate(Map arguments) { } } + public static enum DisplayRevision { + MERGED, + SOURCE_BRANCH; + + private DisplayRevision() { + } + public String toString() { + return this.name().toLowerCase(Locale.ENGLISH); + } + } } diff --git a/src/main/java/hudson/plugins/git/extensions/GitSCMExtension.java b/src/main/java/hudson/plugins/git/extensions/GitSCMExtension.java index af87919873..b6e1ec20d4 100644 --- a/src/main/java/hudson/plugins/git/extensions/GitSCMExtension.java +++ b/src/main/java/hudson/plugins/git/extensions/GitSCMExtension.java @@ -372,4 +372,9 @@ public boolean enableMultipleRevisionDetection() { public GitSCMExtensionDescriptor getDescriptor() { return (GitSCMExtensionDescriptor) super.getDescriptor(); } + + //What should be API of this method? + public Revision decorateRevisionToDisplay(Revision revToDisplay, Revision marked) { + return revToDisplay; + } } diff --git a/src/main/java/hudson/plugins/git/extensions/impl/PreBuildMerge.java b/src/main/java/hudson/plugins/git/extensions/impl/PreBuildMerge.java index eadd0b56cd..10990e705c 100644 --- a/src/main/java/hudson/plugins/git/extensions/impl/PreBuildMerge.java +++ b/src/main/java/hudson/plugins/git/extensions/impl/PreBuildMerge.java @@ -128,6 +128,12 @@ public Revision decorateRevisionToBuild(GitSCM scm, Run build, GitClient g return mergeRevision; } + @Override + //What should be API of this method? + public Revision decorateRevisionToDisplay(Revision revToDisplay, Revision marked) { + return options.getDisplayRevision() == UserMergeOptions.DisplayRevision.SOURCE_BRANCH ? marked : revToDisplay; + } + @Override public void decorateMergeCommand(GitSCM scm, Run build, GitClient git, TaskListener listener, MergeCommand cmd) throws IOException, InterruptedException, GitException { if (options.getMergeStrategy() != null) { diff --git a/src/main/java/hudson/plugins/git/opt/PreBuildMergeOptions.java b/src/main/java/hudson/plugins/git/opt/PreBuildMergeOptions.java index 264710ff92..eff731610f 100644 --- a/src/main/java/hudson/plugins/git/opt/PreBuildMergeOptions.java +++ b/src/main/java/hudson/plugins/git/opt/PreBuildMergeOptions.java @@ -1,7 +1,9 @@ package hudson.plugins.git.opt; +import hudson.plugins.git.UserMergeOptions; import org.eclipse.jgit.transport.RemoteConfig; import org.jenkinsci.plugins.gitclient.MergeCommand; +import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.export.Exported; import org.kohsuke.stapler.export.ExportedBean; @@ -33,6 +35,8 @@ public class PreBuildMergeOptions implements Serializable { public MergeCommand.GitPluginFastForwardMode fastForwardMode = MergeCommand.GitPluginFastForwardMode.FF; + public UserMergeOptions.DisplayRevision displayRevision = UserMergeOptions.DisplayRevision.MERGED; + public RemoteConfig getMergeRemote() { return mergeRemote; } @@ -74,6 +78,18 @@ public void setFastForwardMode(MergeCommand.GitPluginFastForwardMode fastForward this.fastForwardMode = fastForwardMode; } + @Exported + public UserMergeOptions.DisplayRevision getDisplayRevision() { + for (UserMergeOptions.DisplayRevision revision : UserMergeOptions.DisplayRevision.values()) + if (revision.equals(displayRevision)) + return revision; + return UserMergeOptions.DisplayRevision.MERGED; + } + + public void setDisplayRevision(UserMergeOptions.DisplayRevision displayRevision) { + this.displayRevision = displayRevision; + } + @Exported public String getRemoteBranchName() { return (mergeRemote == null) ? null : mergeRemote.getName() + "/" + mergeTarget; diff --git a/src/main/java/hudson/plugins/git/util/Build.java b/src/main/java/hudson/plugins/git/util/Build.java index f77866969b..5567395f21 100644 --- a/src/main/java/hudson/plugins/git/util/Build.java +++ b/src/main/java/hudson/plugins/git/util/Build.java @@ -48,6 +48,8 @@ public class Build implements Serializable, Cloneable { */ public Revision revision; + public Revision displayRevision; + public int hudsonBuildNumber; public Result hudsonBuildResult; @@ -56,6 +58,15 @@ public class Build implements Serializable, Cloneable { public Build(Revision marked, Revision revision, int buildNumber, Result result) { this.marked = marked; this.revision = revision; + this.displayRevision = revision; + this.hudsonBuildNumber = buildNumber; + this.hudsonBuildResult = result; + } + + public Build(Revision marked, Revision revision, int buildNumber, Result result, Revision displayRevision) { + this.marked = marked; + this.revision = revision; + this.displayRevision = displayRevision; this.hudsonBuildNumber = buildNumber; this.hudsonBuildResult = result; } @@ -139,4 +150,9 @@ public Object readResolve() throws IOException { marked = revision; return this; } + + @Exported + public Revision getDisplayRevision() { + return displayRevision; + } } diff --git a/src/main/java/hudson/plugins/git/util/BuildData.java b/src/main/java/hudson/plugins/git/util/BuildData.java index a15faf2485..7e55d396c1 100644 --- a/src/main/java/hudson/plugins/git/util/BuildData.java +++ b/src/main/java/hudson/plugins/git/util/BuildData.java @@ -253,6 +253,16 @@ public Build getLastBuildOfBranch(String branch) { return lastBuild==null?null:lastBuild.revision; } + /** + * Gets revision of the previous build to display. + * @return display revision of the last build. + * May be null will be returned if nothing has been checked out (e.g. due to wrong repository or branch) + */ + @Exported + public @CheckForNull Revision getLastBuiltDisplayRevision() { + return lastBuild==null?null:lastBuild.getDisplayRevision(); + } + @Exported public Map getBuildsByBranchName() { return buildsByBranchName; diff --git a/src/main/resources/hudson/plugins/git/UserMergeOptions/config.jelly b/src/main/resources/hudson/plugins/git/UserMergeOptions/config.jelly index ef350b308b..2bb90a400a 100644 --- a/src/main/resources/hudson/plugins/git/UserMergeOptions/config.jelly +++ b/src/main/resources/hudson/plugins/git/UserMergeOptions/config.jelly @@ -16,4 +16,9 @@ ${it.toString()} + + + ${it.toString()} + + diff --git a/src/main/resources/hudson/plugins/git/util/BuildData/index.jelly b/src/main/resources/hudson/plugins/git/util/BuildData/index.jelly index 7684a80e6f..cb9a6251ef 100644 --- a/src/main/resources/hudson/plugins/git/util/BuildData/index.jelly +++ b/src/main/resources/hudson/plugins/git/util/BuildData/index.jelly @@ -8,7 +8,7 @@

${%Git Build Data}

- ${%Revision}: ${it.lastBuild.SHA1.name()} + ${%Revision}: ${it.lastBuiltDisplayRevision.sha1.name()}
${%SCM}: ${it.scmName}
@@ -21,7 +21,7 @@
    - +
  • ${branch.name}
diff --git a/src/main/resources/hudson/plugins/git/util/BuildData/summary.jelly b/src/main/resources/hudson/plugins/git/util/BuildData/summary.jelly index d79f06c4b2..d2a174d144 100644 --- a/src/main/resources/hudson/plugins/git/util/BuildData/summary.jelly +++ b/src/main/resources/hudson/plugins/git/util/BuildData/summary.jelly @@ -4,7 +4,7 @@ xmlns:f="/lib/form" xmlns:i="jelly:fmt"> - ${%Revision}: ${it.lastBuiltRevision.sha1.name()} + ${%Revision}: ${it.lastBuiltDisplayRevision.sha1.name()}
${%SCM}: ${it.scmName}
@@ -17,7 +17,7 @@
    - +
  • ${branch.name}
  • diff --git a/src/test/java/hudson/plugins/git/extensions/impl/PreBuildMergeTest.java b/src/test/java/hudson/plugins/git/extensions/impl/PreBuildMergeTest.java index 7f784ed73a..7671783bcb 100644 --- a/src/test/java/hudson/plugins/git/extensions/impl/PreBuildMergeTest.java +++ b/src/test/java/hudson/plugins/git/extensions/impl/PreBuildMergeTest.java @@ -11,9 +11,17 @@ import hudson.plugins.git.extensions.GitSCMExtensionTest; import hudson.plugins.git.util.BuildData; import nl.jqno.equalsverifier.EqualsVerifier; +import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.ObjectId; import org.jenkinsci.plugins.gitclient.MergeCommand; import org.junit.Test; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + import static org.junit.Assert.*; /** @@ -26,21 +34,101 @@ public class PreBuildMergeTest extends GitSCMExtensionTest private TestGitRepo repo; private String MASTER_FILE = "commitFileBase"; + private String INTEGRATION_FILE = "branchFile"; + + private String initCommit; public void before() throws Exception { repo = new TestGitRepo("repo", tmp.newFolder(), listener); project = setupBasicProject(repo); // make an initial commit to master - repo.commit(MASTER_FILE, repo.johnDoe, "Initial Commit"); + initCommit = repo.commit(MASTER_FILE, repo.johnDoe, "Initial Commit"); // create integration branch repo.git.branch("integration"); } @Test public void testBasicPreMerge() throws Exception { + // already existing test FreeStyleBuild firstBuild = build(project, Result.SUCCESS); } + @Test + public void testDisplayMergedRevision() throws Exception { + // add some commits to source and target branch + repo.git.checkoutBranch("integration", initCommit); + String integrationCommit = repo.commit(INTEGRATION_FILE, repo.johnDoe, "Integration Commit"); + repo.git.checkoutBranch("master", initCommit); + String masterCommit = repo.commit("Master2", repo.johnDoe, "Master2 Commit"); + + FreeStyleBuild firstBuild = build(project, Result.SUCCESS); + + // git repository placed in build's workspace + TestGitRepo repoInWorkspace = getRepoInWorkspace(firstBuild); + + List commitsInWorkspace = getCommitsOnHead(repoInWorkspace); + + ObjectId mergeCommit = commitsInWorkspace.remove(0); + + // verify state of workspace fit repo + // is it possible to verify merge commit (checking log message?) + assertEquals(Arrays.asList(integrationCommit, masterCommit, initCommit), + commitsInWorkspace.stream().map(AnyObjectId::name).collect(Collectors.toList())); + + // verify revision displayed + assertEquals(GitSCM.class, project.getScm().getClass()); + GitSCM gitSCM = (GitSCM)project.getScm(); + BuildData buildData = gitSCM.getBuildData(firstBuild); + Revision buildRevision = buildData.getLastBuiltDisplayRevision(); + + assertEquals(mergeCommit, buildRevision.getSha1()); + assertEquals(1, buildRevision.getBranches().size()); + assertTrue(buildRevision.containsBranchName("origin/integration")); + } + + @Test + public void testDisplaySourceRevision() throws Exception { + // change UserMergeOption + GitSCM gitSCM = (GitSCM)project.getScm(); + gitSCM.getExtensions().get(PreBuildMerge.class).getOptions().setDisplayRevision(UserMergeOptions.DisplayRevision.SOURCE_BRANCH); + + // add some commits to source and target branch + repo.git.checkoutBranch("integration", initCommit); + String integrationCommit = repo.commit(INTEGRATION_FILE, repo.johnDoe, "Integration Commit"); + repo.git.checkoutBranch("master", initCommit); + String masterCommit = repo.commit("Master2", repo.johnDoe, "Master2 Commit"); + + FreeStyleBuild firstBuild = build(project, Result.SUCCESS); + + // git repository placed in build's workspace + TestGitRepo repoInWorkspace = getRepoInWorkspace(firstBuild); + List commitsInWorkspace = getCommitsOnHead(repoInWorkspace); + + ObjectId mergeCommit = commitsInWorkspace.remove(0); + + // verify state of workspace fit repo + // is it possible to verify merge commit (checking log message?) + assertEquals(Arrays.asList(integrationCommit, masterCommit, initCommit), + commitsInWorkspace.stream().map(AnyObjectId::name).collect(Collectors.toList())); + assertEquals(GitSCM.class, project.getScm().getClass()); + + // verify revision displayed + BuildData buildData = gitSCM.getBuildData(firstBuild); + Revision buildRevision = buildData.getLastBuiltDisplayRevision(); + + assertEquals(masterCommit, buildRevision.getSha1().name()); + assertEquals(1, buildRevision.getBranches().size()); + assertTrue(buildRevision.containsBranchName("origin/master")); + } + + private List getCommitsOnHead(TestGitRepo repoInWorkspace) throws InterruptedException { + return repoInWorkspace.git.revList("HEAD"); + } + + private TestGitRepo getRepoInWorkspace(FreeStyleBuild firstBuild) throws IOException, InterruptedException { + return new TestGitRepo("workspace", new File(firstBuild.getWorkspace().toString()), listener); + } + @Test public void testFailedMerge() throws Exception { FreeStyleBuild firstBuild = build(project, Result.SUCCESS);