diff --git a/src/main/java/hudson/plugins/git/GitAPI.java b/src/main/java/hudson/plugins/git/GitAPI.java index e5c44ff8ea..b3ecb0d1b9 100644 --- a/src/main/java/hudson/plugins/git/GitAPI.java +++ b/src/main/java/hudson/plugins/git/GitAPI.java @@ -1,12 +1,15 @@ package hudson.plugins.git; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + import edu.umd.cs.findbugs.annotations.NonNull; import hudson.EnvVars; import hudson.FilePath; import hudson.model.TaskListener; -import java.io.*; -import java.util.List; -import java.util.Set; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Repository; @@ -113,9 +116,9 @@ public String getRemoteUrl(String name) throws GitException, InterruptedExceptio @Override public void push(String remoteName, String refspec) throws GitException, InterruptedException { if (Git.USE_CLI) { - super.push(remoteName, refspec); + super.push(remoteName, refspec.trim()); } else { - jgit.push(remoteName, refspec); + jgit.push(remoteName, refspec.trim()); } } @@ -368,10 +371,16 @@ public List showRevision(ObjectId r) throws GitException { @SuppressWarnings("deprecation") public void fetch(URIish url, List refspecs) throws GitException, InterruptedException { /* Intentionally using the deprecated method because the replacement method is not serializable. */ + List trimmedRefSpecs = new ArrayList<>(); + for (RefSpec rs : refspecs) { + if (rs != null) { + trimmedRefSpecs.add(new RefSpec(rs.toString().trim())); + } + } if (Git.USE_CLI) { - super.fetch(url, refspecs); + super.fetch(url, trimmedRefSpecs); } else { - jgit.fetch(url, refspecs); + jgit.fetch(url, trimmedRefSpecs); } } diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index ae0e73766e..a181a2625c 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -1,29 +1,15 @@ package org.jenkinsci.plugins.gitclient; -import com.cloudbees.jenkins.plugins.sshcredentials.SSHUserPrivateKey; -import com.cloudbees.plugins.credentials.common.StandardCredentials; -import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials; -import edu.umd.cs.findbugs.annotations.CheckForNull; -import edu.umd.cs.findbugs.annotations.NonNull; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import hudson.EnvVars; -import hudson.FilePath; -import hudson.Launcher; -import hudson.Launcher.LocalLauncher; -import hudson.Proc; -import hudson.Util; -import hudson.console.HyperlinkNote; -import hudson.model.TaskListener; -import hudson.plugins.git.Branch; -import hudson.plugins.git.GitException; -import hudson.plugins.git.GitLockFailedException; -import hudson.plugins.git.GitObject; -import hudson.plugins.git.IGitAPI; -import hudson.plugins.git.IndexEntry; -import hudson.plugins.git.Revision; -import hudson.util.ArgumentListBuilder; -import hudson.util.Secret; -import java.io.*; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.Charset; @@ -59,6 +45,30 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; + +import com.cloudbees.jenkins.plugins.sshcredentials.SSHUserPrivateKey; +import com.cloudbees.plugins.credentials.common.StandardCredentials; +import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials; +import edu.umd.cs.findbugs.annotations.CheckForNull; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import hudson.EnvVars; +import hudson.FilePath; +import hudson.Launcher; +import hudson.Launcher.LocalLauncher; +import hudson.Proc; +import hudson.Util; +import hudson.console.HyperlinkNote; +import hudson.model.TaskListener; +import hudson.plugins.git.Branch; +import hudson.plugins.git.GitException; +import hudson.plugins.git.GitLockFailedException; +import hudson.plugins.git.GitObject; +import hudson.plugins.git.IGitAPI; +import hudson.plugins.git.IndexEntry; +import hudson.plugins.git.Revision; +import hudson.util.ArgumentListBuilder; +import hudson.util.Secret; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; @@ -524,7 +534,13 @@ public FetchCommand fetch_() { @Override public FetchCommand from(URIish remote, List refspecs) { this.url = remote; - this.refspecs = refspecs; + List trimmedRefSpecs = new ArrayList<>(); + if (refspecs != null && !refspecs.isEmpty()) { + for (RefSpec rs : refspecs) { + trimmedRefSpecs.add(new RefSpec(rs.toString().trim())); + } + } + this.refspecs = trimmedRefSpecs; return this; } @@ -609,11 +625,9 @@ public void execute() throws GitException, InterruptedException { addCheckedRemoteUrl(args, url.toString()); } - if (refspecs != null) { + if (refspecs != null && !refspecs.isEmpty()) { for (RefSpec rs : refspecs) { - if (rs != null) { - args.add(rs.toString()); - } + args.add(rs.toString().trim()); } } @@ -667,7 +681,7 @@ public void fetch(String remoteName, RefSpec... refspec) throws GitException, In if (refspec != null && refspec.length > 0) { for (RefSpec rs : refspec) { if (rs != null) { - args.add(rs.toString()); + args.add(rs.toString().trim()); } } } @@ -789,7 +803,11 @@ public CloneCommand depth(Integer depth) { @Override public CloneCommand refspecs(List refspecs) { - this.refspecs = new ArrayList<>(refspecs); + List refSpecsList = new ArrayList<>(); + for (RefSpec ref : refspecs) { + refSpecsList.add(new RefSpec(ref.toString().trim())); + } + this.refspecs = refSpecsList; return this; } @@ -2885,7 +2903,7 @@ public PushCommand to(URIish remote) { @Override public PushCommand ref(String refspec) { - this.refspec = refspec; + this.refspec = refspec.trim(); return this; } diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index a032ff42bd..9489331beb 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -14,18 +14,6 @@ import static org.jenkinsci.plugins.gitclient.CliGitAPIImpl.TIMEOUT; import static org.jenkinsci.plugins.gitclient.CliGitAPIImpl.TIMEOUT_LOG_PREFIX; -import com.cloudbees.plugins.credentials.common.StandardCredentials; -import edu.umd.cs.findbugs.annotations.NonNull; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import hudson.FilePath; -import hudson.Util; -import hudson.model.TaskListener; -import hudson.plugins.git.Branch; -import hudson.plugins.git.GitException; -import hudson.plugins.git.GitLockFailedException; -import hudson.plugins.git.GitObject; -import hudson.plugins.git.IndexEntry; -import hudson.plugins.git.Revision; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -49,6 +37,19 @@ import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Collectors; + +import com.cloudbees.plugins.credentials.common.StandardCredentials; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import hudson.FilePath; +import hudson.Util; +import hudson.model.TaskListener; +import hudson.plugins.git.Branch; +import hudson.plugins.git.GitException; +import hudson.plugins.git.GitLockFailedException; +import hudson.plugins.git.GitObject; +import hudson.plugins.git.IndexEntry; +import hudson.plugins.git.Revision; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.time.FastDateFormat; import org.eclipse.jgit.api.AddNoteCommand; @@ -624,7 +625,13 @@ public org.jenkinsci.plugins.gitclient.FetchCommand fetch_() { @Override public org.jenkinsci.plugins.gitclient.FetchCommand from(URIish remote, List refspecs) { this.url = remote; - this.refspecs = refspecs; + List trimmedRefSpecs = new ArrayList<>(); + if (refspecs != null && !refspecs.isEmpty()) { + for (RefSpec rs : refspecs) { + trimmedRefSpecs.add(new RefSpec(rs.toString().trim())); + } + } + this.refspecs = trimmedRefSpecs; return this; } @@ -669,11 +676,9 @@ public void execute() throws GitException { Git git = git(repo); List allRefSpecs = new ArrayList<>(); - if (refspecs != null) { + if (refspecs != null && !refspecs.isEmpty()) { for (RefSpec rs : refspecs) { - if (rs != null) { - allRefSpecs.add(rs); - } + allRefSpecs.add(rs); } } @@ -1432,7 +1437,11 @@ public CloneCommand reference(String reference) { @Override public CloneCommand refspecs(List refspecs) { - this.refspecs = new ArrayList<>(refspecs); + List refSpecsList = new ArrayList<>(); + for (RefSpec ref : refspecs) { + refSpecsList.add(new RefSpec(ref.toString().trim())); + } + this.refspecs = refSpecsList; return this; } @@ -1992,7 +2001,7 @@ public PushCommand to(URIish remote) { @Override public PushCommand ref(String refspec) { - this.refspec = refspec; + this.refspec = refspec.trim(); return this; } @@ -2023,8 +2032,8 @@ public PushCommand timeout(Integer timeout) { public void execute() throws GitException { try (Repository repo = getRepository()) { RefSpec ref = - (refspec != null) ? new RefSpec(fixRefSpec(refspec, repo)) : Transport.REFSPEC_PUSH_ALL; - listener.getLogger().println("RefSpec is \"" + ref + "\"."); + (refspec != null) ? new RefSpec(fixRefSpec(refspec.trim(), repo)) : Transport.REFSPEC_PUSH_ALL; + listener.getLogger().println("RefSpec is \"" + ref.toString().trim() + "\"."); Git g = git(repo); Config config = g.getRepository().getConfig(); if (remote == null) { diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImpl.java index 3d6b46d049..2168400062 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImpl.java @@ -3,6 +3,13 @@ import static java.util.Arrays.copyOfRange; import static org.apache.commons.lang.StringUtils.join; +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + import hudson.model.TaskListener; import hudson.plugins.git.GitException; import hudson.plugins.git.IGitAPI; @@ -10,12 +17,6 @@ import hudson.plugins.git.Revision; import hudson.plugins.git.Tag; import hudson.remoting.Channel; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; @@ -107,7 +108,7 @@ public void setupSubmoduleUrls(String remote, TaskListener listener) throws GitE @Override @Deprecated public void fetch(String repository, String refspec) throws GitException, InterruptedException { - fetch(repository, new RefSpec(refspec)); + fetch(repository, new RefSpec(refspec.trim())); } /** {@inheritDoc} */ @@ -146,7 +147,7 @@ public void reset() throws GitException, InterruptedException { @Override @Deprecated public void push(URIish url, String refspec) throws GitException, InterruptedException { - push().ref(refspec).to(url).execute(); + push().ref(refspec.trim()).to(url).execute(); } /** {@inheritDoc} */ @@ -159,7 +160,7 @@ public void push(String remoteName, String refspec) throws GitException, Interru } try { - push(new URIish(url), refspec); + push(new URIish(url), refspec.trim()); } catch (URISyntaxException e) { throw new GitException("bad repository URL", e); } diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java index 6b0b65fccf..858d512fef 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java @@ -1,5 +1,18 @@ package org.jenkinsci.plugins.gitclient; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Serializable; +import java.io.Writer; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + import com.cloudbees.plugins.credentials.CredentialsProvider; import com.cloudbees.plugins.credentials.common.StandardCredentials; import com.cloudbees.plugins.credentials.common.StandardUsernameCredentials; @@ -16,18 +29,6 @@ import hudson.remoting.Channel; import hudson.remoting.RemoteOutputStream; import hudson.remoting.RemoteWriter; -import java.io.IOException; -import java.io.OutputStream; -import java.io.Serializable; -import java.io.Writer; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Repository; @@ -480,7 +481,13 @@ public PushCommand push() { @Override public void fetch(URIish url, List refspecs) throws GitException, InterruptedException { /* Intentionally using the deprecated method because the replacement method is not serializable. */ - proxy.fetch(url, refspecs); + List trimmedRefSpecs = new ArrayList<>(); + if (refspecs != null && !refspecs.isEmpty()) { + for (RefSpec rs : refspecs) { + trimmedRefSpecs.add(new RefSpec(rs.toString().trim())); + } + } + proxy.fetch(url, trimmedRefSpecs); } /** {@inheritDoc} */ @@ -492,19 +499,19 @@ public void fetch(String remoteName, RefSpec... refspec) throws GitException, In /** {@inheritDoc} */ @Override public void fetch(String remoteName, RefSpec refspec) throws GitException, InterruptedException { - fetch(remoteName, new RefSpec[] {refspec}); + fetch(remoteName, new RefSpec[] { new RefSpec(refspec.toString().trim())}); } /** {@inheritDoc} */ @Override public void push(String remoteName, String refspec) throws GitException, InterruptedException { - proxy.push(remoteName, refspec); + proxy.push(remoteName, refspec.trim()); } /** {@inheritDoc} */ @Override public void push(URIish url, String refspec) throws GitException, InterruptedException { - proxy.push(url, refspec); + proxy.push(url, refspec.trim()); } /** {@inheritDoc} */ diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitCommand.java b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitCommand.java index a0ace530e4..799c92b26e 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitCommand.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitCommand.java @@ -1,6 +1,8 @@ package org.jenkinsci.plugins.gitclient; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import hudson.EnvVars; import hudson.Launcher; diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientCloneTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientCloneTest.java index c81b9aa7ad..15e0e4d0c0 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientCloneTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientCloneTest.java @@ -40,6 +40,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import org.jvnet.hudson.test.Issue; @RunWith(Parameterized.class) public class GitClientCloneTest { @@ -328,11 +329,16 @@ public void test_clone_refspec() throws Exception { })); } + private String randomSpace() { + return random.nextBoolean() ? " " : ""; + } + @Test + @Issue("JENKINS-70303") // spaces at start or end of refspec should be ignored public void test_clone_refspecs() throws Exception { List refspecs = Arrays.asList( - new RefSpec("+refs/heads/master:refs/remotes/origin/master"), - new RefSpec("+refs/heads/1.4.x:refs/remotes/origin/1.4.x")); + new RefSpec(randomSpace() + "+refs/heads/master:refs/remotes/origin/master" + randomSpace()), + new RefSpec(randomSpace() + "+refs/heads/1.4.x:refs/remotes/origin/1.4.x" + randomSpace())); testGitClient .clone_() .url(workspace.localMirror()) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientFetchTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientFetchTest.java index ef6688af30..625bd77ab7 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientFetchTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientFetchTest.java @@ -12,7 +12,7 @@ import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; -import static org.hamcrest.io.FileMatchers.*; +import static org.hamcrest.io.FileMatchers.anExistingFile; import static org.junit.Assert.assertThrows; import hudson.Util; @@ -109,6 +109,7 @@ public static void computeDefaultBranchName() throws Exception { .in(configDir) .using("git") .getClient()); + String[] output = getDefaultBranchNameCmd.runWithoutAssert("config", "--get", "init.defaultBranch"); for (String s : output) { String result = s.trim(); @@ -155,6 +156,10 @@ public void setUpRepositories() throws Exception { cliGitCommand.run("config", "--local", "tag.gpgSign", "false"); } + private String randomSpace() { + return random.nextBoolean() ? " " : ""; + } + /* Workspace -> original repo, bareWorkspace -> bare repo and newAreaWorkspace -> newArea repo */ @Test public void test_fetch() throws Exception { @@ -217,7 +222,7 @@ public void test_fetch() throws Exception { is(commit2)); /* Fetch new change into newArea repo */ - RefSpec defaultRefSpec = new RefSpec("+refs/heads/*:refs/remotes/origin/*"); + RefSpec defaultRefSpec = new RefSpec(randomSpace() + "+refs/heads/*:refs/remotes/origin/*" + randomSpace()); List refSpecs = new ArrayList<>(); refSpecs.add(defaultRefSpec); newAreaWorkspace.launchCommand("git", "config", "fetch.prune", "false");