Skip to content
Permalink
Browse files

[JENKINS-40834] Should implement for 2.6.x branch but...

- Seems like the JGit Impl is not actually making the remote's HEAD available.
  • Loading branch information...
stephenc committed Jan 10, 2017
1 parent a2ac1ae commit f97f8605c5dc4001b9ba7e2d46a8f5dda2674c4b
@@ -1,7 +1,7 @@
/*
* The MIT License
*
* Copyright (c) 2013-2014, CloudBees, Inc., Stephen Connolly, Amadeus IT Group.
* Copyright (c) 2013-2017, CloudBees, Inc., Stephen Connolly, Amadeus IT Group.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -34,6 +34,8 @@
import hudson.EnvVars;
import hudson.Extension;
import hudson.Util;
import hudson.model.Action;
import hudson.model.Actionable;
import hudson.model.Item;
import hudson.model.TaskListener;
import hudson.plugins.git.Branch;
@@ -54,6 +56,7 @@
import hudson.plugins.git.util.BuildData;
import hudson.scm.SCM;
import hudson.security.ACL;
import java.util.Map;
import jenkins.model.Jenkins;
import jenkins.scm.api.SCMFile;
import jenkins.scm.api.SCMHead;
@@ -64,11 +67,16 @@
import jenkins.scm.api.SCMRevision;
import jenkins.scm.api.SCMSource;
import jenkins.scm.api.SCMSourceCriteria;
import jenkins.scm.api.SCMSourceEvent;
import jenkins.scm.api.SCMSourceOwner;
import jenkins.scm.api.metadata.PrimaryInstanceMetadataAction;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.SymbolicRef;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
@@ -372,6 +380,50 @@ public SCMRevision run(GitClient client, String remoteName) throws IOException,
}, listener, false);
}

@NonNull
@Override
protected List<Action> retrieveActions(@CheckForNull SCMSourceEvent event, @NonNull TaskListener listener)
throws IOException, InterruptedException {
return doRetrieve(new Retriever<List<Action>>() {
@Override
public List<Action> run(GitClient client, String remoteName) throws IOException, InterruptedException {
final Repository repository = client.getRepository();
Ref headRef = repository.getRef(Constants.HEAD);
if (headRef instanceof SymbolicRef) {
String target = headRef.getTarget().getName();
if (target.startsWith(Constants.R_HEADS)){
// shorten standard names
target = target.substring(Constants.R_HEADS.length());
}
List<Action> result = new ArrayList<Action>();
if (StringUtils.isNotBlank(target)) {
result.add(new GitRemoteHeadRefAction(getRemote(), target));
}
return result;
} else {
return Collections.emptyList();
}
}
}, listener, false);
}

@NonNull
@Override
protected List<Action> retrieveActions(@NonNull SCMHead head, @CheckForNull SCMHeadEvent event,
@NonNull TaskListener listener) throws IOException, InterruptedException {
SCMSourceOwner owner = getOwner();
if (owner instanceof Actionable) {
for (GitRemoteHeadRefAction a: ((Actionable) owner).getActions(GitRemoteHeadRefAction.class)) {
if (getRemote().equals(a.getRemote())) {
if (head.getName().equals(a.getName())) {
return Collections.<Action>singletonList(new PrimaryInstanceMetadataAction());
}
}
}
}
return Collections.emptyList();
}

protected String getCacheEntry() {
return getCacheEntry(getRemote());
}
@@ -0,0 +1,67 @@
package jenkins.plugins.git;

import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.model.InvisibleAction;
import java.io.Serializable;

/**
* @author Stephen Connolly
*/
public class GitRemoteHeadRefAction extends InvisibleAction implements Serializable {

private static final long serialVersionUID = 1L;

@NonNull
private final String remote;
@NonNull
private final String name;

public GitRemoteHeadRefAction(@NonNull String remote, @NonNull String name) {
this.remote = remote;
this.name = name;
}

@NonNull
public String getRemote() {
return remote;
}

@NonNull
public String getName() {
return name;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}

GitRemoteHeadRefAction that = (GitRemoteHeadRefAction) o;

if (!remote.equals(that.remote)) {
return false;
}
return name.equals(that.name);
}

@Override
public int hashCode() {
int result = remote.hashCode();
result = 31 * result + name.hashCode();
return result;
}

@Override
public String toString() {
return "GitRemoteHeadRefAction{" +
"remote='" + remote + '\'' +
", name='" + name + '\'' +
'}';
}


}
@@ -2,6 +2,8 @@

import hudson.FilePath;
import hudson.Launcher;
import hudson.model.Action;
import hudson.model.Actionable;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.plugins.git.UserRemoteConfig;
@@ -12,18 +14,27 @@
import hudson.plugins.git.extensions.impl.LocalBranch;
import hudson.util.StreamTaskListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;
import jenkins.scm.api.SCMHead;
import jenkins.scm.api.SCMRevision;
import jenkins.scm.api.SCMSource;
import static org.hamcrest.Matchers.*;

import jenkins.scm.api.SCMSourceOwner;
import jenkins.scm.api.metadata.PrimaryInstanceMetadataAction;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;
import org.mockito.Mockito;

import static org.junit.Assert.*;
import static org.mockito.Mockito.when;

/**
* Tests for {@link AbstractGitSCMSource}
@@ -34,6 +45,7 @@
public JenkinsRule r = new JenkinsRule();
@Rule
public GitSampleRepoRule sampleRepo = new GitSampleRepoRule();
public GitSampleRepoRule sampleRepo2 = new GitSampleRepoRule();

// TODO AbstractGitSCMSourceRetrieveHeadsTest *sounds* like it would be the right place, but it does not in fact retrieve any heads!
@Issue("JENKINS-37482")
@@ -56,6 +68,56 @@ public void retrieveHeads() throws Exception {
assertEquals("[SCMHead{'dev'}, SCMHead{'dev2'}, SCMHead{'master'}]", source.fetch(listener).toString());
}

public static abstract class ActionableSCMSourceOwner extends Actionable implements SCMSourceOwner {

}

@Test
public void retrievePrimaryHead() throws Exception {
sampleRepo.init();
sampleRepo.write("file.txt", "");
sampleRepo.git("status");
sampleRepo.git("add", "file.txt");
sampleRepo.git("status");
sampleRepo.git("commit", "--all", "--message=add-empty-file");
sampleRepo.git("status");
sampleRepo.git("checkout", "-b", "new-primary");
sampleRepo.git("status");
sampleRepo.write("file.txt", "content");
sampleRepo.git("status");
sampleRepo.git("add", "file.txt");
sampleRepo.git("status");
sampleRepo.git("commit", "--all", "--message=add-file");
sampleRepo.git("status");
sampleRepo.git("checkout", "-b", "dev", "master");
sampleRepo.git("status");
sampleRepo.git("checkout", "new-primary");
sampleRepo.git("status");
SCMSource source = new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true);
ActionableSCMSourceOwner owner = Mockito.mock(ActionableSCMSourceOwner.class);
when(owner.getSCMSource(source.getId())).thenReturn(source);
when(owner.getSCMSources()).thenReturn(Collections.singletonList(source));
source.setOwner(owner);
TaskListener listener = StreamTaskListener.fromStderr();
Map<String, SCMHead> headByName = new TreeMap<String, SCMHead>();
for (SCMHead h: source.fetch(listener)) {
headByName.put(h.getName(), h);
}
assertThat(headByName.keySet(), containsInAnyOrder("master", "dev", "new-primary"));
for (Action a : source.fetchActions(null, listener)) {
owner.addAction(a);
}
List<Action> actions = source.fetchActions(headByName.get("new-primary"), null, listener);
PrimaryInstanceMetadataAction primary = null;
for (Action a: actions) {
if (a instanceof PrimaryInstanceMetadataAction) {
primary = (PrimaryInstanceMetadataAction) a;
break;
}
}
assertThat(primary, notNullValue());
}

@Issue("JENKINS-31155")
@Test
public void retrieveRevision() throws Exception {

0 comments on commit f97f860

Please sign in to comment.
You can’t perform that action at this time.