Skip to content

Commit

Permalink
[JENKINS-48061] regrouping and more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rsandell committed Apr 6, 2018
1 parent 2cc1522 commit d686253
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 28 deletions.
35 changes: 25 additions & 10 deletions src/main/java/jenkins/plugins/git/AbstractGitSCMSource.java
Expand Up @@ -370,11 +370,11 @@ protected SCMRevision retrieve(@NonNull final SCMHead head, @NonNull final TaskL
telescope.validate(remote, credentials);
return telescope.getRevision(remote, credentials, head);
}
if (head instanceof GitSCMHeadMixin) {
/*if (head instanceof GitSCMHeadMixin) {
//Since it is a specific SCMHead we are after, that we know the refspec of
//we can save a bit of time and bandwidth by just fetching that refspec
context = context.withoutRefSpecs().withRefSpec(((GitSCMHeadMixin) head).getRef());
}
context = context.withRefSpec(((GitSCMHeadMixin) head).getRef()); //TODO write test using GitRefSCMHead
}*/
return doRetrieve(new Retriever<SCMRevision>() {
@Override
public SCMRevision run(GitClient client, String remoteName) throws IOException, InterruptedException {
Expand Down Expand Up @@ -711,19 +711,21 @@ protected SCMRevision retrieve(@NonNull final String revision, @NonNull final Ta
return null;
}
// first we need to figure out what the revision is. There are six possibilities:
// 1. A branch name (if we have that we can return quickly)
// 2. A tag name (if we have that we will need to fetch the tag to resolve the tag date)
// 3. A short/full revision hash that is the head revision of a branch (if we have that we can return quickly)
// 4. A short revision hash that is the head revision of a branch (if we have that we can return quickly)
// 5. A short/full revision hash for a tag (we'll need to fetch the tag to resolve the tag date)
// 6. A short/full revision hash that is not the head revision of a branch (we'll need to fetch everything to
// 1. A branch name (if we have that we can return quickly)
// 2. A tag name (if we have that we will need to fetch the tag to resolve the tag date)
// 3. A short/full revision hash that is the head revision of a branch (if we have that we can return quickly)
// 3.2 A remote refspec for example pull-requests/1/from
// 3.3 A short/full revision hash of a non default ref (non branch or tag but somewhere else under refs/)
// 4. A short revision hash that is the head revision of a branch (if we have that we can return quickly)
// 5. A short/full revision hash for a tag (we'll need to fetch the tag to resolve the tag date)
// 6. A short/full revision hash that is not the head revision of a branch (we'll need to fetch everything to
// try and resolve the hash from the history of one of the heads)
Git git = Git.with(listener, new EnvVars(EnvVars.masterEnvVars));
GitTool tool = resolveGitTool(context.gitTool());
if (tool != null) {
git.using(tool.getGitExe());
}
GitClient client = git.getClient();
final GitClient client = git.getClient();
client.addDefaultCredentials(getCredentials());
listener.getLogger().printf("Attempting to resolve %s from remote references...%n", revision);
Map<String, ObjectId> remoteReferences = client.getRemoteReferences(
Expand Down Expand Up @@ -767,6 +769,13 @@ protected SCMRevision retrieve(@NonNull final String revision, @NonNull final Ta
fullTagMatches.add(name);
continue;
}
if((Constants.R_REFS + revision.toLowerCase(Locale.ENGLISH)).equals(name.toLowerCase(Locale.ENGLISH))) {
fullHashMatches.add(name);
if (fullHashMatch == null) {
fullHashMatch = rev;
}
continue;
}
if (rev.toLowerCase(Locale.ENGLISH).equals(revision.toLowerCase(Locale.ENGLISH))) {
fullHashMatches.add(name);
if (fullHashMatch == null) {
Expand Down Expand Up @@ -857,6 +866,12 @@ public SCMRevision run(GitClient client, String remoteName) throws IOException,
String hash;
try {
objectId = client.revParse(revision);
if (objectId == null) {
//just to be safe
listener.error("Could not resolve %s", revision);
return null;

}
hash = objectId.name();
String candidatePrefix = Constants.R_REMOTES.substring(Constants.R_REFS.length())
+ context.remoteName() + "/";
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/jenkins/plugins/git/GitBranchSCMHead.java
Expand Up @@ -48,6 +48,14 @@ public final String getRef() {
return Constants.R_HEADS + getName();
}

@Override
public String toString() {
final StringBuilder sb = new StringBuilder("GitBranchSCMHead{");
sb.append("name='").append(getName()).append("'");
sb.append(", ref='").append(getRef()).append("'}");
return sb.toString();
}

@Restricted(NoExternalUse.class)
@Extension
public static class SCMHeadMigrationImpl extends SCMHeadMigration<GitSCMSource, SCMHead, AbstractGitSCMSource.SCMRevisionImpl> {
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/jenkins/plugins/git/GitRefSCMHead.java
Expand Up @@ -54,4 +54,12 @@ public GitRefSCMHead(@NonNull String name) {
public String getRef() {
return ref;
}

@Override
public String toString() {
final StringBuilder sb = new StringBuilder("GitRefSCMHead{");
sb.append("name='").append(getName()).append("'");
sb.append(", ref='").append(ref).append("'}");
return sb.toString();
}
}
2 changes: 1 addition & 1 deletion src/main/java/jenkins/plugins/git/GitSCMBuilder.java
Expand Up @@ -515,7 +515,7 @@ public GitSCM build() {
(AbstractGitSCMSource.SCMRevisionImpl) revision)));
}
if (head() instanceof GitRefSCMHead) {
withoutRefSpecs().withRefSpec(((GitRefSCMHead) head()).getRef());
withRefSpec(((GitRefSCMHead) head()).getRef());
}
return new GitSCM(
asRemoteConfigs(),
Expand Down
93 changes: 77 additions & 16 deletions src/test/java/jenkins/plugins/git/AbstractGitSCMSourceTest.java
Expand Up @@ -25,6 +25,7 @@
import java.util.UUID;
import jenkins.plugins.git.traits.BranchDiscoveryTrait;
import jenkins.plugins.git.traits.IgnoreOnPushNotificationTrait;
import jenkins.plugins.git.traits.RefSpecsSCMSourceTrait;
import jenkins.plugins.git.traits.TagDiscoveryTrait;
import jenkins.scm.api.SCMHead;
import jenkins.scm.api.SCMRevision;
Expand All @@ -49,6 +50,9 @@
*/
public class AbstractGitSCMSourceTest {

static final String GitBranchSCMHead_DEV_MASTER = "[GitBranchSCMHead{name='dev', ref='refs/heads/dev'}, GitBranchSCMHead{name='master', ref='refs/heads/master'}]";
static final String GitBranchSCMHead_DEV_DEV2_MASTER = "[GitBranchSCMHead{name='dev', ref='refs/heads/dev'}, GitBranchSCMHead{name='dev2', ref='refs/heads/dev2'}, GitBranchSCMHead{name='master', ref='refs/heads/master'}]";

@Rule
public JenkinsRule r = new JenkinsRule();
@Rule
Expand All @@ -67,14 +71,14 @@ public void retrieveHeads() throws Exception {
SCMSource source = new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true);
TaskListener listener = StreamTaskListener.fromStderr();
// SCMHeadObserver.Collector.result is a TreeMap so order is predictable:
assertEquals("[SCMHead{'dev'}, SCMHead{'master'}]", source.fetch(listener).toString());
assertEquals(GitBranchSCMHead_DEV_MASTER, source.fetch(listener).toString());
// And reuse cache:
assertEquals("[SCMHead{'dev'}, SCMHead{'master'}]", source.fetch(listener).toString());
assertEquals(GitBranchSCMHead_DEV_MASTER, source.fetch(listener).toString());
sampleRepo.git("checkout", "-b", "dev2");
sampleRepo.write("file", "modified again");
sampleRepo.git("commit", "--all", "--message=dev2");
// After changing data:
assertEquals("[SCMHead{'dev'}, SCMHead{'dev2'}, SCMHead{'master'}]", source.fetch(listener).toString());
assertEquals(GitBranchSCMHead_DEV_DEV2_MASTER, source.fetch(listener).toString());
}

@Test
Expand All @@ -88,14 +92,14 @@ public void retrieveHeadsRequiresBranchDiscovery() throws Exception {
// SCMHeadObserver.Collector.result is a TreeMap so order is predictable:
assertEquals("[]", source.fetch(listener).toString());
source.setTraits(Collections.<SCMSourceTrait>singletonList(new BranchDiscoveryTrait()));
assertEquals("[SCMHead{'dev'}, SCMHead{'master'}]", source.fetch(listener).toString());
assertEquals(GitBranchSCMHead_DEV_MASTER, source.fetch(listener).toString());
// And reuse cache:
assertEquals("[SCMHead{'dev'}, SCMHead{'master'}]", source.fetch(listener).toString());
assertEquals(GitBranchSCMHead_DEV_MASTER, source.fetch(listener).toString());
sampleRepo.git("checkout", "-b", "dev2");
sampleRepo.write("file", "modified again");
sampleRepo.git("commit", "--all", "--message=dev2");
// After changing data:
assertEquals("[SCMHead{'dev'}, SCMHead{'dev2'}, SCMHead{'master'}]", source.fetch(listener).toString());
assertEquals(GitBranchSCMHead_DEV_DEV2_MASTER, source.fetch(listener).toString());
}

@Issue("JENKINS-46207")
Expand All @@ -116,14 +120,14 @@ public void retrieveHeadsSupportsTagDiscovery_ignoreTagsWithoutTagDiscoveryTrait
// SCMHeadObserver.Collector.result is a TreeMap so order is predictable:
assertEquals("[]", source.fetch(listener).toString());
source.setTraits(Collections.<SCMSourceTrait>singletonList(new BranchDiscoveryTrait()));
assertEquals("[SCMHead{'dev'}, SCMHead{'master'}]", source.fetch(listener).toString());
assertEquals(GitBranchSCMHead_DEV_MASTER, source.fetch(listener).toString());
// And reuse cache:
assertEquals("[SCMHead{'dev'}, SCMHead{'master'}]", source.fetch(listener).toString());
assertEquals(GitBranchSCMHead_DEV_MASTER, source.fetch(listener).toString());
sampleRepo.git("checkout", "-b", "dev2");
sampleRepo.write("file", "modified again");
sampleRepo.git("commit", "--all", "--message=dev2");
// After changing data:
assertEquals("[SCMHead{'dev'}, SCMHead{'dev2'}, SCMHead{'master'}]", source.fetch(listener).toString());
assertEquals(GitBranchSCMHead_DEV_DEV2_MASTER, source.fetch(listener).toString());
}

@Issue("JENKINS-46207")
Expand Down Expand Up @@ -168,14 +172,16 @@ public void retrieveHeadsSupportsTagDiscovery_findTagsWithTagDiscoveryTrait() th
}
}
}
assertEquals("[SCMHead{'annotated'}, SCMHead{'dev'}, SCMHead{'lightweight'}, SCMHead{'master'}]", scmHeadSet.toString());
String expected = "[SCMHead{'annotated'}, GitBranchSCMHead{name='dev', ref='refs/heads/dev'}, SCMHead{'lightweight'}, GitBranchSCMHead{name='master', ref='refs/heads/master'}]";
assertEquals(expected, scmHeadSet.toString());
// And reuse cache:
assertEquals("[SCMHead{'annotated'}, SCMHead{'dev'}, SCMHead{'lightweight'}, SCMHead{'master'}]", source.fetch(listener).toString());
assertEquals(expected, source.fetch(listener).toString());
sampleRepo.git("checkout", "-b", "dev2");
sampleRepo.write("file", "modified again");
sampleRepo.git("commit", "--all", "--message=dev2");
// After changing data:
assertEquals("[SCMHead{'annotated'}, SCMHead{'dev'}, SCMHead{'dev2'}, SCMHead{'lightweight'}, SCMHead{'master'}]", source.fetch(listener).toString());
expected = "[SCMHead{'annotated'}, GitBranchSCMHead{name='dev', ref='refs/heads/dev'}, GitBranchSCMHead{name='dev2', ref='refs/heads/dev2'}, SCMHead{'lightweight'}, GitBranchSCMHead{name='master', ref='refs/heads/master'}]";
assertEquals(expected, source.fetch(listener).toString());
}

@Issue("JENKINS-46207")
Expand Down Expand Up @@ -541,6 +547,61 @@ public void retrieveRevision_customRef_abbrev_sha1() throws Exception {
assertEquals("v3", fileAt(v3.substring(0, 7), run, source, listener));
}

@Issue("JENKINS-48061")
@Test
public void retrieveRevision_pr_refspec() 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/pull-requests/1/from", 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("pull-requests/1/from", run, source, listener));
}

@Issue("JENKINS-48061")
@Test
public void retrieveRevision_pr_local_refspec() 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/pull-requests/1/from", 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(),
new RefSpecsSCMSourceTrait("+refs/pull-requests/*/from:refs/remotes/@{remote}/pr/*")));
StreamTaskListener listener = StreamTaskListener.fromStderr();
// Test retrieval of non head revision:
assertEquals("v3", fileAt("pr/1", 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) {
Expand Down Expand Up @@ -572,9 +633,9 @@ public void pruneRemovesDeletedBranches() throws Exception {
GitSCMSource source = new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true);
TaskListener listener = StreamTaskListener.fromStderr();
// SCMHeadObserver.Collector.result is a TreeMap so order is predictable:
assertEquals("[SCMHead{'dev'}, SCMHead{'master'}]", source.fetch(listener).toString());
assertEquals(GitBranchSCMHead_DEV_MASTER, source.fetch(listener).toString());
// And reuse cache:
assertEquals("[SCMHead{'dev'}, SCMHead{'master'}]", source.fetch(listener).toString());
assertEquals(GitBranchSCMHead_DEV_MASTER, source.fetch(listener).toString());

/* Create dev2 branch and write a file to it */
sampleRepo.git("checkout", "-b", "dev2", "master");
Expand All @@ -583,13 +644,13 @@ public void pruneRemovesDeletedBranches() throws Exception {
sampleRepo.git("commit", "--message=dev2-branch-commit-message");

// Verify new branch is visible
assertEquals("[SCMHead{'dev'}, SCMHead{'dev2'}, SCMHead{'master'}]", source.fetch(listener).toString());
assertEquals(GitBranchSCMHead_DEV_DEV2_MASTER, source.fetch(listener).toString());

/* Delete the dev branch */
sampleRepo.git("branch", "-D", "dev");

/* Fetch and confirm dev branch was pruned */
assertEquals("[SCMHead{'dev2'}, SCMHead{'master'}]", source.fetch(listener).toString());
assertEquals("[GitBranchSCMHead{name='dev2', ref='refs/heads/dev2'}, GitBranchSCMHead{name='master', ref='refs/heads/master'}]", source.fetch(listener).toString());
}

@Test
Expand Down
22 changes: 21 additions & 1 deletion src/test/java/jenkins/plugins/git/GitSCMFileSystemTest.java
Expand Up @@ -114,7 +114,7 @@ public void ofSource_Smokes() throws Exception {
sampleRepo.write("file", "modified");
sampleRepo.git("commit", "--all", "--message=dev");
SCMSource source = new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true);
SCMFileSystem fs = SCMFileSystem.of(source, new SCMHead("dev"));
SCMFileSystem fs = SCMFileSystem.of(source, new GitBranchSCMHead("dev"));
assertThat(fs, notNullValue());
SCMFile root = fs.getRoot();
assertThat(root, notNullValue());
Expand Down Expand Up @@ -151,6 +151,26 @@ public void ofSourceRevision() throws Exception {
assertThat(file.contentAsString(), is(""));
}

@Test
public void ofSourceRevision_GitBranchSCMHead() throws Exception {
sampleRepo.init();
sampleRepo.git("checkout", "-b", "dev");
SCMSource source = new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true);
SCMRevision revision = source.fetch(new GitBranchSCMHead("dev"), null);
sampleRepo.write("file", "modified");
sampleRepo.git("commit", "--all", "--message=dev");
SCMFileSystem fs = SCMFileSystem.of(source, new GitBranchSCMHead("dev"), revision);
assertThat(fs, notNullValue());
assertThat(fs.getRoot(), notNullValue());
Iterable<SCMFile> children = fs.getRoot().children();
Iterator<SCMFile> iterator = children.iterator();
assertThat(iterator.hasNext(), is(true));
SCMFile file = iterator.next();
assertThat(iterator.hasNext(), is(false));
assertThat(file.getName(), is("file"));
assertThat(file.contentAsString(), is(""));
}

@Issue("JENKINS-42817")
@Test
public void slashyBranches() throws Exception {
Expand Down
2 changes: 2 additions & 0 deletions src/test/java/jenkins/plugins/git/GitSCMSourceTest.java
Expand Up @@ -269,6 +269,8 @@ public void telescopeFetchRevision() throws Exception {
instance.setTraits(Arrays.<SCMSourceTrait>asList(new BranchDiscoveryTrait(), new TagDiscoveryTrait()));
assertThat(instance.fetch(new SCMHead("foo"), null),
hasProperty("hash", is("6769413a79793e242c73d7377f0006c6aea95480")));
assertThat(instance.fetch(new GitBranchSCMHead("foo"), null),
hasProperty("hash", is("6769413a79793e242c73d7377f0006c6aea95480")));
assertThat(instance.fetch(new SCMHead("bar"), null),
hasProperty("hash", is("3f0b897057d8b43d3b9ff55e3fdefbb021493470")));
assertThat(instance.fetch(new SCMHead("manchu"), null),
Expand Down

0 comments on commit d686253

Please sign in to comment.