diff --git a/pom.xml b/pom.xml index 8958f8d1e5..cc7a26754c 100644 --- a/pom.xml +++ b/pom.xml @@ -112,6 +112,7 @@ org.jenkins-ci.plugins scm-api + ${scm-api-plugin.version} org.jenkins-ci.plugins diff --git a/src/main/java/hudson/plugins/git/util/GitUtils.java b/src/main/java/hudson/plugins/git/util/GitUtils.java index 1f016b1562..9cb55bc6ab 100644 --- a/src/main/java/hudson/plugins/git/util/GitUtils.java +++ b/src/main/java/hudson/plugins/git/util/GitUtils.java @@ -410,6 +410,10 @@ public static String[] fixupNames(String[] names, String[] urls) { return returnNames; } + public static String expand(String str, EnvVars env) { + return env == null ? str : env.expand(str); + } + private static final Logger LOGGER = Logger.getLogger(GitUtils.class.getName()); private static final long serialVersionUID = 1L; diff --git a/src/main/java/jenkins/plugins/git/GitSCMFileSystem.java b/src/main/java/jenkins/plugins/git/GitSCMFileSystem.java index 6e7847d271..063a00dfd7 100644 --- a/src/main/java/jenkins/plugins/git/GitSCMFileSystem.java +++ b/src/main/java/jenkins/plugins/git/GitSCMFileSystem.java @@ -34,6 +34,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import hudson.EnvVars; import hudson.Extension; +import hudson.model.Run; import hudson.model.Item; import hudson.model.TaskListener; import hudson.plugins.git.BranchSpec; @@ -53,6 +54,7 @@ import java.io.Writer; import java.net.URISyntaxException; import java.util.Arrays; +import java.util.Collections; import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; @@ -76,6 +78,8 @@ import org.jenkinsci.plugins.gitclient.Git; import org.jenkinsci.plugins.gitclient.GitClient; +import static hudson.plugins.git.util.GitUtils.expand; + /** * Base implementation of {@link SCMFileSystem}. * @@ -286,6 +290,18 @@ public boolean supportsDescriptor(SCMSourceDescriptor descriptor) { @Override public SCMFileSystem build(@NonNull Item owner, @NonNull SCM scm, @CheckForNull SCMRevision rev) throws IOException, InterruptedException { + return getScmFileSystem(scm, rev, owner, null); + } + + @Override + public SCMFileSystem build(@NonNull Run build, @NonNull SCM scm, SCMRevision rev) + throws IOException, InterruptedException { + Item owner = build.getParent(); + return getScmFileSystem(scm, rev, owner, build); + } + + private SCMFileSystem getScmFileSystem(@NonNull SCM scm, + SCMRevision rev, Item owner, @CheckForNull Run build) throws IOException, InterruptedException { if (rev != null && !(rev instanceof AbstractGitSCMSource.SCMRevisionImpl)) { return null; } @@ -293,14 +309,16 @@ public SCMFileSystem build(@NonNull Item owner, @NonNull SCM scm, @CheckForNull return null; // Spotbugs warns about unchecked cast without this check } GitSCM gitSCM = (GitSCM) scm; + TaskListener listener = new LogTaskListener(LOGGER, Level.FINE); UserRemoteConfig config = gitSCM.getUserRemoteConfigs().get(0); BranchSpec branchSpec = gitSCM.getBranches().get(0); - String remote = config.getUrl(); - TaskListener listener = new LogTaskListener(LOGGER, Level.FINE); + EnvVars env = build == null ? null : build.getEnvironment(listener); + String remote = expand(config.getUrl(), env); if (remote == null) { listener.getLogger().println("Git remote url is null"); return null; } + remote = remote.trim(); String cacheEntry = AbstractGitSCMSource.getCacheEntry(remote); Lock cacheLock = AbstractGitSCMSource.getCacheLock(cacheEntry); cacheLock.lock(); @@ -334,7 +352,7 @@ public SCMFileSystem build(@NonNull Item owner, @NonNull SCM scm, @CheckForNull listener.getLogger().println("Creating git repository in " + cacheDir); client.init(); } - String remoteName = StringUtils.defaultIfBlank(config.getName(), Constants.DEFAULT_REMOTE_NAME); + String remoteName = StringUtils.defaultIfBlank(expand(config.getName(), env), Constants.DEFAULT_REMOTE_NAME).trim(); listener.getLogger().println("Setting " + remoteName + " to " + remote); client.setRemoteUrl(remoteName, remote); listener.getLogger().println("Fetching & pruning " + remoteName + "..."); @@ -344,28 +362,37 @@ public SCMFileSystem build(@NonNull Item owner, @NonNull SCM scm, @CheckForNull } catch (URISyntaxException ex) { listener.getLogger().println("URI syntax exception for '" + remoteName + "' " + ex); } - String prefix = Constants.R_HEADS; + String prefix = Constants.R_HEADS; if(branchSpec.getName().startsWith(Constants.R_TAGS)){ - prefix = Constants.R_TAGS; + prefix = Constants.R_TAGS; } String headName; if (rev != null) { headName = rev.getHead().getName(); } else { if (branchSpec.getName().startsWith(prefix)){ - headName = branchSpec.getName().substring(prefix.length()); + headName = branchSpec.getName().substring(prefix.length()); } else if (branchSpec.getName().startsWith("*/")) { headName = branchSpec.getName().substring(2); } else { headName = branchSpec.getName(); } } - client.fetch_().prune(true).from(remoteURI, Arrays - .asList(new RefSpec( - "+" + prefix + headName + ":" + Constants.R_REMOTES + remoteName + "/" - + headName))).execute(); + headName = expand(headName, env).trim(); + + String refspec = expand(config.getRefspec(), env); + String head = headName; + if (refspec == null) { + refspec = "+" + Constants.R_HEADS + headName + ":" + Constants.R_REMOTES + remoteName + "/" + headName; + head = Constants.R_REMOTES + remoteName + "/" +headName; + } + else { + refspec = refspec.trim(); + } + client.fetch_().prune(true).from(remoteURI, + Collections.singletonList(new RefSpec(refspec))).execute(); listener.getLogger().println("Done."); - return new GitSCMFileSystem(client, remote, Constants.R_REMOTES + remoteName + "/" +headName, (AbstractGitSCMSource.SCMRevisionImpl) rev); + return new GitSCMFileSystem(client, remote, head, (AbstractGitSCMSource.SCMRevisionImpl) rev); } finally { cacheLock.unlock(); } diff --git a/src/main/java/jenkins/plugins/git/GitSCMTelescope.java b/src/main/java/jenkins/plugins/git/GitSCMTelescope.java index 4e762dfd97..375422012e 100644 --- a/src/main/java/jenkins/plugins/git/GitSCMTelescope.java +++ b/src/main/java/jenkins/plugins/git/GitSCMTelescope.java @@ -32,9 +32,12 @@ import com.cloudbees.plugins.credentials.domains.URIRequirementBuilder; import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.EnvVars; import hudson.ExtensionList; import hudson.model.Item; import hudson.model.Queue; +import hudson.model.Run; +import hudson.model.TaskListener; import hudson.model.queue.Tasks; import hudson.plugins.git.BranchSpec; import hudson.plugins.git.GitSCM; @@ -54,6 +57,8 @@ import org.eclipse.jgit.lib.Constants; import org.jenkinsci.plugins.gitclient.GitClient; +import static hudson.plugins.git.util.GitUtils.expand; + /** * An implementation of this extension point allows {@link AbstractGitSCMSource} to examine a repository from a distance * without requiring a local checkout. @@ -181,14 +186,27 @@ public final SCMFileSystem build(@NonNull SCMSource source, @NonNull SCMHead hea @Override public final SCMFileSystem build(@NonNull Item owner, @NonNull SCM scm, SCMRevision rev) throws IOException, InterruptedException { + return build(scm, rev, owner, null); + } + + @Override + public SCMFileSystem build(@NonNull Run build, @NonNull SCM scm, SCMRevision rev) + throws IOException, InterruptedException { + Item owner = build.getParent(); + return build(scm, rev, owner, build); + } + + private SCMFileSystem build(@NonNull SCM scm, SCMRevision rev, Item owner, @CheckForNull Run build) + throws IOException, InterruptedException { if (scm instanceof GitSCM) { // we only support the GitSCM if the branch is completely unambiguous GitSCM git = (GitSCM) scm; List configs = git.getUserRemoteConfigs(); List branches = git.getBranches(); + EnvVars env = build == null ? null : build.getEnvironment(TaskListener.NULL); if (configs.size() == 1) { UserRemoteConfig config = configs.get(0); - String remote = config.getUrl(); + String remote = expand(config.getUrl(), env); if (remote != null && supports(remote) && branches.size() == 1 && !branches.get(0).getName().contains("*")) { StandardCredentials credentials; @@ -210,7 +228,7 @@ public final SCMFileSystem build(@NonNull Item owner, @NonNull SCM scm, SCMRevis validate(remote, credentials); SCMHead head; if (rev == null) { - String name = branches.get(0).getName(); + String name = expand(branches.get(0).getName(), env); if (name.startsWith(Constants.R_TAGS)) { head = new GitTagSCMHead( name.substring(Constants.R_TAGS.length()), @@ -219,8 +237,10 @@ public final SCMFileSystem build(@NonNull Item owner, @NonNull SCM scm, SCMRevis } else if (name.startsWith(Constants.R_HEADS)) { head = new GitBranchSCMHead(name.substring(Constants.R_HEADS.length())); } else { - if (name.startsWith(config.getName() + "/")) { - head = new GitBranchSCMHead(name.substring(config.getName().length() + 1)); + String remoteName = expand(config.getName(), env); + if (name.startsWith(remoteName + "/")) { + head = new GitBranchSCMHead(name.substring( + remoteName.length() + 1)); } else { head = new GitBranchSCMHead(name); }