From 5cfdeaa87dd9fe75c18ef2d6dee1f1d5c29f8ba0 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Wed, 6 Dec 2017 10:22:03 +0000 Subject: [PATCH] [JENKINS-48061] Partial fix for the easy case of non-head revision in history of branch --- .../plugins/git/AbstractGitSCMSource.java | 13 ++- .../plugins/git/AbstractGitSCMSourceTest.java | 82 +++++++++++++++++++ 2 files changed, 92 insertions(+), 3 deletions(-) diff --git a/src/main/java/jenkins/plugins/git/AbstractGitSCMSource.java b/src/main/java/jenkins/plugins/git/AbstractGitSCMSource.java index a08f603d31..9ae09d1531 100644 --- a/src/main/java/jenkins/plugins/git/AbstractGitSCMSource.java +++ b/src/main/java/jenkins/plugins/git/AbstractGitSCMSource.java @@ -815,13 +815,20 @@ public SCMRevision run(GitClient client, String remoteName) throws IOException, try { objectId = client.revParse(revision); hash = objectId.name(); - List branches = client.getBranchesContaining(hash, false); - if (branches.isEmpty()) { + String candidatePrefix = Constants.R_REMOTES.substring(Constants.R_REFS.length()) + + context.remoteName() + "/"; + String name = null; + for (Branch b: client.getBranchesContaining(hash, true)) { + if (b.getName().startsWith(candidatePrefix)) { + name = b.getName().substring(candidatePrefix.length()); + break; + } + } + if (name == null) { listener.getLogger().printf("Could not find a branch containing commit %s%n", hash); return null; } - String name = branches.get(0).getName(); listener.getLogger() .printf("Selected match: %s revision %s%n", name, hash); return new SCMRevisionImpl(new SCMHead(name), hash); diff --git a/src/test/java/jenkins/plugins/git/AbstractGitSCMSourceTest.java b/src/test/java/jenkins/plugins/git/AbstractGitSCMSourceTest.java index ac5db638b4..a42f3abdc4 100644 --- a/src/test/java/jenkins/plugins/git/AbstractGitSCMSourceTest.java +++ b/src/test/java/jenkins/plugins/git/AbstractGitSCMSourceTest.java @@ -34,6 +34,7 @@ import jenkins.scm.api.SCMSourceOwner; import jenkins.scm.api.metadata.PrimaryInstanceMetadataAction; import jenkins.scm.api.trait.SCMSourceTrait; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.Issue; @@ -427,6 +428,87 @@ public void retrieveRevision() throws Exception { assertThat(source.fetchRevisions(listener), hasItems("master", "dev", "v1")); // we do not care to return commit hashes or other references } + + @Issue("JENKINS-48061") + @Test + public void retrieveRevision_nonHead() throws Exception { + sampleRepo.init(); + sampleRepo.write("file", "v1"); + sampleRepo.git("commit", "--all", "--message=v1"); + sampleRepo.git("tag", "v1"); + String v1 = sampleRepo.head(); + sampleRepo.write("file", "v2"); + sampleRepo.git("commit", "--all", "--message=v2"); // master + sampleRepo.git("checkout", "-b", "dev"); + sampleRepo.write("file", "v3"); + sampleRepo.git("commit", "--all", "--message=v3"); // dev + String v3 = sampleRepo.head(); + sampleRepo.write("file", "v4"); + sampleRepo.git("commit", "--all", "--message=v4"); // dev + // SCM.checkout does not permit a null build argument, unfortunately. + Run run = r.buildAndAssertSuccess(r.createFreeStyleProject()); + GitSCMSource source = new GitSCMSource(sampleRepo.toString()); + source.setTraits(Arrays.asList(new BranchDiscoveryTrait(), new TagDiscoveryTrait())); + StreamTaskListener listener = StreamTaskListener.fromStderr(); + // Test retrieval of non head revision: + assertEquals("v3", fileAt(v3, run, source, listener)); + } + + @Issue("JENKINS-48061") + @Test + @Ignore("Cannot fix until JENKINS-48385 merged") // TODO unignore once JENKINS-48385 + public void retrieveRevision_nonAdvertised() throws Exception { + sampleRepo.init(); + sampleRepo.write("file", "v1"); + sampleRepo.git("commit", "--all", "--message=v1"); + sampleRepo.git("tag", "v1"); + String v1 = sampleRepo.head(); + sampleRepo.write("file", "v2"); + sampleRepo.git("commit", "--all", "--message=v2"); // master + sampleRepo.git("checkout", "-b", "dev"); + sampleRepo.write("file", "v3"); + sampleRepo.git("commit", "--all", "--message=v3"); // dev + String v3 = sampleRepo.head(); + sampleRepo.git("reset", "--hard", "HEAD^"); // dev, the v3 ref is eligible for GC but still fetchable + sampleRepo.write("file", "v4"); + sampleRepo.git("commit", "--all", "--message=v4"); // dev + // SCM.checkout does not permit a null build argument, unfortunately. + Run run = r.buildAndAssertSuccess(r.createFreeStyleProject()); + GitSCMSource source = new GitSCMSource(sampleRepo.toString()); + source.setTraits(Arrays.asList(new BranchDiscoveryTrait(), new TagDiscoveryTrait())); + StreamTaskListener listener = StreamTaskListener.fromStderr(); + // Test retrieval of non head revision: + assertEquals("v3", fileAt(v3, run, source, listener)); + } + + @Issue("JENKINS-48061") + @Test + @Ignore("Cannot fix until JENKINS-48385 merged") // TODO unignore once JENKINS-48385 + public void retrieveRevision_customRef() throws Exception { + sampleRepo.init(); + sampleRepo.write("file", "v1"); + sampleRepo.git("commit", "--all", "--message=v1"); + sampleRepo.git("tag", "v1"); + String v1 = sampleRepo.head(); + sampleRepo.write("file", "v2"); + sampleRepo.git("commit", "--all", "--message=v2"); // master + sampleRepo.git("checkout", "-b", "dev"); + sampleRepo.write("file", "v3"); + sampleRepo.git("commit", "--all", "--message=v3"); // dev + String v3 = sampleRepo.head(); + sampleRepo.git("update-ref", "refs/custom/foo", v3); // now this is an advertised ref so cannot be GC'd + sampleRepo.git("reset", "--hard", "HEAD^"); // dev + sampleRepo.write("file", "v4"); + sampleRepo.git("commit", "--all", "--message=v4"); // dev + // SCM.checkout does not permit a null build argument, unfortunately. + Run run = r.buildAndAssertSuccess(r.createFreeStyleProject()); + GitSCMSource source = new GitSCMSource(sampleRepo.toString()); + source.setTraits(Arrays.asList(new BranchDiscoveryTrait(), new TagDiscoveryTrait())); + StreamTaskListener listener = StreamTaskListener.fromStderr(); + // Test retrieval of non head revision: + assertEquals("v3", fileAt(v3, run, source, listener)); + } + private String fileAt(String revision, Run run, SCMSource source, TaskListener listener) throws Exception { SCMRevision rev = source.fetch(revision, listener); if (rev == null) {