From 58a322534f70180f5cba17e8f09c0e40df7fd962 Mon Sep 17 00:00:00 2001 From: Samantha Schwarz Date: Thu, 17 Nov 2016 13:29:49 -0500 Subject: [PATCH 001/226] Clean takes a flag that will add a --force flag to clean. See bug report https://issues.jenkins-ci.org/browse/JENKINS-26660 for more details --- src/main/java/hudson/plugins/git/GitAPI.java | 3 ++- .../jenkinsci/plugins/gitclient/CliGitAPIImpl.java | 8 ++++++-- .../org/jenkinsci/plugins/gitclient/GitClient.java | 3 ++- .../jenkinsci/plugins/gitclient/JGitAPIImpl.java | 7 ++++--- .../jenkinsci/plugins/gitclient/RemoteGitImpl.java | 4 ++-- .../jenkinsci/plugins/gitclient/GitAPITestCase.java | 13 ++++++++++++- 6 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/main/java/hudson/plugins/git/GitAPI.java b/src/main/java/hudson/plugins/git/GitAPI.java index f7a3f0ff90..ff8d43b7cd 100644 --- a/src/main/java/hudson/plugins/git/GitAPI.java +++ b/src/main/java/hudson/plugins/git/GitAPI.java @@ -308,7 +308,8 @@ public void submoduleClean(boolean recursive) throws GitException { /** {@inheritDoc} */ public void clean() throws GitException, InterruptedException { - if (Git.USE_CLI) super.clean(); else jgit.clean(); + // false provides original functionality + if (Git.USE_CLI) super.clean(false); else jgit.clean(false); } /** {@inheritDoc} */ diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 0f3ce47dfd..cba5abdc47 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -670,12 +670,16 @@ public void execute() throws GitException, InterruptedException { * Remove untracked files and directories, including files listed * in the ignore rules. * + * @param cleanSubmodule flag to add extra -f * @throws hudson.plugins.git.GitException if underlying git operation fails. * @throws java.lang.InterruptedException if interrupted. */ - public void clean() throws GitException, InterruptedException { + public void clean(boolean cleanSubmodule) throws GitException, InterruptedException { reset(true); - launchCommand("clean", "-fdx"); + String cmd = "-fdx"; + if (cleanSubmodule) cmd = "-ffdx"; + + launchCommand("clean", cmd); } /** {@inheritDoc} */ diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/GitClient.java b/src/main/java/org/jenkinsci/plugins/gitclient/GitClient.java index d886af1104..75374e8f05 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/GitClient.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/GitClient.java @@ -430,10 +430,11 @@ public interface GitClient { * git-clean(1) for working copy to * match a fresh clone. * + * @param cleanSubmodule flag to add extra -f * @throws hudson.plugins.git.GitException if underlying git operation fails. * @throws java.lang.InterruptedException if interrupted. */ - void clean() throws GitException, InterruptedException; + void clean(boolean cleanSubmodule) throws GitException, InterruptedException; diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index 3b769db970..21cb41401a 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -1178,13 +1178,14 @@ void format(RevCommit commit, @Nullable RevCommit parent, PrintWriter pw, Boolea /** * clean. * + * @param cleanSubmodule flag to add extra -f * @throws hudson.plugins.git.GitException if underlying git operation fails. */ - public void clean() throws GitException { + public void clean(boolean cleanSubmodule) throws GitException { try (Repository repo = getRepository()) { Git git = git(repo); git.reset().setMode(HARD).call(); - git.clean().setCleanDirectories(true).setIgnore(false).call(); + git.clean().setCleanDirectories(true).setIgnore(false).setForce(cleanSubmodule).call(); } catch (GitAPIException e) { throw new GitException(e); } @@ -1914,7 +1915,7 @@ private Iterable submodules() throws IOException { public void submoduleClean(boolean recursive) throws GitException { try { for (JGitAPIImpl sub : submodules()) { - sub.clean(); + sub.clean(false); if (recursive) { sub.submoduleClean(true); } diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java index d543b65eb3..386b822480 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java @@ -445,8 +445,8 @@ public void prune(RemoteConfig repository) throws GitException, InterruptedExcep * @throws hudson.plugins.git.GitException if underlying git operation fails. * @throws java.lang.InterruptedException if interrupted. */ - public void clean() throws GitException, InterruptedException { - proxy.clean(); + public void clean(boolean cleanSubmodule) throws GitException, InterruptedException { + proxy.clean(cleanSubmodule); } /** {@inheritDoc} */ diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 9b5866bc08..566c8140fb 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -828,16 +828,27 @@ public void test_clean() throws Exception { w.touch(fileName2); w.touch(fileName, "new content"); - w.git.clean(); + String dirName3 = "dir-with-submodule"; + File submodule = w.file(dirName3); + assertTrue("Did not create dir " + dirName3, submodule.mkdir()); + WorkingArea workingArea = new WorkingArea(submodule); + workingArea.init(); + workingArea.commitEmpty("init"); + + w.git.clean(false); assertFalse(w.exists(dirName1)); assertFalse(w.exists(fileName1)); assertFalse(w.exists(fileName2)); + assertTrue(w.exists(dirName3)); assertEquals("content " + fileName, w.contentOf(fileName)); assertEquals("content " + fileNameFace, w.contentOf(fileNameFace)); assertEquals("content " + fileNameSwim, w.contentOf(fileNameSwim)); String status = w.cmd("git status"); assertTrue("unexpected status " + status, status.contains("working directory clean") || status.contains("working tree clean")); + w.git.clean(true); + assertFalse(w.exists(dirName3)); + /* A few poorly placed tests of hudson.FilePath - testing JENKINS-22434 */ FilePath fp = new FilePath(w.file(fileName)); assertTrue(fp + " missing", fp.exists()); From c10831825f7c698e5ea876f133d892e057ae2ca3 Mon Sep 17 00:00:00 2001 From: Samantha Schwarz Date: Thu, 17 Nov 2016 15:22:59 -0500 Subject: [PATCH 002/226] Make original API available and update tests --- src/main/java/hudson/plugins/git/GitAPI.java | 3 +- .../plugins/gitclient/CliGitAPIImpl.java | 14 +++++++ .../plugins/gitclient/GitClient.java | 11 +++++ .../plugins/gitclient/JGitAPIImpl.java | 15 +++++++ .../plugins/gitclient/RemoteGitImpl.java | 10 +++++ .../plugins/gitclient/GitAPITestCase.java | 42 +++++++++++++------ 6 files changed, 81 insertions(+), 14 deletions(-) diff --git a/src/main/java/hudson/plugins/git/GitAPI.java b/src/main/java/hudson/plugins/git/GitAPI.java index ff8d43b7cd..f7a3f0ff90 100644 --- a/src/main/java/hudson/plugins/git/GitAPI.java +++ b/src/main/java/hudson/plugins/git/GitAPI.java @@ -308,8 +308,7 @@ public void submoduleClean(boolean recursive) throws GitException { /** {@inheritDoc} */ public void clean() throws GitException, InterruptedException { - // false provides original functionality - if (Git.USE_CLI) super.clean(false); else jgit.clean(false); + if (Git.USE_CLI) super.clean(); else jgit.clean(); } /** {@inheritDoc} */ diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index cba5abdc47..89b4f4444b 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -682,6 +682,20 @@ public void clean(boolean cleanSubmodule) throws GitException, InterruptedExcept launchCommand("clean", cmd); } + /** + * Remove untracked files and directories, including files listed + * in the ignore rules. + * + * @throws hudson.plugins.git.GitException if underlying git operation fails. + * @throws java.lang.InterruptedException if interrupted. + */ + public void clean() throws GitException, InterruptedException { + reset(true); + String cmd = "-fdx"; + + launchCommand("clean", cmd); + } + /** {@inheritDoc} */ public ObjectId revParse(String revName) throws GitException, InterruptedException { diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/GitClient.java b/src/main/java/org/jenkinsci/plugins/gitclient/GitClient.java index 75374e8f05..0041b43603 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/GitClient.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/GitClient.java @@ -424,6 +424,17 @@ public interface GitClient { */ void prune(RemoteConfig repository) throws GitException, InterruptedException; + /** + * Fully revert working copy to a clean state, i.e. run both + * git-reset(1) --hard then + * git-clean(1) for working copy to + * match a fresh clone. + * + * @throws hudson.plugins.git.GitException if underlying git operation fails. + * @throws java.lang.InterruptedException if interrupted. + */ + void clean() throws GitException, InterruptedException; + /** * Fully revert working copy to a clean state, i.e. run both * git-reset(1) --hard then diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index 21cb41401a..d731a48e4c 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -1191,6 +1191,21 @@ public void clean(boolean cleanSubmodule) throws GitException { } } + /** + * clean. + * + * @throws hudson.plugins.git.GitException if underlying git operation fails. + */ + public void clean() throws GitException { + try (Repository repo = getRepository()) { + Git git = git(repo); + git.reset().setMode(HARD).call(); + git.clean().setCleanDirectories(true).setIgnore(false).call(); + } catch (GitAPIException e) { + throw new GitException(e); + } + } + /** * clone_. * diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java index 386b822480..40c2a4817f 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java @@ -449,6 +449,16 @@ public void clean(boolean cleanSubmodule) throws GitException, InterruptedExcept proxy.clean(cleanSubmodule); } + /** + * clean. + * + * @throws hudson.plugins.git.GitException if underlying git operation fails. + * @throws java.lang.InterruptedException if interrupted. + */ + public void clean() throws GitException, InterruptedException { + proxy.clean(); + } + /** {@inheritDoc} */ public void branch(String name) throws GitException, InterruptedException { proxy.branch(name); diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 566c8140fb..33a22e4b61 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -786,6 +786,35 @@ public void test_addRemoteUrl_local_clone() throws Exception { assertEquals("Wrong origin URL after add", localMirror(), w.git.getRemoteUrl("origin")); } + public void test_clean_with_parameter() throws Exception { + w.init(); + w.commitEmpty("init"); + + String dirName1 = "dir1"; + String fileName1 = dirName1 + File.separator + "fileName1"; + String fileName2 = "fileName2"; + assertTrue("Did not create dir " + dirName1, w.file(dirName1).mkdir()); + w.touch(fileName1); + w.touch(fileName2); + + String dirName3 = "dir-with-submodule"; + File submodule = w.file(dirName3); + assertTrue("Did not create dir " + dirName3, submodule.mkdir()); + WorkingArea workingArea = new WorkingArea(submodule); + workingArea.init(); + workingArea.commitEmpty("init"); + + w.git.clean(false); + assertFalse(w.exists(dirName1)); + assertFalse(w.exists(fileName1)); + assertFalse(w.exists(fileName2)); + assertTrue(w.exists(dirName3)); + + w.git.clean(true); + assertFalse(w.exists(dirName3)); + + } + @Bug(20410) public void test_clean() throws Exception { w.init(); @@ -828,27 +857,16 @@ public void test_clean() throws Exception { w.touch(fileName2); w.touch(fileName, "new content"); - String dirName3 = "dir-with-submodule"; - File submodule = w.file(dirName3); - assertTrue("Did not create dir " + dirName3, submodule.mkdir()); - WorkingArea workingArea = new WorkingArea(submodule); - workingArea.init(); - workingArea.commitEmpty("init"); - - w.git.clean(false); + w.git.clean(); assertFalse(w.exists(dirName1)); assertFalse(w.exists(fileName1)); assertFalse(w.exists(fileName2)); - assertTrue(w.exists(dirName3)); assertEquals("content " + fileName, w.contentOf(fileName)); assertEquals("content " + fileNameFace, w.contentOf(fileNameFace)); assertEquals("content " + fileNameSwim, w.contentOf(fileNameSwim)); String status = w.cmd("git status"); assertTrue("unexpected status " + status, status.contains("working directory clean") || status.contains("working tree clean")); - w.git.clean(true); - assertFalse(w.exists(dirName3)); - /* A few poorly placed tests of hudson.FilePath - testing JENKINS-22434 */ FilePath fp = new FilePath(w.file(fileName)); assertTrue(fp + " missing", fp.exists()); From 4a33eb94760d22b8f692a5beade549a41e5a5f08 Mon Sep 17 00:00:00 2001 From: Samantha Schwarz Date: Thu, 17 Nov 2016 16:46:09 -0500 Subject: [PATCH 003/226] Remove duplication --- .../java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 89b4f4444b..85476de852 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -690,10 +690,7 @@ public void clean(boolean cleanSubmodule) throws GitException, InterruptedExcept * @throws java.lang.InterruptedException if interrupted. */ public void clean() throws GitException, InterruptedException { - reset(true); - String cmd = "-fdx"; - - launchCommand("clean", cmd); + this.clean(false); } /** {@inheritDoc} */ From aad3bd23c1811ccfe02bf0a242f34bf9e288113a Mon Sep 17 00:00:00 2001 From: Samantha Schwarz Date: Fri, 18 Nov 2016 13:56:35 -0500 Subject: [PATCH 004/226] Remove more duplication --- .../org/jenkinsci/plugins/gitclient/JGitAPIImpl.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index d731a48e4c..ad933e9ac4 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -1197,13 +1197,7 @@ public void clean(boolean cleanSubmodule) throws GitException { * @throws hudson.plugins.git.GitException if underlying git operation fails. */ public void clean() throws GitException { - try (Repository repo = getRepository()) { - Git git = git(repo); - git.reset().setMode(HARD).call(); - git.clean().setCleanDirectories(true).setIgnore(false).call(); - } catch (GitAPIException e) { - throw new GitException(e); - } + this.clean(false); } /** @@ -1930,7 +1924,7 @@ private Iterable submodules() throws IOException { public void submoduleClean(boolean recursive) throws GitException { try { for (JGitAPIImpl sub : submodules()) { - sub.clean(false); + sub.clean(); if (recursive) { sub.submoduleClean(true); } From 3a292af69a2d52e1a3ae84d338aeff913db5ed96 Mon Sep 17 00:00:00 2001 From: Samantha Schwarz Date: Fri, 18 Nov 2016 16:29:24 -0500 Subject: [PATCH 005/226] Trigger rebuild due to maven failure From 4875932376f6d43eda4ba05f0022c3f4c6905fea Mon Sep 17 00:00:00 2001 From: Tzafrir Poupko Date: Wed, 23 Nov 2016 15:07:57 +0200 Subject: [PATCH 006/226] Show merges in generated changelog Make list merges optional and explicit Support chaining listMerges in ChangeLogCommand Change max value to allow testing current JGit behavior --- .../plugins/gitclient/ChangelogCommand.java | 7 ++++ .../plugins/gitclient/CliGitAPIImpl.java | 8 ++++ .../plugins/gitclient/JGitAPIImpl.java | 9 ++++- .../plugins/gitclient/GitAPITestCase.java | 37 ++++++++++++++----- 4 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/ChangelogCommand.java b/src/main/java/org/jenkinsci/plugins/gitclient/ChangelogCommand.java index 96c2a0ee67..31a1e69d35 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/ChangelogCommand.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/ChangelogCommand.java @@ -121,4 +121,11 @@ public interface ChangelogCommand extends GitCommand { * ChangelogCommand instance or files will be left open. */ void abort(); + + /** + * Include merge commits in the changelog + * @param flag true if merge commits should be listed + * @return a {@link org.jenkinsci.plugins.gitclient.ChangelogCommand} object. + */ + ChangelogCommand listMerges(boolean flag); } diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 5affbddc7e..9bfb630895 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -835,6 +835,7 @@ public ChangelogCommand changelog() { Integer n = null; Writer out = null; + boolean listMerges = false; public ChangelogCommand excludes(String rev) { revs.add(sanitize('^'+rev)); @@ -873,6 +874,8 @@ public void execute() throws GitException, InterruptedException { args.add("--format="+RAW); if (n!=null) args.add("-n").add(n); + if (listMerges) + args.add("-m"); for (String rev : this.revs) args.add(rev); @@ -888,6 +891,11 @@ public void execute() throws GitException, InterruptedException { throw new GitException("Error launching git whatchanged",e); } } + + public ChangelogCommand listMerges(boolean flag) { + listMerges = flag; + 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 81dfe4d003..390fc4f584 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -1058,6 +1058,7 @@ public ChangelogCommand changelog() { RevWalk walk = new RevWalk(or); Writer out; boolean hasIncludedRev = false; + boolean listMerges = false; public ChangelogCommand excludes(String rev) { try { @@ -1131,8 +1132,7 @@ public void execute() throws GitException, InterruptedException { this.includes("HEAD"); } for (RevCommit commit : walk) { - // git whatachanged doesn't show the merge commits unless -m is given - if (commit.getParentCount()>1) continue; + if (commit.getParentCount() > 1 && !listMerges) continue; formatter.format(commit, null, pw, true); } @@ -1142,6 +1142,11 @@ public void execute() throws GitException, InterruptedException { closeResources(); } } + + public ChangelogCommand listMerges(boolean flag) { + this.listMerges = flag; + return this; + } }; } diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 8524db8c04..06785ac8a5 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -3013,6 +3013,30 @@ public void test_merge_with_message() throws Exception { assertEquals("Custom message merge failed. Should have set custom merge message.", mergeMessage, resultMessage); } + public void test_changelog_with_merge_commit() throws Exception { + w.init(); + w.commitEmpty("init"); + + // First commit to branch1 + w.git.branch("branch1"); + w.git.checkout("branch1"); + w.touch("file1", "content1"); + w.git.add("file1"); + w.git.commit("commit1"); + String commitSha1 = w.git.revParse("HEAD").name(); + + // Merge branch1 into master + w.git.checkout("master"); + String mergeMessage = "Merge message to be tested."; + w.git.merge().setMessage(mergeMessage).setGitPluginFastForwardMode(MergeCommand.GitPluginFastForwardMode.NO_FF).setRevisionToMerge(w.git.getHeadRev(w.repoPath(), "branch1")).execute(); + // Obtain last commit message + String mergeSha1 = w.git.revParse("HEAD").name(); + + assertThat("Merge commit exists in output",get_changelog(w.git.changelog()),not(containsString(mergeSha1))); + assertThat("Merge commit exists in output",get_changelog(w.git.changelog().listMerges(false)),not(containsString(mergeSha1))); + assertThat("Merge commit is not the first commit",get_changelog(w.git.changelog().listMerges(true)),startsWith(("commit " + mergeSha1))); + } + @Deprecated public void test_merge_refspec() throws Exception { w.init(); @@ -3563,15 +3587,10 @@ public void test_getHeadRev_returns_accurate_SHA1_values() throws Exception { check_headRev(w.repoPath(), getMirrorHead()); } - private void check_changelog_sha1(final String sha1, final String branchName) throws InterruptedException - { - ChangelogCommand changelogCommand = w.git.changelog(); - changelogCommand.max(1); + private String get_changelog(ChangelogCommand changelogCommand) throws InterruptedException{ StringWriter writer = new StringWriter(); - changelogCommand.to(writer); - changelogCommand.execute(); - String splitLog[] = writer.toString().split("[\\n\\r]", 3); // Extract first line of changelog - assertEquals("Wrong changelog line 1 on branch " + branchName, "commit " + sha1, splitLog[0]); + changelogCommand.to(writer).execute(); + return writer.toString(); } public void test_changelog() throws Exception { @@ -3581,7 +3600,7 @@ public void test_changelog() throws Exception { w.git.add("changelog-file"); w.git.commit("changelog-commit-message"); String sha1 = w.git.revParse("HEAD").name(); - check_changelog_sha1(sha1, "master"); + assertThat("Wrong changelog line 1 on branch master", get_changelog(w.git.changelog().max(1)),startsWith("commit " + sha1)); } public void test_show_revision_for_merge() throws Exception { From 87a0e378b9baf2d547f4a8f90055c2d799ad2776 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 27 Dec 2017 09:15:15 -0700 Subject: [PATCH 007/226] Require JDK 8 for compile and runtime Depend on Jenkins LTS 2.60.1. Test in Jenkinsfile with Jenkins 2.60.1 and 2.89.1. Using Jenkins 2.89.1 requires sshd 2.2 (require upper bounds check) --- Jenkinsfile | 2 +- pom.xml | 33 ++++++++------------------------- 2 files changed, 9 insertions(+), 26 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index b4badc79b8..17cb60ac35 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,7 +1,7 @@ #!groovy // build both versions, retry test failures -buildPlugin(jenkinsVersions: [null, '2.60.3'], +buildPlugin(jenkinsVersions: [null, '2.89.1'], findbugs: [run:true, archive:true, unstableTotalAll: '0'], failFast: false) diff --git a/pom.xml b/pom.xml index b015e75943..8bd7048e52 100644 --- a/pom.xml +++ b/pom.xml @@ -5,13 +5,13 @@ org.jenkins-ci.plugins plugin - 2.37 + 3.2 org.jenkins-ci.plugins git-client - 2.7.1-SNAPSHOT + 3.0.0-SNAPSHOT hpi Jenkins Git client plugin @@ -45,8 +45,8 @@ UTF-8 -Dfile.encoding=${project.build.sourceEncoding} 2.9 - 1.625.3 - 7 + 2.60.1 + 8 4.5.4.201711221230-r 4.5.0.201609210915-r @@ -137,7 +137,7 @@ org.jenkins-ci.modules sshd - 1.11 + 2.2 test @@ -198,8 +198,8 @@ maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 @@ -213,7 +213,7 @@ true false - http://docs.oracle.com/javase/7/docs/api/ + http://docs.oracle.com/javase/8/docs/api/ http://download.eclipse.org/jgit/site/${jgit.javadoc.version}/org.eclipse.jgit/apidocs/ @@ -256,23 +256,6 @@ - - org.apache.maven.plugins - maven-enforcer-plugin - 1.4.2.jenkins-1 - - - - - - org.jenkins-ci.modules:instance-identity - - org.jenkins-ci.modules:ssh-cli-auth - - - - - From 01af3ff432b6dd1340e40b709ee5582d944f6a0a Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 27 Dec 2017 09:25:13 -0700 Subject: [PATCH 008/226] Fail on findbugs warnings Prior to requiring JDK at compile time and at run time, the Jenkins versions being tested (1.625.3 and 2.60.1) were too different to have a single code base be free of findbugs warnings with both Jenkins versions. Now that JDK 8 is required, the build can be configured to fail if a new findbugs warning is introduced. --- pom.xml | 2 +- src/main/java/hudson/plugins/git/GitTool.java | 9 --------- .../jenkinsci/plugins/gitclient/AbstractGitAPIImpl.java | 5 ++++- .../plugins/gitclient/LegacyCompatibleGitAPIImpl.java | 5 ++++- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/pom.xml b/pom.xml index 8bd7048e52..c726396da7 100644 --- a/pom.xml +++ b/pom.xml @@ -228,7 +228,7 @@ findbugs-maven-plugin ${skipFindbugs} - false + true true true diff --git a/src/main/java/hudson/plugins/git/GitTool.java b/src/main/java/hudson/plugins/git/GitTool.java index 14888df7dd..64eb61a40f 100644 --- a/src/main/java/hudson/plugins/git/GitTool.java +++ b/src/main/java/hudson/plugins/git/GitTool.java @@ -79,9 +79,6 @@ private static GitTool[] getInstallations(DescriptorImpl descriptor) { */ public static GitTool getDefaultInstallation() { Jenkins jenkinsInstance = Jenkins.getInstance(); - if (jenkinsInstance == null) { - return null; - } DescriptorImpl gitTools = jenkinsInstance.getDescriptorByType(GitTool.DescriptorImpl.class); GitTool tool = gitTools.getInstallation(GitTool.DEFAULT); if (tool != null) { @@ -120,9 +117,6 @@ public static void onLoaded() { //Creates default tool installation if needed. Uses "git" or migrates data from previous versions Jenkins jenkinsInstance = Jenkins.getInstance(); - if (jenkinsInstance == null) { - return; - } DescriptorImpl descriptor = (DescriptorImpl) jenkinsInstance.getDescriptor(GitTool.class); GitTool[] installations = getInstallations(descriptor); @@ -192,9 +186,6 @@ public List> getApplicableDesccriptors() { public List> getApplicableDescriptors() { List> r = new ArrayList<>(); Jenkins jenkinsInstance = Jenkins.getInstance(); - if (jenkinsInstance == null) { - return r; - } for (ToolDescriptor td : jenkinsInstance.>getDescriptorList(ToolInstallation.class)) { if (GitTool.class.isAssignableFrom(td.clazz)) { // This checks cast is allowed r.add((ToolDescriptor)td); // This is the unchecked cast diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/AbstractGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/AbstractGitAPIImpl.java index b102d6244d..823759a57c 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/AbstractGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/AbstractGitAPIImpl.java @@ -92,7 +92,10 @@ public void merge(ObjectId rev) throws GitException, InterruptedException { * @return a {@link java.lang.Object} object. */ protected Object writeReplace() { - return remoteProxyFor(Channel.current().export(GitClient.class, this)); + Channel currentChannel = Channel.current(); + if (currentChannel == null) + return null; + return remoteProxyFor(currentChannel.export(GitClient.class, this)); } /** diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImpl.java index 8d88e74b64..7651619f62 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImpl.java @@ -195,7 +195,10 @@ public final List lsTree(String treeIsh) throws GitException, Interr /** {@inheritDoc} */ @Override protected Object writeReplace() { - return remoteProxyFor(Channel.current().export(IGitAPI.class, this)); + Channel currentChannel = Channel.current(); + if (currentChannel == null) + return null; + return remoteProxyFor(currentChannel.export(IGitAPI.class, this)); } /** From b5b2b69f2c0e63f9bf7d6314f4f1d339adbb38f6 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 27 Dec 2017 09:40:06 -0700 Subject: [PATCH 009/226] Use Java 8 switch over string for clarity --- .../jenkinsci/plugins/gitclient/Netrc.java | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/Netrc.java b/src/main/java/org/jenkinsci/plugins/gitclient/Netrc.java index 45a4ab88c0..8b92a66587 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/Netrc.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/Netrc.java @@ -122,20 +122,24 @@ synchronized private Netrc parse() { break; case REQ_KEY: - if ("login".equals(match)) { - state = ParseState.LOGIN; - } - else if ("password".equals(match)) { - state = ParseState.PASSWORD; - } - else if ("macdef".equals(match)) { - state = ParseState.MACDEF; - } - else if ("machine".equals(match)) { - state = ParseState.MACHINE; - } - else { + if (null == match) { state = ParseState.REQ_VALUE; + } else switch (match) { + case "login": + state = ParseState.LOGIN; + break; + case "password": + state = ParseState.PASSWORD; + break; + case "macdef": + state = ParseState.MACDEF; + break; + case "machine": + state = ParseState.MACHINE; + break; + default: + state = ParseState.REQ_VALUE; + break; } break; From dd879703ecc292cac207028112b143717636532f Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 27 Dec 2017 09:45:57 -0700 Subject: [PATCH 010/226] Use JDK 8 lambda expressions for easier reading --- .../java/hudson/plugins/git/Revision.java | 7 +- .../plugins/gitclient/JGitAPIImpl.java | 6 +- .../plugins/gitclient/GitAPITestCase.java | 77 +++++-------------- 3 files changed, 23 insertions(+), 67 deletions(-) diff --git a/src/main/java/hudson/plugins/git/Revision.java b/src/main/java/hudson/plugins/git/Revision.java index 9268468db2..6e40cd4b6b 100644 --- a/src/main/java/hudson/plugins/git/Revision.java +++ b/src/main/java/hudson/plugins/git/Revision.java @@ -118,12 +118,7 @@ public String toString() { StringBuilder s = new StringBuilder("Revision " + revisionName + " ("); if (branches != null) { Joiner.on(", ").appendTo(s, - Iterables.transform(branches, new Function() { - - public String apply(Branch from) { - return Util.fixNull(from.getName()); - } - })); + Iterables.transform(branches, (Branch from) -> Util.fixNull(from.getName()))); } s.append(')'); return s.toString(); diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index a9f0038e25..73793e1dd2 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -2563,11 +2563,7 @@ public String describe(ObjectId tip) throws IOException { throw new GitException("No tags can describe "+tip); // if all the nodes are dominated by all the tags, the walk stops - Collections.sort(candidates,new Comparator() { - public int compare(Candidate o1, Candidate o2) { - return o1.depth-o2.depth; - } - }); + Collections.sort(candidates, (Candidate o1, Candidate o2) -> o1.depth-o2.depth); return candidates.get(0).describe(tipId); } catch (IOException e) { diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 1ac97c2996..5066f7d24c 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -672,18 +672,12 @@ public void test_clone_refspec() throws Exception { w.git.clone_().url(localMirror()).repositoryName("origin").execute(); final WorkingArea w2 = new WorkingArea(); w2.launchCommand("git", "clone", localMirror(), "./"); - w2.git.withRepository(new RepositoryCallback() { - public Void invoke(final Repository realRepo, VirtualChannel channel) throws IOException, InterruptedException { - return w.git.withRepository(new RepositoryCallback() { - public Void invoke(final Repository implRepo, VirtualChannel channel) { - final String realRefspec = realRepo.getConfig().getString(ConfigConstants.CONFIG_REMOTE_SECTION, Constants.DEFAULT_REMOTE_NAME, "fetch"); - final String implRefspec = implRepo.getConfig().getString(ConfigConstants.CONFIG_REMOTE_SECTION, Constants.DEFAULT_REMOTE_NAME, "fetch"); - assertEquals("Refspec not as git-clone", realRefspec, implRefspec); - return null; - } - }); - } - }); + w2.git.withRepository((final Repository realRepo, VirtualChannel channel) -> w.git.withRepository((final Repository implRepo, VirtualChannel channel1) -> { + final String realRefspec = realRepo.getConfig().getString(ConfigConstants.CONFIG_REMOTE_SECTION, Constants.DEFAULT_REMOTE_NAME, "fetch"); + final String implRefspec = implRepo.getConfig().getString(ConfigConstants.CONFIG_REMOTE_SECTION, Constants.DEFAULT_REMOTE_NAME, "fetch"); + assertEquals("Refspec not as git-clone", realRefspec, implRefspec); + return null; + })); } public void test_clone_refspecs() throws Exception { @@ -692,14 +686,13 @@ public void test_clone_refspecs() throws Exception { new RefSpec("+refs/heads/1.4.x:refs/remotes/origin/1.4.x") ); w.git.clone_().url(localMirror()).refspecs(refspecs).repositoryName("origin").execute(); - w.git.withRepository(new RepositoryCallback() { - public Void invoke(Repository repo, VirtualChannel channel) throws IOException, InterruptedException { + w.git.withRepository((Repository repo, VirtualChannel channel) -> { String[] fetchRefSpecs = repo.getConfig().getStringList(ConfigConstants.CONFIG_REMOTE_SECTION, Constants.DEFAULT_REMOTE_NAME, "fetch"); assertEquals("Expected 2 refspecs", 2, fetchRefSpecs.length); assertEquals("Incorrect refspec 1", "+refs/heads/master:refs/remotes/origin/master", fetchRefSpecs[0]); assertEquals("Incorrect refspec 2", "+refs/heads/1.4.x:refs/remotes/origin/1.4.x", fetchRefSpecs[1]); return null; - }}); + }); Set remoteBranches = w.git.getRemoteBranches(); assertBranchesExist(remoteBranches, "origin/master"); assertBranchesExist(remoteBranches, "origin/1.4.x"); @@ -2227,12 +2220,11 @@ private void assertSubmoduleRepository(File submoduleDir) throws Exception { /* Assert that when we invoke the repository callback it gets a * functioning repository object */ - submoduleClient.withRepository(new RepositoryCallback() { - public Void invoke(final Repository repo, VirtualChannel channel) throws IOException, InterruptedException { - assertTrue(repo.getDirectory() + " is not a valid repository", - repo.getObjectDatabase().exists()); - return null; - }}); + submoduleClient.withRepository((final Repository repo, VirtualChannel channel) -> { + assertTrue(repo.getDirectory() + " is not a valid repository", + repo.getObjectDatabase().exists()); + return null; + }); } private String listDir(File dir) { @@ -3742,27 +3734,16 @@ public void test_show_revision_for_merge() throws Exception { List revisionDetails = w.git.showRevision(from, to); - Collection commits = Collections2.filter(revisionDetails, new Predicate() { - public boolean apply(String detail) { - return detail.startsWith("commit "); - } - }); + Collection commits = Collections2.filter(revisionDetails, (String detail) -> detail.startsWith("commit ")); assertEquals(3, commits.size()); assertTrue(commits.contains("commit 4f2964e476776cf59be3e033310f9177bedbf6a8")); // Merge commit is duplicated as have to capture changes that may have been made as part of merge assertTrue(commits.contains("commit b53374617e85537ec46f86911b5efe3e4e2fa54b (from 4f2964e476776cf59be3e033310f9177bedbf6a8)")); assertTrue(commits.contains("commit b53374617e85537ec46f86911b5efe3e4e2fa54b (from 45e76942914664ee19f31d90e6f2edbfe0d13a46)")); - Collection diffs = Collections2.filter(revisionDetails, new Predicate() { - public boolean apply(String detail) { - return detail.startsWith(":"); - } - }); - Collection paths = Collections2.transform(diffs, new Function() { - public String apply(String diff) { - return diff.substring(diff.indexOf('\t')+1).trim(); // Windows diff output ^M removed by trim() - } - }); + Collection diffs = Collections2.filter(revisionDetails, (String detail) -> detail.startsWith(":")); + Collection paths = Collections2.transform(diffs, (String diff) -> diff.substring(diff.indexOf('\t')+1).trim() // Windows diff output ^M removed by trim() + ); assertTrue(paths.contains(".gitignore")); // Some irrelevant changes will be listed due to merge commit @@ -3786,20 +3767,12 @@ public void test_show_revision_for_merge_exclude_files() throws Exception { List revisionDetails = w.git.showRevision(from, to, useRawOutput); - Collection commits = Collections2.filter(revisionDetails, new Predicate() { - public boolean apply(String detail) { - return detail.startsWith("commit "); - } - }); + Collection commits = Collections2.filter(revisionDetails, (String detail) -> detail.startsWith("commit ")); assertEquals(2, commits.size()); assertTrue(commits.contains("commit 4f2964e476776cf59be3e033310f9177bedbf6a8")); assertTrue(commits.contains("commit b53374617e85537ec46f86911b5efe3e4e2fa54b")); - Collection diffs = Collections2.filter(revisionDetails, new Predicate() { - public boolean apply(String detail) { - return detail.startsWith(":"); - } - }); + Collection diffs = Collections2.filter(revisionDetails, (String detail) -> detail.startsWith(":")); assertTrue(diffs.isEmpty()); } @@ -3827,11 +3800,7 @@ public void test_show_revision_for_single_commit() throws Exception { w = clone(localMirror()); ObjectId to = ObjectId.fromString("51de9eda47ca8dcf03b2af58dfff7355585f0d0c"); List revisionDetails = w.git.showRevision(null, to); - Collection commits = Collections2.filter(revisionDetails, new Predicate() { - public boolean apply(String detail) { - return detail.startsWith("commit "); - } - }); + Collection commits = Collections2.filter(revisionDetails, (String detail) -> detail.startsWith("commit ")); assertEquals(1, commits.size()); assertTrue(commits.contains("commit 51de9eda47ca8dcf03b2af58dfff7355585f0d0c")); } @@ -3844,11 +3813,7 @@ public void test_show_revision_for_first_commit() throws Exception { w.git.commit("first"); ObjectId first = w.head(); List revisionDetails = w.git.showRevision(first); - Collection commits = Collections2.filter(revisionDetails, new Predicate() { - public boolean apply(String detail) { - return detail.startsWith("commit "); - } - }); + Collection commits = Collections2.filter(revisionDetails, (String detail) -> detail.startsWith("commit ")); assertTrue("Commits '" + commits + "' missing " + first.getName(), commits.contains("commit " + first.getName())); assertEquals("Commits '" + commits + "' wrong size", 1, commits.size()); } From f242028710f902c4ced6351148e3b9990bd22d32 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 27 Dec 2017 09:52:26 -0700 Subject: [PATCH 011/226] Use JDK 8 member reference for easier reading test --- .../jenkinsci/plugins/gitclient/GitAPITestCase.java | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 5066f7d24c..03edbceb6d 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -18,6 +18,7 @@ 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; @@ -467,22 +468,14 @@ private void check_remote_url(final String repositoryName) throws InterruptedExc } private void assertBranchesExist(Set branches, String ... names) throws InterruptedException { - Collection branchNames = Collections2.transform(branches, new Function() { - public String apply(Branch branch) { - return branch.getName(); - } - }); + Collection branchNames = Collections2.transform(branches, GitObject::getName); for (String name : names) { assertTrue(name + " branch not found in " + branchNames, branchNames.contains(name)); } } private void assertBranchesNotExist(Set branches, String ... names) throws InterruptedException { - Collection branchNames = Collections2.transform(branches, new Function() { - public String apply(Branch branch) { - return branch.getName(); - } - }); + Collection branchNames = Collections2.transform(branches, GitObject::getName); for (String name : names) { assertFalse(name + " branch found in " + branchNames, branchNames.contains(name)); } From 4a67e82da9f6dd32c69eef8f9614e2289f48d446 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 27 Dec 2017 10:03:49 -0700 Subject: [PATCH 012/226] Use JGit 4.9.2 JGit versions prior to 4.9.0 required work arounds and test exclusions for tag fetching, renamed submodules, a merge test, and a submodule cleanup test case. JGit 4.9.0 no longer requires those work arounds, so they are removed from the code. Previously, the tags refspec had to be passed in addition to setting the FETCH_TAGS tagOpt. JGit 4.9.0 fixed that bug. Previously, renamed submodules were not well-behaved in JGit (compared to command line git). JGit 4.9.0 fixed that bug. Previously, JGit did not copy the expected revision in a particular merge test cases in GitAPITestCase, while command line git did. JGit 4.9.0 has made JGit consistent with command line git in this case. Previously, GitClient.submoduleClean() left untracked content in the JGit implementation. That is now fixed (though that may purely be a fix in the GitClient, not in JGit). --- pom.xml | 4 +-- .../plugins/gitclient/JGitAPIImpl.java | 9 ++---- .../plugins/gitclient/GitAPITestCase.java | 10 +++---- .../plugins/gitclient/GitClientTest.java | 28 ++++++++----------- 4 files changed, 21 insertions(+), 30 deletions(-) diff --git a/pom.xml b/pom.xml index c726396da7..69cb19f23f 100644 --- a/pom.xml +++ b/pom.xml @@ -47,8 +47,8 @@ 2.9 2.60.1 8 - 4.5.4.201711221230-r - 4.5.0.201609210915-r + 4.9.2.201712150930-r + 4.9.2.201712150930-r diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index 73793e1dd2..9ab6c9d247 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -587,10 +587,6 @@ public void execute() throws GitException, InterruptedException { Git git = git(repo); List allRefSpecs = new ArrayList<>(); - if (tags) { - // see http://stackoverflow.com/questions/14876321/jgit-fetch-dont-update-tag - allRefSpecs.add(new RefSpec("+refs/tags/*:refs/tags/*")); - } if (refspecs != null) for (RefSpec rs: refspecs) if (rs != null) @@ -623,6 +619,9 @@ public void execute() throws GitException, InterruptedException { FetchCommand fetch = git.fetch(); fetch.setTagOpt(tags ? TagOpt.FETCH_TAGS : TagOpt.NO_TAGS); + if (allRefSpecs.isEmpty() && tags) { + allRefSpecs.add(new RefSpec("+refs/tags/*:refs/tags/*")); + } fetch.setRemote(url.toString()); fetch.setCredentialsProvider(getProvider()); @@ -656,9 +655,7 @@ public void fetch(String remoteName, RefSpec... refspec) throws GitException { if (remoteName != null) fetch.setRemote(remoteName); fetch.setCredentialsProvider(getProvider()); - // see http://stackoverflow.com/questions/14876321/jgit-fetch-dont-update-tag List refSpecs = new ArrayList<>(); - refSpecs.add(new RefSpec("+refs/tags/*:refs/tags/*")); if (refspec != null && refspec.length > 0) for (RefSpec rs: refspec) if (rs != null) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 03edbceb6d..d671bad639 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -1006,12 +1006,12 @@ public void test_fetch() throws Exception { * command line less than 1.9. Assert that change arrives in * repo if git command line 1.9 or later. */ newArea.git.merge().setRevisionToMerge(bareCommit5).execute(); - assertTrue("JGit should not have copied the revision", newArea.git instanceof CliGitAPIImpl); - assertTrue("Wrong git version", w.cgit().isAtLeastVersion(1, 9, 0, 0)); + // JGit 4.9.0 and later copy the revision, JGit 4.8.0 and earlier did not + // assertTrue("JGit should not have copied the revision", newArea.git instanceof CliGitAPIImpl); + if (newArea.git instanceof CliGitAPIImpl) { + assertTrue("Wrong git version", w.cgit().isAtLeastVersion(1, 9, 0, 0)); + } expectedHead = bareCommit5; - } catch (org.eclipse.jgit.api.errors.JGitInternalException je) { - String expectedSubString = "Missing commit " + bareCommit5.name(); - assertTrue("Wrong jgit message :" + je.getMessage(), je.getMessage().contains(expectedSubString)); } catch (GitException ge) { assertTrue("Wrong cli git message :" + ge.getMessage(), ge.getMessage().contains("Could not merge") || diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java index bb1a8e1d75..79b4655e7a 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java @@ -779,6 +779,13 @@ public void testCheckoutWithoutLFSWhenLFSNotAvailable() throws Exception { assertEquals("Incorrect non-LFS file contents in " + uuidFile, expectedContent, fileContent); } + /* + * JGit versions prior to 4.9.0 required a work around that the + * tags refspec had to be passed in addition to setting the + * FETCH_TAGS tagOpt. JGit 4.9.0 fixed that bug. This test would + * throw a DuplicateRef exception with JGit 4.9.0 prior to the + * removal of the work around (from JGitAPIImpl). + */ @Test public void testDeleteRef() throws Exception { assertThat(gitClient.getRefNames(""), is(empty())); @@ -1525,22 +1532,15 @@ public void testSubmoduleClean() throws Exception { // Test may fail if updateSubmodule called with remoteTracking == true // and the remoteTracking argument is used in the updateSubmodule call updateSubmodule(upstream, branchName, null); - if (gitImplName.equals("git")) { - assertSubmoduleDirectories(gitClient, true, "firewall", "ntp", "sshkeys"); - assertSubmoduleContents("firewall", "ntp", "sshkeys"); - } else { - assertSubmoduleDirectories(gitClient, true, "firewall", "ntp"); // No renamed submodule - assertSubmoduleContents("firewall", "ntp"); // No renamed submodule - } + assertSubmoduleDirectories(gitClient, true, "firewall", "ntp", "sshkeys"); + assertSubmoduleContents("firewall", "ntp", "sshkeys"); final File firewallDir = new File(repoRoot, "modules/firewall"); final File firewallFile = File.createTempFile("untracked-", ".txt", firewallDir); final File ntpDir = new File(repoRoot, "modules/ntp"); final File ntpFile = File.createTempFile("untracked-", ".txt", ntpDir); - if (gitImplName.equals("git")) { - final File sshkeysDir = new File(repoRoot, "modules/sshkeys"); - final File sshkeysFile = File.createTempFile("untracked-", ".txt", sshkeysDir); - } + final File sshkeysDir = new File(repoRoot, "modules/sshkeys"); + final File sshkeysFile = File.createTempFile("untracked-", ".txt", sshkeysDir); assertStatusUntrackedContent(gitClient, true); @@ -1551,12 +1551,6 @@ public void testSubmoduleClean() throws Exception { /* GitClient submoduleClean expected to modify submodules */ boolean recursive = random.nextBoolean(); gitClient.submoduleClean(recursive); - if (!gitImplName.equals("git")) { - /* Fix damage done by JGit.submoduleClean() - * JGit won't leave repo clean, but does remove untracked content - */ - FileUtils.deleteQuietly(new File(repoRoot, "modules/sshkeys")); - } assertStatusUntrackedContent(gitClient, false); } From 2d3f9ce7a336fce34f84d555ec8ec9d9f8867151 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 30 Dec 2017 07:50:45 -0700 Subject: [PATCH 013/226] Simplify README link to CONTRIBUTING --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 27e4bb0de8..9c11e4cd45 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ JGit whenever the git client plugin is available. Contributing to the Plugin ========================== -Refer to [contributing to the plugin](https://github.com/jenkinsci/git-client-plugin/blob/master/CONTRIBUTING.md) +Refer to [contributing to the plugin](CONTRIBUTING.md) for suggestions to speed the acceptance of your contributions. Building the Plugin From 217cc4f5c04481956d46fa4d7ce72954a2d6fa05 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 31 Dec 2017 16:50:35 -0700 Subject: [PATCH 014/226] Use JGit 4.10.0 --- pom.xml | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 69cb19f23f..a370d960ed 100644 --- a/pom.xml +++ b/pom.xml @@ -47,8 +47,8 @@ 2.9 2.60.1 8 - 4.9.2.201712150930-r - 4.9.2.201712150930-r + 4.10.0.201712302008-r + 4.10.0.201712302008-r @@ -95,6 +95,18 @@ org.eclipse.jgit org.eclipse.jgit.http.server ${jgit.version} + + + + com.jcraft + jsch + + + + org.apache.httpcomponents + httpclient + + + com.jcraft + jsch + + + + org.apache.httpcomponents + httpclient + + org.jenkins-ci.plugins From ef26091f4a436d6466bf02bc92fc0771147ea939 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 31 Dec 2017 18:25:23 -0700 Subject: [PATCH 015/226] Update overview with current usage No need to mention validated merge plugin now that we have the branch source plugins. --- src/main/javadoc/overview.html | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/main/javadoc/overview.html b/src/main/javadoc/overview.html index 762c46223c..ec138c1e99 100644 --- a/src/main/javadoc/overview.html +++ b/src/main/javadoc/overview.html @@ -5,31 +5,26 @@ -The Jenkins git client plugin provides an API to execute -general-purpose git operations on a local or remote repository. Its -primary use is from the -git-plugin; -as such, it is also used by -gerrit-plugin, -git-parameter-plugin, -workflow and cloudbees validated merge plugins. +The Jenkins git client plugin provides an API to execute general-purpose git operations on a local or remote repository. +Its primary use is from the +git plugin; +as such, it is also used by the +gerrit plugin, +git parameter plugin, +and the branch source plugins (GitHub branch source, Bitbucket branch source, Gitea, and others).

Plugin developers are encouraged to use -GitClient API in -replacement for the legacy IGitAPI. +GitClient API +instead of the legacy IGitAPI. -

The plugin isolates this low-level git stuff from git-plugin, allowing -alternate git implementations +

The plugin isolates low-level git commands from the git-plugin, allowing alternate git implementations (like JGit).

-

For backwards compatibility, this plugin uses API classes from the -hudson.plugins.git package.

+

For backwards compatibility, this plugin uses API classes from the hudson.plugins.git package.

-

The git client plugin also bundles JGit and JGit http server so -that callers can rely on JGit and the JGit http server being available -without including it in their own plugin packaging. This is used to -reduce the size of the packaging of the git-server plugin, and may be -useful in other plugins.

+

The git client plugin bundles JGit and JGit http server. +Callers can rely on JGit and the JGit http server being available without including it in their own plugin packaging. +This reduces the size dependent plugins like git-server plugin, and may be useful in other plugins.

From d5cc7805ebb5ff10f95741e08d68a539df4ddb9a Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 3 Jan 2018 12:21:03 -0700 Subject: [PATCH 016/226] Remove redundant maven-compiler-plugin source/target setting Already covered by the java.level setting. --- pom.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/pom.xml b/pom.xml index a370d960ed..e85e17c266 100644 --- a/pom.xml +++ b/pom.xml @@ -219,13 +219,6 @@ - - maven-compiler-plugin - - 1.8 - 1.8 - - org.apache.maven.plugins maven-javadoc-plugin From f37ddaeda2957868002b652ff2fe5e373c9a1d12 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 3 Jan 2018 12:24:12 -0700 Subject: [PATCH 017/226] Use parent pom findbugs settings --- pom.xml | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/pom.xml b/pom.xml index e85e17c266..46767bdca9 100644 --- a/pom.xml +++ b/pom.xml @@ -240,25 +240,6 @@ maven-hpi-plugin true - - org.codehaus.mojo - findbugs-maven-plugin - - ${skipFindbugs} - true - true - true - - - - run-findbugs - verify - - check - - - - maven-surefire-plugin From 34dde2c5be01f51d570040863a241ce41699357e Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 3 Jan 2018 13:20:31 -0700 Subject: [PATCH 018/226] Refer to plugins.jenkins.io for plugin docs Use new URL's for plugin references (except pom) --- README.md | 4 ++-- src/main/javadoc/overview.html | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9c11e4cd45..eb18d2515b 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ Utility plugin for Git-related support ====================================== -Extracted from [git-plugin](https://wiki.jenkins-ci.org/display/JENKINS/Git+Plugin) +Extracted from [git-plugin](https://plugins.jenkins.io/git) to make it easier for other plugins to use and contribute new features. Includes JGit as a library so that other Jenkins components can rely on JGit whenever the git client plugin is available. -* see [Jenkins wiki](https://wiki.jenkins-ci.org/display/JENKINS/Git+Client+Plugin) for feature descriptions +* see [Jenkins wiki](https://plugins.jenkins.io/git-client) for feature descriptions * use [JIRA](https://issues.jenkins-ci.org) to report issues / feature requests Contributing to the Plugin diff --git a/src/main/javadoc/overview.html b/src/main/javadoc/overview.html index ec138c1e99..59683fa4e9 100644 --- a/src/main/javadoc/overview.html +++ b/src/main/javadoc/overview.html @@ -7,10 +7,10 @@ The Jenkins git client plugin provides an API to execute general-purpose git operations on a local or remote repository. Its primary use is from the -git plugin; +git plugin; as such, it is also used by the -gerrit plugin, -git parameter plugin, +gerrit trigger plugin, +git parameter plugin, and the branch source plugins (GitHub branch source, Bitbucket branch source, Gitea, and others).

Plugin developers are encouraged to use From 1679626a7e4223d8b4b6fb4d2c267e159746fe22 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 3 Jan 2018 13:22:30 -0700 Subject: [PATCH 019/226] Assume JGit javadoc will publish with new releases Previous JGit patch releases would sometimes be delivered without a matching javadoc release. This change assumes that the JGit project will deliver javadoc for patch releases. --- pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 46767bdca9..8c4d7f67fb 100644 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,6 @@ 2.60.1 8 4.10.0.201712302008-r - 4.10.0.201712302008-r @@ -231,7 +230,7 @@ false http://docs.oracle.com/javase/8/docs/api/ - http://download.eclipse.org/jgit/site/${jgit.javadoc.version}/org.eclipse.jgit/apidocs/ + http://download.eclipse.org/jgit/site/${jgit.version}/org.eclipse.jgit/apidocs/ From beddf1151ad2dd6b9f36704baf155343dd65132b Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 3 Jan 2018 13:28:32 -0700 Subject: [PATCH 020/226] Depend on Jenkins 2.60.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8c4d7f67fb..ffef218996 100644 --- a/pom.xml +++ b/pom.xml @@ -45,7 +45,7 @@ UTF-8 -Dfile.encoding=${project.build.sourceEncoding} 2.9 - 2.60.1 + 2.60.3 8 4.10.0.201712302008-r From df83c1ff4237ef0db419caf53b5dc4723bc28ed0 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 3 Jan 2018 13:28:55 -0700 Subject: [PATCH 021/226] Test with Jenkins 2.89.2 --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 17cb60ac35..b192c3b708 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,7 +1,7 @@ #!groovy // build both versions, retry test failures -buildPlugin(jenkinsVersions: [null, '2.89.1'], +buildPlugin(jenkinsVersions: [null, '2.89.2'], findbugs: [run:true, archive:true, unstableTotalAll: '0'], failFast: false) From bdf5833ae1870dde8240b968f7670a0c3ca0d9ed Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 3 Jan 2018 19:31:06 -0700 Subject: [PATCH 022/226] Add tags refspec related comment inline Don't rely on readers to search through commit messages. Code is what matters, and comments in code are better than comments in a commit message. --- .../java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index 9ab6c9d247..9130884120 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -619,6 +619,11 @@ public void execute() throws GitException, InterruptedException { FetchCommand fetch = git.fetch(); fetch.setTagOpt(tags ? TagOpt.FETCH_TAGS : TagOpt.NO_TAGS); + /* JGit 4.5 required a work around that the tags refspec had to be passed in addition to setting + * the FETCH_TAGS tagOpt. JGit 4.9.0 fixed that bug. + * However, JGit 4.9 and later will not accept an empty refspec. + * If the refspec is empty and tag fetch is requested, must add the tags refspec to fetch. + */ if (allRefSpecs.isEmpty() && tags) { allRefSpecs.add(new RefSpec("+refs/tags/*:refs/tags/*")); } From 1929efc663ca583c152f55eb9b6769daf7c62b4f Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 3 Jan 2018 20:00:55 -0700 Subject: [PATCH 023/226] Simplify the lambda use --- src/main/java/hudson/plugins/git/Revision.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/hudson/plugins/git/Revision.java b/src/main/java/hudson/plugins/git/Revision.java index 6e40cd4b6b..78ca91d818 100644 --- a/src/main/java/hudson/plugins/git/Revision.java +++ b/src/main/java/hudson/plugins/git/Revision.java @@ -118,7 +118,7 @@ public String toString() { StringBuilder s = new StringBuilder("Revision " + revisionName + " ("); if (branches != null) { Joiner.on(", ").appendTo(s, - Iterables.transform(branches, (Branch from) -> Util.fixNull(from.getName()))); + Iterables.transform(branches, from -> Util.fixNull(from.getName()))); } s.append(')'); return s.toString(); From c53153f452e69501722d4b12bf9c6ecd8129d64b Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 3 Jan 2018 21:03:43 -0700 Subject: [PATCH 024/226] Throw ObjectStreamException if no serialization channel --- .../org/jenkinsci/plugins/gitclient/AbstractGitAPIImpl.java | 5 +++-- .../plugins/gitclient/LegacyCompatibleGitAPIImpl.java | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/AbstractGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/AbstractGitAPIImpl.java index 823759a57c..4f38e9009c 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/AbstractGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/AbstractGitAPIImpl.java @@ -90,11 +90,12 @@ public void merge(ObjectId rev) throws GitException, InterruptedException { * When sent to remote, switch to the proxy. * * @return a {@link java.lang.Object} object. + * @throws java.io.ObjectStreamException if current channel is null */ - protected Object writeReplace() { + protected Object writeReplace() throws java.io.ObjectStreamException { Channel currentChannel = Channel.current(); if (currentChannel == null) - return null; + throw new java.io.WriteAbortedException("No current channel", new java.lang.NullPointerException()); return remoteProxyFor(currentChannel.export(GitClient.class, this)); } diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImpl.java index 7651619f62..93a4ddacfd 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImpl.java @@ -194,10 +194,10 @@ public final List lsTree(String treeIsh) throws GitException, Interr /** {@inheritDoc} */ @Override - protected Object writeReplace() { + protected Object writeReplace() throws java.io.ObjectStreamException { Channel currentChannel = Channel.current(); if (currentChannel == null) - return null; + throw new java.io.WriteAbortedException("No current channel", new java.lang.NullPointerException()); return remoteProxyFor(currentChannel.export(IGitAPI.class, this)); } From d4e55360e2dd5f41bc556d7c181ecc29e4258109 Mon Sep 17 00:00:00 2001 From: Mostyn Bramley-Moore Date: Mon, 8 Jan 2018 11:19:41 +0100 Subject: [PATCH 025/226] [JENKINS-48258] add distinctive temp file prefix to aid debugging --- .../org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 218bbaaee1..cb40533630 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -1521,12 +1521,19 @@ private File createTempFileInSystemDir(String prefix, String suffix) throws IOEx * * Package protected for testing. Not to be used outside this class * - * @param prefix file name prefix for the generated temporary file + * @param prefix file name prefix for the generated temporary file (will be preceeded by "jenkins-gitclient-") * @param suffix file name suffix for the generated temporary file * @return temporary file * @throws IOException on error */ File createTempFile(String prefix, String suffix) throws IOException { + String common_prefix = "jenkins-gitclient-"; + if (prefix == null) { + prefix = common_prefix; + } else { + prefix = common_prefix + prefix; + } + if (workspace == null) { return createTempFileInSystemDir(prefix, suffix); } From 30ca6f31b748205d07be22ba9e0c3c4e45098f04 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 20 Jan 2018 18:29:57 -0700 Subject: [PATCH 026/226] Use Jenkins 2.89.3 in compatibility test --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index b192c3b708..355bd6cac5 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,7 +1,7 @@ #!groovy // build both versions, retry test failures -buildPlugin(jenkinsVersions: [null, '2.89.2'], +buildPlugin(jenkinsVersions: [null, '2.89.3'], findbugs: [run:true, archive:true, unstableTotalAll: '0'], failFast: false) From 19a0422608aa57c0b884dd671e8319c05bf3eb05 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Thu, 25 Jan 2018 09:44:53 -0700 Subject: [PATCH 027/226] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 4b1e583a16..a595811b16 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins git-client - 2.7.1 + 2.7.2-SNAPSHOT hpi Jenkins Git client plugin @@ -38,7 +38,7 @@ scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git https://github.com/jenkinsci/${project.artifactId}-plugin - git-client-2.7.1 + HEAD From 60443da9d782eda7b89b63557aa1a3b962f94f57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Wed, 31 Jan 2018 12:57:50 +0100 Subject: [PATCH 028/226] Avoid refering now deprecated MasterComputer.localChannel to avoid loading classes over remoting --- .../org/jenkinsci/plugins/gitclient/AbstractGitAPIImpl.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/AbstractGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/AbstractGitAPIImpl.java index b102d6244d..aea9540dc9 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/AbstractGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/AbstractGitAPIImpl.java @@ -1,11 +1,10 @@ package org.jenkinsci.plugins.gitclient; import com.cloudbees.plugins.credentials.common.StandardUsernameCredentials; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import hudson.FilePath; import hudson.ProxyConfiguration; import hudson.plugins.git.GitException; import hudson.remoting.Channel; -import jenkins.model.Jenkins.MasterComputer; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Repository; @@ -26,7 +25,7 @@ abstract class AbstractGitAPIImpl implements GitClient, Serializable { /** {@inheritDoc} */ public T withRepository(RepositoryCallback callable) throws IOException, InterruptedException { try (Repository repo = getRepository()) { - return callable.invoke(repo, MasterComputer.localChannel); + return callable.invoke(repo, FilePath.localChannel); } } From 9d32f3c712786dc5227eb5a668512dd56dc46b6c Mon Sep 17 00:00:00 2001 From: "Feblot, Alexandre" Date: Wed, 5 Apr 2017 14:36:30 +0200 Subject: [PATCH 029/226] Test for JENKINS-43198: jgit.clean() failures --- .../jenkinsci/plugins/gitclient/GitClientTest.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java index 600f1a1677..511cb142cc 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java @@ -340,12 +340,17 @@ public void testNullChangelogDestinationExcludes() throws Exception { @Test @Issue("JENKINS-43198") public void testCleanSubdirGitignore() throws Exception { - final String filename = "this_is/not_ok/more/subdirs/file.txt"; - commitFile(".gitignore", "/this_is/not_ok\n", "set up gitignore"); - createFile(filename, "hi there"); - assertFileInWorkingDir(gitClient, filename); + final String filename1 = "this_is/not_ok/more/subdirs/file.txt"; + final String filename2 = "this_is_also/not_ok_either/more/subdirs/file.txt"; + commitFile(".gitignore", "/this_is/not_ok\n/this_is_also/not_ok_either\n", "set up gitignore"); + createFile(filename1, "hi there"); + createFile(filename2, "hi there"); + assertFileInWorkingDir(gitClient, filename1); + assertFileInWorkingDir(gitClient, filename2); gitClient.clean(); assertDirNotInWorkingDir(gitClient, "this_is"); + assumeThat(gitImplName, is("git")); // Temporary until JENKINS-43198 is fixed in JGit 1.10.1 or later + assertDirNotInWorkingDir(gitClient, "this_is_also"); } @Test From 14c53b28ae81884dfd216c360becabe3abc18b60 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 10 Feb 2018 19:53:48 -0700 Subject: [PATCH 030/226] Include param in javadoc --- src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java index 581455816b..3dbcf3fd5b 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java @@ -443,6 +443,7 @@ public void prune(RemoteConfig repository) throws GitException, InterruptedExcep /** * clean. * + * @param cleanSubmodule flag to add extra -f * @throws hudson.plugins.git.GitException if underlying git operation fails. * @throws java.lang.InterruptedException if interrupted. */ From 3ea5191e968add13afb3afaf54aee015cf9af45c Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 22 Jan 2018 09:16:08 -0700 Subject: [PATCH 031/226] Use false for git env values Conversation with Johannes Schindelin, maintainer of git for Windows. --- .../java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index dac4c4fb0f..33675c419f 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -1651,9 +1651,9 @@ private String launchCommandWithCredentials(ArgumentListBuilder args, File workD EnvVars env = environment; if (!PROMPT_FOR_AUTHENTICATION && isAtLeastVersion(2, 3, 0, 0)) { env = new EnvVars(env); - env.put("GIT_TERMINAL_PROMPT", "0"); // Don't prompt for auth from command line git + env.put("GIT_TERMINAL_PROMPT", "false"); // Don't prompt for auth from command line git if (isWindows()) { - env.put("GCM_INTERACTIVE", "never"); // Don't prompt for auth from git credentials manager for windows + env.put("GCM_INTERACTIVE", "false"); // Don't prompt for auth from git credentials manager for windows } } try { From 1bfc00f0d56a1329213d8ead712b7dccfbd49110 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 12 Feb 2018 17:45:13 -0700 Subject: [PATCH 032/226] Remove empty exclusions from git-server test dependency --- pom.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pom.xml b/pom.xml index ffef218996..8152d0a6a5 100644 --- a/pom.xml +++ b/pom.xml @@ -147,9 +147,6 @@ git-server 1.7 test - - - com.googlecode.json-simple From 3868dea2bb4dabf9f46c9d6f0d845f3fac853e5a Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 9 Mar 2018 16:37:12 -0800 Subject: [PATCH 033/226] Use parent pom 3.5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8152d0a6a5..847e75fcda 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 3.2 + 3.5 From 53cc604a9ab08b5ac5005ce64386527db5588007 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 9 Mar 2018 16:41:01 -0800 Subject: [PATCH 034/226] Use JGIt 4.11.0 --- pom.xml | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 847e75fcda..6c302748a4 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ 2.9 2.60.3 8 - 4.10.0.201712302008-r + 4.11.0.201803080745-r @@ -84,6 +84,11 @@ org.apache.httpcomponents httpclient + + + com.jcraft + jzlib + @@ -105,6 +110,11 @@ org.apache.httpcomponents httpclient + + + com.jcraft + jzlib + @@ -124,6 +134,34 @@ org.apache.httpcomponents httpclient + + + com.jcraft + jzlib + + + + + + org.eclipse.jgit + org.eclipse.jgit.lfs + ${jgit.version} + + + + com.jcraft + jsch + + + + org.apache.httpcomponents + httpclient + + + + com.jcraft + jzlib + From b9374f583717a3a5fa0b6666bbc64f031aea0ad5 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 9 Mar 2018 16:42:07 -0800 Subject: [PATCH 035/226] Replace info propperty with single use --- pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 6c302748a4..c8b6378312 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,6 @@ UTF-8 -Dfile.encoding=${project.build.sourceEncoding} - 2.9 2.60.3 8 4.11.0.201803080745-r @@ -295,7 +294,7 @@ org.apache.maven.plugins maven-project-info-reports-plugin - ${maven-project-info-reports-plugin.version} + 2.9 From d3be6a1509f73a8be2b2366f6e56ebfddde60ada Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 9 Mar 2018 16:43:50 -0800 Subject: [PATCH 036/226] Use equalsverifier 2.4.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c8b6378312..aaeee51266 100644 --- a/pom.xml +++ b/pom.xml @@ -176,7 +176,7 @@ nl.jqno.equalsverifier equalsverifier - 2.4 + 2.4.3 test From 9586cfd1d840f9cb51d322dab026d31c90e374ab Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 9 Mar 2018 16:45:28 -0800 Subject: [PATCH 037/226] Use maven compiler plugin 3.7.0 --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index aaeee51266..6b64898d05 100644 --- a/pom.xml +++ b/pom.xml @@ -242,6 +242,7 @@ maven-compiler-plugin + 3.7.0 maven-surefire-plugin From 997da04796063a927f44c103fd6a1449e1b189a8 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 9 Mar 2018 16:45:46 -0800 Subject: [PATCH 038/226] Use maven surefire plugin 2.20.1 --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 6b64898d05..cad7e7386f 100644 --- a/pom.xml +++ b/pom.xml @@ -246,6 +246,7 @@ maven-surefire-plugin + 2.20.1 maven-javadoc-plugin From 717d812d270d5fe6534ebdbe47dcc2549b4a5121 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 9 Mar 2018 16:46:25 -0800 Subject: [PATCH 039/226] Use maven javadoc plugin 3.0.0 --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index cad7e7386f..0e4724d7d1 100644 --- a/pom.xml +++ b/pom.xml @@ -250,6 +250,7 @@ maven-javadoc-plugin + 3.0.0 From 841502e4287a262856b4dec3936c4b2c490cd7ad Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 9 Mar 2018 17:32:28 -0800 Subject: [PATCH 040/226] Fix tests for JGit 4.11 --- .../plugins/gitclient/GitAPITestCase.java | 59 ++++++++----------- 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 0a23542c36..2aef109b3b 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -588,6 +588,16 @@ public void test_clone_shared() throws IOException, InterruptedException assertNoObjectsInRepository(); } + public void test_clone_null_branch() throws IOException, InterruptedException + { + w.git.clone_().url(localMirror()).repositoryName("origin").shared().execute(); + createRevParseBranch(); + w.git.checkout("origin/master", null); + check_remote_url("origin"); + assertAlternateFilePointsToLocalMirror(); + assertNoObjectsInRepository(); + } + public void test_clone_unshared() throws IOException, InterruptedException { w.git.clone_().url(localMirror()).repositoryName("origin").shared(false).execute(); @@ -2011,17 +2021,7 @@ public void test_submodule_checkout_and_clean_transitions() throws Exception { assertDirExists(modulesDir); assertFileExists(keeperFile); assertFileContents(keeperFile, ""); - /* Command line git checkout creates empty directories for modules, JGit does not */ - /* That behavioral difference seems harmless */ - if (w.git instanceof CliGitAPIImpl) { - assertSubmoduleDirs(w.repo, true, false); - } else { - assertDirNotFound(ntpDir); - assertDirNotFound(firewallDir); - assertDirNotFound(sshkeysDir); - assertFileNotFound(ntpContributingFile); - assertFileNotFound(sshkeysModuleFile); - } + assertSubmoduleDirs(w.repo, true, false); /* Call submodule update without recursion */ w.git.submoduleUpdate().recursive(false).execute(); @@ -2034,9 +2034,8 @@ public void test_submodule_checkout_and_clean_transitions() throws Exception { assertSubmoduleRepository(new File(w.repo, "modules/firewall")); assertSubmoduleRepository(new File(w.repo, "modules/sshkeys")); } else { - assertDirNotFound(ntpDir); - assertDirNotFound(firewallDir); - assertDirNotFound(sshkeysDir); + /* JGit does not fully support renamed submodules - creates directories but not content */ + assertSubmoduleDirs(w.repo, true, false); } /* Call submodule update with recursion */ @@ -2050,9 +2049,8 @@ public void test_submodule_checkout_and_clean_transitions() throws Exception { assertSubmoduleRepository(new File(w.repo, "modules/firewall")); assertSubmoduleRepository(new File(w.repo, "modules/sshkeys")); } else { - assertDirNotFound(ntpDir); - assertDirNotFound(firewallDir); - assertDirNotFound(sshkeysDir); + /* JGit does not fully support renamed submodules - creates directories but not content */ + assertSubmoduleDirs(w.repo, true, false); } String notSubBranchName = "tests/notSubmodules"; @@ -2152,14 +2150,7 @@ public void test_submodule_checkout_and_clean_transitions() throws Exception { // w.git.checkout().ref(subRefName).branch(subBranch).execute(); w.git.checkout().ref(subRefName).execute(); assertDirExists(modulesDir); - if (w.git instanceof CliGitAPIImpl) { - assertSubmoduleDirs(w.repo, true, false); - } else { - /* JGit does not support renamed submodules - creates none of the directories */ - assertDirNotFound(ntpDir); - assertDirNotFound(firewallDir); - assertDirNotFound(sshkeysDir); - } + assertSubmoduleDirs(w.repo, true, false); w.git.submoduleClean(true); assertSubmoduleDirs(w.repo, true, false); @@ -3428,15 +3419,15 @@ public void test_getHeadRev_namespaces_withSimpleBranchNames() throws Exception w = clone(tempRemoteDir.getAbsolutePath()); final String remote = tempRemoteDir.getAbsolutePath(); - final String[][] checkBranchSpecs = {}; -//TODO: Fix and enable test -// { -// {"master", commits.getProperty("refs/heads/master")}, -// {"a_tests/b_namespace1/master", commits.getProperty("refs/heads/a_tests/b_namespace1/master")}, -// {"a_tests/b_namespace2/master", commits.getProperty("refs/heads/a_tests/b_namespace2/master")}, -// {"a_tests/b_namespace3/master", commits.getProperty("refs/heads/a_tests/b_namespace3/master")}, -// {"b_namespace3/master", commits.getProperty("refs/heads/b_namespace3/master")} -// }; + final String[][] checkBranchSpecs = + //TODO: Fix and enable test + { + {"a_tests/b_namespace1/master", commits.getProperty("refs/heads/a_tests/b_namespace1/master")}, + // {"a_tests/b_namespace2/master", commits.getProperty("refs/heads/a_tests/b_namespace2/master")}, + // {"a_tests/b_namespace3/master", commits.getProperty("refs/heads/a_tests/b_namespace3/master")}, + // {"b_namespace3/master", commits.getProperty("refs/heads/b_namespace3/master")}, + // {"master", commits.getProperty("refs/heads/master")}, + }; for(String[] branch : checkBranchSpecs) { final ObjectId objectId = ObjectId.fromString(branch[1]); From b80adcde32953e20b0674a7ad67a84c9fa9e32b7 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 9 Mar 2018 22:23:21 -0700 Subject: [PATCH 041/226] [maven-release-plugin] prepare release git-client-3.0.0-beta1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 0e4724d7d1..7b073651e9 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins git-client - 3.0.0-SNAPSHOT + 3.0.0-beta1 hpi Jenkins Git client plugin @@ -38,7 +38,7 @@ scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git https://github.com/jenkinsci/${project.artifactId}-plugin - HEAD + git-client-3.0.0-beta1 From 62d02cfdd7d9dc52c10c5d6ac735faeb9422e2e3 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 9 Mar 2018 22:23:27 -0700 Subject: [PATCH 042/226] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 7b073651e9..0e4724d7d1 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins git-client - 3.0.0-beta1 + 3.0.0-SNAPSHOT hpi Jenkins Git client plugin @@ -38,7 +38,7 @@ scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git https://github.com/jenkinsci/${project.artifactId}-plugin - git-client-3.0.0-beta1 + HEAD From 9ac7da85beabced66742c8329b0c2958d988ccfd Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 10 Mar 2018 05:48:58 -0800 Subject: [PATCH 043/226] Remove JENKINS-43198 workaround - JGit fixed it Remove of certain patterns of file names and directories failed with JGit and succeeded with CliGit when using JGit versions prior to 4.11.0. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=514434 --- .../jenkinsci/plugins/gitclient/JGitAPIImpl.java | 13 ------------- .../jenkinsci/plugins/gitclient/GitClientTest.java | 1 - 2 files changed, 14 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index c17c2fad22..0e9f7e7ad9 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -1293,19 +1293,6 @@ public void clean(boolean cleanSubmodule) throws GitException { git.clean().setCleanDirectories(true).setIgnore(false).setForce(cleanSubmodule).call(); } catch (GitAPIException e) { throw new GitException(e); - // Fix JENKINS-43198: - // don't throw a "Could not delete file" if the file has actually been deleted - // See JGit bug 514434 https://bugs.eclipse.org/bugs/show_bug.cgi?id=514434 - } catch(JGitInternalException e) { - String expected = "Could not delete file "; - if (e.getMessage().startsWith(expected)) { - String path = e.getMessage().substring(expected.length()); - if (Files.exists(Paths.get(path))) { - throw e; - } // else don't throw, everything is ok. - } else { - throw e; - } } } diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java index 511cb142cc..f2a69626ad 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java @@ -349,7 +349,6 @@ public void testCleanSubdirGitignore() throws Exception { assertFileInWorkingDir(gitClient, filename2); gitClient.clean(); assertDirNotInWorkingDir(gitClient, "this_is"); - assumeThat(gitImplName, is("git")); // Temporary until JENKINS-43198 is fixed in JGit 1.10.1 or later assertDirNotInWorkingDir(gitClient, "this_is_also"); } From d00b79a77995c90ae4dad411566f513491305320 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 5 Mar 2018 07:13:22 -0700 Subject: [PATCH 044/226] Remove the TODO question A few users have requested SSL client credentials --- src/main/java/org/jenkinsci/plugins/gitclient/GitClient.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/GitClient.java b/src/main/java/org/jenkinsci/plugins/gitclient/GitClient.java index 4a81f3753d..89f4aae5aa 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/GitClient.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/GitClient.java @@ -49,7 +49,6 @@ public interface GitClient { CredentialsMatcher CREDENTIALS_MATCHER = CredentialsMatchers.anyOf( CredentialsMatchers.instanceOf(StandardUsernamePasswordCredentials.class), CredentialsMatchers.instanceOf(SSHUserPrivateKey.class) - // TODO does anyone use SSL client certificates with GIT? ); /** From 7048de81826108149dd0890415cb59dc152d5537 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 5 Mar 2018 08:06:47 -0700 Subject: [PATCH 045/226] Add unsupported operation exception message --- .../gitclient/jgit/PreemptiveAuthHttpClientConnection.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/jgit/PreemptiveAuthHttpClientConnection.java b/src/main/java/org/jenkinsci/plugins/gitclient/jgit/PreemptiveAuthHttpClientConnection.java index 6c2b816a3a..6705573a99 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/jgit/PreemptiveAuthHttpClientConnection.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/jgit/PreemptiveAuthHttpClientConnection.java @@ -443,12 +443,12 @@ public boolean verify(String hostname, SSLSession session) { public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException { - throw new UnsupportedOperationException(); // TODO message + throw new UnsupportedOperationException("Unsupported hostname verifier called for " + host); } public void verify(String host, X509Certificate cert) throws SSLException { - throw new UnsupportedOperationException(); // TODO message + throw new UnsupportedOperationException("Unsupported hostname verifier called for " + host + " with X.509 certificate"); } public void verify(String host, SSLSocket ssl) throws IOException { From 0d43367e2700ebccfc1db5cb29efa665620ff048 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 5 Mar 2018 09:30:22 -0700 Subject: [PATCH 046/226] extractBranchNameFromBranchSpec allows tags Admit that behavior added in 2014 will continue to be the expected behavior. --- .../plugins/gitclient/LegacyCompatibleGitAPIImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImpl.java index 93a4ddacfd..139dedcead 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImpl.java @@ -269,8 +269,8 @@ protected String extractBranchNameFromBranchSpec(String branchSpec) { } else if (branchSpec.startsWith("refs/heads/")) { branch = branchSpec; } else if (branchSpec.startsWith("refs/tags/")) { - //TODO: Discuss if tags shall be allowed. - //hudson.plugins.git.util.DefaultBuildChooser.getCandidateRevisions() in git plugin 2.0.1 explicitly allowed it. + // Tags are allowed because git plugin 2.0.1 + // DefaultBuildChooser.getCandidateRevisions() allowed them. branch = branchSpec; } else { /* Old behaviour - retained for compatibility. From 42fbc34cc227fd1514710d54e790cb6489c20282 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 21 Mar 2018 22:51:05 -0600 Subject: [PATCH 047/226] Use 3.0.0-beta2-SNAPSHOT version 3.0.0-SNAPSHOT is reported as too old for git plugin dependency on 3.0.0-beta1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0e4724d7d1..7c678858f2 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins git-client - 3.0.0-SNAPSHOT + 3.0.0-beta2-SNAPSHOT hpi Jenkins Git client plugin From d51b941afb9bb2c24e78d42097e651007014ae8c Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 9 Apr 2018 14:50:59 -0600 Subject: [PATCH 048/226] Use parent pom 3.7 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7c678858f2..342e82634a 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 3.5 + 3.7 From a90c77d6de4c6469739d6e06cc676aac903401e0 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 16 Apr 2018 11:33:45 -0600 Subject: [PATCH 049/226] Use parent pom 3.8 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 342e82634a..3977e023ef 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 3.7 + 3.8 From 74675071ec6be57fabe2440f1814076ac92679f5 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 14 Apr 2018 11:04:52 -0600 Subject: [PATCH 050/226] Adapt to git 2.17.0 exception message change --- .../jenkinsci/plugins/gitclient/GitAPITestCase.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 1ac97c2996..69ed88ce75 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -4214,7 +4214,7 @@ public void test_isBareRepository_working_null() throws IOException, Interrupted assertFalse("null is a bare repository", w.igit().isBareRepository(null)); fail("Did not throw expected exception"); } catch (GitException ge) { - assertTrue("Wrong exception message: " + ge, ge.getMessage().contains("Not a git repository")); + assertTrue("Wrong exception message: " + ge, ge.getMessage().toLowerCase().contains("not a git repository")); } } @@ -4225,7 +4225,7 @@ public void test_isBareRepository_bare_null() throws IOException, InterruptedExc assertTrue("null is not a bare repository", w.igit().isBareRepository(null)); fail("Did not throw expected exception"); } catch (GitException ge) { - assertTrue("Wrong exception message: " + ge, ge.getMessage().contains("Not a git repository")); + assertTrue("Wrong exception message: " + ge, ge.getMessage().toLowerCase().contains("not a git repository")); } } @@ -4289,7 +4289,7 @@ public void test_isBareRepository_working_dot() throws IOException, InterruptedE fail("Did not throw expected exception"); } } catch (GitException ge) { - assertTrue("Wrong exception message: " + ge, ge.getMessage().contains("Not a git repository")); + assertTrue("Wrong exception message: " + ge, ge.getMessage().toLowerCase().contains("not a git repository")); } } @@ -4325,7 +4325,7 @@ public void test_isBareRepository_bare_dot_git() throws IOException, Interrupted assertFalse("CliGitAPIImpl did not throw expected exception", w.igit() instanceof CliGitAPIImpl); } catch (GitException ge) { /* Only enters this path for CliGit */ - assertTrue("Wrong exception message: " + ge, ge.getMessage().contains("Not a git repository")); + assertTrue("Wrong exception message: " + ge, ge.getMessage().toLowerCase().contains("not a git repository")); } } @@ -4340,7 +4340,7 @@ public void test_isBareRepository_working_no_such_location() throws IOException, assertFalse("CliGitAPIImpl did not throw expected exception", w.igit() instanceof CliGitAPIImpl); } catch (GitException ge) { /* Only enters this path for CliGit */ - assertTrue("Wrong exception message: " + ge, ge.getMessage().contains("Not a git repository")); + assertTrue("Wrong exception message: " + ge, ge.getMessage().toLowerCase().contains("not a git repository")); } } @@ -4354,7 +4354,7 @@ public void test_isBareRepository_bare_no_such_location() throws IOException, In assertFalse("CliGitAPIImpl did not throw expected exception", w.igit() instanceof CliGitAPIImpl); } catch (GitException ge) { /* Only enters this path for CliGit */ - assertTrue("Wrong exception message: " + ge, ge.getMessage().contains("Not a git repository")); + assertTrue("Wrong exception message: " + ge, ge.getMessage().toLowerCase().contains("not a git repository")); } } From e2520d9a1a52fa210004e9a0d4cea42d97cf9fae Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 14 Apr 2018 09:01:20 -0600 Subject: [PATCH 051/226] [JENKINS-50573] Prefer URL username with ssh URL When using an ssh private key, the CliGitAPIImpl implementation previously passed a "-l" command line argument from the username associated with the ssh key. OpenSSH implementations prior to OpenSSH 7.7 would only use that command line argument if no username were included in the ssh URI. OpenSSH 7.7 changes the ssh command line argument parsing rules. Previously, the last user name specified would be used, including the user name in the URL. With OpenSSH 7.7, the first user name specified is used, even if a user name is specified in the URL. The command line: ssh -l jenkins git@github.com:jenkinsci/git-client-plugin.git uses the username 'git' with OpenSSH versions before 7.7 and uses the username 'jenkins' with OpenSSH 7.7. OpenSSH 7.7 is included in Windows Git 2.17 and in OpenBSD 6.3. The CredentialsTest class can test this case. --- .../org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java | 10 ++++++++-- .../jenkinsci/plugins/gitclient/CredentialsTest.java | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 68e8e5eb1c..fba6065ac7 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -1647,11 +1647,17 @@ private String launchCommandWithCredentials(ArgumentListBuilder args, File workD listener.getLogger().println("using GIT_SSH to set credentials " + sshUser.getDescription()); key = createSshKeyFile(sshUser); + // Prefer url username if set, OpenSSH 7.7 argument precedence change + // See JENKINS-50573 for details + String userName = url.getUser(); + if (userName == null) { + userName = sshUser.getUsername(); + } if (launcher.isUnix()) { - ssh = createUnixGitSSH(key, sshUser.getUsername()); + ssh = createUnixGitSSH(key, userName); pass = createUnixSshAskpass(sshUser); } else { - ssh = createWindowsGitSSH(key, sshUser.getUsername()); + ssh = createWindowsGitSSH(key, userName); pass = createWindowsSshAskpass(sshUser); } diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index ea9146b5f5..090589a1e2 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -325,7 +325,7 @@ public static Collection gitRepoUrls() throws MalformedURLException, FileNotFoun } } Collections.shuffle(repos); // randomize test order - int toIndex = Math.min(repos.size(), TEST_ALL_CREDENTIALS ? 90 : 6); // Don't run more than 90 variations of test - about 3 minutes + int toIndex = Math.min(repos.size(), TEST_ALL_CREDENTIALS ? 120 : 6); // Don't run more than 120 variations of test - about 3 minutes return repos.subList(0, toIndex); } From 1199beea0743e60e09c987b1306cc0a8fdfb6879 Mon Sep 17 00:00:00 2001 From: presPetkov Date: Fri, 20 Apr 2018 12:00:53 +0100 Subject: [PATCH 052/226] Jenkins 48258 ssh text file busy (#2) * JENKINS-48258 Use a copy of ssh file * Corrected exception handling as per bug report * Fixed error * Fixed error --- .../plugins/gitclient/CliGitAPIImpl.java | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 8c8d2b08f9..457af4c07d 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -1965,6 +1965,8 @@ private File createWindowsGitSSH(File key, String user) throws IOException { private File createUnixGitSSH(File key, String user) throws IOException { File ssh = createTempFile("ssh", ".sh"); + File ssh_copy = new File(ssh.toString() + "-copy"); + boolean isCopied = false; try (PrintWriter w = new PrintWriter(ssh, Charset.defaultCharset().toString())) { w.println("#!/bin/sh"); // ${SSH_ASKPASS} might be ignored if ${DISPLAY} is not set @@ -1975,7 +1977,31 @@ private File createUnixGitSSH(File key, String user) throws IOException { w.println("ssh -i \"" + key.getAbsolutePath() + "\" -l \"" + user + "\" -o StrictHostKeyChecking=no \"$@\""); } ssh.setExecutable(true, true); - return ssh; + //JENKINS-48258 git client plugin occasionally fails with "text file busy" error + //The following creates a copy of the generated file and deletes the original + //In case of a failure return the original and delete the copy + String fromLocation = ssh.toString(); + String toLocation = ssh_copy.toString(); + //Copying ssh file + try { + new ProcessBuilder("cp", fromLocation, toLocation).start().waitFor(); + isCopied = true; + ssh_copy.setExecutable(true,true); + //Deleting original file + deleteTempFile(ssh); + } + catch(InterruptedException ie) + { + //Delete the copied file in case of failure + if(isCopied) + { + deleteTempFile(ssh_copy); + } + //Previous operation failed. Return original file + return ssh; + } + + return ssh_copy; } private String launchCommandIn(ArgumentListBuilder args, File workDir) throws GitException, InterruptedException { From 8dd3909f8e91cd3ddeaf1a87de6078ae6dac7d1a Mon Sep 17 00:00:00 2001 From: presPetkov Date: Fri, 20 Apr 2018 12:05:50 +0100 Subject: [PATCH 053/226] Fixed indentation --- .../jenkinsci/plugins/gitclient/CliGitAPIImpl.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 457af4c07d..406ca21430 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -1983,13 +1983,13 @@ private File createUnixGitSSH(File key, String user) throws IOException { String fromLocation = ssh.toString(); String toLocation = ssh_copy.toString(); //Copying ssh file - try { - new ProcessBuilder("cp", fromLocation, toLocation).start().waitFor(); - isCopied = true; - ssh_copy.setExecutable(true,true); - //Deleting original file - deleteTempFile(ssh); - } + try { + new ProcessBuilder("cp", fromLocation, toLocation).start().waitFor(); + isCopied = true; + ssh_copy.setExecutable(true,true); + //Deleting original file + deleteTempFile(ssh); + } catch(InterruptedException ie) { //Delete the copied file in case of failure From 5130db9dc293f10bd493a64c8c5fd9a69450f012 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 14 Apr 2018 11:04:52 -0600 Subject: [PATCH 054/226] Ignore case in git exception message substring asserts Command line git 2.17.0 changed the case of a word in a message and caused tests to fail. Case insensitive comparisons are good enough for these tests. Also replaced several duplicated locations with a method that is easier to read and produces a better diagnostic on failure. --- .../plugins/gitclient/GitAPITestCase.java | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 2aef109b3b..52b078e8ea 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -932,6 +932,11 @@ public void test_clean() throws Exception { assertTrue("unexpected final status " + finalStatus + " dir contents: " + dirContents, finalStatus.contains("working directory clean") || finalStatus.contains("working tree clean")); } + private void assertExceptionMessageContains(GitException ge, String expectedSubstring) { + String actual = ge.getMessage().toLowerCase(); + assertTrue("Expected '" + expectedSubstring + "' exception message, but was: " + actual, actual.contains(expectedSubstring)); + } + public void test_fetch() throws Exception { /* Create a working repo containing a commit */ w.init(); @@ -1056,7 +1061,7 @@ public void test_fetch() throws Exception { ge.getMessage().contains("Could not merge") || ge.getMessage().contains("not something we can merge") || ge.getMessage().contains("does not point to a commit")); - assertTrue("Wrong message :" + ge.getMessage(), ge.getMessage().contains(bareCommit5.name())); + assertExceptionMessageContains(ge, bareCommit5.name()); } /* Assert that expected change is in repo after merge. With * git 1.7 and 1.8, it should be bareCommit4. With git 1.9 @@ -1068,7 +1073,7 @@ public void test_fetch() throws Exception { newArea.git.fetch("invalid-remote-name"); fail("Should have thrown an exception"); } catch (GitException ge) { - assertTrue("Wrong message :" + ge.getMessage(), ge.getMessage().contains("invalid-remote-name")); + assertExceptionMessageContains(ge, "invalid-remote-name"); } } @@ -1874,7 +1879,7 @@ public void test_push_from_shallow_clone() throws Exception { assertEquals(sha1.name(), remoteSha1); } catch (GitException e) { // expected for git cli < 1.9.0 - assertTrue("Wrong exception message: " + e, e.getMessage().contains("push from shallow repository")); + assertExceptionMessageContains(e, "push from shallow repository"); assertFalse("git >= 1.9.0 can't push from shallow repository", w.cgit().isAtLeastVersion(1, 9, 0, 0)); } } @@ -2362,7 +2367,7 @@ public void assertFixSubmoduleUrlsThrows() throws InterruptedException { } catch (GitException ge) { assertTrue("GitException not on CliGit", w.igit() instanceof CliGitAPIImpl); assertTrue("Wrong message in " + ge.getMessage(), ge.getMessage().startsWith("Could not determine remote")); - assertTrue("Wrong remote in " + ge.getMessage(), ge.getMessage().contains("origin")); + assertExceptionMessageContains(ge, "origin"); } } @@ -3203,14 +3208,14 @@ public void test_merge_refspec() throws Exception { assertTrue("Exception not thrown by CliGit", w.git instanceof CliGitAPIImpl); } catch (GitException moa) { assertFalse("Exception thrown by CliGit", w.git instanceof CliGitAPIImpl); - assertTrue("Exception message didn't mention " + badBase.toString(), moa.getMessage().contains(badSHA1)); + assertExceptionMessageContains(moa, badSHA1); } try { assertNull("Base unexpected for bad SHA1", w.igit().mergeBase(badBase, branch1)); assertTrue("Exception not thrown by CliGit", w.git instanceof CliGitAPIImpl); } catch (GitException moa) { assertFalse("Exception thrown by CliGit", w.git instanceof CliGitAPIImpl); - assertTrue("Exception message didn't mention " + badBase.toString(), moa.getMessage().contains(badSHA1)); + assertExceptionMessageContains(moa, badSHA1); } w.igit().merge("branch1"); @@ -3551,7 +3556,7 @@ public void test_getRemoteReferences_withMatchingPattern() throws Exception { try { references = w.git.getRemoteReferences(remoteMirrorURL, "notexists-*", false, false); } catch (GitException ge) { - assertTrue("Wrong exception message: " + ge, ge.getMessage().contains("unexpected ls-remote output")); + assertExceptionMessageContains(ge, "unexpected ls-remote output"); } assertTrue(references.isEmpty()); } @@ -4192,7 +4197,7 @@ public void test_isBareRepository_working_null() throws IOException, Interrupted assertFalse("null is a bare repository", w.igit().isBareRepository(null)); fail("Did not throw expected exception"); } catch (GitException ge) { - assertTrue("Wrong exception message: " + ge, ge.getMessage().contains("Not a git repository")); + assertExceptionMessageContains(ge, "not a git repository"); } } @@ -4203,7 +4208,7 @@ public void test_isBareRepository_bare_null() throws IOException, InterruptedExc assertTrue("null is not a bare repository", w.igit().isBareRepository(null)); fail("Did not throw expected exception"); } catch (GitException ge) { - assertTrue("Wrong exception message: " + ge, ge.getMessage().contains("Not a git repository")); + assertExceptionMessageContains(ge, "not a git repository"); } } @@ -4267,7 +4272,7 @@ public void test_isBareRepository_working_dot() throws IOException, InterruptedE fail("Did not throw expected exception"); } } catch (GitException ge) { - assertTrue("Wrong exception message: " + ge, ge.getMessage().contains("Not a git repository")); + assertExceptionMessageContains(ge, "not a git repository"); } } @@ -4303,7 +4308,7 @@ public void test_isBareRepository_bare_dot_git() throws IOException, Interrupted assertFalse("CliGitAPIImpl did not throw expected exception", w.igit() instanceof CliGitAPIImpl); } catch (GitException ge) { /* Only enters this path for CliGit */ - assertTrue("Wrong exception message: " + ge, ge.getMessage().contains("Not a git repository")); + assertExceptionMessageContains(ge, "not a git repository"); } } @@ -4318,7 +4323,7 @@ public void test_isBareRepository_working_no_such_location() throws IOException, assertFalse("CliGitAPIImpl did not throw expected exception", w.igit() instanceof CliGitAPIImpl); } catch (GitException ge) { /* Only enters this path for CliGit */ - assertTrue("Wrong exception message: " + ge, ge.getMessage().contains("Not a git repository")); + assertExceptionMessageContains(ge, "not a git repository"); } } @@ -4332,7 +4337,7 @@ public void test_isBareRepository_bare_no_such_location() throws IOException, In assertFalse("CliGitAPIImpl did not throw expected exception", w.igit() instanceof CliGitAPIImpl); } catch (GitException ge) { /* Only enters this path for CliGit */ - assertTrue("Wrong exception message: " + ge, ge.getMessage().contains("Not a git repository")); + assertExceptionMessageContains(ge, "not a git repository"); } } From 1462e9f275c4d1506e16d2a9355450e7012753e1 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 5 Feb 2018 11:51:43 +0100 Subject: [PATCH 055/226] Use JGit exactRef instead of getRef to resolve precise ref The JGit implementation has deprecated getRef and replaced it with two implementations, one for exactRef() and one for findRef(). In this case, the ref is being formed into an exact reference, so the exactRef() call is the correct choice. --- src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index 0e9f7e7ad9..bfdd3728f2 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -344,7 +344,7 @@ private void doCheckout(String ref) throws GitException { for (String remote : repo.getRemoteNames()) { // look for exactly ONE remote tracking branch String matchingRemoteBranch = Constants.R_REMOTES + remote + "/" + ref; - if (repo.getRef(matchingRemoteBranch) != null) { + if (repo.exactRef(matchingRemoteBranch) != null) { remoteTrackingBranches.add(matchingRemoteBranch); } } From 17ba565a9d18b44e56fc4d203d41692ba6a9becf Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 5 Feb 2018 14:20:53 +0100 Subject: [PATCH 056/226] Rely on JGit setAuthor() null handling Remove redundant check for null ref in branch checkout Also rename doCheckout methods to more clearly say what they do. Add null ref check to tests --- .../plugins/gitclient/JGitAPIImpl.java | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index bfdd3728f2..f1eef746ef 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -303,16 +303,16 @@ public void execute() throws GitException, InterruptedException { } if (branch == null) - doCheckout(ref); + doCheckoutWithResetAndRetry(ref); else if (deleteBranch) - doCheckoutCleanBranch(branch, ref); + doCheckoutWithResetAndRetryAndCleanBranch(branch, ref); else doCheckout(ref, branch); } }; } - private void doCheckout(String ref) throws GitException { + private void doCheckoutWithResetAndRetry(String ref) throws GitException { boolean retried = false; Repository repo = null; while (true) { @@ -400,14 +400,13 @@ private void doCheckout(String ref) throws GitException { private void doCheckout(String ref, String branch) throws GitException { try (Repository repo = getRepository()) { - if (ref == null) ref = repo.resolve(HEAD).name(); git(repo).checkout().setName(branch).setCreateBranch(true).setForce(true).setStartPoint(ref).call(); - } catch (IOException | GitAPIException e) { + } catch (GitAPIException e) { throw new GitException("Could not checkout " + branch + " with start point " + ref, e); } } - private void doCheckoutCleanBranch(String branch, String ref) throws GitException { + private void doCheckoutWithResetAndRetryAndCleanBranch(String branch, String ref) throws GitException { try (Repository repo = getRepository()) { RefUpdate refUpdate = repo.updateRef(R_HEADS + branch); refUpdate.setNewObjectId(repo.resolve(ref)); @@ -421,7 +420,7 @@ private void doCheckoutCleanBranch(String branch, String ref) throws GitExceptio throw new GitException("Could not update " + branch + " to " + ref); } - doCheckout(branch); + doCheckoutWithResetAndRetry(branch); } catch (IOException e) { throw new GitException("Could not checkout " + branch + " with start point " + ref, e); } @@ -444,9 +443,7 @@ private Git git(Repository repo) { /** {@inheritDoc} */ public void commit(String message) throws GitException { try (Repository repo = getRepository()) { - CommitCommand cmd = git(repo).commit().setMessage(message); - if (author!=null) - cmd.setAuthor(author); + CommitCommand cmd = git(repo).commit().setMessage(message).setAuthor(author); if (committer!=null) cmd.setCommitter(new PersonIdent(committer,new Date())); cmd.call(); From 22646aa579041632a79fb57633c37726529a0935 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 5 Feb 2018 15:46:43 +0100 Subject: [PATCH 057/226] Add JGitAPIImpl @Override annotations --- .../plugins/gitclient/JGitAPIImpl.java | 134 +++++++++++++++++- 1 file changed, 133 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index f1eef746ef..67c01f9199 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -38,7 +38,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -175,16 +174,19 @@ public class JGitAPIImpl extends LegacyCompatibleGitAPIImpl { /** * clearCredentials. */ + @Override public void clearCredentials() { asSmartCredentialsProvider().clearCredentials(); } /** {@inheritDoc} */ + @Override public void addCredentials(String url, StandardCredentials credentials) { asSmartCredentialsProvider().addCredentials(url, credentials); } /** {@inheritDoc} */ + @Override public void addDefaultCredentials(StandardCredentials credentials) { asSmartCredentialsProvider().addDefaultCredentials(credentials); } @@ -210,16 +212,19 @@ private synchronized CredentialsProvider getProvider() { } /** {@inheritDoc} */ + @Override public GitClient subGit(String subdir) { return new JGitAPIImpl(new File(workspace, subdir), listener); } /** {@inheritDoc} */ + @Override public void setAuthor(String name, String email) throws GitException { author = new PersonIdent(name,email); } /** {@inheritDoc} */ + @Override public void setCommitter(String name, String email) throws GitException { committer = new PersonIdent(name,email); } @@ -230,6 +235,7 @@ public void setCommitter(String name, String email) throws GitException { * @throws hudson.plugins.git.GitException if underlying git operation fails. * @throws java.lang.InterruptedException if interrupted. */ + @Override public void init() throws GitException, InterruptedException { init_().workspace(workspace.getAbsolutePath()).execute(); } @@ -247,6 +253,7 @@ private void doInit(String workspace, boolean bare) throws GitException { * * @return a {@link org.jenkinsci.plugins.gitclient.CheckoutCommand} object. */ + @Override public CheckoutCommand checkout() { return new CheckoutCommand() { @@ -255,26 +262,31 @@ public CheckoutCommand checkout() { public boolean deleteBranch; public List sparseCheckoutPaths = Collections.emptyList(); + @Override public CheckoutCommand ref(String ref) { this.ref = ref; return this; } + @Override public CheckoutCommand branch(String branch) { this.branch = branch; return this; } + @Override public CheckoutCommand deleteBranchIfExist(boolean deleteBranch) { this.deleteBranch = deleteBranch; return this; } + @Override public CheckoutCommand sparseCheckoutPaths(List sparseCheckoutPaths) { this.sparseCheckoutPaths = sparseCheckoutPaths == null ? Collections.emptyList() : sparseCheckoutPaths; return this; } + @Override public CheckoutCommand timeout(Integer timeout) { // noop in jgit return this; @@ -295,6 +307,7 @@ public CheckoutCommand lfsCredentials(StandardCredentials lfsCredentials) { return lfsCheckoutIsNotSupported(); } + @Override public void execute() throws GitException, InterruptedException { if(! sparseCheckoutPaths.isEmpty()) { @@ -428,6 +441,7 @@ private void doCheckoutWithResetAndRetryAndCleanBranch(String branch, String ref /** {@inheritDoc} */ + @Override public void add(String filePattern) throws GitException { try (Repository repo = getRepository()) { git(repo).add().addFilepattern(filePattern).call(); @@ -441,6 +455,7 @@ private Git git(Repository repo) { } /** {@inheritDoc} */ + @Override public void commit(String message) throws GitException { try (Repository repo = getRepository()) { CommitCommand cmd = git(repo).commit().setMessage(message).setAuthor(author); @@ -453,6 +468,7 @@ public void commit(String message) throws GitException { } /** {@inheritDoc} */ + @Override public void branch(String name) throws GitException { try (Repository repo = getRepository()) { git(repo).branchCreate().setName(name).call(); @@ -462,6 +478,7 @@ public void branch(String name) throws GitException { } /** {@inheritDoc} */ + @Override public void deleteBranch(String name) throws GitException { try (Repository repo = getRepository()) { git(repo).branchDelete().setForce(true).setBranchNames(name).call(); @@ -476,6 +493,7 @@ public void deleteBranch(String name) throws GitException { * @return a {@link java.util.Set} object. * @throws hudson.plugins.git.GitException if underlying git operation fails. */ + @Override public Set getBranches() throws GitException { try (Repository repo = getRepository()) { List refs = git(repo).branchList().setListMode(ListBranchCommand.ListMode.ALL).call(); @@ -495,6 +513,7 @@ public Set getBranches() throws GitException { * @return a {@link java.util.Set} object. * @throws hudson.plugins.git.GitException if underlying git operation fails. */ + @Override public Set getRemoteBranches() throws GitException { try (Repository repo = getRepository()) { List refs = git(repo).branchList().setListMode(ListBranchCommand.ListMode.REMOTE).call(); @@ -509,6 +528,7 @@ public Set getRemoteBranches() throws GitException { } /** {@inheritDoc} */ + @Override public void tag(String name, String message) throws GitException { try (Repository repo = getRepository()) { git(repo).tag().setName(name).setMessage(message).setForceUpdate(true).call(); @@ -518,6 +538,7 @@ public void tag(String name, String message) throws GitException { } /** {@inheritDoc} */ + @Override public boolean tagExists(String tagName) throws GitException { try (Repository repo = getRepository()) { Ref tag = repo.getRefDatabase().getRef(R_TAGS + tagName); @@ -532,6 +553,7 @@ public boolean tagExists(String tagName) throws GitException { * * @return a {@link org.jenkinsci.plugins.gitclient.FetchCommand} object. */ + @Override public org.jenkinsci.plugins.gitclient.FetchCommand fetch_() { return new org.jenkinsci.plugins.gitclient.FetchCommand() { public URIish url; @@ -541,12 +563,14 @@ public org.jenkinsci.plugins.gitclient.FetchCommand fetch_() { private boolean shouldPrune = false; public boolean tags = true; + @Override public org.jenkinsci.plugins.gitclient.FetchCommand from(URIish remote, List refspecs) { this.url = remote; this.refspecs = refspecs; return this; } + @Override public org.jenkinsci.plugins.gitclient.FetchCommand prune() { return prune(true); } @@ -557,6 +581,7 @@ public org.jenkinsci.plugins.gitclient.FetchCommand prune(boolean prune) { return this; } + @Override public org.jenkinsci.plugins.gitclient.FetchCommand shallow(boolean shallow) { if (shallow) { listener.getLogger().println("[WARNING] JGit doesn't support shallow clone. This flag is ignored"); @@ -564,21 +589,25 @@ public org.jenkinsci.plugins.gitclient.FetchCommand shallow(boolean shallow) { return this; } + @Override public org.jenkinsci.plugins.gitclient.FetchCommand timeout(Integer timeout) { // noop in jgit return this; } + @Override public org.jenkinsci.plugins.gitclient.FetchCommand tags(boolean tags) { this.tags = tags; return this; } + @Override public org.jenkinsci.plugins.gitclient.FetchCommand depth(Integer depth) { listener.getLogger().println("[WARNING] JGit doesn't support shallow clone and therefore depth is meaningless. This flag is ignored"); return this; } + @Override public void execute() throws GitException, InterruptedException { try (Repository repo = getRepository()) { Git git = git(repo); @@ -646,11 +675,13 @@ public void execute() throws GitException, InterruptedException { * @throws hudson.plugins.git.GitException if any. * @throws java.lang.InterruptedException if any. */ + @Override public void fetch(URIish url, List refspecs) throws GitException, InterruptedException { fetch_().from(url, refspecs).execute(); } /** {@inheritDoc} */ + @Override public void fetch(String remoteName, RefSpec... refspec) throws GitException { try (Repository repo = getRepository()) { FetchCommand fetch = git(repo).fetch().setTagOpt(TagOpt.FETCH_TAGS); @@ -671,11 +702,13 @@ public void fetch(String remoteName, RefSpec... refspec) throws GitException { } /** {@inheritDoc} */ + @Override public void fetch(String remoteName, RefSpec refspec) throws GitException { fetch(remoteName, new RefSpec[] {refspec}); } /** {@inheritDoc} */ + @Override public void ref(String refName) throws GitException, InterruptedException { refName = refName.replace(' ', '_'); try (Repository repo = getRepository()) { @@ -696,6 +729,7 @@ public void ref(String refName) throws GitException, InterruptedException { } /** {@inheritDoc} */ + @Override public boolean refExists(String refName) throws GitException, InterruptedException { refName = refName.replace(' ', '_'); try (Repository repo = getRepository()) { @@ -707,6 +741,7 @@ public boolean refExists(String refName) throws GitException, InterruptedExcepti } /** {@inheritDoc} */ + @Override public void deleteRef(String refName) throws GitException, InterruptedException { refName = refName.replace(' ', '_'); try (Repository repo = getRepository()) { @@ -729,6 +764,7 @@ public void deleteRef(String refName) throws GitException, InterruptedException } /** {@inheritDoc} */ + @Override public Set getRefNames(String refPrefix) throws GitException, InterruptedException { if (refPrefix.isEmpty()) { refPrefix = RefDatabase.ALL; @@ -749,6 +785,7 @@ public Set getRefNames(String refPrefix) throws GitException, Interrupte } /** {@inheritDoc} */ + @Override public Map getHeadRev(String url) throws GitException, InterruptedException { Map heads = new HashMap<>(); try (Repository repo = openDummyRepository(); @@ -766,6 +803,7 @@ public Map getHeadRev(String url) throws GitException, Interru } /** {@inheritDoc} */ + @Override public Map getRemoteReferences(String url, String pattern, boolean headsOnly, boolean tagsOnly) throws GitException, InterruptedException { Map references = new HashMap<>(); @@ -901,6 +939,7 @@ private String replaceGlobCharsWithRegExChars(String glob) } /** {@inheritDoc} */ + @Override public ObjectId getHeadRev(String remoteRepoUrl, String branchSpec) throws GitException { try (Repository repo = openDummyRepository(); final Transport tn = Transport.open(repo, new URIish(remoteRepoUrl))) { @@ -941,6 +980,7 @@ public void close() { } /** {@inheritDoc} */ + @Override public String getRemoteUrl(String name) throws GitException { try (Repository repo = getRepository()) { return repo.getConfig().getString("remote",name,"url"); @@ -954,6 +994,7 @@ public String getRemoteUrl(String name) throws GitException { * @throws hudson.plugins.git.GitException if underlying git operation fails. */ @NonNull + @Override public Repository getRepository() throws GitException { try { return new RepositoryBuilder().setWorkTree(workspace).build(); @@ -967,11 +1008,13 @@ public Repository getRepository() throws GitException { * * @return a {@link hudson.FilePath} object. */ + @Override public FilePath getWorkTree() { return new FilePath(workspace); } /** {@inheritDoc} */ + @Override public void setRemoteUrl(String name, String url) throws GitException { try (Repository repo = getRepository()) { StoredConfig config = repo.getConfig(); @@ -983,6 +1026,7 @@ public void setRemoteUrl(String name, String url) throws GitException { } /** {@inheritDoc} */ + @Override public void addRemoteUrl(String name, String url) throws GitException, InterruptedException { try (Repository repo = getRepository()) { StoredConfig config = repo.getConfig(); @@ -999,6 +1043,7 @@ public void addRemoteUrl(String name, String url) throws GitException, Interrupt } /** {@inheritDoc} */ + @Override public void addNote(String note, String namespace) throws GitException { try (Repository repo = getRepository()) { ObjectId head = repo.resolve(HEAD); // commit to put a note on @@ -1034,6 +1079,7 @@ private String qualifyNotesNamespace(String namespace) { } /** {@inheritDoc} */ + @Override public void appendNote(String note, String namespace) throws GitException { try (Repository repo = getRepository()) { ObjectId head = repo.resolve(HEAD); // commit to put a note on @@ -1093,6 +1139,7 @@ public ChangelogCommand excludes(ObjectId rev) { } } + @Override public ChangelogCommand includes(String rev) { try { includes(repo.resolve(rev)); @@ -1283,6 +1330,7 @@ void format(RevCommit commit, @Nullable RevCommit parent, PrintWriter pw, Boolea * @param cleanSubmodule flag to add extra -f * @throws hudson.plugins.git.GitException if underlying git operation fails. */ + @Override public void clean(boolean cleanSubmodule) throws GitException { try (Repository repo = getRepository()) { Git git = git(repo); @@ -1298,6 +1346,7 @@ public void clean(boolean cleanSubmodule) throws GitException { * * @throws hudson.plugins.git.GitException if underlying git operation fails. */ + @Override public void clean() throws GitException { this.clean(false); } @@ -1307,6 +1356,7 @@ public void clean() throws GitException { * * @return a {@link org.jenkinsci.plugins.gitclient.CloneCommand} object. */ + @Override public CloneCommand clone_() { return new CloneCommand() { @@ -1318,16 +1368,19 @@ public CloneCommand clone_() { boolean tags = true; List refspecs; + @Override public CloneCommand url(String url) { this.url = url; return this; } + @Override public CloneCommand repositoryName(String name) { this.remote = name; return this; } + @Override public CloneCommand shallow() { return shallow(true); } @@ -1340,6 +1393,7 @@ public CloneCommand shallow(boolean shallow) { return this; } + @Override public CloneCommand shared() { return shared(true); } @@ -1350,36 +1404,43 @@ public CloneCommand shared(boolean shared) { return this; } + @Override public CloneCommand reference(String reference) { this.reference = reference; return this; } + @Override public CloneCommand refspecs(List refspecs) { this.refspecs = new ArrayList<>(refspecs); return this; } + @Override public CloneCommand timeout(Integer timeout) { this.timeout = timeout; return this; } + @Override public CloneCommand tags(boolean tags) { this.tags = tags; return this; } + @Override public CloneCommand noCheckout() { // this.noCheckout = true; ignored, we never do a checkout return this; } + @Override public CloneCommand depth(Integer depth) { listener.getLogger().println("[WARNING] JGit doesn't support shallow clone and therefore depth is meaningless. This flag is ignored"); return this; } + @Override public void execute() throws GitException, InterruptedException { Repository repository = null; @@ -1478,6 +1539,7 @@ else if (!referencePath.isDirectory()) * * @return a {@link org.jenkinsci.plugins.gitclient.MergeCommand} object. */ + @Override public MergeCommand merge() { return new MergeCommand() { @@ -1488,11 +1550,13 @@ public MergeCommand merge() { boolean commit = true; String comment; + @Override public MergeCommand setRevisionToMerge(ObjectId rev) { this.rev = rev; return this; } + @Override public MergeCommand setStrategy(MergeCommand.Strategy strategy) { if (strategy != null && !strategy.toString().isEmpty() && strategy != MergeCommand.Strategy.DEFAULT) { if (strategy == MergeCommand.Strategy.OURS) { @@ -1517,6 +1581,7 @@ public MergeCommand setStrategy(MergeCommand.Strategy strategy) { return this; } + @Override public MergeCommand setGitPluginFastForwardMode(MergeCommand.GitPluginFastForwardMode fastForwardMode) { if (fastForwardMode == MergeCommand.GitPluginFastForwardMode.FF) { this.fastForwardMode = FastForwardMode.FF; @@ -1528,21 +1593,25 @@ public MergeCommand setGitPluginFastForwardMode(MergeCommand.GitPluginFastForwar return this; } + @Override public MergeCommand setSquash(boolean squash){ this.squash = squash; return this; } + @Override public MergeCommand setMessage(String comment) { this.comment = comment; return this; } + @Override public MergeCommand setCommit(boolean commit) { this.commit = commit; return this; } + @Override public void execute() throws GitException, InterruptedException { try (Repository repo = getRepository()) { Git git = git(repo); @@ -1567,37 +1636,44 @@ public void execute() throws GitException, InterruptedException { * * @return a {@link org.jenkinsci.plugins.gitclient.InitCommand} object. */ + @Override public InitCommand init_() { return new InitCommand() { public String workspace; public boolean bare; + @Override public InitCommand workspace(String workspace) { this.workspace = workspace; return this; } + @Override public InitCommand bare(boolean bare) { this.bare = bare; return this; } + @Override public void execute() throws GitException, InterruptedException { doInit(workspace, bare); } }; } + @Override public RebaseCommand rebase() { return new RebaseCommand() { private String upstream; + @Override public RebaseCommand setUpstream(String upstream) { this.upstream = upstream; return this; } + @Override public void execute() throws GitException, InterruptedException { try (Repository repo = getRepository()) { Git git = git(repo); @@ -1614,6 +1690,7 @@ public void execute() throws GitException, InterruptedException { } /** {@inheritDoc} */ + @Override public void deleteTag(String tagName) throws GitException { try (Repository repo = getRepository()) { git(repo).tagDelete().setTags(tagName).call(); @@ -1623,6 +1700,7 @@ public void deleteTag(String tagName) throws GitException { } /** {@inheritDoc} */ + @Override public String getTagMessage(String tagName) throws GitException { try (Repository repo = getRepository(); ObjectReader or = repo.newObjectReader(); @@ -1634,6 +1712,7 @@ public String getTagMessage(String tagName) throws GitException { } /** {@inheritDoc} */ + @Override public List getSubmodules(String treeIsh) throws GitException { try (Repository repo = getRepository(); ObjectReader or = repo.newObjectReader(); @@ -1655,6 +1734,7 @@ public List getSubmodules(String treeIsh) throws GitException { } /** {@inheritDoc} */ + @Override public void addSubmodule(String remoteURL, String subdir) throws GitException { try (Repository repo = getRepository()) { git(repo).submoduleAdd().setPath(subdir).setURI(remoteURL).call(); @@ -1664,6 +1744,7 @@ public void addSubmodule(String remoteURL, String subdir) throws GitException { } /** {@inheritDoc} */ + @Override public Set getTagNames(String tagPattern) throws GitException { if (tagPattern == null) tagPattern = "*"; @@ -1683,6 +1764,7 @@ public Set getTagNames(String tagPattern) throws GitException { } /** {@inheritDoc} */ + @Override public Set getRemoteTagNames(String tagPattern) throws GitException { /* BUG: Lists local tag names, not remote tag names */ if (tagPattern == null) tagPattern = "*"; @@ -1709,6 +1791,7 @@ public Set getRemoteTagNames(String tagPattern) throws GitException { * @return true if this workspace has a git repository * @throws hudson.plugins.git.GitException if underlying git operation fails. */ + @Override public boolean hasGitRepo() throws GitException { try (Repository repo = getRepository()) { return repo.getObjectDatabase().exists(); @@ -1718,6 +1801,7 @@ public boolean hasGitRepo() throws GitException { } /** {@inheritDoc} */ + @Override public boolean isCommitInRepo(ObjectId commit) throws GitException { if (commit == null) { return false; @@ -1730,6 +1814,7 @@ public boolean isCommitInRepo(ObjectId commit) throws GitException { } /** {@inheritDoc} */ + @Override public void prune(RemoteConfig repository) throws GitException { try (Repository gitRepo = getRepository()) { String remote = repository.getName(); @@ -1773,6 +1858,7 @@ private Set listRemoteBranches(String remote) throws NotSupportedExcepti * * @return a {@link org.jenkinsci.plugins.gitclient.PushCommand} object. */ + @Override public PushCommand push() { return new PushCommand() { public URIish remote; @@ -1780,16 +1866,19 @@ public PushCommand push() { public boolean force; public boolean tags; + @Override public PushCommand to(URIish remote) { this.remote = remote; return this; } + @Override public PushCommand ref(String refspec) { this.refspec = refspec; return this; } + @Override public PushCommand force() { return force(true); } @@ -1800,16 +1889,19 @@ public PushCommand force(boolean force) { return this; } + @Override public PushCommand tags(boolean tags) { this.tags = tags; return this; } + @Override public PushCommand timeout(Integer timeout) { // noop in jgit return this; } + @Override public void execute() throws GitException, InterruptedException { try (Repository repo = getRepository()) { RefSpec ref = (refspec != null) ? new RefSpec(fixRefSpec(repo)) : Transport.REFSPEC_PUSH_ALL; @@ -1890,6 +1982,7 @@ private String fixRefSpec(Repository repository) throws IOException { * * @return a {@link org.jenkinsci.plugins.gitclient.RevListCommand} object. */ + @Override public RevListCommand revList_() { return new RevListCommand() { @@ -1899,6 +1992,7 @@ public RevListCommand revList_() public String refspec; public List out; + @Override public RevListCommand all() { return all(true); } @@ -1909,11 +2003,13 @@ public RevListCommand all(boolean all) { return this; } + @Override public RevListCommand nowalk(boolean nowalk) { this.nowalk = nowalk; return this; } + @Override public RevListCommand firstParent() { return firstParent(true); } @@ -1924,16 +2020,19 @@ public RevListCommand firstParent(boolean firstParent) { return this; } + @Override public RevListCommand to(List revs){ this.out = revs; return this; } + @Override public RevListCommand reference(String reference){ this.refspec = reference; return this; } + @Override public void execute() throws GitException, InterruptedException { if (firstParent) { throw new UnsupportedOperationException("not implemented yet"); @@ -1984,6 +2083,7 @@ else if (refspec != null) * @return a {@link java.util.List} object. * @throws hudson.plugins.git.GitException if underlying git operation fails. */ + @Override public List revListAll() throws GitException { List oidList = new ArrayList<>(); RevListCommand revListCommand = revList_(); @@ -1998,6 +2098,7 @@ public List revListAll() throws GitException { } /** {@inheritDoc} */ + @Override public List revList(String ref) throws GitException { List oidList = new ArrayList<>(); RevListCommand revListCommand = revList_(); @@ -2012,6 +2113,7 @@ public List revList(String ref) throws GitException { } /** {@inheritDoc} */ + @Override public ObjectId revParse(String revName) throws GitException { try (Repository repo = getRepository()) { ObjectId id = repo.resolve(revName + "^{commit}"); @@ -2024,11 +2126,13 @@ public ObjectId revParse(String revName) throws GitException { } /** {@inheritDoc} */ + @Override public List showRevision(ObjectId from, ObjectId to) throws GitException { return showRevision(from, to, true); } /** {@inheritDoc} */ + @Override public List showRevision(ObjectId from, ObjectId to, Boolean useRawOutput) throws GitException { try (Repository repo = getRepository(); ObjectReader or = repo.newObjectReader(); @@ -2076,6 +2180,7 @@ private Iterable submodules() throws IOException { } /** {@inheritDoc} */ + @Override public void submoduleClean(boolean recursive) throws GitException { try { for (JGitAPIImpl sub : submodules()) { @@ -2094,41 +2199,49 @@ public void submoduleClean(boolean recursive) throws GitException { * * @return a {@link org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand} object. */ + @Override public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand submoduleUpdate() { return new org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand() { boolean recursive = false; boolean remoteTracking = false; String ref = null; + @Override public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand recursive(boolean recursive) { this.recursive = recursive; return this; } + @Override public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand remoteTracking(boolean remoteTracking) { this.remoteTracking = remoteTracking; return this; } + @Override public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand parentCredentials(boolean parentCredentials) { // No-op for JGit implementation return this; } + @Override public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand ref(String ref) { this.ref = ref; return this; } + @Override public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand timeout(Integer timeout) { // noop in jgit return this; } + @Override public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand useBranch(String submodule, String branchname) { return this; } + @Override public void execute() throws GitException, InterruptedException { if (remoteTracking) { listener.getLogger().println("[ERROR] JGit doesn't support remoteTracking submodules yet."); @@ -2167,6 +2280,7 @@ public void execute() throws GitException, InterruptedException { /** {@inheritDoc} */ @Deprecated + @Override public void merge(String refSpec) throws GitException, InterruptedException { try (Repository repo = getRepository()) { merge(repo.resolve(refSpec)); @@ -2177,11 +2291,13 @@ public void merge(String refSpec) throws GitException, InterruptedException { /** {@inheritDoc} */ @Deprecated + @Override public void push(RemoteConfig repository, String refspec) throws GitException, InterruptedException { push(repository.getName(),refspec); } /** {@inheritDoc} */ + @Override public List getBranchesContaining(String revspec) throws GitException, InterruptedException { // For the reasons of backward compatibility - we do not query remote branches here. return getBranchesContaining(revspec, false); @@ -2210,6 +2326,7 @@ public List getBranchesContaining(String revspec) throws GitException, I * Since we reuse {@link RevWalk}, it'd be nice to flag commits reachable from 't' as uninteresting * and keep them across resets, but I'm not sure how to do it. */ + @Override public List getBranchesContaining(String revspec, boolean allBranches) throws GitException, InterruptedException { try (Repository repo = getRepository(); ObjectReader or = repo.newObjectReader(); @@ -2285,6 +2402,7 @@ private List getAllBranchRefs(boolean originBranches) { /** {@inheritDoc} */ @Deprecated + @Override public ObjectId mergeBase(ObjectId id1, ObjectId id2) throws InterruptedException { try (Repository repo = getRepository(); ObjectReader or = repo.newObjectReader(); @@ -2305,6 +2423,7 @@ public ObjectId mergeBase(ObjectId id1, ObjectId id2) throws InterruptedExceptio /** {@inheritDoc} */ @Deprecated + @Override public String getAllLogEntries(String branch) throws InterruptedException { try (Repository repo = getRepository(); ObjectReader or = repo.newObjectReader(); @@ -2350,6 +2469,7 @@ private void markRefs(RevWalk walk, Predicate filter) throws IOException { * @throws java.lang.InterruptedException if interrupted. */ @Deprecated + @Override public void submoduleInit() throws GitException, InterruptedException { try (Repository repo = getRepository()) { git(repo).submoduleInit().call(); @@ -2365,6 +2485,7 @@ public void submoduleInit() throws GitException, InterruptedException { * @throws java.lang.InterruptedException if interrupted. */ @Deprecated + @Override public void submoduleSync() throws GitException, InterruptedException { try (Repository repo = getRepository()) { git(repo).submoduleSync().call(); @@ -2375,6 +2496,7 @@ public void submoduleSync() throws GitException, InterruptedException { /** {@inheritDoc} */ @Deprecated + @Override public String getSubmoduleUrl(String name) throws GitException, InterruptedException { String v = null; try (Repository repo = getRepository()) { @@ -2386,6 +2508,7 @@ public String getSubmoduleUrl(String name) throws GitException, InterruptedExcep /** {@inheritDoc} */ @Deprecated + @Override public void setSubmoduleUrl(String name, String url) throws GitException, InterruptedException { try (Repository repo = getRepository()) { StoredConfig config = repo.getConfig(); @@ -2405,6 +2528,7 @@ public void setSubmoduleUrl(String name, String url) throws GitException, Interr * whoever manipulating Git. */ @Deprecated + @Override public void setupSubmoduleUrls(Revision rev, TaskListener listener) throws GitException { throw new UnsupportedOperationException("not implemented yet"); } @@ -2418,6 +2542,7 @@ public void setupSubmoduleUrls(Revision rev, TaskListener listener) throws GitEx * whoever manipulating Git. */ @Deprecated + @Override public void fixSubmoduleUrls(String remote, TaskListener listener) throws GitException, InterruptedException { throw new UnsupportedOperationException(); } @@ -2439,6 +2564,7 @@ public void fixSubmoduleUrls(String remote, TaskListener listener) throws GitExc * As we walk further and find enough tags, we go into wind-down mode and only walk * to the point of accurately determining all the depths. */ + @Override public String describe(String tip) throws GitException, InterruptedException { try (Repository repo = getRepository()) { final ObjectReader or = repo.newObjectReader(); @@ -2569,6 +2695,7 @@ public String describe(ObjectId tip) throws IOException { /** {@inheritDoc} */ @Deprecated + @Override public List lsTree(String treeIsh, boolean recursive) throws GitException, InterruptedException { try (Repository repo = getRepository(); ObjectReader or = repo.newObjectReader(); @@ -2594,6 +2721,7 @@ public List lsTree(String treeIsh, boolean recursive) throws GitExce /** {@inheritDoc} */ @Deprecated + @Override public void reset(boolean hard) throws GitException, InterruptedException { try (Repository repo = getRepository()) { ResetCommand reset = new ResetCommand(repo); @@ -2606,6 +2734,7 @@ public void reset(boolean hard) throws GitException, InterruptedException { /** {@inheritDoc} */ @Deprecated + @Override public boolean isBareRepository(String GIT_DIR) throws GitException, InterruptedException { Repository repo = null; boolean isBare = false; @@ -2633,6 +2762,7 @@ public boolean isBareRepository(String GIT_DIR) throws GitException, Interrupted /** {@inheritDoc} */ @Deprecated + @Override public String getDefaultRemote(String _default_) throws GitException, InterruptedException { Set remotes = getConfig(null).getSubsections("remote"); if (remotes.contains(_default_)) return _default_; @@ -2641,6 +2771,7 @@ public String getDefaultRemote(String _default_) throws GitException, Interrupte /** {@inheritDoc} */ @Deprecated + @Override public void setRemoteUrl(String name, String url, String GIT_DIR) throws GitException, InterruptedException { try (Repository repo = new RepositoryBuilder().setGitDir(new File(GIT_DIR)).build()) { StoredConfig config = repo.getConfig(); @@ -2653,6 +2784,7 @@ public void setRemoteUrl(String name, String url, String GIT_DIR) throws GitExce /** {@inheritDoc} */ @Deprecated + @Override public String getRemoteUrl(String name, String GIT_DIR) throws GitException, InterruptedException { return getConfig(GIT_DIR).getString("remote", name, "url"); } From fbf876d4f4506bb98836d1adac683316715ddeea Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 7 Feb 2018 21:03:30 +0100 Subject: [PATCH 058/226] Use JGit LsRemoteCommand for getHeadRev Reduce unnecessary reimplementation of LsRemoteCommand in the JGitAPIImpl source code. --- .../jenkinsci/plugins/gitclient/JGitAPIImpl.java | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index 67c01f9199..b62a27289b 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -787,19 +787,7 @@ public Set getRefNames(String refPrefix) throws GitException, Interrupte /** {@inheritDoc} */ @Override public Map getHeadRev(String url) throws GitException, InterruptedException { - Map heads = new HashMap<>(); - try (Repository repo = openDummyRepository(); - final Transport tn = Transport.open(repo, new URIish(url))) { - tn.setCredentialsProvider(getProvider()); - try (FetchConnection c = tn.openFetch()) { - for (final Ref r : c.getRefs()) { - heads.put(r.getName(), r.getPeeledObjectId() != null ? r.getPeeledObjectId() : r.getObjectId()); - } - } - } catch (IOException | URISyntaxException e) { - throw new GitException(e); - } - return heads; + return getRemoteReferences(url, null, true, false); } /** {@inheritDoc} */ @@ -834,7 +822,7 @@ public Map getRemoteReferences(String url, String pattern, boo references.put(refName, refObjectId); } } - } catch (GitAPIException | IOException e) { + } catch (JGitInternalException | GitAPIException | IOException e) { throw new GitException(e); } return references; From 2794867ff309b82f080a293e897fb0bfb276e3f2 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 5 Feb 2018 15:06:55 +0100 Subject: [PATCH 059/226] Remove duplicate JGit getBranches implementations --- .../plugins/gitclient/JGitAPIImpl.java | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index b62a27289b..80377b768c 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -495,16 +495,7 @@ public void deleteBranch(String name) throws GitException { */ @Override public Set getBranches() throws GitException { - try (Repository repo = getRepository()) { - List refs = git(repo).branchList().setListMode(ListBranchCommand.ListMode.ALL).call(); - Set branches = new HashSet<>(refs.size()); - for (Ref ref : refs) { - branches.add(new Branch(ref)); - } - return branches; - } catch (GitAPIException e) { - throw new GitException(e); - } + return getBranchesInternal(ListBranchCommand.ListMode.ALL); } /** @@ -515,8 +506,12 @@ public Set getBranches() throws GitException { */ @Override public Set getRemoteBranches() throws GitException { + return getBranchesInternal(ListBranchCommand.ListMode.REMOTE); + } + + public Set getBranchesInternal(ListBranchCommand.ListMode mode) throws GitException { try (Repository repo = getRepository()) { - List refs = git(repo).branchList().setListMode(ListBranchCommand.ListMode.REMOTE).call(); + List refs = git(repo).branchList().setListMode(mode).call(); Set branches = new HashSet<>(refs.size()); for (Ref ref : refs) { branches.add(new Branch(ref)); From 0cce45083adafe488d4206e3a2c3e2da51f46078 Mon Sep 17 00:00:00 2001 From: presPetkov Date: Tue, 24 Apr 2018 09:41:36 +0100 Subject: [PATCH 060/226] Fixed indentation --- .../jenkinsci/plugins/gitclient/CliGitAPIImpl.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 406ca21430..541635cdbd 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -1983,13 +1983,13 @@ private File createUnixGitSSH(File key, String user) throws IOException { String fromLocation = ssh.toString(); String toLocation = ssh_copy.toString(); //Copying ssh file - try { - new ProcessBuilder("cp", fromLocation, toLocation).start().waitFor(); - isCopied = true; - ssh_copy.setExecutable(true,true); - //Deleting original file - deleteTempFile(ssh); - } + try { + new ProcessBuilder("cp", fromLocation, toLocation).start().waitFor(); + isCopied = true; + ssh_copy.setExecutable(true,true); + //Deleting original file + deleteTempFile(ssh); + } catch(InterruptedException ie) { //Delete the copied file in case of failure From fbec88af1b5cab15a9c1c2310a7977324fd893d8 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 14 Apr 2018 09:01:20 -0600 Subject: [PATCH 061/226] [JENKINS-50573] Prefer URL username with ssh URL When using an ssh private key, the CliGitAPIImpl implementation previously passed a "-l" command line argument from the username associated with the ssh key. OpenSSH implementations prior to OpenSSH 7.7 would only use that command line argument if no username were included in the ssh URI. OpenSSH 7.7 changes the ssh command line argument parsing rules. Previously, the last user name specified would be used, including the user name in the URL. With OpenSSH 7.7, the first user name specified is used, even if a user name is specified in the URL. The command line: ssh -l jenkins git@github.com:jenkinsci/git-client-plugin.git uses the username 'git' with OpenSSH versions before 7.7 and uses the username 'jenkins' with OpenSSH 7.7. OpenSSH 7.7 is included in Windows Git 2.17 and in OpenBSD 6.3. The CredentialsTest class can test this case. --- .../org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java | 10 ++++++++-- .../jenkinsci/plugins/gitclient/CredentialsTest.java | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 8c8d2b08f9..1496caa7b6 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -1669,11 +1669,17 @@ private String launchCommandWithCredentials(ArgumentListBuilder args, File workD listener.getLogger().println("using GIT_SSH to set credentials " + sshUser.getDescription()); key = createSshKeyFile(sshUser); + // Prefer url username if set, OpenSSH 7.7 argument precedence change + // See JENKINS-50573 for details + String userName = url.getUser(); + if (userName == null) { + userName = sshUser.getUsername(); + } if (launcher.isUnix()) { - ssh = createUnixGitSSH(key, sshUser.getUsername()); + ssh = createUnixGitSSH(key, userName); pass = createUnixSshAskpass(sshUser); } else { - ssh = createWindowsGitSSH(key, sshUser.getUsername()); + ssh = createWindowsGitSSH(key, userName); pass = createWindowsSshAskpass(sshUser); } diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index ea9146b5f5..090589a1e2 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -325,7 +325,7 @@ public static Collection gitRepoUrls() throws MalformedURLException, FileNotFoun } } Collections.shuffle(repos); // randomize test order - int toIndex = Math.min(repos.size(), TEST_ALL_CREDENTIALS ? 90 : 6); // Don't run more than 90 variations of test - about 3 minutes + int toIndex = Math.min(repos.size(), TEST_ALL_CREDENTIALS ? 120 : 6); // Don't run more than 120 variations of test - about 3 minutes return repos.subList(0, toIndex); } From a203196b26e1a8528e28d01b17efd0a74163f02a Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 4 May 2018 05:04:43 -0600 Subject: [PATCH 062/226] Use parent pom 3.9 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3977e023ef..c4c1e959c5 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 3.8 + 3.9 From 1201797917f5949a226bae3f9d82be27fe9b66f2 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 4 May 2018 06:26:17 -0600 Subject: [PATCH 063/226] [maven-release-plugin] prepare release git-client-3.0.0-beta2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c4c1e959c5..4ca04ac436 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins git-client - 3.0.0-beta2-SNAPSHOT + 3.0.0-beta2 hpi Jenkins Git client plugin @@ -38,7 +38,7 @@ scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git https://github.com/jenkinsci/${project.artifactId}-plugin - HEAD + git-client-3.0.0-beta2 From 7859f2cec4a863b6ab6d4f82ed145ee720f02f2b Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 4 May 2018 06:26:24 -0600 Subject: [PATCH 064/226] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 4ca04ac436..c29815c18a 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins git-client - 3.0.0-beta2 + 3.0.0-beta3-SNAPSHOT hpi Jenkins Git client plugin @@ -38,7 +38,7 @@ scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git https://github.com/jenkinsci/${project.artifactId}-plugin - git-client-3.0.0-beta2 + HEAD From ab31c3690d38787e689ef1481a34d702935493ab Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 9 May 2018 09:15:52 -0600 Subject: [PATCH 065/226] Use Jenkins 2.107.3 for compatibility test Use sshd 2.4 in test Not a compile time dependency --- Jenkinsfile | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 355bd6cac5..1bff8e26b0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,7 +1,7 @@ #!groovy // build both versions, retry test failures -buildPlugin(jenkinsVersions: [null, '2.89.3'], +buildPlugin(jenkinsVersions: [null, '2.107.3'], findbugs: [run:true, archive:true, unstableTotalAll: '0'], failFast: false) diff --git a/pom.xml b/pom.xml index c29815c18a..ae40a637a5 100644 --- a/pom.xml +++ b/pom.xml @@ -194,7 +194,7 @@ org.jenkins-ci.modules sshd - 2.2 + 2.4 test From 1aeb45bc24723c5e69818b3ff3a3f9adeb44e94b Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 11 May 2018 04:52:55 -0600 Subject: [PATCH 066/226] Special case jgit 4.5 in CredentialsTest JGit 4.5 handles absence of username from the ssh URL differently than JGit 4.11. The ssh URL github.com:MarkEWaite/tasks.git with the username argument "git" is handled correctly by JGit 4.11 and incorrectly by JGit 4.5. JGit 4.5 handles conflicts between the username embedded in the ssh URL and the username argument differently than JGit 4.11. The ssh URL git@github.com:MarkEWaite/tasks.git with the username argument "jenkins" is handled correctly by JGit 4.11 and incorrectly by JGit 4.5. JGit 4.5 honors the username argument instead of the username embedded in the ssh URL. JGit 4.11 honors the username embedded in the ssh URL instead of the username argument. Secure shell versions prior to OpenSSH 7.7 honored the username embedded in the ssh URL instead of the username argument. That is the definitive behavior. Git plugin changes have been made to cause OpenSSH 7.7 (and later) to honor the username embedded in the ssh URL instead of the username argument. Those changes should keep consistent behavior across all versions of OpenSSH and all supported versions of command line git. --- .../jenkinsci/plugins/gitclient/CredentialsTest.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index 090589a1e2..7498840868 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -272,7 +272,17 @@ public static Collection gitRepoUrls() throws MalformedURLException, FileNotFoun if (skipIf.equals(implementation)) { continue; } - if (implementation.startsWith("jgit") && skipIf.startsWith("jgit")) { // Treat jgitapache like jgit + if (implementation.startsWith("jgit") && skipIf.equals("jgit")) { // Treat jgitapache like jgit + continue; + } + // JGit 4.5 as used in git client plugin prior to 3.0.0 does not handle + // github.com:MarkEWaite/tasks.git correctly (no username in the URL), while it handles + // git@github.com:MarkEWaite/tasks.git correctly. + // This special case should be removed when JGit 4.11 is used. + // JGit 4.11 as used in git client plugin prior to 3.0.0 handles + // github.com:MarkEWaite/tasks.git correctly (no username in the URL), and handles + // git@github.com:MarkEWaite/tasks.git correctly. + if (implementation.startsWith("jgit") && skipIf.startsWith("jgit-4.5")) { // Treat jgitapache like jgit continue; } } From c19928e1fbcd956a546731a28152603777e77bb1 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 11 May 2018 04:57:18 -0600 Subject: [PATCH 067/226] Narrow jgit exclusion in credentials test JGit 4.5 handles absence of username from the ssh URL differently than JGit 4.11. The ssh URL github.com:MarkEWaite/tasks.git with the username argument "git" is handled correctly by JGit 4.11 and incorrectly by JGit 4.5. JGit 4.5 handles conflicts between the username embedded in the ssh URL and the username argument differently than JGit 4.11. The ssh URL git@github.com:MarkEWaite/tasks.git with the username argument "jenkins" is handled correctly by JGit 4.11 and incorrectly by JGit 4.5. JGit 4.5 honors the username argument instead of the username embedded in the ssh URL. JGit 4.11 honors the username embedded in the ssh URL instead of the username argument. Secure shell versions prior to OpenSSH 7.7 honored the username embedded in the ssh URL instead of the username argument. That is the definitive behavior. Git plugin changes have been made to cause OpenSSH 7.7 (and later) to honor the username embedded in the ssh URL instead of the username argument. Those changes should keep consistent behavior across all versions of OpenSSH and all supported versions of command line git. --- .../java/org/jenkinsci/plugins/gitclient/CredentialsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index 090589a1e2..ffb0db8c3f 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -272,7 +272,7 @@ public static Collection gitRepoUrls() throws MalformedURLException, FileNotFoun if (skipIf.equals(implementation)) { continue; } - if (implementation.startsWith("jgit") && skipIf.startsWith("jgit")) { // Treat jgitapache like jgit + if (implementation.startsWith("jgit") && skipIf.equals("jgit")) { // Treat jgitapache like jgit continue; } } From d93e0005cade2b72ef5f7142799e9dc4bd577846 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 12 May 2018 08:05:45 -0600 Subject: [PATCH 068/226] [maven-release-plugin] prepare release git-client-2.7.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index a595811b16..8f1ba32abb 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins git-client - 2.7.2-SNAPSHOT + 2.7.2 hpi Jenkins Git client plugin @@ -38,7 +38,7 @@ scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git https://github.com/jenkinsci/${project.artifactId}-plugin - HEAD + git-client-2.7.2 From 3d59be97b6fecb99833b78fe046227e348cd6cf3 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 12 May 2018 08:05:51 -0600 Subject: [PATCH 069/226] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8f1ba32abb..c233716c2e 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins git-client - 2.7.2 + 2.7.3-SNAPSHOT hpi Jenkins Git client plugin @@ -38,7 +38,7 @@ scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git https://github.com/jenkinsci/${project.artifactId}-plugin - git-client-2.7.2 + HEAD From 0f2cea17972dcd4e155c8a6e0842d2604361de67 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Tue, 15 May 2018 10:49:33 -0600 Subject: [PATCH 070/226] Use parent pom 3.11 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c29815c18a..65b9dde927 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 3.9 + 3.11 From 9da2b27caec1991f49e107f867214eecf25cabeb Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Thu, 17 May 2018 06:34:07 -0600 Subject: [PATCH 071/226] Use parent pom 3.12 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b34575eb17..f27a157bc0 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 3.11 + 3.12 From 5a679eaba89f8497472317bf3a4c418bf42ad177 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Thu, 17 May 2018 06:36:24 -0600 Subject: [PATCH 072/226] Add incrementals support --- .mvn/extensions.xml | 7 +++++++ .mvn/maven.config | 2 ++ pom.xml | 6 ++++-- 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 .mvn/extensions.xml create mode 100644 .mvn/maven.config diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml new file mode 100644 index 0000000000..510f24fbcd --- /dev/null +++ b/.mvn/extensions.xml @@ -0,0 +1,7 @@ + + + io.jenkins.tools.incrementals + git-changelist-maven-extension + 1.0-beta-3 + + diff --git a/.mvn/maven.config b/.mvn/maven.config new file mode 100644 index 0000000000..2a0299c486 --- /dev/null +++ b/.mvn/maven.config @@ -0,0 +1,2 @@ +-Pconsume-incrementals +-Pmight-produce-incrementals diff --git a/pom.xml b/pom.xml index f27a157bc0..ced469959c 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins git-client - 3.0.0-beta3-SNAPSHOT + ${revision}${changelist} hpi Jenkins Git client plugin @@ -38,10 +38,12 @@ scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git https://github.com/jenkinsci/${project.artifactId}-plugin - HEAD + ${scmTag} + 3.0.0-beta3 + -SNAPSHOT UTF-8 -Dfile.encoding=${project.build.sourceEncoding} 2.60.3 From 3406baa7a8d922937a4b3b905ac205022963d755 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 27 May 2018 07:28:45 -0600 Subject: [PATCH 073/226] [maven-release-plugin] prepare release git-client-3.0.0-beta3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ced469959c..3e2c8189f8 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins git-client - ${revision}${changelist} + 3.0.0-beta3 hpi Jenkins Git client plugin @@ -38,7 +38,7 @@ scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git https://github.com/jenkinsci/${project.artifactId}-plugin - ${scmTag} + git-client-3.0.0-beta3 From fcd29e6a7a45fc7d07c736d2161f1c483d4d4560 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 27 May 2018 07:28:51 -0600 Subject: [PATCH 074/226] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3e2c8189f8..9a65d081d0 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins git-client - 3.0.0-beta3 + 3.0.0-beta4-SNAPSHOT hpi Jenkins Git client plugin @@ -38,7 +38,7 @@ scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git https://github.com/jenkinsci/${project.artifactId}-plugin - git-client-3.0.0-beta3 + ${scmTag} From f5b5217d557d5583ffb40e4357049d46e55173c1 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 27 May 2018 07:55:20 -0600 Subject: [PATCH 075/226] Maven 3.5.0 or later is required The incrementals support requires maven 3.5.0 or later. Also renames title of the link to the documentation page. The Jenkins plugins site is not a wiki. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index eb18d2515b..23aab99ce7 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ to make it easier for other plugins to use and contribute new features. Includes JGit as a library so that other Jenkins components can rely on JGit whenever the git client plugin is available. -* see [Jenkins wiki](https://plugins.jenkins.io/git-client) for feature descriptions +* see [Jenkins plugins site](https://plugins.jenkins.io/git-client) for feature descriptions * use [JIRA](https://issues.jenkins-ci.org) to report issues / feature requests Contributing to the Plugin @@ -19,7 +19,7 @@ Building the Plugin =================== $ java -version # Requires Java 1.8 - $ mvn -version # Requires a modern maven version; maven 3.2.5 and 3.5.0 are known to work + $ mvn -version # Requires Apache Maven 3.5.0 or later $ mvn clean install To Do From 0b6f4561ac6d05f9d88e0b65433a9db84b88d5ab Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 27 May 2018 18:23:03 -0600 Subject: [PATCH 076/226] Run mvn incrementals:reincrementalify Needed after mvn release:prepare release:perform --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9a65d081d0..e46fb6f185 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins git-client - 3.0.0-beta4-SNAPSHOT + ${revision}${changelist} hpi Jenkins Git client plugin @@ -42,7 +42,7 @@ - 3.0.0-beta3 + 3.0.0-beta4 -SNAPSHOT UTF-8 -Dfile.encoding=${project.build.sourceEncoding} From cfe67f845106aed73771025587e325710d40f365 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 27 May 2018 07:41:34 -0600 Subject: [PATCH 077/226] Use equalsverifier 2.4.6 in tests --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e46fb6f185..d4b509567e 100644 --- a/pom.xml +++ b/pom.xml @@ -178,7 +178,7 @@ nl.jqno.equalsverifier equalsverifier - 2.4.3 + 2.4.6 test From aa7de43da46a5b09039362f6c6d9fd02871d2cd8 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 8 Jun 2018 17:23:31 -0600 Subject: [PATCH 078/226] Remove unselectable='on' from javadoc overview Not accepted by the JDK 10 javadoc processor, not important enough to bother trying to retain that setting. --- src/main/javadoc/overview.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/javadoc/overview.html b/src/main/javadoc/overview.html index 59683fa4e9..c24cd95964 100644 --- a/src/main/javadoc/overview.html +++ b/src/main/javadoc/overview.html @@ -7,10 +7,10 @@ The Jenkins git client plugin provides an API to execute general-purpose git operations on a local or remote repository. Its primary use is from the -git plugin; +git plugin; as such, it is also used by the -gerrit trigger plugin, -git parameter plugin, +gerrit trigger plugin, +git parameter plugin, and the branch source plugins (GitHub branch source, Bitbucket branch source, Gitea, and others).

Plugin developers are encouraged to use @@ -18,7 +18,7 @@ instead of the legacy IGitAPI.

The plugin isolates low-level git commands from the git-plugin, allowing alternate git implementations -(like JGit).

+(like JGit).

For backwards compatibility, this plugin uses API classes from the hudson.plugins.git package.

From 0b65c5666f9d0a6372de5cea71bf9d2c6857f7cf Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 8 Jun 2018 17:50:32 -0600 Subject: [PATCH 079/226] Use html5 valid javadoc markup --- pom.xml | 1 + .../plugins/gitclient/ChangelogCommand.java | 2 +- .../plugins/gitclient/GitClient.java | 42 +++++++++---------- .../gitclient/LegacyCompatibleGitAPIImpl.java | 23 +++++----- 4 files changed, 35 insertions(+), 33 deletions(-) diff --git a/pom.xml b/pom.xml index d4b509567e..c27e1e9d78 100644 --- a/pom.xml +++ b/pom.xml @@ -271,6 +271,7 @@ http://docs.oracle.com/javase/8/docs/api/ http://download.eclipse.org/jgit/site/${jgit.version}/org.eclipse.jgit/apidocs/ + -html5
diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/ChangelogCommand.java b/src/main/java/org/jenkinsci/plugins/gitclient/ChangelogCommand.java index 96c2a0ee67..6074e15381 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/ChangelogCommand.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/ChangelogCommand.java @@ -9,7 +9,7 @@ * Command builder for generating changelog in the format {@code GitSCM} expects. * *

- * The output format is that of git-whatchanged, which looks something like this: + * The output format is that of git-whatchanged, which looks something like this: * *

  * commit dadaf808d99c4c23c53476b0c48e25a181016300
diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/GitClient.java b/src/main/java/org/jenkinsci/plugins/gitclient/GitClient.java
index 89f4aae5aa..f3a412bd5e 100644
--- a/src/main/java/org/jenkinsci/plugins/gitclient/GitClient.java
+++ b/src/main/java/org/jenkinsci/plugins/gitclient/GitClient.java
@@ -231,7 +231,7 @@ public interface GitClient {
 
     /**
      * Checks out the specified commit/tag/branch into the workspace.
-     * (equivalent of git checkout branch.)
+     * (equivalent of git checkout branch.)
      *
      * @param ref A git object references expression (either a sha1, tag or branch)
      * @deprecated use {@link #checkout()} and {@link org.jenkinsci.plugins.gitclient.CheckoutCommand}
@@ -246,7 +246,7 @@ public interface GitClient {
      *
      * This will fail if the branch already exists.
      *
-     * @param ref A git object references expression. For backward compatibility, null will checkout current HEAD
+     * @param ref A git object references expression. For backward compatibility, null will checkout current HEAD
      * @param branch name of the branch to create from reference
      * @deprecated use {@link #checkout()} and {@link org.jenkinsci.plugins.gitclient.CheckoutCommand}
      * @throws hudson.plugins.git.GitException if underlying git operation fails.
@@ -268,7 +268,7 @@ public interface GitClient {
      *
      * 
    *
  • The branch of the specified name branch exists and points to the specified ref - *
  • HEAD points to branch. IOW, the workspace is on the specified branch. + *
  • HEAD points to branch. In other words, the workspace is on the specified branch. *
  • Both index and workspace are the same tree with ref. * (no dirty files and no staged changes, although this method will not touch untracked files * in the workspace.) @@ -276,7 +276,7 @@ public interface GitClient { * *

    * This method is preferred over the {@link #checkout(String, String)} family of methods, as - * this method is affected far less by the current state of the repository. The checkout + * this method is affected far less by the current state of the repository. The checkout * methods, in their attempt to emulate the "git checkout" command line behaviour, have too many * side effects. In Jenkins, where you care a lot less about throwing away local changes and * care a lot more about resetting the workspace into a known state, methods like this is more useful. @@ -297,7 +297,7 @@ public interface GitClient { * Clone a remote repository * * @param url URL for remote repository to clone - * @param origin upstream track name, defaults to origin by convention + * @param origin upstream track name, defaults to origin by convention * @param useShallowClone option to create a shallow clone, that has some restriction but will make clone operation * @param reference (optional) reference to a local clone for faster clone operations (reduce network and local storage costs) * @throws hudson.plugins.git.GitException if underlying git operation fails. @@ -314,7 +314,7 @@ public interface GitClient { /** * Fetch commits from url which match any of the passed in - * refspecs. Assumes remote.remoteName.url has been set. + * refspecs. Assumes remote.remoteName.url has been set. * * @deprecated use {@link #fetch_()} and configure a {@link org.jenkinsci.plugins.gitclient.FetchCommand} * @param url a {@link org.eclipse.jgit.transport.URIish} object. @@ -490,7 +490,7 @@ public interface GitClient { // --- manage tags /** - * Create (or update) a tag. If tag already exist it gets updated (equivalent to git tag --force) + * Create (or update) a tag. If tag already exist it gets updated (equivalent to git tag --force) * * @param tagName a {@link java.lang.String} object. * @param comment a {@link java.lang.String} object. @@ -551,7 +551,7 @@ public interface GitClient { // --- manage refs /** - * Create (or update) a ref. The ref will reference HEAD (equivalent to git update-ref ... HEAD). + * Create (or update) a ref. The ref will reference HEAD (equivalent to git update-ref ... HEAD). * * @param refName the full name of the ref (e.g. "refs/myref"). Spaces will be replaced with underscores. * @throws hudson.plugins.git.GitException if underlying git operation fails. @@ -560,7 +560,7 @@ public interface GitClient { void ref(String refName) throws GitException, InterruptedException; /** - * Check if a ref exists. Equivalent to comparing the return code of git show-ref to zero. + * Check if a ref exists. Equivalent to comparing the return code of git show-ref to zero. * * @param refName the full name of the ref (e.g. "refs/myref"). Spaces will be replaced with underscores. * @return True if the ref exists, false otherwse. @@ -570,7 +570,7 @@ public interface GitClient { boolean refExists(String refName) throws GitException, InterruptedException; /** - * Deletes a ref. Has no effect if the ref does not exist, equivalent to git update-ref -d. + * Deletes a ref. Has no effect if the ref does not exist, equivalent to git update-ref -d. * * @param refName the full name of the ref (e.g. "refs/myref"). Spaces will be replaced with underscores. * @throws hudson.plugins.git.GitException if underlying git operation fails. @@ -579,7 +579,7 @@ public interface GitClient { void deleteRef(String refName) throws GitException, InterruptedException; /** - * List refs with the given prefix. Equivalent to git for-each-ref --format="%(refname)". + * List refs with the given prefix. Equivalent to git for-each-ref --format="%(refname)". * * @param refPrefix the literal prefix any ref returned will have. The empty string implies all. * @return a set of refs, each beginning with the given prefix. Empty if none. @@ -612,7 +612,7 @@ public interface GitClient { ObjectId getHeadRev(String remoteRepoUrl, String branch) throws GitException, InterruptedException; /** - * List references in a remote repository. Equivalent to git ls-remote [--heads] [--tags] <repository> [<refs>]. + * List references in a remote repository. Equivalent to git ls-remote [--heads] [--tags] <repository> [<refs>]. * * @param remoteRepoUrl * Remote repository URL. @@ -631,8 +631,8 @@ public interface GitClient { Map getRemoteReferences(String remoteRepoUrl, String pattern, boolean headsOnly, boolean tagsOnly) throws GitException, InterruptedException; /** - * List symbolic references in a remote repository. Equivalent to git ls-remote --symref <repository> - * [<refs>]. Note: the response may be empty for multiple reasons + * List symbolic references in a remote repository. Equivalent to git ls-remote --symref <repository> + * [<refs>]. Note: the response may be empty for multiple reasons * * @param remoteRepoUrl Remote repository URL. * @param pattern Only references matching the given pattern are displayed. @@ -645,7 +645,7 @@ public interface GitClient { Map getRemoteSymbolicReferences(String remoteRepoUrl, String pattern) throws GitException, InterruptedException; /** - * Retrieve commit object that is direct child for revName revision reference. + * Retrieve commit object that is direct child for revName revision reference. * * @param revName a commit sha1 or tag/branch refname * @throws hudson.plugins.git.GitException when no such commit / revName is found in repository. @@ -722,7 +722,7 @@ public interface GitClient { /** * Run submodule update optionally recursively on all submodules - * (equivalent of git submodule update --recursive.) + * (equivalent of git submodule update --recursive.) * * @deprecated use {@link #submoduleUpdate()} and {@link org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand} * @param recursive a boolean. @@ -734,7 +734,7 @@ public interface GitClient { /** * Run submodule update optionally recursively on all submodules, with a specific * reference passed to git clone if needing to --init. - * (equivalent of git submodule update --recursive --reference 'reference'.) + * (equivalent of git submodule update --recursive --reference 'reference'.) * * @deprecated use {@link #submoduleUpdate()} and {@link org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand} * @param recursive a boolean. @@ -746,7 +746,7 @@ public interface GitClient { /** * Run submodule update optionally recursively on all submodules, optionally with remoteTracking submodules - * (equivalent of git submodule update --recursive --remote.) + * (equivalent of git submodule update --recursive --remote.) * * @deprecated use {@link #submoduleUpdate()} and {@link org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand} * @param recursive a boolean. @@ -758,7 +758,7 @@ public interface GitClient { /** * Run submodule update optionally recursively on all submodules, optionally with remoteTracking, with a specific * reference passed to git clone if needing to --init. - * (equivalent of git submodule update --recursive --remote --reference 'reference'.) + * (equivalent of git submodule update --recursive --remote --reference 'reference'.) * * @deprecated use {@link #submoduleUpdate()} and {@link org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand} * @param recursive a boolean. @@ -887,7 +887,7 @@ public interface GitClient { * For merge commit, this method reports one diff per each parent. This makes this method * behave differently from {@link #changelog()}. * - * @return The git show output, in raw format. + * @return The git show output, in raw format. * @param from a {@link org.eclipse.jgit.lib.ObjectId} object. * @param to a {@link org.eclipse.jgit.lib.ObjectId} object. * @throws hudson.plugins.git.GitException if underlying git operation fails. @@ -911,7 +911,7 @@ public interface GitClient { * For merge commit, this method reports one diff per each parent. This makes this method * behave differently from {@link #changelog()}. * - * @return The git show output, in raw format. + * @return The git show output, in raw format. * @param from a {@link org.eclipse.jgit.lib.ObjectId} object. * @param to a {@link org.eclipse.jgit.lib.ObjectId} object. * @param useRawOutput a {java.lang.Boolean} object. diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImpl.java index 139dedcead..acf41c41b2 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImpl.java @@ -241,18 +241,19 @@ public List showRevision(ObjectId r) throws GitException, InterruptedExc * current use cases are not disrupted by a behavioral change. *

    * E.g. - * - * - * - * - * - * - * - * + *
    branch specnormalized
    mastermaster*
    feature1feature1*
    feature1/master
    master feature1/master*
    origin/mastermaster*
    repo2/feature1feature1*
    refs/heads/feature1refs/heads/feature1
    + * + * + * + * + * + * + * + * * - * - * - * + * + * + * *
    Branch Spec Normalization Examples
    branch specnormalized
    mastermaster*
    feature1feature1*
    feature1/master
    master feature1/master*
    origin/mastermaster*
    repo2/feature1feature1*
    refs/heads/feature1refs/heads/feature1
    origin/namespaceA/fix15
    fix15 namespaceA/fix15*
    refs/heads/namespaceA/fix15refs/heads/namespaceA/fix15
    remotes/origin/namespaceA/fix15refs/heads/namespaceA/fix15
    fix15 namespaceA/fix15*
    refs/heads/namespaceA/fix15refs/heads/namespaceA/fix15
    remotes/origin/namespaceA/fix15refs/heads/namespaceA/fix15

    * *) TODO: Normalize to "refs/heads/" * From b6b58cc52c884fbb42d3bb4bd87f538aceaf2d61 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 9 Jun 2018 06:03:47 -0600 Subject: [PATCH 080/226] Don't use javadoc -html5 arg yet The javadoc -html5 argument requires JDK 9 or JDK 10. Breaks compile on Java 8, though it did not break compile on ci.jenkins.io. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c27e1e9d78..d06438eacc 100644 --- a/pom.xml +++ b/pom.xml @@ -271,7 +271,7 @@ http://docs.oracle.com/javase/8/docs/api/ http://download.eclipse.org/jgit/site/${jgit.version}/org.eclipse.jgit/apidocs/ - -html5 + From 48ea5118ec01e3cd9359d901369cf1339be04af5 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 10 Jun 2018 21:59:48 -0600 Subject: [PATCH 081/226] Test with Jenkins 2.121.1 --- Jenkinsfile | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 1bff8e26b0..beffbfdf56 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,9 +1,6 @@ #!groovy // build both versions, retry test failures -buildPlugin(jenkinsVersions: [null, '2.107.3'], +buildPlugin(jenkinsVersions: [null, '2.121.1'], findbugs: [run:true, archive:true, unstableTotalAll: '0'], failFast: false) - -// No plugin compatibility tests, retry test failures -// buildPlugin(failFast: false) From 0ef4d20d057714bc5da618793b1c0c1c7bc9258e Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 13 Jun 2018 21:15:03 -0600 Subject: [PATCH 082/226] Include coverage reporting instructions in README --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 23aab99ce7..2f18e3bc45 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,14 @@ Contributing to the Plugin Refer to [contributing to the plugin](CONTRIBUTING.md) for suggestions to speed the acceptance of your contributions. +Code coverage reporting is available as a maven target and is actively +monitored. Please improve code coverage with the tests you submit. +Code coverage reporting is written to `target/site/jacoco/` by the maven command: + +``` + $ mvn -P enable-jacoco clean install jacoco:report +``` + Building the Plugin =================== From e7910affb052be4ac141bd15298eac5dd9801780 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Thu, 5 Jul 2018 05:29:58 -0600 Subject: [PATCH 083/226] Use parent pom 3.17 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d06438eacc..1252b83144 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 3.12 + 3.17 From 99b08a4414325886f2c9bf83719a6dbe95fa2986 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Thu, 5 Jul 2018 18:47:17 -0600 Subject: [PATCH 084/226] Format pom with tidy:pom --- pom.xml | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/pom.xml b/pom.xml index 1252b83144..58ff7c6c3a 100644 --- a/pom.xml +++ b/pom.xml @@ -51,24 +51,6 @@ 4.11.0.201803080745-r - - - jgit-repository - Eclipse JGit Repository - https://repo.eclipse.org/content/groups/releases/ - - - repo.jenkins-ci.org - https://repo.jenkins-ci.org/public/ - - - - - repo.jenkins-ci.org - https://repo.jenkins-ci.org/public/ - - - org.eclipse.jgit @@ -239,6 +221,24 @@ + + + jgit-repository + Eclipse JGit Repository + https://repo.eclipse.org/content/groups/releases/ + + + repo.jenkins-ci.org + https://repo.jenkins-ci.org/public/ + + + + + repo.jenkins-ci.org + https://repo.jenkins-ci.org/public/ + + + @@ -295,6 +295,7 @@ + From f7126b1ec13f74f612d0413febb20f5f83eb0508 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Fri, 6 Jul 2018 12:11:36 -0400 Subject: [PATCH 085/226] Convert anonymous MasterToSlaveFileCallable to member org.jenkinsci.remoting.util.AnonymousClassWarnings warn: WARNING: Attempt to (de-)serialize anonymous class org.jenkinsci.plugins.gitclient.RemoteGitImpl$CommandInvocationHandler$1 WARNING: Attempt to (de-)serialize anonymous class org.jenkinsci.plugins.gitclient.Git$1 see: https://jenkins.io/redirect/serialization-of-anonymous-classes/ --- .../org/jenkinsci/plugins/gitclient/Git.java | 36 ++++++++------- .../plugins/gitclient/RemoteGitImpl.java | 46 ++++++++++--------- 2 files changed, 43 insertions(+), 39 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/Git.java b/src/main/java/org/jenkinsci/plugins/gitclient/Git.java index 3d8c616441..ead40c530a 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/Git.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/Git.java @@ -117,23 +117,7 @@ public Git using(String exe) { * @throws java.lang.InterruptedException if interrupted. */ public GitClient getClient() throws IOException, InterruptedException { - jenkins.MasterToSlaveFileCallable callable = new jenkins.MasterToSlaveFileCallable() { - public GitClient invoke(File f, VirtualChannel channel) throws IOException, InterruptedException { - if (listener == null) listener = TaskListener.NULL; - if (env == null) env = new EnvVars(); - - if (exe == null || JGitTool.MAGIC_EXENAME.equalsIgnoreCase(exe)) { - return new JGitAPIImpl(f, listener); - } - - if (JGitApacheTool.MAGIC_EXENAME.equalsIgnoreCase(exe)) { - final PreemptiveAuthHttpClientConnectionFactory factory = new PreemptiveAuthHttpClientConnectionFactory(); - return new JGitAPIImpl(f, listener, factory); - } - // Ensure we return a backward compatible GitAPI, even API only claim to provide a GitClient - return new GitAPI(exe, f, listener, env); - } - }; + jenkins.MasterToSlaveFileCallable callable = new GitAPIMasterToSlaveFileCallable(); GitClient git = (repository!=null ? repository.act(callable) : callable.invoke(null,null)); Jenkins jenkinsInstance = Jenkins.getInstance(); if (jenkinsInstance != null && git != null) @@ -151,4 +135,22 @@ public GitClient invoke(File f, VirtualChannel channel) throws IOException, Inte public static final boolean USE_CLI = Boolean.valueOf(System.getProperty(Git.class.getName() + ".useCLI", "true")); private static final long serialVersionUID = 1L; + + private class GitAPIMasterToSlaveFileCallable extends jenkins.MasterToSlaveFileCallable { + public GitClient invoke(File f, VirtualChannel channel) throws IOException, InterruptedException { + if (listener == null) listener = TaskListener.NULL; + if (env == null) env = new EnvVars(); + + if (exe == null || JGitTool.MAGIC_EXENAME.equalsIgnoreCase(exe)) { + return new JGitAPIImpl(f, listener); + } + + if (JGitApacheTool.MAGIC_EXENAME.equalsIgnoreCase(exe)) { + final PreemptiveAuthHttpClientConnectionFactory factory = new PreemptiveAuthHttpClientConnectionFactory(); + return new JGitAPIImpl(f, listener, factory); + } + // Ensure we return a backward compatible GitAPI, even API only claim to provide a GitClient + return new GitAPI(exe, f, listener, env); + } + } } diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java index 3dbcf3fd5b..888cf4dbd6 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/RemoteGitImpl.java @@ -143,34 +143,36 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl public void execute() throws GitException, InterruptedException { try { - channel.call(new jenkins.security.MasterToSlaveCallable() { - public Void call() throws GitException { - try { - GitCommand cmd = createCommand(); - for (Invocation inv : invocations) { - inv.replay(cmd); - } - cmd.execute(); - return null; - } catch (InvocationTargetException | IllegalAccessException | InterruptedException e) { - throw new GitException(e); - } - } - - private GitCommand createCommand() throws InvocationTargetException, IllegalAccessException { - for (Method m : GitClient.class.getMethods()) { - if (m.getReturnType()==command && m.getParameterTypes().length==0) - return command.cast(m.invoke(proxy)); - } - throw new IllegalStateException("Can't find the factory method for "+command); - } - }); + channel.call(new GitCommandMasterToSlaveCallable()); } catch (IOException e) { throw new GitException(e); } } private static final long serialVersionUID = 1L; + + private class GitCommandMasterToSlaveCallable extends jenkins.security.MasterToSlaveCallable { + public Void call() throws GitException { + try { + GitCommand cmd = createCommand(); + for (Invocation inv : invocations) { + inv.replay(cmd); + } + cmd.execute(); + return null; + } catch (InvocationTargetException | IllegalAccessException | InterruptedException e) { + throw new GitException(e); + } + } + + private GitCommand createCommand() throws InvocationTargetException, IllegalAccessException { + for (Method m : GitClient.class.getMethods()) { + if (m.getReturnType()==command && m.getParameterTypes().length==0) + return command.cast(m.invoke(proxy)); + } + throw new IllegalStateException("Can't find the factory method for "+command); + } + } } private OutputStream wrap(OutputStream os) { From 56fe40083a9d1a1809b290ba76225c6c7735682f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sun, 8 Jul 2018 10:18:10 +0200 Subject: [PATCH 086/226] Update Jenkins job link in CONTRIBUTING documentation The Cloudbees Jenkins is not used anymore. --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 202834bf1f..b7ed38f339 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,7 @@ or can be submitted directly if you have commit permission to the git-client-plugin repository. Pull requests are evaluated by the -[Cloudbees Jenkins job](https://jenkins.ci.cloudbees.com/job/plugins/job/git-client-plugin/). +[ci.jenkins.io Jenkins job](https://ci.jenkins.io/job/Plugins/job/git-client-plugin/). You should receive e-mail with the results of the evaluation. Before submitting your change, please assure that you've added tests From add681f93250545e0181f4e938e165ff8cb256f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch-Zweibr=C3=BCcken-=C5=A0afa=C5=99=C3=ADk?= Date: Tue, 10 Jul 2018 22:58:04 +0200 Subject: [PATCH 087/226] Decouple git fetch tests more from execution environment Otherwise they would fail if fetch.prune = true on system or global level. --- .../java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 52b078e8ea..a4d11a9927 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -981,6 +981,7 @@ public void test_fetch() throws Exception { RefSpec defaultRefSpec = new RefSpec("+refs/heads/*:refs/remotes/origin/*"); List refSpecs = new ArrayList<>(); refSpecs.add(defaultRefSpec); + newArea.cmd("git config fetch.prune false"); newArea.git.fetch(new URIish(bare.repo.toString()), refSpecs); /* Confirm the fetch did not alter working branch */ @@ -1249,6 +1250,7 @@ public void test_fetch_needs_preceding_prune() throws Exception { try { /* Fetch parent/a into newArea repo - fails for * CliGitAPIImpl, succeeds for JGitAPIImpl */ + newArea.cmd("git config fetch.prune false"); newArea.git.fetch(new URIish(bare.repo.toString()), refSpecs); assertTrue("CliGit should have thrown an exception", newArea.git instanceof JGitAPIImpl); } catch (GitException ge) { @@ -1329,6 +1331,7 @@ public void test_fetch_with_prune() throws Exception { refSpecs.add(defaultRefSpec); /* Fetch without prune should leave branch1 in newArea */ + newArea.cmd("git config fetch.prune false"); newArea.git.fetch_().from(new URIish(bare.repo.toString()), refSpecs).execute(); remoteBranches = newArea.git.getRemoteBranches(); assertBranchesExist(remoteBranches, "origin/master", "origin/branch1", "origin/branch2", "origin/HEAD"); From 6aa0af10636b059d28bde80a8e03a714a57fdbe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sat, 7 Jul 2018 18:36:25 +0200 Subject: [PATCH 088/226] Use @Issue annotation consistently --- .../gitclient/CliGitAPITempFileTest.java | 2 +- .../plugins/gitclient/GitAPITestCase.java | 49 +++++++++---------- .../gitclient/WarnTempDirValueTest.java | 4 +- 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPITempFileTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPITempFileTest.java index 0a74dde048..d2ab3c3633 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPITempFileTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPITempFileTest.java @@ -91,7 +91,7 @@ public void createWorkspace() throws Exception { * */ @Test - @Issue("JENKINS-44301") // and 43931 and ... + @Issue({"JENKINS-44301", "JENKINS-43931"}) // and ... public void testTempFilePathCharactersValid() throws IOException { CliGitAPIImplExtension cliGit = new CliGitAPIImplExtension("git", workspace, null, null); for (int charIndex = 0; charIndex < INVALID_CHARACTERS.length(); charIndex++) { diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index a4d11a9927..2dd2859420 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -69,7 +69,7 @@ import org.eclipse.jgit.transport.RefSpec; import org.eclipse.jgit.transport.RemoteConfig; import org.eclipse.jgit.transport.URIish; -import org.jvnet.hudson.test.Bug; +import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.TemporaryDirectoryAllocator; import org.objenesis.ObjenesisStd; @@ -852,7 +852,7 @@ public void test_clean_with_parameter() throws Exception { } - @Bug(20410) + @Issue("JENKINS-20410") public void test_clean() throws Exception { w.init(); w.commitEmpty("init"); @@ -1159,7 +1159,7 @@ public void test_push_tags() throws Exception { assertTrue("tag3 wasn't pushed", bare.cmd("git tag").contains("tag3")); } - @Bug(19591) + @Issue("JENKINS-19591") public void test_fetch_needs_preceding_prune() throws Exception { /* Create a working repo containing a commit */ w.init(); @@ -1427,7 +1427,7 @@ public void test_fetch_noTags() throws Exception { assertTrue("Tags have been found : " + tags, tags.isEmpty()); } - @Bug(37794) + @Issue("JENKINS-37794") public void test_getTagNames_supports_slashes_in_tag_names() throws Exception { w.init(); w.commitEmpty("init-getTagNames-supports-slashes"); @@ -1473,7 +1473,7 @@ public void test_create_branch() throws Exception { assertTrue("test branch not listed", branches.contains("test")); } - @Bug(34309) + @Issue("JENKINS-34309") public void test_list_branches() throws Exception { w.init(); Set branches = w.git.getBranches(); @@ -1586,7 +1586,7 @@ public void test_delete_branch() throws Exception { } } - @Bug(23299) + @Issue("JENKINS-23299") public void test_create_tag() throws Exception { w.init(); String gitDir = w.repoPath() + File.separator + ".git"; @@ -1920,7 +1920,7 @@ public void test_notes_append_first_note() throws Exception { /** * A rev-parse warning message should not break revision parsing. */ - @Bug(11177) + @Issue("JENKINS-11177") public void test_jenkins_11177() throws Exception { w.init(); @@ -2479,12 +2479,12 @@ private void base_checkout_replaces_tracked_changes(boolean defineBranch) throws assertTrue("Missing untracked file", w.file("untracked-file").exists()); } - @Bug(23424) + @Issue("JENKINS-23424") public void test_checkout_replaces_tracked_changes() throws Exception { base_checkout_replaces_tracked_changes(false); } - @Bug(23424) + @Issue("JENKINS-23424") public void test_checkout_replaces_tracked_changes_with_branch() throws Exception { base_checkout_replaces_tracked_changes(true); } @@ -2499,7 +2499,7 @@ public void test_checkout_replaces_tracked_changes_with_branch() throws Exceptio * checkout, after the submodule branch checkout, and within one * of the submodules. */ - @Bug(8122) + @Issue("JENKINS-8122") public void test_submodule_tags_not_fetched_into_parent() throws Exception { w.git.clone_().url(localMirror()).repositoryName("origin").execute(); checkoutTimeout = 1 + random.nextInt(60 * 24); @@ -2944,7 +2944,7 @@ public void test_merge_strategy_correct_fail() throws Exception { } } - @Bug(12402) + @Issue("JENKINS-12402") public void test_merge_fast_forward_mode_ff() throws Exception { w.init(); @@ -3341,7 +3341,7 @@ public void test_changelog_abort() throws InterruptedException, IOException assertTrue("No SHA1 in " + writer.toString(), writer.toString().contains(sha1)); } - @Bug(23299) + @Issue("JENKINS-23299") public void test_getHeadRev() throws Exception { Map heads = w.git.getHeadRev(remoteMirrorURL); ObjectId master = w.git.getHeadRev(remoteMirrorURL, "refs/heads/master"); @@ -3372,7 +3372,7 @@ public void test_getHeadRevFromPublicRepoWithInvalidCredential() throws Exceptio assertEquals("URL is " + remoteMirrorURL + ", heads is " + heads, master, heads.get("refs/heads/master")); } - @Bug(25444) + @Issue("JENKINS-25444") public void test_fetch_delete_cleans() throws Exception { w.init(); w.touch("file1", "old"); @@ -3826,7 +3826,7 @@ public void test_show_revision_for_single_commit() throws Exception { assertTrue(commits.contains("commit 51de9eda47ca8dcf03b2af58dfff7355585f0d0c")); } - @Bug(22343) + @Issue("JENKINS-22343") public void test_show_revision_for_first_commit() throws Exception { w.init(); w.touch("a"); @@ -3976,7 +3976,7 @@ public void test_checkout() throws Exception { assertEquals("Wrong SHA1 as checkout of git-client-1.6.0", sha1Expected, sha1); } - @Bug(37185) + @Issue("JENKINS-37185") @NotImplementedInJGit /* JGit doesn't have timeout */ public void test_checkout_honor_timeout() throws Exception { w = clone(localMirror()); @@ -3985,7 +3985,7 @@ public void test_checkout_honor_timeout() throws Exception { w.git.checkout().branch("master").ref("origin/master").timeout(checkoutTimeout).deleteBranchIfExist(true).execute(); } - @Bug(25353) + @Issue("JENKINS-25353") @NotImplementedInJGit /* JGit lock file management ignored for now */ public void test_checkout_interrupted() throws Exception { w = clone(localMirror()); @@ -4004,7 +4004,7 @@ public void test_checkout_interrupted() throws Exception { assertFalse("lock file '" + lockFile.getCanonicalPath() + " not removed by cleanup", lockFile.exists()); } - @Bug(25353) + @Issue("JENKINS-25353") @NotImplementedInJGit /* JGit lock file management ignored for now */ public void test_checkout_interrupted_with_existing_lock() throws Exception { w = clone(localMirror()); @@ -4025,7 +4025,7 @@ public void test_checkout_interrupted_with_existing_lock() throws Exception { assertTrue("lock file '" + lockFile.getCanonicalPath() + " removed by cleanup", lockFile.exists()); } - @Bug(19108) + @Issue("JENKINS-19108") public void test_checkoutBranch() throws Exception { w.init(); w.commitEmpty("c1"); @@ -4127,7 +4127,7 @@ public void test_revList_local_branch() throws Exception { assertEquals("Wrong list size: " + revList, 2, revList.size()); } - @Bug(20153) + @Issue("JENKINS-20153") public void test_checkoutBranch_null() throws Exception { w.init(); w.commitEmpty("c1"); @@ -4150,7 +4150,7 @@ private String formatBranches(List branches) { return Util.join(names,","); } - @Bug(18988) + @Issue("JENKINS-18988") public void test_localCheckoutConflict() throws Exception { w.init(); w.touch("foo","old"); @@ -4525,13 +4525,8 @@ public void test_longpaths_disabled() throws Exception { /** * Test parsing of changelog with unicode characters in commit messages. */ + @Issue({"JENKINS-6203", "JENKINS-14798", "JENKINS-23091"}) public void test_unicodeCharsInChangelog() throws Exception { - - // Test for - // https://issues.jenkins-ci.org/browse/JENKINS-6203 - // https://issues.jenkins-ci.org/browse/JENKINS-14798 - // https://issues.jenkins-ci.org/browse/JENKINS-23091 - File tempRemoteDir = temporaryDirectoryAllocator.allocate(); extract(new ZipFile("src/test/resources/unicodeCharsInChangelogRepo.zip"), tempRemoteDir); File pathToTempRepo = new File(tempRemoteDir, "unicodeCharsInChangelogRepo"); @@ -4577,7 +4572,7 @@ public void test_git_init_creates_directory_if_needed() throws Exception { } } - @Bug(40023) + @Issue("JENKINS-40023") public void test_changelog_with_merge_commit_and_max_log_history() throws Exception { w.init(); w.commitEmpty("init"); diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/WarnTempDirValueTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/WarnTempDirValueTest.java index 6eec4d5364..35b5fa16dc 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/WarnTempDirValueTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/WarnTempDirValueTest.java @@ -19,7 +19,7 @@ import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import org.jvnet.hudson.test.Bug; +import org.jvnet.hudson.test.Issue; /** * The msysgit implementation (through at least 1.9.0) fails some credential @@ -92,7 +92,7 @@ public void noWarningForDefaultValue() throws IOException, InterruptedException } @Test - @Bug(22706) + @Issue("JENKINS-22706") public void warnWhenValueContainsSpaceCharacter() throws IOException, InterruptedException { EnvVars env = new hudson.EnvVars(); assertFalse(env.get(envVarName, "/tmp").contains(" ")); From d31af997762c7b5a8b1a171ffd1baf35fdae661c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sat, 7 Jul 2018 19:32:40 +0200 Subject: [PATCH 089/226] Always import JUnit's Assert methods statically --- .../gitclient/CliGitAPIImplAuthTest.java | 3 +- .../plugins/gitclient/CliGitCommand.java | 9 +++-- ...reemptiveAuthHttpClientConnectionTest.java | 37 ++++++++++--------- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplAuthTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplAuthTest.java index 013db6ff70..faf80f407f 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplAuthTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplAuthTest.java @@ -11,7 +11,6 @@ import java.util.Random; import java.util.concurrent.TimeUnit; import static org.hamcrest.Matchers.hasItems; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.*; @@ -140,7 +139,7 @@ private String[] run(ArgumentListBuilder args) throws IOException, InterruptedEx result = result + "\nstderr not empty:\n" + bytesErr.toString("UTF-8"); } output = result.split("[\\n\\r]"); - Assert.assertEquals(args.toString() + " command failed and reported '" + Arrays.toString(output) + "'", 0, status); + assertEquals(args.toString() + " command failed and reported '" + Arrays.toString(output) + "'", 0, status); return output; } diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitCommand.java b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitCommand.java index 7214ebbbfd..f771808cdc 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitCommand.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitCommand.java @@ -1,5 +1,7 @@ package org.jenkinsci.plugins.gitclient; +import static org.junit.Assert.*; + import hudson.EnvVars; import hudson.Launcher; import hudson.model.TaskListener; @@ -13,7 +15,6 @@ import java.util.Iterator; import java.util.List; import java.util.concurrent.TimeUnit; -import org.junit.Assert; /** * Run a command line git command, return output as array of String, optionally @@ -64,7 +65,7 @@ private String[] run(boolean assertProcessStatus) throws IOException, Interrupte } output = result.split("[\\n\\r]"); if (assertProcessStatus) { - Assert.assertEquals(args.toString() + " command failed and reported '" + Arrays.toString(output) + "'", 0, status); + assertEquals(args.toString() + " command failed and reported '" + Arrays.toString(output) + "'", 0, status); } return output; } @@ -72,7 +73,7 @@ private String[] run(boolean assertProcessStatus) throws IOException, Interrupte public void assertOutputContains(String... expectedRegExes) { List notFound = new ArrayList<>(); boolean modified = notFound.addAll(Arrays.asList(expectedRegExes)); - Assert.assertTrue("Missing regular expressions in assertion", modified); + assertTrue("Missing regular expressions in assertion", modified); for (String line : output) { for (Iterator iterator = notFound.iterator(); iterator.hasNext();) { String regex = iterator.next(); @@ -82,7 +83,7 @@ public void assertOutputContains(String... expectedRegExes) { } } if (!notFound.isEmpty()) { - Assert.fail(Arrays.toString(output) + " did not match all strings in notFound: " + Arrays.toString(expectedRegExes)); + fail(Arrays.toString(output) + " did not match all strings in notFound: " + Arrays.toString(expectedRegExes)); } } diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/jgit/PreemptiveAuthHttpClientConnectionTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/jgit/PreemptiveAuthHttpClientConnectionTest.java index 2e813bf601..aa781ca2a5 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/jgit/PreemptiveAuthHttpClientConnectionTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/jgit/PreemptiveAuthHttpClientConnectionTest.java @@ -1,8 +1,9 @@ package org.jenkinsci.plugins.gitclient.jgit; +import static org.junit.Assert.*; + import org.apache.http.auth.NTCredentials; import org.eclipse.jgit.transport.URIish; -import org.junit.Assert; import org.junit.Test; /** @@ -15,7 +16,7 @@ public class PreemptiveAuthHttpClientConnectionTest { final URIish actual = PreemptiveAuthHttpClientConnection.goUp(input); - Assert.assertEquals(null, actual); + assertEquals(null, actual); } @Test public void goUp_slash() throws Exception { @@ -23,7 +24,7 @@ public class PreemptiveAuthHttpClientConnectionTest { final URIish actual = PreemptiveAuthHttpClientConnection.goUp(input); - Assert.assertEquals(null, actual); + assertEquals(null, actual); } @Test public void goUp_slashSlash() throws Exception { @@ -31,8 +32,8 @@ public class PreemptiveAuthHttpClientConnectionTest { final URIish actual = PreemptiveAuthHttpClientConnection.goUp(input); - Assert.assertNotNull(actual); - Assert.assertEquals("http://example.com", actual.toString()); + assertNotNull(actual); + assertEquals("http://example.com", actual.toString()); } @Test public void goUp_one() throws Exception { @@ -40,8 +41,8 @@ public class PreemptiveAuthHttpClientConnectionTest { final URIish actual = PreemptiveAuthHttpClientConnection.goUp(input); - Assert.assertNotNull(actual); - Assert.assertEquals("http://example.com", actual.toString()); + assertNotNull(actual); + assertEquals("http://example.com", actual.toString()); } @Test public void goUp_oneSlash() throws Exception { @@ -49,8 +50,8 @@ public class PreemptiveAuthHttpClientConnectionTest { final URIish actual = PreemptiveAuthHttpClientConnection.goUp(input); - Assert.assertNotNull(actual); - Assert.assertEquals("http://example.com", actual.toString()); + assertNotNull(actual); + assertEquals("http://example.com", actual.toString()); } @Test public void goUp_oneSlashTwo() throws Exception { @@ -58,8 +59,8 @@ public class PreemptiveAuthHttpClientConnectionTest { final URIish actual = PreemptiveAuthHttpClientConnection.goUp(input); - Assert.assertNotNull(actual); - Assert.assertEquals("http://example.com/one", actual.toString()); + assertNotNull(actual); + assertEquals("http://example.com/one", actual.toString()); } @Test public void goUp_oneSlashSlashTwoSlash() throws Exception { @@ -67,8 +68,8 @@ public class PreemptiveAuthHttpClientConnectionTest { final URIish actual = PreemptiveAuthHttpClientConnection.goUp(input); - Assert.assertNotNull(actual); - Assert.assertEquals("http://example.com/one/", actual.toString()); + assertNotNull(actual); + assertEquals("http://example.com/one/", actual.toString()); } @Test public void goUp_oneSlashTwoSlash() throws Exception { @@ -76,17 +77,17 @@ public class PreemptiveAuthHttpClientConnectionTest { final URIish actual = PreemptiveAuthHttpClientConnection.goUp(input); - Assert.assertNotNull(actual); - Assert.assertEquals("http://example.com/one", actual.toString()); + assertNotNull(actual); + assertEquals("http://example.com/one", actual.toString()); } private static void createNTCredentials(final String inputUserName, final String inputPassword, final String expectedDomain, final String expectedUserName, final String expectedPassword) { final NTCredentials actual = PreemptiveAuthHttpClientConnection.createNTCredentials(inputUserName, inputPassword); - Assert.assertEquals(expectedDomain, actual.getDomain()); - Assert.assertEquals(expectedUserName, actual.getUserName()); - Assert.assertEquals(expectedPassword, actual.getPassword()); + assertEquals(expectedDomain, actual.getDomain()); + assertEquals(expectedUserName, actual.getUserName()); + assertEquals(expectedPassword, actual.getPassword()); } @Test public void createNTCredentials_plainUser() throws Exception { From 42efddd146bcc83eeff7afb855b32a69f42b5662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sat, 7 Jul 2018 18:50:53 +0200 Subject: [PATCH 090/226] Fix invalid Javadoc --- .../java/org/jenkinsci/plugins/gitclient/CliGitCommand.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitCommand.java b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitCommand.java index f771808cdc..8801cb3047 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitCommand.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitCommand.java @@ -113,9 +113,6 @@ private void setConfigIfEmpty(String configName, String value) throws Exception * values assigned for user.name and user.email. This method checks the * existing values, and if they are not set, assigns default values. * If the values are already set, they are unchanged. - * - * @param userName user name to be defined (if value not already set) - * @param userEmail email address to be defined (if value not already set) */ public void setDefaults() throws Exception { setConfigIfEmpty("user.name", "Vojtěch-Zweibrücken-Šafařík"); From cb8f6bff73bce3f5c5ed2b30697b549320299102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sat, 7 Jul 2018 19:47:57 +0200 Subject: [PATCH 091/226] Make access modifiers more consistent Reduce scope where possible. --- .../plugins/gitclient/CliGitAPIImplTest.java | 14 ++++++------- .../gitclient/CliGitAPITempFileTest.java | 2 +- .../plugins/gitclient/CliGitCommand.java | 8 ++++---- .../plugins/gitclient/GitAPITestCase.java | 20 +++++++++---------- .../plugins/gitclient/GitClientTest.java | 10 +++++----- .../GitURIRequirementsBuilderTest.java | 2 +- .../plugins/gitclient/LogHandler.java | 6 +++--- .../plugins/gitclient/NetrcTest.java | 9 ++++----- .../plugins/gitclient/RemotingTest.java | 2 +- .../plugins/gitclient/StringSharesPrefix.java | 4 ++-- ...andardUsernamePasswordCredentialsImpl.java | 2 +- 11 files changed, 39 insertions(+), 40 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplTest.java index 3c36b675de..8feeba40b5 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplTest.java @@ -57,15 +57,15 @@ protected void runTest() throws Throwable { } } - class VersionTest { + private class VersionTest { - public boolean expectedIsAtLeastVersion; - public int major; - public int minor; - public int rev; - public int bugfix; + private boolean expectedIsAtLeastVersion; + private int major; + private int minor; + private int rev; + private int bugfix; - public VersionTest(boolean assertTrueOrFalse, int major, int minor, int rev, int bugfix) { + private VersionTest(boolean assertTrueOrFalse, int major, int minor, int rev, int bugfix) { this.expectedIsAtLeastVersion = assertTrueOrFalse; this.major = major; this.minor = minor; diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPITempFileTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPITempFileTest.java index d2ab3c3633..b95562bb56 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPITempFileTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPITempFileTest.java @@ -116,7 +116,7 @@ private static boolean isWindows() { private class CliGitAPIImplExtension extends CliGitAPIImpl { - public CliGitAPIImplExtension(String gitExe, File workspace, TaskListener listener, EnvVars environment) { + private CliGitAPIImplExtension(String gitExe, File workspace, TaskListener listener, EnvVars environment) { super(gitExe, workspace, listener, environment); } } diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitCommand.java b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitCommand.java index 8801cb3047..f6e9b70224 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitCommand.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitCommand.java @@ -44,13 +44,13 @@ class CliGitCommand { } } - public String[] run(String... arguments) throws IOException, InterruptedException { + String[] run(String... arguments) throws IOException, InterruptedException { args = new ArgumentListBuilder("git"); args.add(arguments); return run(true); } - public String[] run() throws IOException, InterruptedException { + String[] run() throws IOException, InterruptedException { return run(true); } @@ -70,7 +70,7 @@ private String[] run(boolean assertProcessStatus) throws IOException, Interrupte return output; } - public void assertOutputContains(String... expectedRegExes) { + void assertOutputContains(String... expectedRegExes) { List notFound = new ArrayList<>(); boolean modified = notFound.addAll(Arrays.asList(expectedRegExes)); assertTrue("Missing regular expressions in assertion", modified); @@ -114,7 +114,7 @@ private void setConfigIfEmpty(String configName, String value) throws Exception * existing values, and if they are not set, assigns default values. * If the values are already set, they are unchanged. */ - public void setDefaults() throws Exception { + void setDefaults() throws Exception { setConfigIfEmpty("user.name", "Vojtěch-Zweibrücken-Šafařík"); setConfigIfEmpty("user.email", "email.address.from.git.client.plugin.test@example.com"); } diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 2dd2859420..3672ca4b2f 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -83,12 +83,12 @@ */ public abstract class GitAPITestCase extends TestCase { - public final TemporaryDirectoryAllocator temporaryDirectoryAllocator = new TemporaryDirectoryAllocator(); + private final TemporaryDirectoryAllocator temporaryDirectoryAllocator = new TemporaryDirectoryAllocator(); protected hudson.EnvVars env = new hudson.EnvVars(); protected TaskListener listener; - protected LogHandler handler = null; + private LogHandler handler = null; private int logCount = 0; private static final String LOGGING_STARTED = "Logging started"; @@ -295,32 +295,32 @@ File touch(String path, String content) throws IOException { return f; } - public void rm(String path) { + void rm(String path) { file(path).delete(); } - public String contentOf(String path) throws IOException { + String contentOf(String path) throws IOException { return FileUtils.readFileToString(file(path), "UTF-8"); } /** * Creates a CGit implementation. Sometimes we need this for testing JGit impl. */ - protected CliGitAPIImpl cgit() throws Exception { + CliGitAPIImpl cgit() throws Exception { return (CliGitAPIImpl)Git.with(listener, env).in(repo).using("git").getClient(); } /** * Creates a JGit implementation. Sometimes we need this for testing CliGit impl. */ - protected JGitAPIImpl jgit() throws Exception { + JGitAPIImpl jgit() throws Exception { return (JGitAPIImpl)Git.with(listener, env).in(repo).using("jgit").getClient(); } /** * Creates a {@link Repository} object out of it. */ - protected FileRepository repo() throws IOException { + FileRepository repo() throws IOException { return bare ? new FileRepository(repo) : new FileRepository(new File(repo, ".git")); } @@ -334,14 +334,14 @@ ObjectId head() throws IOException, InterruptedException { /** * Casts the {@link #git} to {@link IGitAPI} */ - public IGitAPI igit() { + IGitAPI igit() { return (IGitAPI)git; } } protected WorkingArea w; - WorkingArea clone(String src) throws Exception { + protected WorkingArea clone(String src) throws Exception { WorkingArea x = new WorkingArea(); x.launchCommand("git", "clone", src, x.repoPath()); return new WorkingArea(x.repo); @@ -408,7 +408,7 @@ private ObjectId getMirrorHead() throws IOException, InterruptedException /** * Obtains the local mirror of https://github.com/jenkinsci/git-client-plugin.git and return URLish to it. */ - public String localMirror() throws IOException, InterruptedException { + protected String localMirror() throws IOException, InterruptedException { File base = new File(".").getAbsoluteFile(); for (File f=base; f!=null; f=f.getParentFile()) { if (new File(f,"target").exists()) { diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java index f2a69626ad..d4d3d02914 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java @@ -73,10 +73,10 @@ public class GitClientTest { private GitClient srcGitClient; /* commit known to exist in upstream. */ - final ObjectId upstreamCommit = ObjectId.fromString("f75720d5de9d79ab4be2633a21de23b3ccbf8ce3"); - final String upstreamCommitAuthor = "Teubel György"; - final String upsstreamCommitEmail = ""; - final ObjectId upstreamCommitPredecessor = ObjectId.fromString("867e5f148377fd5a6d96e5aafbdaac132a117a5a"); + private final ObjectId upstreamCommit = ObjectId.fromString("f75720d5de9d79ab4be2633a21de23b3ccbf8ce3"); + private final String upstreamCommitAuthor = "Teubel György"; + private final String upsstreamCommitEmail = ""; + private final ObjectId upstreamCommitPredecessor = ObjectId.fromString("867e5f148377fd5a6d96e5aafbdaac132a117a5a"); /* URL of upstream (GitHub) repository. */ private final String upstreamRepoURL = "https://github.com/jenkinsci/git-client-plugin"; @@ -220,7 +220,7 @@ private ObjectId commitFile(final String path, final String content, final Strin return headList.get(0); } - public void createFile(String path, String content) throws Exception { + private void createFile(String path, String content) throws Exception { File aFile = new File(repoRoot, path); File parentDir = aFile.getParentFile(); if (parentDir != null) { diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitURIRequirementsBuilderTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitURIRequirementsBuilderTest.java index e0f952ba6a..327eadc34e 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitURIRequirementsBuilderTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitURIRequirementsBuilderTest.java @@ -550,7 +550,7 @@ public void smokes() throws Exception { } - T firstOrNull(List list, Class type) { + private static T firstOrNull(List list, Class type) { for (Object i: list) { if (type.isInstance(i)) return type.cast(i); diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/LogHandler.java b/src/test/java/org/jenkinsci/plugins/gitclient/LogHandler.java index a1a342d606..4f78b8a183 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/LogHandler.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/LogHandler.java @@ -29,11 +29,11 @@ public void close() throws SecurityException { messages = new ArrayList<>(); } - /* package */ List getMessages() { + List getMessages() { return messages; } - /* package */ boolean containsMessageSubstring(String messageSubstring) { + boolean containsMessageSubstring(String messageSubstring) { for (String message : messages) { if (message.contains(messageSubstring)) { return true; @@ -42,7 +42,7 @@ public void close() throws SecurityException { return false; } - /* package */ List getTimeouts() { + List getTimeouts() { List timeouts = new ArrayList<>(); for (String message : getMessages()) { int start = message.indexOf(CliGitAPIImpl.TIMEOUT_LOG_PREFIX); diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/NetrcTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/NetrcTest.java index ed1fcfa6ac..64a46fde13 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/NetrcTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/NetrcTest.java @@ -29,8 +29,7 @@ public class NetrcTest private String testFilePath_1a; private String testFilePath_2; - - enum TestHost { + private enum TestHost { H1_01("1-srvr-lp.example.com", "jenkins", "pw4jenkins"), H1_02("2-ldap-lp.example.com", "ldap", "pw4ldap"), H1_03("3-jenk-pl.example.com", "jenkins", "jenkinspwd"), @@ -56,9 +55,9 @@ enum TestHost { H2_03("builder3.example.com", null, null), H2_04("builder4.example.com", "jenk", "myvoice"); - public String machine; - public String login; - public String password; + private String machine; + private String login; + private String password; private TestHost(String _machine, String _login, String _password) { diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/RemotingTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/RemotingTest.java index 9b5f65672b..179f1ae8dd 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/RemotingTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/RemotingTest.java @@ -47,7 +47,7 @@ private void setCliGitDefaults() throws Exception { cliGitDefaultsSet = true; } - public Work(GitClient git) throws Exception { + private Work(GitClient git) throws Exception { setCliGitDefaults(); this.git = git; } diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/StringSharesPrefix.java b/src/test/java/org/jenkinsci/plugins/gitclient/StringSharesPrefix.java index 584645cbfb..2a50cbccf7 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/StringSharesPrefix.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/StringSharesPrefix.java @@ -6,7 +6,7 @@ /** * Tests if the argument shares a prefix. */ -public class StringSharesPrefix extends SubstringMatcher { +class StringSharesPrefix extends SubstringMatcher { public StringSharesPrefix(String substring) { super(substring); } @Override @@ -32,5 +32,5 @@ protected String relationship() { * the substring that the returned matcher will expect to share a * prefix of any examined string */ - public static Matcher sharesPrefix(String prefix) { return new StringSharesPrefix(prefix); } + static Matcher sharesPrefix(String prefix) { return new StringSharesPrefix(prefix); } } diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/trilead/StandardUsernamePasswordCredentialsImpl.java b/src/test/java/org/jenkinsci/plugins/gitclient/trilead/StandardUsernamePasswordCredentialsImpl.java index 4aa788983f..b0662f805b 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/trilead/StandardUsernamePasswordCredentialsImpl.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/trilead/StandardUsernamePasswordCredentialsImpl.java @@ -5,7 +5,7 @@ import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials; import hudson.util.Secret; -/* package */ class StandardUsernamePasswordCredentialsImpl implements StandardUsernamePasswordCredentials { +class StandardUsernamePasswordCredentialsImpl implements StandardUsernamePasswordCredentials { private final String userName; private final Secret password; From 481dc5de0eb5253c759b2c9b987506e2855c384e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sat, 7 Jul 2018 19:52:24 +0200 Subject: [PATCH 092/226] Refactor old style Java code Use extended for loop and streams. --- .../plugins/gitclient/CliGitAPIImplTest.java | 22 +++++++++---------- .../plugins/gitclient/CliGitCommand.java | 8 +------ .../plugins/gitclient/LogHandler.java | 7 +----- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplTest.java index 8feeba40b5..91688628dc 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplTest.java @@ -78,20 +78,20 @@ private void doTest(String versionOutput, VersionTest[] versions) { setTimeoutVisibleInCurrentTest(false); /* No timeout for git --version command */ CliGitAPIImpl git = new CliGitAPIImpl("git", new File("."), listener, env); git.computeGitVersion(versionOutput); - for (int i = 0; i < versions.length; ++i) { - String msg = versionOutput + " for " + versions[i].major + versions[i].minor + versions[i].rev + versions[i].bugfix; - if (versions[i].expectedIsAtLeastVersion) { + for (VersionTest version : versions) { + String msg = versionOutput + " for " + version.major + version.minor + version.rev + version.bugfix; + if (version.expectedIsAtLeastVersion) { assertTrue("Failed " + msg, git.isAtLeastVersion( - versions[i].major, - versions[i].minor, - versions[i].rev, - versions[i].bugfix)); + version.major, + version.minor, + version.rev, + version.bugfix)); } else { assertFalse("Passed " + msg, git.isAtLeastVersion( - versions[i].major, - versions[i].minor, - versions[i].rev, - versions[i].bugfix)); + version.major, + version.minor, + version.rev, + version.bugfix)); } } } diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitCommand.java b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitCommand.java index f6e9b70224..9611291425 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitCommand.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitCommand.java @@ -12,7 +12,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.concurrent.TimeUnit; @@ -75,12 +74,7 @@ void assertOutputContains(String... expectedRegExes) { boolean modified = notFound.addAll(Arrays.asList(expectedRegExes)); assertTrue("Missing regular expressions in assertion", modified); for (String line : output) { - for (Iterator iterator = notFound.iterator(); iterator.hasNext();) { - String regex = iterator.next(); - if (line.matches(regex)) { - iterator.remove(); - } - } + notFound.removeIf(line::matches); } if (!notFound.isEmpty()) { fail(Arrays.toString(output) + " did not match all strings in notFound: " + Arrays.toString(expectedRegExes)); diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/LogHandler.java b/src/test/java/org/jenkinsci/plugins/gitclient/LogHandler.java index 4f78b8a183..41661f63d7 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/LogHandler.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/LogHandler.java @@ -34,12 +34,7 @@ List getMessages() { } boolean containsMessageSubstring(String messageSubstring) { - for (String message : messages) { - if (message.contains(messageSubstring)) { - return true; - } - } - return false; + return messages.stream().anyMatch(message -> message.contains(messageSubstring)); } List getTimeouts() { From 18f8a138a4ba2dd19fa513a2d6fde4870b2a4e16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sat, 7 Jul 2018 20:00:16 +0200 Subject: [PATCH 093/226] Use more suitable assertion methods --- src/test/java/hudson/plugins/git/GitToolTest.java | 4 ++-- src/test/java/hudson/plugins/git/RevisionTest.java | 2 +- src/test/java/hudson/plugins/git/TagTest.java | 4 ++-- .../jenkinsci/plugins/gitclient/CliGitAPIImplTest.java | 2 +- .../org/jenkinsci/plugins/gitclient/GitClientTest.java | 10 ++++------ .../gitclient/LegacyCompatibleGitAPIImplTest.java | 4 ++-- 6 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/test/java/hudson/plugins/git/GitToolTest.java b/src/test/java/hudson/plugins/git/GitToolTest.java index b7d2b53c09..8bb904b870 100644 --- a/src/test/java/hudson/plugins/git/GitToolTest.java +++ b/src/test/java/hudson/plugins/git/GitToolTest.java @@ -59,8 +59,8 @@ public void testGetDescriptor() { @Test public void testGetInstallationFromDescriptor() { GitTool.DescriptorImpl descriptor = gitTool.getDescriptor(); - assertEquals(null, descriptor.getInstallation("")); - assertEquals(null, descriptor.getInstallation("not-a-valid-git-install")); + assertNull(descriptor.getInstallation("")); + assertNull(descriptor.getInstallation("not-a-valid-git-install")); } @Test diff --git a/src/test/java/hudson/plugins/git/RevisionTest.java b/src/test/java/hudson/plugins/git/RevisionTest.java index 7c8f194ca8..be4a6dba3f 100644 --- a/src/test/java/hudson/plugins/git/RevisionTest.java +++ b/src/test/java/hudson/plugins/git/RevisionTest.java @@ -73,7 +73,7 @@ public void testSetSha1() { assertEquals(rev.getSha1(), newObjectId); assertEquals(rev.getSha1String(), newSHA1); rev.setSha1(null); - assertEquals(rev.getSha1(), null); + assertNull(rev.getSha1()); assertEquals(rev.getSha1String(), ""); } diff --git a/src/test/java/hudson/plugins/git/TagTest.java b/src/test/java/hudson/plugins/git/TagTest.java index 75fb7a1a30..664cca6218 100644 --- a/src/test/java/hudson/plugins/git/TagTest.java +++ b/src/test/java/hudson/plugins/git/TagTest.java @@ -20,7 +20,7 @@ public void assignTag() { @Test public void testGetCommitMessage() { - assertEquals(null, tag.getCommitMessage()); + assertNull(tag.getCommitMessage()); } @Test @@ -32,7 +32,7 @@ public void testSetCommitMessage() { @Test public void testGetCommitSHA1() { - assertEquals(null, tag.getCommitSHA1()); + assertNull(tag.getCommitSHA1()); } @Test diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplTest.java index 91688628dc..ab45c37141 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplTest.java @@ -296,7 +296,7 @@ public void test_git_branch_with_line_breaks_and_long_strings() throws Exception setTimeoutVisibleInCurrentTest(false); CliGitAPIImpl git = new CliGitAPIImpl("git", new File("."), listener, env); Set branches = git.parseBranches(gitBranchOutput); - assertTrue("\"git branch -a -v --no-abbrev\" output correctly parsed", branches.size() == 2); + assertEquals("\"git branch -a -v --no-abbrev\" output correctly parsed", 2, branches.size()); } @Override diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java index d4d3d02914..992dd41e97 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java @@ -859,7 +859,7 @@ public void testGetHeadRev_String_String_URI_Exception() throws Exception { public void testGetHeadRev_String_String_Empty_Result() throws Exception { String url = repoRoot.getAbsolutePath(); ObjectId nonExistent = gitClient.getHeadRev(url, "this branch doesn't exist"); - assertEquals(null, nonExistent); + assertNull(nonExistent); } @Test @@ -875,9 +875,8 @@ public void testGetRemoteReferences() throws Exception { String pattern = null; boolean headsOnly = false; // Need variations here boolean tagsOnly = false; // Need variations here - Map expResult = null; // Working here Map result = gitClient.getRemoteReferences(url, pattern, headsOnly, tagsOnly); - assertEquals(expResult, result); + assertNull(result); } @Issue("JENKINS-30589") @@ -1142,7 +1141,7 @@ public void testModifiedTrackedFilesReset() throws Exception { lastModifiedFile = file; } } - assertTrue("No files modified " + repoRoot, lastModifiedFile != null); + assertNotNull("No files modified " + repoRoot, lastModifiedFile); /* Checkout a new branch - verify no files retain modification */ gitClient.checkout().branch("master-" + randomUUID).ref(commitA.getName()).execute(); @@ -1189,8 +1188,7 @@ private void assertSubmoduleContents(GitClient client, String... directories) th dirList.add(dir.getName()); } } - assertThat(dirList, containsInAnyOrder(expectedDirList.toArray(new String[expectedDirList.size()]))); - assertThat(expectedDirList, containsInAnyOrder(dirList.toArray(new String[dirList.size()]))); + assertThat(dirList, containsInAnyOrder(expectedDirList.toArray())); } private void assertSubmoduleContents(String... directories) throws Exception { diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImplTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImplTest.java index 954f6ee59d..252a573e04 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImplTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/LegacyCompatibleGitAPIImplTest.java @@ -210,8 +210,8 @@ public void testGetTagsOnCommit() throws Exception { List result = myGit.getTagsOnCommit(uniqueTagName); myGit.deleteTag(uniqueTagName); assertFalse("Tag list empty for " + uniqueTagName, result.isEmpty()); - assertEquals("Unexpected SHA1 for commit: " + result.get(0).getCommitMessage(), null, result.get(0).getCommitSHA1()); - assertEquals("Unexpected message for commit: " + result.get(0).getCommitSHA1(), null, result.get(0).getCommitMessage()); + assertNull("Unexpected SHA1 for commit: " + result.get(0).getCommitMessage(), result.get(0).getCommitSHA1()); + assertNull("Unexpected message for commit: " + result.get(0).getCommitSHA1(), result.get(0).getCommitMessage()); } @Test From bbe4d11d23b3c3dcb8fe77a2092c758989a7934c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sat, 7 Jul 2018 20:25:29 +0200 Subject: [PATCH 094/226] Fix typo in variable name --- .../java/org/jenkinsci/plugins/gitclient/GitClientTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java index 992dd41e97..1d6de0472c 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java @@ -75,7 +75,7 @@ public class GitClientTest { /* commit known to exist in upstream. */ private final ObjectId upstreamCommit = ObjectId.fromString("f75720d5de9d79ab4be2633a21de23b3ccbf8ce3"); private final String upstreamCommitAuthor = "Teubel György"; - private final String upsstreamCommitEmail = ""; + private final String upstreamCommitEmail = ""; private final ObjectId upstreamCommitPredecessor = ObjectId.fromString("867e5f148377fd5a6d96e5aafbdaac132a117a5a"); /* URL of upstream (GitHub) repository. */ @@ -399,7 +399,7 @@ public void testSetAuthor_String_String() throws Exception { @Test(expected = GitException.class) public void testCommitNotFoundException() throws GitException, InterruptedException { /* Search wrong repository for a commit */ - assertAuthor(upstreamCommitPredecessor, upstreamCommit, upstreamCommitAuthor, upsstreamCommitEmail); + assertAuthor(upstreamCommitPredecessor, upstreamCommit, upstreamCommitAuthor, upstreamCommitEmail); } @Test From a64d7bffae24b8a84261b8745569264cafb7ec62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sat, 7 Jul 2018 20:26:51 +0200 Subject: [PATCH 095/226] Inline variable --- .../java/org/jenkinsci/plugins/gitclient/CredentialsTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index ffb0db8c3f..0604353348 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -221,8 +221,7 @@ private BasicSSHUserPrivateKey newPrivateKeyCredential(String username, File pri private StandardUsernamePasswordCredentials newUsernamePasswordCredential(String username, String password) { CredentialsScope scope = CredentialsScope.GLOBAL; String id = "username-" + username + "-password-" + password + random.nextInt(); - StandardUsernamePasswordCredentials usernamePasswordCredential = new UsernamePasswordCredentialsImpl(scope, id, "desc: " + id, username, password); - return usernamePasswordCredential; + return new UsernamePasswordCredentialsImpl(scope, id, "desc: " + id, username, password); } private static boolean isCredentialsSupported() throws IOException, InterruptedException { From 5d9e805bd023e7f9e060990520d47ee347d57ff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sat, 7 Jul 2018 20:33:48 +0200 Subject: [PATCH 096/226] Remove redundant empty constructors --- src/test/java/hudson/plugins/git/IndexEntryTest.java | 3 --- .../java/org/jenkinsci/plugins/gitclient/LogHandlerTest.java | 3 --- 2 files changed, 6 deletions(-) diff --git a/src/test/java/hudson/plugins/git/IndexEntryTest.java b/src/test/java/hudson/plugins/git/IndexEntryTest.java index d6141dfb31..5fa3f2610b 100644 --- a/src/test/java/hudson/plugins/git/IndexEntryTest.java +++ b/src/test/java/hudson/plugins/git/IndexEntryTest.java @@ -13,9 +13,6 @@ public class IndexEntryTest { private final String file = ".git" + File.separator + "index-entry-file"; private IndexEntry entry; - public IndexEntryTest() { - } - @Before public void setUp() { entry = new IndexEntry(mode, type, object, file); diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/LogHandlerTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/LogHandlerTest.java index df07d9fcef..ae9a46323c 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/LogHandlerTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/LogHandlerTest.java @@ -11,9 +11,6 @@ public class LogHandlerTest { private LogHandler handler; - public LogHandlerTest() { - } - @Before public void setUp() { handler = new LogHandler(); From 6bf636ad45d31fb53b64715ee0cfb1a625b926aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sat, 7 Jul 2018 20:34:30 +0200 Subject: [PATCH 097/226] Remove useless test --- src/test/java/hudson/plugins/git/IndexEntryTest.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/test/java/hudson/plugins/git/IndexEntryTest.java b/src/test/java/hudson/plugins/git/IndexEntryTest.java index 5fa3f2610b..6fd53e40a2 100644 --- a/src/test/java/hudson/plugins/git/IndexEntryTest.java +++ b/src/test/java/hudson/plugins/git/IndexEntryTest.java @@ -134,11 +134,6 @@ public void testEquals() { assertEquals(entryNull4, entryNull4a); assertEquals(entryNull4a, entryNull4); - IndexEntry entryNullA = null; - IndexEntry entryNullB = null; - assertEquals(entryNullA, entryNullB); - assertEquals(entryNullB, entryNullA); - assertNotEquals(entry, null); assertNotEquals(entry, "not an IndexEntry object"); } From f160c61baa6883e04fc973491e00802cec4ef81a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sat, 7 Jul 2018 20:36:14 +0200 Subject: [PATCH 098/226] Remove useless variable --- .../java/org/jenkinsci/plugins/gitclient/GitClientTest.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java index 1d6de0472c..25a33d047d 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java @@ -585,8 +585,6 @@ private void assertBranch(GitClient client, String branchName) throws Exception gitCmd.assertOutputContains(".*On branch.*" + branchName + ".*"); } - private int lastFetchPath = -1; - private void fetch(GitClient client, String remote, String firstRefSpec, String... optionalRefSpecs) throws Exception { List refSpecs = new ArrayList<>(); RefSpec refSpec = new RefSpec(firstRefSpec); @@ -594,8 +592,7 @@ private void fetch(GitClient client, String remote, String firstRefSpec, String. for (String refSpecString : optionalRefSpecs) { refSpecs.add(new RefSpec(refSpecString)); } - lastFetchPath = random.nextInt(2); - switch (lastFetchPath) { + switch (random.nextInt(2)) { default: case 0: if (remote.equals("origin")) { From 6dba777477d2053fe1d1bd24f53170a9b3803d5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sat, 7 Jul 2018 20:38:16 +0200 Subject: [PATCH 099/226] Remove extra test constructor Instantiate instance variable directly (similar to all other ones). --- .../plugins/gitclient/CliGitAPIImplAuthTest.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplAuthTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplAuthTest.java index faf80f407f..282ac524d1 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplAuthTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplAuthTest.java @@ -22,19 +22,15 @@ */ public class CliGitAPIImplAuthTest { - private final Launcher launcher; - - public CliGitAPIImplAuthTest() { - launcher = new Launcher.LocalLauncher(TaskListener.NULL); - } - - private CliGitAPIImpl git; + private final Launcher launcher = new Launcher.LocalLauncher(TaskListener.NULL); private final Random random = new Random(); private final String[] CARET_SPECIALS = {"^", "&", "\\", "<", ">", "|", " ", "\"", "\t"}; private final String[] PERCENT_SPECIALS = {"%"}; + private CliGitAPIImpl git; + @Before public void setUp() { git = new CliGitAPIImpl("git", new File("."), TaskListener.NULL, new EnvVars()); From 1fc88f5c330c6888563875ad5d96d31a15a0631d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sat, 7 Jul 2018 20:40:57 +0200 Subject: [PATCH 100/226] Reduce variable scope --- src/test/java/hudson/plugins/git/TagTest.java | 8 ++++---- .../gitclient/trilead/CredentialsProviderImplTest.java | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/test/java/hudson/plugins/git/TagTest.java b/src/test/java/hudson/plugins/git/TagTest.java index 664cca6218..6c16189ecb 100644 --- a/src/test/java/hudson/plugins/git/TagTest.java +++ b/src/test/java/hudson/plugins/git/TagTest.java @@ -8,13 +8,13 @@ import nl.jqno.equalsverifier.EqualsVerifier; public class TagTest { - private final String tagName = "git-client-1.8.1"; - private final String tagSHA1String = "3725b67f3daa6621dd01356c96c08a1f85b90c61"; - private final ObjectId tagSHA1 = ObjectId.fromString(tagSHA1String); - Tag tag; + + private Tag tag; @Before public void assignTag() { + String tagName = "git-client-1.8.1"; + ObjectId tagSHA1 = ObjectId.fromString("3725b67f3daa6621dd01356c96c08a1f85b90c61"); tag = new Tag(tagName, tagSHA1); } diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/trilead/CredentialsProviderImplTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/trilead/CredentialsProviderImplTest.java index 19d39c8bda..63f6c46e56 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/trilead/CredentialsProviderImplTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/trilead/CredentialsProviderImplTest.java @@ -20,7 +20,6 @@ public class CredentialsProviderImplTest { private CredentialsProviderImpl provider; private TaskListener listener; - private StandardUsernameCredentials cred; private final String USER_NAME = "user-name"; private final URIish uri; private final String SECRET_VALUE = "secret-credentials-provider-impl-test"; @@ -36,7 +35,7 @@ public CredentialsProviderImplTest() throws URISyntaxException { public void setUp() { Secret secret = Secret.fromString(SECRET_VALUE); listener = StreamTaskListener.fromStdout(); - cred = new StandardUsernamePasswordCredentialsImpl(USER_NAME, secret); + StandardUsernameCredentials cred = new StandardUsernamePasswordCredentialsImpl(USER_NAME, secret); provider = new CredentialsProviderImpl(listener, cred); } From b01f47c40019ec5245a01ceeecbcca609f87ce29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sat, 7 Jul 2018 20:43:51 +0200 Subject: [PATCH 101/226] Refactor test helper classes --- .../jenkinsci/plugins/gitclient/RemotingTest.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/RemotingTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/RemotingTest.java index 179f1ae8dd..fc745cb681 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/RemotingTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/RemotingTest.java @@ -35,6 +35,9 @@ public void testRemotability() throws Exception { } private static class Work implements Callable { + + private static final long serialVersionUID = 1L; + private final GitClient git; private static boolean cliGitDefaultsSet = false; @@ -52,6 +55,7 @@ private Work(GitClient git) throws Exception { this.git = git; } + @Override public Void call() throws IOException { try { git.init(); @@ -69,8 +73,6 @@ public Void call() throws IOException { } } - private static final long serialVersionUID = 1L; - @Override public void checkRoles(RoleChecker rc) throws SecurityException { throw new UnsupportedOperationException("unexpected call to checkRoles in private static Work class"); @@ -78,11 +80,13 @@ public void checkRoles(RoleChecker rc) throws SecurityException { } private static class RepositoryCallableImpl implements RepositoryCallback { - public FilePath invoke(Repository repo, VirtualChannel channel) throws IOException, InterruptedException { + + private static final long serialVersionUID = 1L; + + @Override + public FilePath invoke(Repository repo, VirtualChannel channel) { assertNotNull(repo); return new FilePath(repo.getWorkTree()); } - - private static final long serialVersionUID = 1L; } } From 67e7f4283d32b8fb9a43aa0bef86cf8741a75f9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sat, 7 Jul 2018 22:52:52 +0200 Subject: [PATCH 102/226] Refactor test to use JenkinsRule instead of deprecated HudsonTestCase --- .../plugins/gitclient/RemotingTest.java | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/RemotingTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/RemotingTest.java index fc745cb681..df84d1b32c 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/RemotingTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/RemotingTest.java @@ -1,5 +1,7 @@ package org.jenkinsci.plugins.gitclient; +import static org.junit.Assert.*; + import hudson.FilePath; import hudson.model.Computer; import hudson.model.StreamBuildListener; @@ -8,8 +10,10 @@ import hudson.slaves.DumbSlave; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Repository; -import org.jvnet.hudson.test.HudsonTestCase; - +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.jvnet.hudson.test.JenkinsRule; import java.io.File; import java.io.IOException; import org.jenkinsci.remoting.RoleChecker; @@ -17,15 +21,22 @@ /** * @author Kohsuke Kawaguchi */ -public class RemotingTest extends HudsonTestCase { +public class RemotingTest { + + @ClassRule + public static JenkinsRule j = new JenkinsRule(); + + @ClassRule + public static TemporaryFolder tempFolder = new TemporaryFolder(); + /** * Makes sure {@link GitClient} is remotable. */ + @Test public void testRemotability() throws Exception { - DumbSlave s = createSlave(); + DumbSlave s = j.createSlave(); - File dir = createTmpDir(); - final GitClient jgit = new JGitAPIImpl(dir,StreamBuildListener.fromStdout()); + GitClient jgit = new JGitAPIImpl(tempFolder.getRoot(), StreamBuildListener.fromStdout()); Computer c = s.toComputer(); c.connect(false).get(); @@ -34,7 +45,7 @@ public void testRemotability() throws Exception { channel.close(); } - private static class Work implements Callable { + private static class Work implements Callable { private static final long serialVersionUID = 1L; @@ -62,10 +73,12 @@ public Void call() throws IOException { git.getWorkTree().child("foo").touch(0); git.add("foo"); PersonIdent alice = new PersonIdent("alice", "alice@jenkins-ci.org"); - git.commit("committing changes", alice, alice); + git.setAuthor(alice); + git.setCommitter(alice); + git.commit("committing changes"); FilePath ws = git.withRepository(new RepositoryCallableImpl()); - assertEquals(ws,git.getWorkTree()); + assertEquals(ws, git.getWorkTree()); return null; } catch (InterruptedException e) { From 318cd4cab3aa985a305d83c8611ea7c4c7b2a413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sat, 7 Jul 2018 23:08:55 +0200 Subject: [PATCH 103/226] Replace Guava method to create lists --- .../org/jenkinsci/plugins/gitclient/GitAPITestCase.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 3672ca4b2f..10c8ff45f6 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -76,7 +76,6 @@ import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; -import com.google.common.collect.Lists; /** * @author Nicolas De Loof @@ -684,7 +683,7 @@ public void test_clone_refspec() throws Exception { } public void test_clone_refspecs() throws Exception { - List refspecs = Lists.newArrayList( + 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") ); @@ -2668,17 +2667,17 @@ public void test_sparse_checkout() throws Exception { workingArea.git.clone_().url(w.repoPath()).execute(); checkoutTimeout = 1 + random.nextInt(60 * 24); - workingArea.git.checkout().ref("origin/master").branch("master").deleteBranchIfExist(true).sparseCheckoutPaths(Lists.newArrayList("dir1")).timeout(checkoutTimeout).execute(); + workingArea.git.checkout().ref("origin/master").branch("master").deleteBranchIfExist(true).sparseCheckoutPaths(Arrays.asList("dir1")).timeout(checkoutTimeout).execute(); assertTrue(workingArea.exists("dir1")); assertFalse(workingArea.exists("dir2")); assertFalse(workingArea.exists("dir3")); - workingArea.git.checkout().ref("origin/master").branch("master").deleteBranchIfExist(true).sparseCheckoutPaths(Lists.newArrayList("dir2")).timeout(checkoutTimeout).execute(); + workingArea.git.checkout().ref("origin/master").branch("master").deleteBranchIfExist(true).sparseCheckoutPaths(Arrays.asList("dir2")).timeout(checkoutTimeout).execute(); assertFalse(workingArea.exists("dir1")); assertTrue(workingArea.exists("dir2")); assertFalse(workingArea.exists("dir3")); - workingArea.git.checkout().ref("origin/master").branch("master").deleteBranchIfExist(true).sparseCheckoutPaths(Lists.newArrayList("dir1", "dir2")).timeout(checkoutTimeout).execute(); + workingArea.git.checkout().ref("origin/master").branch("master").deleteBranchIfExist(true).sparseCheckoutPaths(Arrays.asList("dir1", "dir2")).timeout(checkoutTimeout).execute(); assertTrue(workingArea.exists("dir1")); assertTrue(workingArea.exists("dir2")); assertFalse(workingArea.exists("dir3")); From 36bea1308ed4cc02f3e0a16b5feb0f2f7ace68d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sat, 7 Jul 2018 18:39:56 +0200 Subject: [PATCH 104/226] Remove unused test code It was left behind in commit c29628b28cc6c6326c7769a516b2e87ca1f6194f. --- .../plugins/gitclient/CredentialsTest.java | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index 0604353348..577556c8d0 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -26,7 +26,6 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; -import org.apache.commons.lang.StringUtils; import org.eclipse.jgit.lib.ObjectId; import static org.hamcrest.Matchers.*; import org.junit.After; @@ -73,7 +72,6 @@ public class CredentialsTest { private File repo; private StandardCredentials testedCredential; - private List expectedLogSubstrings = new ArrayList<>(); private final Random random = new Random(); @Rule @@ -150,11 +148,6 @@ public void setUp() throws IOException, InterruptedException { listener = new hudson.util.LogTaskListener(logger, Level.ALL); listener.getLogger().println(LOGGING_STARTED); git = Git.with(listener, new hudson.EnvVars()).in(repo).using(gitImpl).getClient(); - if (gitImpl.equals("git")) { - addExpectedLogSubstring("> git fetch "); - addExpectedLogSubstring("> git checkout -b master "); - } - addExpectedLogSubstring("Using reference repository: "); assertTrue("Bad username, password, privateKey combo: '" + username + "', '" + password + "'", (password == null || password.isEmpty()) ^ (privateKey == null || !privateKey.exists())); @@ -184,28 +177,6 @@ public void clearCredentials() { } } - private void checkExpectedLogSubstring() { - try { - String messages = StringUtils.join(handler.getMessages(), ";"); - assertTrue("Logging not started: " + messages, handler.containsMessageSubstring(LOGGING_STARTED)); - for (String expectedLogSubstring : expectedLogSubstrings) { - assertTrue("No '" + expectedLogSubstring + "' in " + messages, - handler.containsMessageSubstring(expectedLogSubstring)); - } - } finally { - clearExpectedLogSubstring(); - handler.close(); - } - } - - protected void addExpectedLogSubstring(String expectedLogSubstring) { - this.expectedLogSubstrings.add(expectedLogSubstring); - } - - protected void clearExpectedLogSubstring() { - this.expectedLogSubstrings = new ArrayList<>(); - } - private BasicSSHUserPrivateKey newPrivateKeyCredential(String username, File privateKey) throws IOException { CredentialsScope scope = CredentialsScope.GLOBAL; String id = "private-key-" + privateKey.getPath() + random.nextInt(); From de9da9a7f942e113b919b200b1811332acdb6aeb Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 14 Jul 2018 07:42:39 -0600 Subject: [PATCH 105/226] Report better exception if filename not supported When LANG=C mvn -Dtest=CliGitAPIImplTest#test_clean test fails, give a better message than the exception from "git add". This is not foolproof, just an aid for diagnosing test failures when the locale is unable to support the filename in the test. --- .../org/jenkinsci/plugins/gitclient/GitAPITestCase.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 10c8ff45f6..c4de9029f9 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -865,7 +865,14 @@ public void test_clean() throws Exception { */ String fileName = "\uD835\uDD65-\u5c4f\u5e55\u622a\u56fe-\u0041\u030a-\u00c5-\u212b-fileName.xml"; w.touch(fileName, "content " + fileName); - w.git.add(fileName); + try { + w.git.add(fileName); + } catch (GitException ge) { + // Exception should contain actual file name + // If mangled name is seen instead, throw a clear exception to indicate root cause + assertTrue("System locale does not support filename '" + fileName + "'", ge.getMessage().contains("?-????-A?-?-?-fileName.xml")); + throw ge; // Fail the test on exception even if the preceding assertion did not fail + } w.git.commit(fileName); /* JENKINS-27910 reported that certain cyrillic file names From 94706e3ca8a334dbf7f6df996c7e4b84ae42fa2a Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 14 Jul 2018 11:59:00 -0600 Subject: [PATCH 106/226] Use equalsverifier 2.4.8 - latest release --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 58ff7c6c3a..e3bd0884dc 100644 --- a/pom.xml +++ b/pom.xml @@ -160,7 +160,7 @@ nl.jqno.equalsverifier equalsverifier - 2.4.6 + 2.4.8 test From 54357c30854b189a45bae30a26e81f5fc8225300 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 14 Jul 2018 11:55:15 -0600 Subject: [PATCH 107/226] Use JGit 5.0.1 - latest release Adapt JGitAPIImpl getRef and GitAPITestCase getRef calls to JGit 5.0.1 --- pom.xml | 2 +- .../jenkinsci/plugins/gitclient/JGitAPIImpl.java | 8 ++++---- .../plugins/gitclient/GitAPITestCase.java | 14 +++++++------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pom.xml b/pom.xml index e3bd0884dc..7615eb787c 100644 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,7 @@ -Dfile.encoding=${project.build.sourceEncoding} 2.60.3 8 - 4.11.0.201803080745-r + 5.0.1.201806211838-r diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index 80377b768c..dd458a4614 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -536,7 +536,7 @@ public void tag(String name, String message) throws GitException { @Override public boolean tagExists(String tagName) throws GitException { try (Repository repo = getRepository()) { - Ref tag = repo.getRefDatabase().getRef(R_TAGS + tagName); + Ref tag = repo.getRefDatabase().exactRef(R_TAGS + tagName); return tag != null; } catch (IOException e) { throw new GitException(e); @@ -708,7 +708,7 @@ public void ref(String refName) throws GitException, InterruptedException { refName = refName.replace(' ', '_'); try (Repository repo = getRepository()) { RefUpdate refUpdate = repo.updateRef(refName); - refUpdate.setNewObjectId(repo.getRef(Constants.HEAD).getObjectId()); + refUpdate.setNewObjectId(repo.exactRef(Constants.HEAD).getObjectId()); switch (refUpdate.forceUpdate()) { case NOT_ATTEMPTED: case LOCK_FAILURE: @@ -742,7 +742,7 @@ public void deleteRef(String refName) throws GitException, InterruptedException try (Repository repo = getRepository()) { RefUpdate refUpdate = repo.updateRef(refName); // Required, even though this is a forced delete. - refUpdate.setNewObjectId(repo.getRef(Constants.HEAD).getObjectId()); + refUpdate.setNewObjectId(repo.exactRef(Constants.HEAD).getObjectId()); refUpdate.setForceUpdate(true); switch (refUpdate.delete()) { case NOT_ATTEMPTED: @@ -1937,7 +1937,7 @@ private String fixRefSpec(Repository repository) throws IOException { switch (spec) { default: case 0: //for the source ref. we use the repository to determine what should be pushed - Ref ref = repository.getRef(specs[spec]); + Ref ref = repository.findRef(specs[spec]); if (ref == null) { throw new IOException(String.format("Ref %s not found.", specs[spec])); } diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index c4de9029f9..871a9d1de3 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -4043,7 +4043,7 @@ public void test_checkoutBranch() throws Exception { assertEquals(w.head(),w.git.revParse("t1")); assertEquals(w.head(),w.git.revParse("foo")); - Ref head = w.repo().getRef("HEAD"); + Ref head = w.repo().exactRef("HEAD"); assertTrue(head.isSymbolic()); assertEquals("refs/heads/foo",head.getTarget().getName()); } @@ -4105,20 +4105,20 @@ public void test_revList_remote_branch() throws Exception { w = clone(localMirror()); List revList = w.git.revList("origin/1.4.x"); assertEquals("Wrong list size: " + revList, 267, revList.size()); - Ref branchRef = w.repo().getRef("origin/1.4.x"); + Ref branchRef = w.repo().findRef("origin/1.4.x"); assertTrue("origin/1.4.x not in revList", revList.contains(branchRef.getObjectId())); } public void test_revList_tag() throws Exception { w.init(); w.commitEmpty("c1"); - Ref commitRefC1 = w.repo().getRef("HEAD"); + Ref commitRefC1 = w.repo().exactRef("HEAD"); w.tag("t1"); - Ref tagRefT1 = w.repo().getRef("t1"); - Ref head = w.repo().getRef("HEAD"); + Ref tagRefT1 = w.repo().findRef("t1"); + Ref head = w.repo().exactRef("HEAD"); assertEquals("head != t1", head.getObjectId(), tagRefT1.getObjectId()); w.commitEmpty("c2"); - Ref commitRefC2 = w.repo().getRef("HEAD"); + Ref commitRefC2 = w.repo().exactRef("HEAD"); List revList = w.git.revList("t1"); assertTrue("c1 not in revList", revList.contains(commitRefC1.getObjectId())); assertEquals("Wrong list size: " + revList, 1, revList.size()); @@ -4144,7 +4144,7 @@ public void test_checkoutBranch_null() throws Exception { assertEquals(w.head(),w.git.revParse(sha1)); - Ref head = w.repo().getRef("HEAD"); + Ref head = w.repo().exactRef("HEAD"); assertFalse(head.isSymbolic()); } From 596982d3a4b1bfcb2eddde55c87c166e62531b2b Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 15 Jul 2018 05:09:41 -0600 Subject: [PATCH 108/226] Ignore the .@tmp/ directory Prevent build failures from incrementals process which wants the output of "git status -s" to be empty. The directory is an artifact of automated tests and should never be committed to the repository. --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 88b008a986..ddf4940128 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ target/ work/ +.@tmp/ .project .classpath @@ -21,4 +22,4 @@ tags # emacs backup files *~ -/nbproject/ \ No newline at end of file +/nbproject/ From 064a3c82b20a5fff6699b095513156dcbd73586e Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 15 Jul 2018 19:53:13 -0600 Subject: [PATCH 109/226] Use JGit repository object directly --- .../java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index dd458a4614..b041f22f65 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -536,7 +536,7 @@ public void tag(String name, String message) throws GitException { @Override public boolean tagExists(String tagName) throws GitException { try (Repository repo = getRepository()) { - Ref tag = repo.getRefDatabase().exactRef(R_TAGS + tagName); + Ref tag = repo.exactRef(R_TAGS + tagName); return tag != null; } catch (IOException e) { throw new GitException(e); @@ -728,7 +728,7 @@ public void ref(String refName) throws GitException, InterruptedException { public boolean refExists(String refName) throws GitException, InterruptedException { refName = refName.replace(' ', '_'); try (Repository repo = getRepository()) { - Ref ref = repo.getRefDatabase().getRef(refName); + Ref ref = repo.findRef(refName); return ref != null; } catch (IOException e) { throw new GitException("Error checking ref " + refName, e); From dbc44436bc74b0005164d5d4a40d2d395a15d447 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 15 Jul 2018 19:54:14 -0600 Subject: [PATCH 110/226] Remove unused JGitAPIImpl imports --- src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index b041f22f65..9ab4d36329 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -30,8 +30,6 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; -import java.nio.file.Files; -import java.nio.file.Paths; import java.lang.reflect.Field; import java.net.URISyntaxException; import java.util.ArrayList; From b354bb7e8421c6f9e445028077e8e42d9d0902fd Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 15 Jul 2018 20:36:41 -0600 Subject: [PATCH 111/226] Use getRefsByPrefix(String) instead of deprecated getRefs(String) --- .../java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index 9ab4d36329..f1c5b691a9 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -765,10 +765,10 @@ public Set getRefNames(String refPrefix) throws GitException, Interrupte refPrefix = refPrefix.replace(' ', '_'); } try (Repository repo = getRepository()) { - Map refList = repo.getRefDatabase().getRefs(refPrefix); + List refList = repo.getRefDatabase().getRefsByPrefix(refPrefix); // The key set for refList will have refPrefix removed, so to recover it we just grab the full name. Set refs = new HashSet<>(refList.size()); - for (Ref ref : refList.values()) { + for (Ref ref : refList) { refs.add(ref.getName()); } return refs; @@ -1753,8 +1753,8 @@ public Set getRemoteTagNames(String tagPattern) throws GitException { try (Repository repo = getRepository()) { Set tags = new HashSet<>(); FileNameMatcher matcher = new FileNameMatcher(tagPattern, '/'); - Map refList = repo.getRefDatabase().getRefs(R_TAGS); - for (Ref ref : refList.values()) { + List refList = repo.getRefDatabase().getRefsByPrefix(R_TAGS); + for (Ref ref : refList) { String name = ref.getName().substring(R_TAGS.length()); matcher.reset(); matcher.append(name); From 66b3791f6ee41070d56eb6e81905c10e76d8756e Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 15 Jul 2018 19:53:13 -0600 Subject: [PATCH 112/226] Remove incorrect JGit implementation comment Method is now mapping from a List to Set. No longer uses the deprecated JGit method that returned a Map. --- src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index f1c5b691a9..2dbdde6e29 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -766,7 +766,6 @@ public Set getRefNames(String refPrefix) throws GitException, Interrupte } try (Repository repo = getRepository()) { List refList = repo.getRefDatabase().getRefsByPrefix(refPrefix); - // The key set for refList will have refPrefix removed, so to recover it we just grab the full name. Set refs = new HashSet<>(refList.size()); for (Ref ref : refList) { refs.add(ref.getName()); From 84f0216cd2c113424eb9a13693df471081b7329c Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 23 Jul 2018 09:17:57 -0600 Subject: [PATCH 113/226] Include master branch CredentialsTest improvements Remove unreferenced expectedLogSubstrings and related methods. Simplify newUsernamePasswordCredential() method --- .../plugins/gitclient/CredentialsTest.java | 32 +------------------ 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index 7498840868..479dcfe17b 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -26,7 +26,6 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; -import org.apache.commons.lang.StringUtils; import org.eclipse.jgit.lib.ObjectId; import static org.hamcrest.Matchers.*; import org.junit.After; @@ -73,7 +72,6 @@ public class CredentialsTest { private File repo; private StandardCredentials testedCredential; - private List expectedLogSubstrings = new ArrayList<>(); private final Random random = new Random(); @Rule @@ -150,11 +148,6 @@ public void setUp() throws IOException, InterruptedException { listener = new hudson.util.LogTaskListener(logger, Level.ALL); listener.getLogger().println(LOGGING_STARTED); git = Git.with(listener, new hudson.EnvVars()).in(repo).using(gitImpl).getClient(); - if (gitImpl.equals("git")) { - addExpectedLogSubstring("> git fetch "); - addExpectedLogSubstring("> git checkout -b master "); - } - addExpectedLogSubstring("Using reference repository: "); assertTrue("Bad username, password, privateKey combo: '" + username + "', '" + password + "'", (password == null || password.isEmpty()) ^ (privateKey == null || !privateKey.exists())); @@ -184,28 +177,6 @@ public void clearCredentials() { } } - private void checkExpectedLogSubstring() { - try { - String messages = StringUtils.join(handler.getMessages(), ";"); - assertTrue("Logging not started: " + messages, handler.containsMessageSubstring(LOGGING_STARTED)); - for (String expectedLogSubstring : expectedLogSubstrings) { - assertTrue("No '" + expectedLogSubstring + "' in " + messages, - handler.containsMessageSubstring(expectedLogSubstring)); - } - } finally { - clearExpectedLogSubstring(); - handler.close(); - } - } - - protected void addExpectedLogSubstring(String expectedLogSubstring) { - this.expectedLogSubstrings.add(expectedLogSubstring); - } - - protected void clearExpectedLogSubstring() { - this.expectedLogSubstrings = new ArrayList<>(); - } - private BasicSSHUserPrivateKey newPrivateKeyCredential(String username, File privateKey) throws IOException { CredentialsScope scope = CredentialsScope.GLOBAL; String id = "private-key-" + privateKey.getPath() + random.nextInt(); @@ -221,8 +192,7 @@ private BasicSSHUserPrivateKey newPrivateKeyCredential(String username, File pri private StandardUsernamePasswordCredentials newUsernamePasswordCredential(String username, String password) { CredentialsScope scope = CredentialsScope.GLOBAL; String id = "username-" + username + "-password-" + password + random.nextInt(); - StandardUsernamePasswordCredentials usernamePasswordCredential = new UsernamePasswordCredentialsImpl(scope, id, "desc: " + id, username, password); - return usernamePasswordCredential; + return new UsernamePasswordCredentialsImpl(scope, id, "desc: " + id, username, password); } private static boolean isCredentialsSupported() throws IOException, InterruptedException { From 3a4f629bace912df8533a7fb5a60ddd9daf12122 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 23 Jul 2018 09:25:08 -0600 Subject: [PATCH 114/226] Limit credentials test time rather than test count The CredentialsTest uses a ClassRule JenkinsRule to reduce setup time for each test. A ClassRule JenkinsRule is safe because each of the credentials tests is independent of all other credentials tests. The JenkinsRule test is limited to not more than 180 seconds for a single JenkinsRule test. Because I have many authentication test configurations (approaching 100 currently), the tests can fail because they reach the JenkinsRule timeout. Previously the failure was prevented by limiting the number of tests which can be executed. This change uses elapsed time as the limiter rather than number of tests. All tests executed more than 130 seconds after the first CredentialsTest will be skipped. Since the order of CredentialsTests is intentionally randomized and the tests are run on multiple platforms with multiple Jenkins versions, this should give a reasonable chance that most CredentialsTest combinations will be executed in a single CI run in my home CI setup. Note that the CredentialsTest depends on private credentials data. The ci.jenkins.io execution will run at most one copy of this test if it detects an RSA private key file on the agent executing the test. --- .../plugins/gitclient/CredentialsTest.java | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index 479dcfe17b..d63c7ffb97 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -30,6 +30,7 @@ import static org.hamcrest.Matchers.*; import org.junit.After; import static org.junit.Assert.*; +import static org.junit.Assume.*; import org.junit.Before; import org.junit.Test; import org.junit.Rule; @@ -94,6 +95,8 @@ public class CredentialsTest { private final static File CURR_DIR = new File("."); + private static long firstTestStartTime = 0; + private static PrintStream log() { return StreamTaskListener.fromStdout().getLogger(); } @@ -118,6 +121,9 @@ public CredentialsTest(String gitImpl, String gitRepoUrl, String username, Strin if (specialsIndex >= SPECIALS_TO_CHECK.length()) { specialsIndex = 0; } + if (firstTestStartTime == 0) { + firstTestStartTime = System.currentTimeMillis(); + } log().println(show("Repo", gitRepoUrl) + show("spec", specialCharacter) + show("impl", gitImpl) @@ -305,8 +311,8 @@ public static Collection gitRepoUrls() throws MalformedURLException, FileNotFoun } } Collections.shuffle(repos); // randomize test order - int toIndex = Math.min(repos.size(), TEST_ALL_CREDENTIALS ? 120 : 6); // Don't run more than 120 variations of test - about 3 minutes - return repos.subList(0, toIndex); + // If we're not testing all credentials, take 6 or less + return TEST_ALL_CREDENTIALS ? repos : repos.subList(0, Math.min(repos.size(), 6)); } private void addCredential(String username, String password, File privateKey) throws IOException { @@ -317,8 +323,19 @@ private void addCredential(String username, String password, File privateKey) th } } + /** + * Returns true if less than than 130 seconds have elapsed since start. + * JenkinsRule test timeout defaults to 180 seconds. + * + * @return true if less than than 130 seconds have elapsed since start + */ + private boolean testPeriodNotExpired() { + return (System.currentTimeMillis() - firstTestStartTime) < (130 * 1000L); + } + @Test public void testRemoteReferencesWithCredentials() throws Exception { + assumeTrue(testPeriodNotExpired()); addCredential(username, password, privateKey); Map remoteReferences; switch (random.nextInt(4)) { From 1666bb2afc421707393c89df907a7acf127d4e4c Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 23 Jul 2018 09:43:53 -0600 Subject: [PATCH 115/226] Remove unused arguments from CredentialsTest.addCredential --- .../java/org/jenkinsci/plugins/gitclient/CredentialsTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index d63c7ffb97..e3ec1312fc 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -315,7 +315,7 @@ public static Collection gitRepoUrls() throws MalformedURLException, FileNotFoun return TEST_ALL_CREDENTIALS ? repos : repos.subList(0, Math.min(repos.size(), 6)); } - private void addCredential(String username, String password, File privateKey) throws IOException { + private void addCredential() throws IOException { if (random.nextBoolean()) { git.addDefaultCredentials(testedCredential); } else { @@ -336,7 +336,7 @@ private boolean testPeriodNotExpired() { @Test public void testRemoteReferencesWithCredentials() throws Exception { assumeTrue(testPeriodNotExpired()); - addCredential(username, password, privateKey); + addCredential(); Map remoteReferences; switch (random.nextInt(4)) { default: From 142a1d129f18f2e0d6e407064b84da54dfa04b16 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 23 Jul 2018 09:55:54 -0600 Subject: [PATCH 116/226] Use '~' to show private key path in CredentialsTest --- .../org/jenkinsci/plugins/gitclient/CredentialsTest.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index e3ec1312fc..7344430961 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -365,7 +365,12 @@ private String show(String name, String value) { private String show(String name, File file) { if (file != null) { - return " " + name + ": '" + file.getPath() + "'"; + String homePath = HOME_DIR.getAbsolutePath(); + String filePath = file.getAbsolutePath(); + if (filePath.startsWith(homePath)) { + filePath = filePath.replace(homePath, "~"); + } + return " " + name + ": '" + filePath + "'"; } return ""; } From 68fa4a8a0d2a8351a83217f98374719024f1e0fb Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 23 Jul 2018 10:32:27 -0600 Subject: [PATCH 117/226] Add CredentialsTest for fetch --- .../plugins/gitclient/CredentialsTest.java | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index 7344430961..fc6a57dc07 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -8,6 +8,7 @@ import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl; import com.google.common.io.Files; import hudson.model.Fingerprint; +import hudson.plugins.git.GitException; import hudson.util.LogTaskListener; import hudson.util.StreamTaskListener; import java.io.File; @@ -16,6 +17,7 @@ import java.io.IOException; import java.io.PrintStream; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; @@ -27,6 +29,9 @@ import java.util.logging.Logger; import java.util.regex.Pattern; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.transport.RefSpec; +import org.eclipse.jgit.transport.RemoteConfig; +import org.eclipse.jgit.transport.URIish; import static org.hamcrest.Matchers.*; import org.junit.After; import static org.junit.Assert.*; @@ -315,6 +320,31 @@ public static Collection gitRepoUrls() throws MalformedURLException, FileNotFoun return TEST_ALL_CREDENTIALS ? repos : repos.subList(0, Math.min(repos.size(), 6)); } + private void doFetch(String source) throws InterruptedException, URISyntaxException { + /* Save some bandwidth with shallow clone for CliGit, not yet available for JGit */ + URIish sourceURI = new URIish(source); + List refSpecs = new ArrayList<>(); + refSpecs.add(new RefSpec("+refs/heads/master:refs/remotes/origin/master")); + FetchCommand cmd = git.fetch_().from(sourceURI, refSpecs).tags(false); + if (gitImpl.equals("git")) { + // Reduce network transfer by using shallow clone + // JGit does not support shallow clone + cmd.shallow(true).depth(1); + } + cmd.execute(); + } + + private String listDir(File dir) { + File[] files = repo.listFiles(); + StringBuilder fileList = new StringBuilder(); + for (File file : files) { + fileList.append(file.getName()); + fileList.append(','); + } + fileList.deleteCharAt(fileList.length() - 1); + return fileList.toString(); + } + private void addCredential() throws IOException { if (random.nextBoolean()) { git.addDefaultCredentials(testedCredential); @@ -333,6 +363,33 @@ private boolean testPeriodNotExpired() { return (System.currentTimeMillis() - firstTestStartTime) < (130 * 1000L); } + @Test + public void testFetchWithCredentials() throws URISyntaxException, GitException, InterruptedException, MalformedURLException, IOException { + assumeTrue(testPeriodNotExpired()); + File clonedFile = new File(repo, fileToCheck); + git.init_().workspace(repo.getAbsolutePath()).execute(); + assertFalse("file " + fileToCheck + " in " + repo + ", has " + listDir(repo), clonedFile.exists()); + addCredential(); + /* Fetch with remote URL */ + doFetch(gitRepoURL); + git.setRemoteUrl("origin", gitRepoURL); + ObjectId master = git.getHeadRev(gitRepoURL, "master"); + log().println("Checking out " + master.getName().substring(0, 8) + " from " + gitRepoURL); + git.checkout().branch("master").ref(master.getName()).deleteBranchIfExist(true).execute(); + if (submodules) { + log().println("Initializing submodules from " + gitRepoURL); + git.submoduleInit(); + SubmoduleUpdateCommand subcmd = git.submoduleUpdate().parentCredentials(useParentCreds); + subcmd.execute(); + } + assertTrue("master: " + master + " not in repo", git.isCommitInRepo(master)); + assertEquals("Master != HEAD", master, git.getRepository().getRef("master").getObjectId()); + assertEquals("Wrong branch", "master", git.getRepository().getBranch()); + assertTrue("No file " + fileToCheck + ", has " + listDir(repo), clonedFile.exists()); + /* prune opens a remote connection to list remote branches */ + git.prune(new RemoteConfig(git.getRepository().getConfig(), "origin")); + } + @Test public void testRemoteReferencesWithCredentials() throws Exception { assumeTrue(testPeriodNotExpired()); From c0989301374b73bc1dde8423b1bcfb8a89f4643b Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 23 Jul 2018 10:41:37 -0600 Subject: [PATCH 118/226] Always use addDefaultCredentials for private keys Automated tests from a command line will block while prompting for the passphrase of a private key if git.addCredentials() is used. No prompting seen if git.addDefaultCredentials() is used. Need to investigate the difference in behavior between those two cases. --- .../java/org/jenkinsci/plugins/gitclient/CredentialsTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index fc6a57dc07..e7166cc292 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -346,7 +346,9 @@ private String listDir(File dir) { } private void addCredential() throws IOException { - if (random.nextBoolean()) { + // Always use addDefaultCredentials for private keys + // addCredential stops tests to prompt for passphrase + if (random.nextBoolean() || this.privateKey != null) { git.addDefaultCredentials(testedCredential); } else { git.addCredentials(gitRepoURL, testedCredential); From 2b546f30210692e0b13dc57f0f272f3ef0191a22 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 23 Jul 2018 10:56:32 -0600 Subject: [PATCH 119/226] Add JENKINS-50573 test case When the fetch_() arguments included a URIish that is a remote name (like "origin") instead of a remote URL (like "git@github.com:jenkinsci/git-client-plugin.git"), the credential detection code inside the CliGitAPIImpl did not realize that the changes were required in the ssh based credentials. GitSCMFileSystem passes a remote name as the argument instead of passing the remote URL. Using the remote name is elegant, since it avoids a lookup of the remote name and relies on git to perform that lookup itself. --- .../java/org/jenkinsci/plugins/gitclient/CredentialsTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index e7166cc292..f8b789ab16 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -375,6 +375,8 @@ public void testFetchWithCredentials() throws URISyntaxException, GitException, /* Fetch with remote URL */ doFetch(gitRepoURL); git.setRemoteUrl("origin", gitRepoURL); + /* Fetch with remote name "origin" instead of remote URL */ + doFetch("origin"); ObjectId master = git.getHeadRev(gitRepoURL, "master"); log().println("Checking out " + master.getName().substring(0, 8) + " from " + gitRepoURL); git.checkout().branch("master").ref(master.getName()).deleteBranchIfExist(true).execute(); From 4a963edfaf691d0d4071a317ba1dcb69a6b386d7 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 23 Jul 2018 11:21:24 -0600 Subject: [PATCH 120/226] Fix [JENKINS-50573] by passing remoteURL to launchCommandWithCredentials CliGitAPIImpl.fetch_() takes an argument which includes a URIish that generally represents the URL to the remote git repository. However, there are places in the git plugin (like GitSCMFileSystem) where the caller uses the simplification of calling with the remote name ("origin") instead of the remote URL. That simplification avoids extracting or remembering the remote URL for a repository which is already established. Unfortunately, that simplification bypasses the code in CliGitAPIImpl which inspects the URL being used and decides if authentication needs to be adjusted to accomodate the incompatible change made in OpenSSH 7.7. OpenSSH 7.7 has made a sensible choice. The Jenkins git plugin relied on an undocumented and unexpected behavior of OpenSSH versions prior to OpenSSH 7.7. Passing the remoteURL allows the CliGitAPIImpl code to adapt to the OpenSSH 7.7 change. Refer to the closed OpenSSH 7.7 bug report at http://bugzilla.mindrot.org/show_bug.cgi?id=2849 Refer to the rejected OpenSSH pull request at https://github.com/openssh/openssh-portable/pull/91 Refer to the closed Git for Windows issue at https://github.com/git-for-windows/git/issues/1616 --- .../plugins/gitclient/CliGitAPIImpl.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index fba6065ac7..56a06062cc 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -402,7 +402,22 @@ public void execute() throws GitException, InterruptedException { warnIfWindowsTemporaryDirNameHasSpaces(); - launchCommandWithCredentials(args, workspace, cred, url, timeout); + /* If url looks like a remote name reference, convert to remote URL for authentication */ + /* See JENKINS-50573 for more details */ + /* "git remote add" rejects remote names with ':' (and it is a common character in remote URLs) */ + /* "git remote add" allows remote names with '@' but internal git parsing problems seem likely (and it is a common character in remote URLs) */ + /* "git remote add" allows remote names with '/' but git client plugin parsing problems will occur (and it is a common character in remote URLs) */ + /* "git remote add" allows remote names with '\' but git client plugin parsing problems will occur */ + URIish remoteUrl = url; + if (!url.isRemote() && !StringUtils.containsAny(url.toString(), ":@/\\")) { + try { + remoteUrl = new URIish(getRemoteUrl(url.toString())); + } catch (URISyntaxException e) { + listener.getLogger().println("Unexpected remote name or URL: '" + url + "'"); + } + } + + launchCommandWithCredentials(args, workspace, cred, remoteUrl, timeout); } }; } From bc96c6209cb166ee3b0376d62b78b9af09832245 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 23 Jul 2018 12:05:46 -0600 Subject: [PATCH 121/226] Adapt test to JGit 5.0.1 --- .../java/org/jenkinsci/plugins/gitclient/CredentialsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index 05de80ba39..df9e7aa031 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -377,7 +377,7 @@ public void testFetchWithCredentials() throws URISyntaxException, GitException, subcmd.execute(); } assertTrue("master: " + master + " not in repo", git.isCommitInRepo(master)); - assertEquals("Master != HEAD", master, git.getRepository().getRef("master").getObjectId()); + assertEquals("Master != HEAD", master, git.getRepository().findRef("master").getObjectId()); assertEquals("Wrong branch", "master", git.getRepository().getBranch()); assertTrue("No file " + fileToCheck + ", has " + listDir(repo), clonedFile.exists()); /* prune opens a remote connection to list remote branches */ From 603630de68c433c00bdd02a64dde3824c509ceb2 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 23 Jul 2018 13:46:12 -0600 Subject: [PATCH 122/226] Use Java 8 StringJoiner in CredentialsTest Cleaner code and easier to read. --- .../org/jenkinsci/plugins/gitclient/CredentialsTest.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index df9e7aa031..c87885a9ab 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Map; import java.util.Random; +import java.util.StringJoiner; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; @@ -326,13 +327,11 @@ private void doFetch(String source) throws InterruptedException, URISyntaxExcept private String listDir(File dir) { File[] files = repo.listFiles(); - StringBuilder fileList = new StringBuilder(); + StringJoiner joiner = new StringJoiner(","); for (File file : files) { - fileList.append(file.getName()); - fileList.append(','); + joiner.add(file.getName()); } - fileList.deleteCharAt(fileList.length() - 1); - return fileList.toString(); + return joiner.toString(); } private void addCredential() throws IOException { From 28864cfc008d0e14062b50b69f88112f09f38d7d Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 23 Jul 2018 14:52:14 -0600 Subject: [PATCH 123/226] Always use addDefaultCredentials in CredentialsTest addCredentials fails some github username / password tests addCredential stops some private key tests to prompt for passphrase --- .../jenkinsci/plugins/gitclient/CredentialsTest.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index c87885a9ab..acd47c2d91 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -335,13 +335,11 @@ private String listDir(File dir) { } private void addCredential() throws IOException { - // Always use addDefaultCredentials for private keys + // Always use addDefaultCredentials + git.addDefaultCredentials(testedCredential); // addCredential stops tests to prompt for passphrase - if (random.nextBoolean() || this.privateKey != null) { - git.addDefaultCredentials(testedCredential); - } else { - git.addCredentials(gitRepoURL, testedCredential); - } + // addCredentials fails some github username / password tests + // git.addCredentials(gitRepoURL, testedCredential); } /** From faa77de65f4d7434074258b0ca8eee14c2334f3f Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 23 Jul 2018 17:32:13 -0600 Subject: [PATCH 124/226] Set stop time based on longest Credentials test Control the upper bound on test execution by the duration of the longest running credentials test in this session. --- .../plugins/gitclient/CredentialsTest.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index acd47c2d91..1807463d59 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -102,6 +102,8 @@ public class CredentialsTest { private final static File CURR_DIR = new File("."); private static long firstTestStartTime = 0; + private static long longestTestDuration = 0; + private long currentTestStartTime = 0; private static PrintStream log() { return StreamTaskListener.fromStdout().getLogger(); @@ -130,6 +132,7 @@ public CredentialsTest(String gitImpl, String gitRepoUrl, String username, Strin if (firstTestStartTime == 0) { firstTestStartTime = System.currentTimeMillis(); } + currentTestStartTime = System.currentTimeMillis(); log().println(show("Repo", gitRepoUrl) + show("spec", specialCharacter) + show("impl", gitImpl) @@ -182,6 +185,14 @@ public void checkFingerprintNotSet() throws Exception { assertThat("Fingerprint should not be set after API level use", fingerprint, nullValue()); } + @After + public void recordLongestTestTime() { + long elapsedTime = System.currentTimeMillis() - currentTestStartTime; + if (elapsedTime > longestTestDuration) { + longestTestDuration = elapsedTime; + } + } + @After public void clearCredentials() { if (git != null) { @@ -343,13 +354,13 @@ private void addCredential() throws IOException { } /** - * Returns true if less than than 130 seconds have elapsed since start. + * Returns true if another test should be allowed to start. * JenkinsRule test timeout defaults to 180 seconds. * - * @return true if less than than 130 seconds have elapsed since start + * @return true if another test should be allowed to start */ private boolean testPeriodNotExpired() { - return (System.currentTimeMillis() - firstTestStartTime) < (130 * 1000L); + return (System.currentTimeMillis() - firstTestStartTime) < (180 * 1000L - 3 * longestTestDuration - 2000L); } @Test From 589cd95ecd5a95a03e0998c4b04276a1d0473411 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 23 Jul 2018 19:53:54 -0600 Subject: [PATCH 125/226] Annotate tests with @Issue("JENKINS-50573") --- .../org/jenkinsci/plugins/gitclient/CredentialsTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index 1807463d59..503ed59338 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -43,6 +43,7 @@ import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import org.json.simple.JSONObject; import org.json.simple.JSONArray; @@ -364,6 +365,7 @@ private boolean testPeriodNotExpired() { } @Test + @Issue("JENKINS_50573") public void testFetchWithCredentials() throws URISyntaxException, GitException, InterruptedException, MalformedURLException, IOException { assumeTrue(testPeriodNotExpired()); File clonedFile = new File(repo, fileToCheck); @@ -415,6 +417,13 @@ public void testRemoteReferencesWithCredentials() throws Exception { assertThat(remoteReferences.keySet(), hasItems("refs/heads/master")); } + @Test + @Issue("JENKINS_50573") + public void isURIishRemote() throws Exception { + URIish uri = new URIish(gitRepoURL); + assertTrue("Should be remote but isn't: " + uri, uri.isRemote()); + } + private String show(String name, String value) { if (value != null && !value.isEmpty()) { return " " + name + ": '" + value + "'"; From 139ab0a613ee0d109e011c52189c70e0bf201f15 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 23 Jul 2018 17:32:13 -0600 Subject: [PATCH 126/226] Set stop time based on longest Credentials test Control the upper bound on test execution by the duration of the longest running credentials test in this session. --- .../plugins/gitclient/CredentialsTest.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index f8b789ab16..f4bcc14ef4 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -101,6 +101,8 @@ public class CredentialsTest { private final static File CURR_DIR = new File("."); private static long firstTestStartTime = 0; + private static long longestTestDuration = 0; + private long currentTestStartTime = 0; private static PrintStream log() { return StreamTaskListener.fromStdout().getLogger(); @@ -129,6 +131,7 @@ public CredentialsTest(String gitImpl, String gitRepoUrl, String username, Strin if (firstTestStartTime == 0) { firstTestStartTime = System.currentTimeMillis(); } + currentTestStartTime = System.currentTimeMillis(); log().println(show("Repo", gitRepoUrl) + show("spec", specialCharacter) + show("impl", gitImpl) @@ -181,6 +184,14 @@ public void checkFingerprintNotSet() throws Exception { assertThat("Fingerprint should not be set after API level use", fingerprint, nullValue()); } + @After + public void recordLongestTestTime() { + long elapsedTime = System.currentTimeMillis() - currentTestStartTime; + if (elapsedTime > longestTestDuration) { + longestTestDuration = elapsedTime; + } + } + @After public void clearCredentials() { if (git != null) { @@ -356,13 +367,13 @@ private void addCredential() throws IOException { } /** - * Returns true if less than than 130 seconds have elapsed since start. + * Returns true if another test should be allowed to start. * JenkinsRule test timeout defaults to 180 seconds. * - * @return true if less than than 130 seconds have elapsed since start + * @return true if another test should be allowed to start */ private boolean testPeriodNotExpired() { - return (System.currentTimeMillis() - firstTestStartTime) < (130 * 1000L); + return (System.currentTimeMillis() - firstTestStartTime) < (180 * 1000L - 3 * longestTestDuration - 2000L); } @Test From eb8db943eebb089de333aa1b0a3d8b02cf5cd2fa Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 23 Jul 2018 14:52:14 -0600 Subject: [PATCH 127/226] Always use addDefaultCredentials in CredentialsTest addCredentials fails some github username / password tests addCredential stops some private key tests to prompt for passphrase --- .../jenkinsci/plugins/gitclient/CredentialsTest.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index f4bcc14ef4..16b853f2da 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -357,13 +357,11 @@ private String listDir(File dir) { } private void addCredential() throws IOException { - // Always use addDefaultCredentials for private keys + // Always use addDefaultCredentials + git.addDefaultCredentials(testedCredential); // addCredential stops tests to prompt for passphrase - if (random.nextBoolean() || this.privateKey != null) { - git.addDefaultCredentials(testedCredential); - } else { - git.addCredentials(gitRepoURL, testedCredential); - } + // addCredentials fails some github username / password tests + // git.addCredentials(gitRepoURL, testedCredential); } /** From 99a70bbfae66ee4c767211d14eeb953be413c4c6 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 23 Jul 2018 11:46:37 -0600 Subject: [PATCH 128/226] Remove ssh related comment from https username/password code segment A comment about ssh authentication does not help the reader of the code when it appears in a section which is using username/password instead of private keys. GIT_ASKPASS provides the path to the script which will be called to answer git's prompt for credentials. SSH_ASKPASS is likely not needed in this section of the code, since the code is handling http and https, not ssh private keys. --- src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 56a06062cc..32dd98e590 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -1699,7 +1699,6 @@ private String launchCommandWithCredentials(ArgumentListBuilder args, File workD env = new EnvVars(env); env.put("GIT_ASKPASS", askpass.getAbsolutePath()); - // SSH binary does not recognize GIT_ASKPASS, so set SSH_ASKPASS also, in the case we have an ssh:// URL env.put("SSH_ASKPASS", askpass.getAbsolutePath()); } From ffbd2245b8471c98072c38fd39708e1dec583551 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Tue, 24 Jul 2018 06:18:11 -0600 Subject: [PATCH 129/226] Increase credentials test timeout buffer On heavily loaded machines in my test cluster the timeout buffer was not enough to prevent the tests from reaching the 180 second timeout of the JenkinsRule. --- .../java/org/jenkinsci/plugins/gitclient/CredentialsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index 16b853f2da..6247c76979 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -371,7 +371,7 @@ private void addCredential() throws IOException { * @return true if another test should be allowed to start */ private boolean testPeriodNotExpired() { - return (System.currentTimeMillis() - firstTestStartTime) < (180 * 1000L - 3 * longestTestDuration - 2000L); + return (System.currentTimeMillis() - firstTestStartTime) < (180 * 1000L - 4 * longestTestDuration - 2000L); } @Test From 9c769b916e2c50bb8da2cd488bb73772c68dd355 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Tue, 24 Jul 2018 12:19:45 -0600 Subject: [PATCH 130/226] Add no tests after 120 secs in credentials test Previous attempts failed trying to use an algorithmic technique to maximize test time on fast machines. Two minutes of credential testing still provides a good sampling of the authentication test cases. --- .../plugins/gitclient/CredentialsTest.java | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index 6247c76979..d5e1f3fbb9 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -101,8 +101,6 @@ public class CredentialsTest { private final static File CURR_DIR = new File("."); private static long firstTestStartTime = 0; - private static long longestTestDuration = 0; - private long currentTestStartTime = 0; private static PrintStream log() { return StreamTaskListener.fromStdout().getLogger(); @@ -131,7 +129,6 @@ public CredentialsTest(String gitImpl, String gitRepoUrl, String username, Strin if (firstTestStartTime == 0) { firstTestStartTime = System.currentTimeMillis(); } - currentTestStartTime = System.currentTimeMillis(); log().println(show("Repo", gitRepoUrl) + show("spec", specialCharacter) + show("impl", gitImpl) @@ -184,14 +181,6 @@ public void checkFingerprintNotSet() throws Exception { assertThat("Fingerprint should not be set after API level use", fingerprint, nullValue()); } - @After - public void recordLongestTestTime() { - long elapsedTime = System.currentTimeMillis() - currentTestStartTime; - if (elapsedTime > longestTestDuration) { - longestTestDuration = elapsedTime; - } - } - @After public void clearCredentials() { if (git != null) { @@ -371,7 +360,7 @@ private void addCredential() throws IOException { * @return true if another test should be allowed to start */ private boolean testPeriodNotExpired() { - return (System.currentTimeMillis() - firstTestStartTime) < (180 * 1000L - 4 * longestTestDuration - 2000L); + return (System.currentTimeMillis() - firstTestStartTime) < ((180 - 60) * 1000L); } @Test From 9d60ef490a2a4f6b1b0ca82328a2e051e9b1d559 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Tue, 24 Jul 2018 12:35:26 -0600 Subject: [PATCH 131/226] [maven-release-plugin] prepare release git-client-2.7.3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c233716c2e..17dd2aefbc 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins git-client - 2.7.3-SNAPSHOT + 2.7.3 hpi Jenkins Git client plugin @@ -38,7 +38,7 @@ scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git https://github.com/jenkinsci/${project.artifactId}-plugin - HEAD + git-client-2.7.3 From 0b2d2f45f48a747d7c264a119364d0d08c6034a9 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Tue, 24 Jul 2018 12:35:32 -0600 Subject: [PATCH 132/226] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 17dd2aefbc..496f609768 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins git-client - 2.7.3 + 2.7.4-SNAPSHOT hpi Jenkins Git client plugin @@ -38,7 +38,7 @@ scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git https://github.com/jenkinsci/${project.artifactId}-plugin - git-client-2.7.3 + HEAD From b6c4e3a718b96999e4574c933a5dcc9e4b977ddc Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Tue, 24 Jul 2018 17:06:47 -0600 Subject: [PATCH 133/226] [maven-release-plugin] prepare release git-client-3.0.0-beta4 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 7615eb787c..eb6fa43625 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins git-client - ${revision}${changelist} + 3.0.0-beta4 hpi Jenkins Git client plugin @@ -38,7 +38,7 @@ scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git https://github.com/jenkinsci/${project.artifactId}-plugin - ${scmTag} + git-client-3.0.0-beta4 From d32a38e4f79f907f1203debb865cb12027541ae7 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Tue, 24 Jul 2018 17:06:53 -0600 Subject: [PATCH 134/226] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index eb6fa43625..24da026422 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins git-client - 3.0.0-beta4 + 3.0.0-beta5-SNAPSHOT hpi Jenkins Git client plugin @@ -38,7 +38,7 @@ scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git https://github.com/jenkinsci/${project.artifactId}-plugin - git-client-3.0.0-beta4 + ${scmTag} From c6d6cb6daef2a3f2a2a9beddd5ae0e2a16a90cb9 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Tue, 24 Jul 2018 17:11:10 -0600 Subject: [PATCH 135/226] Run mvn incrementals:reincrementalify Needed after mvn release:prepare release:perform --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 24da026422..86b4aa3451 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins git-client - 3.0.0-beta5-SNAPSHOT + ${revision}${changelist} hpi Jenkins Git client plugin @@ -42,7 +42,7 @@ - 3.0.0-beta4 + 3.0.0-beta5 -SNAPSHOT UTF-8 -Dfile.encoding=${project.build.sourceEncoding} From 71ffde990cfab74f3df2326b4c373f7c571acc70 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 7 Jul 2018 15:28:45 -0600 Subject: [PATCH 136/226] Assert annotated tag is null The earlier assertNotEquals was not as strong as a specific assertion that in the case of command line git, it is expected that an annotated tag will not be found (and will thus return null). It is a strange condition that getHeadRev for an annotated tag returns null from command line git and returns non-null from JGit, but that is the reality. --- .../java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 871a9d1de3..85df77996b 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -1612,7 +1612,7 @@ public void test_create_tag() throws Exception { if (w.git instanceof JGitAPIImpl) { assertEquals("Annotated tag does not match SHA1", init, testTag); } else { - assertNotEquals("Annotated tag unexpectedly equals SHA1", init, testTag); + assertNull("Annotated tag unexpectedly not null", testTag); } /* Because refs/tags/test syntax is more specific than "test", From c4bd385d1f762c8b1e96eb430b269cf0e190547a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sun, 15 Jul 2018 21:43:57 +0200 Subject: [PATCH 137/226] Improve create tag test readability --- .../plugins/gitclient/GitAPITestCase.java | 56 +++++++++---------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 85df77996b..55b37f37e0 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -8,7 +8,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; import static org.jenkinsci.plugins.gitclient.StringSharesPrefix.sharesPrefix; -import static org.junit.Assert.*; import hudson.FilePath; import hudson.Launcher; @@ -73,8 +72,6 @@ import org.jvnet.hudson.test.TemporaryDirectoryAllocator; import org.objenesis.ObjenesisStd; -import com.google.common.base.Function; -import com.google.common.base.Predicate; import com.google.common.collect.Collections2; /** @@ -1597,38 +1594,39 @@ public void test_create_tag() throws Exception { w.init(); String gitDir = w.repoPath() + File.separator + ".git"; w.commitEmpty("init"); - ObjectId init = w.git.revParse("HEAD"); // Remember SHA1 of init commit - w.git.tag("test", "this is a tag"); - - /* JGit seems to have the better behavior in this case, always - * returning the SHA1 of the commit. Most users are using - * command line git, so the difference is retained in command - * line git for compatibility with any legacy command line git - * use cases which depend on returning the SHA-1 of the - * annotated tag rather than the SHA-1 of the commit to which - * the annotated tag points. + ObjectId commitId = w.git.revParse("HEAD"); + w.git.tag("test", "this is an annotated tag"); + + /* + * Spec: "test" (short tag syntax) + * CliGit does not support this syntax for remotes. + * JGit fully supports this syntax. */ - ObjectId testTag = w.git.getHeadRev(gitDir, "test"); // Remember SHA1 of annotated test tag + String shortTagRef = "test"; + ObjectId tagHeadIdByShortRef = w.git.getHeadRev(gitDir, shortTagRef); if (w.git instanceof JGitAPIImpl) { - assertEquals("Annotated tag does not match SHA1", init, testTag); + assertEquals("annotated tag does not match commit SHA1", commitId, tagHeadIdByShortRef); } else { - assertNull("Annotated tag unexpectedly not null", testTag); + assertNull("annotated tag unexpectedly not null", tagHeadIdByShortRef); } + assertEquals("annotated tag does not match commit SHA1", commitId, w.git.revParse(shortTagRef)); - /* Because refs/tags/test syntax is more specific than "test", - * and because the more specific syntax was only introduced in - * more recent git client plugin versions (like 1.10.0 and - * later), the CliGit and JGit behavior are kept the same here - * in order to fix JENKINS-23299. + /* + * Spec: "refs/tags/test" (more specific tag syntax) + * CliGit and JGit fully support this syntax. */ - ObjectId testTagCommit = w.git.getHeadRev(gitDir, "refs/tags/test"); // SHA1 of commit identified by test tag - assertEquals("Annotated tag doesn't match queried commit SHA1", init, testTagCommit); - assertEquals(init, w.git.revParse("test")); // SHA1 of commit identified by test tag - assertEquals(init, w.git.revParse("refs/tags/test")); // SHA1 of commit identified by test tag - assertTrue("test tag not created", w.cmd("git tag").contains("test")); - String message = w.cmd("git tag -l -n1"); - assertTrue("unexpected test tag message : " + message, message.contains("this is a tag")); - assertNull(w.git.getHeadRev(gitDir, "not-a-valid-tag")); // Confirm invalid tag returns null + String longTagRef = "refs/tags/test"; + assertEquals("annotated tag does not match commit SHA1", commitId, w.git.getHeadRev(gitDir, longTagRef)); + assertEquals("annotated tag does not match commit SHA1", commitId, w.git.revParse(longTagRef)); + + String tagNames = w.cmd("git tag -l").trim(); + assertEquals("tag not created", "test", tagNames); + + String tagNamesWithMessages = w.cmd("git tag -l -n1"); + assertTrue("unexpected tag message : " + tagNamesWithMessages, tagNamesWithMessages.contains("this is an annotated tag")); + + ObjectId invalidTagId = w.git.getHeadRev(gitDir, "not-a-valid-tag"); + assertNull("did not expect reference for invalid tag but got : " + invalidTagId, invalidTagId); } public void test_delete_tag() throws Exception { From f8b605f9d44c4d7e8ef98006b559488bc6e33736 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Thu, 19 Jul 2018 22:29:23 -0600 Subject: [PATCH 138/226] Update test comment to match actual behavior --- .../org/jenkinsci/plugins/gitclient/GitAPITestCase.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 55b37f37e0..4182ef0d53 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -1601,6 +1601,13 @@ public void test_create_tag() throws Exception { * Spec: "test" (short tag syntax) * CliGit does not support this syntax for remotes. * JGit fully supports this syntax. + * + * JGit seems to have the better behavior in this case, always + * returning the SHA1 of the commit. Most users are using + * command line git, so the difference is retained in command + * line git for compatibility with any legacy command line git + * use cases which depend on returning null rather than the + * SHA-1 of the commit to which the annotated tag points. */ String shortTagRef = "test"; ObjectId tagHeadIdByShortRef = w.git.getHeadRev(gitDir, shortTagRef); From 34389bc45d3276d4574eb8397afc4d452d2f13df Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 25 Jul 2018 07:21:17 -0600 Subject: [PATCH 139/226] Prevent [failed-to-read] test failure reports The Jenkins jobs in my environment have been reporting: TEST-org.jenkinsci.plugins.gitclient.CredentialsTest.xml.[failed-to-read] I assume the failure is caused by a JUnit results file that is read by Jenkins before the tests are complete. Since the credentials test in my environment runs for at least 120 seconds and writes manny debugging messages, I assume the file is incomplete until test execution has finished. The hope is that this change will reduce the file size enough that Jenkins won't see an incomplete test result. --- .../plugins/gitclient/CredentialsTest.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index e83d231091..68065c374c 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -106,10 +106,6 @@ public class CredentialsTest { private static long longestTestDuration = 0; private long currentTestStartTime = 0; - private static PrintStream log() { - return StreamTaskListener.fromStdout().getLogger(); - } - /* Windows refuses directory names with '*', '<', '>', '|', '?', and ':' */ private final String SPECIALS_TO_CHECK = "%()`$&{}[]" + (isWindows() ? "" : "*<>:|?"); @@ -134,12 +130,6 @@ public CredentialsTest(String gitImpl, String gitRepoUrl, String username, Strin firstTestStartTime = System.currentTimeMillis(); } currentTestStartTime = System.currentTimeMillis(); - log().println(show("Repo", gitRepoUrl) - + show("spec", specialCharacter) - + show("impl", gitImpl) - + show("user", username) - + show("pass", password) - + show("key", privateKey)); } @Before @@ -162,7 +152,6 @@ public void setUp() throws IOException, InterruptedException { logger.addHandler(handler); logger.setLevel(Level.ALL); listener = new hudson.util.LogTaskListener(logger, Level.ALL); - listener.getLogger().println(LOGGING_STARTED); git = Git.with(listener, new hudson.EnvVars()).in(repo).using(gitImpl).getClient(); assertTrue("Bad username, password, privateKey combo: '" + username + "', '" + password + "'", @@ -378,10 +367,8 @@ public void testFetchWithCredentials() throws URISyntaxException, GitException, /* Fetch with remote name "origin" instead of remote URL */ doFetch("origin"); ObjectId master = git.getHeadRev(gitRepoURL, "master"); - log().println("Checking out " + master.getName().substring(0, 8) + " from " + gitRepoURL); git.checkout().branch("master").ref(master.getName()).deleteBranchIfExist(true).execute(); if (submodules) { - log().println("Initializing submodules from " + gitRepoURL); git.submoduleInit(); SubmoduleUpdateCommand subcmd = git.submoduleUpdate().parentCredentials(useParentCreds); subcmd.execute(); From 74d12cbca78d6b29b40ada78931fc50347511f64 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 25 Jul 2018 07:21:17 -0600 Subject: [PATCH 140/226] Prevent [failed-to-read] test failure reports The Jenkins jobs in my environment have been reporting: TEST-org.jenkinsci.plugins.gitclient.CredentialsTest.xml.[failed-to-read] I assume the failure is caused by a JUnit results file that is read by Jenkins before the tests are complete. Since the credentials test in my environment runs for at least 120 seconds and writes manny debugging messages, I assume the file is incomplete until test execution has finished. The hope is that this change will reduce the file size enough that Jenkins won't see an incomplete test result. --- .../plugins/gitclient/CredentialsTest.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index d5e1f3fbb9..c371429430 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -102,10 +102,6 @@ public class CredentialsTest { private static long firstTestStartTime = 0; - private static PrintStream log() { - return StreamTaskListener.fromStdout().getLogger(); - } - /* Windows refuses directory names with '*', '<', '>', '|', '?', and ':' */ private final String SPECIALS_TO_CHECK = "%()`$&{}[]" + (isWindows() ? "" : "*<>:|?"); @@ -129,12 +125,6 @@ public CredentialsTest(String gitImpl, String gitRepoUrl, String username, Strin if (firstTestStartTime == 0) { firstTestStartTime = System.currentTimeMillis(); } - log().println(show("Repo", gitRepoUrl) - + show("spec", specialCharacter) - + show("impl", gitImpl) - + show("user", username) - + show("pass", password) - + show("key", privateKey)); } @Before @@ -157,7 +147,6 @@ public void setUp() throws IOException, InterruptedException { logger.addHandler(handler); logger.setLevel(Level.ALL); listener = new hudson.util.LogTaskListener(logger, Level.ALL); - listener.getLogger().println(LOGGING_STARTED); git = Git.with(listener, new hudson.EnvVars()).in(repo).using(gitImpl).getClient(); assertTrue("Bad username, password, privateKey combo: '" + username + "', '" + password + "'", @@ -376,10 +365,8 @@ public void testFetchWithCredentials() throws URISyntaxException, GitException, /* Fetch with remote name "origin" instead of remote URL */ doFetch("origin"); ObjectId master = git.getHeadRev(gitRepoURL, "master"); - log().println("Checking out " + master.getName().substring(0, 8) + " from " + gitRepoURL); git.checkout().branch("master").ref(master.getName()).deleteBranchIfExist(true).execute(); if (submodules) { - log().println("Initializing submodules from " + gitRepoURL); git.submoduleInit(); SubmoduleUpdateCommand subcmd = git.submoduleUpdate().parentCredentials(useParentCreds); subcmd.execute(); From b353f4b69a345b00c5a7be15cf8c38714b15a8c0 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 25 Jul 2018 08:40:20 -0600 Subject: [PATCH 141/226] Limit credentials test to one minute instead of two Hope to avoid the premature reading of the test results file --- .../java/org/jenkinsci/plugins/gitclient/CredentialsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index c371429430..e6663d34fa 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -349,7 +349,7 @@ private void addCredential() throws IOException { * @return true if another test should be allowed to start */ private boolean testPeriodNotExpired() { - return (System.currentTimeMillis() - firstTestStartTime) < ((180 - 60) * 1000L); + return (System.currentTimeMillis() - firstTestStartTime) < ((180 - 120) * 1000L); } @Test From 5237c21c62a218ff55d7fecee4a3e5f2ba33d7ea Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 25 Jul 2018 08:40:20 -0600 Subject: [PATCH 142/226] Limit credentials test to one minute instead of two Hope to avoid the premature reading of the test results file --- .../java/org/jenkinsci/plugins/gitclient/CredentialsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index 68065c374c..8eb24a3972 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -350,7 +350,7 @@ private void addCredential() throws IOException { * @return true if another test should be allowed to start */ private boolean testPeriodNotExpired() { - return (System.currentTimeMillis() - firstTestStartTime) < ((180 - 60) * 1000L); + return (System.currentTimeMillis() - firstTestStartTime) < ((180 - 120) * 1000L); } @Test From bb2a5143263e9105980428548982bddc337b80ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sun, 15 Jul 2018 15:34:50 +0200 Subject: [PATCH 143/226] Improve tests that are system locale dependent This is a follow-up to de9da9a7f942e113b919b200b1811332acdb6aeb. --- .../plugins/gitclient/GitAPITestCase.java | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 4182ef0d53..1cd1b3bb41 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -848,7 +848,7 @@ public void test_clean_with_parameter() throws Exception { } - @Issue("JENKINS-20410") + @Issue({"JENKINS-20410", "JENKINS-27910", "JENKINS-22434"}) public void test_clean() throws Exception { w.init(); w.commitEmpty("init"); @@ -862,28 +862,27 @@ public void test_clean() throws Exception { */ String fileName = "\uD835\uDD65-\u5c4f\u5e55\u622a\u56fe-\u0041\u030a-\u00c5-\u212b-fileName.xml"; w.touch(fileName, "content " + fileName); - try { + withSystemLocaleReporting(fileName, () -> { w.git.add(fileName); - } catch (GitException ge) { - // Exception should contain actual file name - // If mangled name is seen instead, throw a clear exception to indicate root cause - assertTrue("System locale does not support filename '" + fileName + "'", ge.getMessage().contains("?-????-A?-?-?-fileName.xml")); - throw ge; // Fail the test on exception even if the preceding assertion did not fail - } - w.git.commit(fileName); + w.git.commit(fileName); + }); /* JENKINS-27910 reported that certain cyrillic file names * failed to delete if the encoding was not UTF-8. */ String fileNameSwim = "\u00d0\u00bf\u00d0\u00bb\u00d0\u00b0\u00d0\u00b2\u00d0\u00b0\u00d0\u00bd\u00d0\u00b8\u00d0\u00b5-swim.png"; w.touch(fileNameSwim, "content " + fileNameSwim); - w.git.add(fileNameSwim); - w.git.commit(fileNameSwim); + withSystemLocaleReporting(fileNameSwim, () -> { + w.git.add(fileNameSwim); + w.git.commit(fileNameSwim); + }); String fileNameFace = "\u00d0\u00bb\u00d0\u00b8\u00d1\u2020\u00d0\u00be-face.png"; w.touch(fileNameFace, "content " + fileNameFace); - w.git.add(fileNameFace); - w.git.commit(fileNameFace); + withSystemLocaleReporting(fileNameFace, () -> { + w.git.add(fileNameFace); + w.git.commit(fileNameFace); + }); w.touch(".gitignore", ".test"); w.git.add(".gitignore"); @@ -4624,4 +4623,21 @@ private boolean isWindows() { return File.pathSeparatorChar==';'; } + private void withSystemLocaleReporting(String fileName, TestedCode code) throws Exception { + try { + code.run(); + } catch (GitException ge) { + // Exception message should contain the actual file name. + // It may just contain ? for characters that are not encoded correctly due to the system locale. + // If such a mangled file name is seen instead, throw a clear exception to indicate the root cause. + assertTrue("System locale does not support filename '" + fileName + "'", ge.getMessage().contains("?")); + // Rethrow exception for all other issues. + throw ge; + } + } + + @FunctionalInterface + interface TestedCode { + void run() throws Exception; + } } From e4c210af36bf29b491859e872c18907d4fe37778 Mon Sep 17 00:00:00 2001 From: Fujii Hironori Date: Thu, 8 Mar 2018 17:42:35 -0800 Subject: [PATCH 144/226] [JENKINS-21248] Support shallow submodule update --- .../plugins/gitclient/CliGitAPIImpl.java | 18 ++++++++++++++++++ .../plugins/gitclient/JGitAPIImpl.java | 14 ++++++++++++++ .../gitclient/SubmoduleUpdateCommand.java | 17 +++++++++++++++++ .../plugins/gitclient/GitAPITestCase.java | 12 ++++++++++++ 4 files changed, 61 insertions(+) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index f0d4e0dc88..617b6f0edf 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -1067,9 +1067,11 @@ public SubmoduleUpdateCommand submoduleUpdate() { boolean recursive = false; boolean remoteTracking = false; boolean parentCredentials = false; + boolean shallow = false; String ref = null; Map submodBranch = new HashMap<>(); public Integer timeout; + public Integer depth = 1; public SubmoduleUpdateCommand recursive(boolean recursive) { this.recursive = recursive; @@ -1101,6 +1103,16 @@ public SubmoduleUpdateCommand timeout(Integer timeout) { return this; } + public SubmoduleUpdateCommand shallow(boolean shallow) { + this.shallow = shallow; + return this; + } + + public SubmoduleUpdateCommand depth(Integer depth) { + this.depth = depth; + return this; + } + /** * @throws GitException if executing the Git command fails * @throws InterruptedException if called methods throw same exception @@ -1131,6 +1143,12 @@ else if (!referencePath.isDirectory()) else args.add("--reference", ref); } + if (shallow) { + if (depth == null){ + depth = 1; + } + args.add("--depth=" + depth); + } // We need to call submodule update for each configured diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index 2dbdde6e29..b99ef489f3 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -2184,6 +2184,7 @@ public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand submoduleUpdate() return new org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand() { boolean recursive = false; boolean remoteTracking = false; + boolean shallow = false; String ref = null; @Override @@ -2216,6 +2217,15 @@ public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand timeout(Integer ti return this; } + public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand shallow(boolean shallow) { + this.shallow = shallow; + return this; + } + + public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand depth(Integer depth) { + return this; + } + @Override public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand useBranch(String submodule, String branchname) { return this; @@ -2231,6 +2241,10 @@ public void execute() throws GitException, InterruptedException { listener.getLogger().println("[ERROR] JGit doesn't support submodule update --reference yet."); throw new UnsupportedOperationException("not implemented yet"); } + if (shallow) { + listener.getLogger().println("[ERROR] JGit doesn't support shallow submodules yet."); + throw new UnsupportedOperationException("not implemented yet"); + } try (Repository repo = getRepository()) { SubmoduleUpdateCommand update = git(repo).submoduleUpdate(); diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/SubmoduleUpdateCommand.java b/src/main/java/org/jenkinsci/plugins/gitclient/SubmoduleUpdateCommand.java index ada0c10ad6..e4f55c2df3 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/SubmoduleUpdateCommand.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/SubmoduleUpdateCommand.java @@ -58,4 +58,21 @@ public interface SubmoduleUpdateCommand extends GitCommand { * @return a {@link org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand} object. */ SubmoduleUpdateCommand timeout(Integer timeout); + + /** + * shallow. + * + * @param shallow a boolean. + * @return a {@link org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand} object. + */ + SubmoduleUpdateCommand shallow(boolean shallow); + + /** + * When shallow cloning, allow for a depth to be set in cases where you need more than the immediate last commit. + * Has no effect if shallow is set to false (default) + * + * @param depth number of revisions to be included in shallow clone + * @return a {@link org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand} object. + */ + SubmoduleUpdateCommand depth(Integer depth); } diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 1cd1b3bb41..6f2ceacc12 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -2588,6 +2588,18 @@ public void test_submodule_update() throws Exception { assertFixSubmoduleUrlsThrows(); } + @NotImplementedInJGit + public void test_submodule_update_shallow() throws Exception { + w.init(); + w.git.clone_().url(localMirror()).repositoryName("sub2_origin").execute(); + w.git.checkout().branch("tests/getRelativeSubmodule").ref("sub2_origin/tests/getRelativeSubmodule").deleteBranchIfExist(true).execute(); + w.git.submoduleInit(); + w.git.submoduleUpdate().shallow(true).execute(); + + final String shallow = ".git" + File.separator + "modules" + File.separator + "sub" + File.separator + "shallow"; + assertTrue("Shallow file does not exist: " + shallow, w.exists(shallow)); + } + @NotImplementedInJGit public void test_trackingSubmoduleBranches() throws Exception { if (! ((CliGitAPIImpl)w.git).isAtLeastVersion(1,8,2,0)) { From e7540f365376607815a5419096aa09b1e69e088f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sun, 29 Jul 2018 14:45:26 +0200 Subject: [PATCH 145/226] Make shallow clone & fetch tests more consistent & clear --- .../plugins/gitclient/GitAPITestCase.java | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 6f2ceacc12..bcdc2c423d 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -556,12 +556,13 @@ public void test_clone_shallow() throws Exception assertBranchesExist(w.git.getBranches(), "master"); assertAlternatesFileNotFound(); /* JGit does not support shallow clone */ - assertEquals("isShallow?", w.igit() instanceof CliGitAPIImpl, w.cgit().isShallowRepository()); - final String shallow = ".git" + File.separator + "shallow"; - assertEquals("Shallow file existence: " + shallow, w.igit() instanceof CliGitAPIImpl, w.exists(shallow)); + boolean hasShallowCloneSupport = w.git instanceof CliGitAPIImpl && w.cgit().isAtLeastVersion(1, 5, 0, 0); + assertEquals("isShallow?", hasShallowCloneSupport, w.cgit().isShallowRepository()); + String shallow = ".git" + File.separator + "shallow"; + assertEquals("shallow file existence: " + shallow, hasShallowCloneSupport, w.exists(shallow)); } - public void test_clone_shallow_with_depth() throws IOException, InterruptedException + public void test_clone_shallow_with_depth() throws Exception { w.git.clone_().url(localMirror()).repositoryName("origin").shallow(true).depth(2).execute(); w.git.checkout("origin/master", "master"); @@ -569,8 +570,10 @@ public void test_clone_shallow_with_depth() throws IOException, InterruptedExcep assertBranchesExist(w.git.getBranches(), "master"); assertAlternatesFileNotFound(); /* JGit does not support shallow clone */ - final String shallow = ".git" + File.separator + "shallow"; - assertEquals("Shallow file existence: " + shallow, w.igit() instanceof CliGitAPIImpl, w.exists(shallow)); + boolean hasShallowCloneSupport = w.git instanceof CliGitAPIImpl && w.cgit().isAtLeastVersion(1, 5, 0, 0); + assertEquals("isShallow?", hasShallowCloneSupport, w.cgit().isShallowRepository()); + String shallow = ".git" + File.separator + "shallow"; + assertEquals("shallow file existence: " + shallow, hasShallowCloneSupport, w.exists(shallow)); } public void test_clone_shared() throws IOException, InterruptedException @@ -1401,9 +1404,11 @@ public void test_fetch_shallow() throws Exception { assertBranchesExist(w.git.getRemoteBranches(), "origin/master"); final String alternates = ".git" + File.separator + "objects" + File.separator + "info" + File.separator + "alternates"; assertFalse("Alternates file found: " + alternates, w.exists(alternates)); - /* JGit does not support shallow clone */ - final String shallow = ".git" + File.separator + "shallow"; - assertEquals("Shallow file: " + shallow, w.igit() instanceof CliGitAPIImpl, w.exists(shallow)); + /* JGit does not support shallow fetch */ + boolean hasShallowFetchSupport = w.git instanceof CliGitAPIImpl && w.cgit().isAtLeastVersion(1, 5, 0, 0); + assertEquals("isShallow?", hasShallowFetchSupport, w.cgit().isShallowRepository()); + String shallow = ".git" + File.separator + "shallow"; + assertEquals("shallow file existence: " + shallow, hasShallowFetchSupport, w.exists(shallow)); } public void test_fetch_shallow_depth() throws Exception { @@ -1414,9 +1419,11 @@ public void test_fetch_shallow_depth() throws Exception { assertBranchesExist(w.git.getRemoteBranches(), "origin/master"); final String alternates = ".git" + File.separator + "objects" + File.separator + "info" + File.separator + "alternates"; assertFalse("Alternates file found: " + alternates, w.exists(alternates)); - /* JGit does not support shallow clone */ - final String shallow = ".git" + File.separator + "shallow"; - assertEquals("Shallow file: " + shallow, w.igit() instanceof CliGitAPIImpl, w.exists(shallow)); + /* JGit does not support shallow fetch */ + boolean hasShallowFetchSupport = w.git instanceof CliGitAPIImpl && w.cgit().isAtLeastVersion(1, 5, 0, 0); + assertEquals("isShallow?", hasShallowFetchSupport, w.cgit().isShallowRepository()); + String shallow = ".git" + File.separator + "shallow"; + assertEquals("shallow file existence: " + shallow, hasShallowFetchSupport, w.exists(shallow)); } public void test_fetch_noTags() throws Exception { From b3f7b6b5ab3a88a0b5ae70205869051553a9b2c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sat, 28 Jul 2018 23:08:02 +0200 Subject: [PATCH 146/226] [JENKINS-21248] Improve shallow submodule update implementation * in case the used git does not support shallow submodules, just log a warning instead of throwing an exception * Javadoc texts are used from the already existing CloneCommand * tests are running fine now and cover more cases * file:// has to be used as protocol for local remotes, otherwise git doesn't perform shallow cloning * a local repository has to be used for shallow clone testing, because GitHub doesn't allow fetching dedicated commits * see https://github.com/isaacs/github/issues/436 * this would result in the following error: Server does not allow request for unadvertised object * other minor improvements --- .../plugins/gitclient/CliGitAPIImpl.java | 13 ++-- .../plugins/gitclient/CloneCommand.java | 2 +- .../plugins/gitclient/JGitAPIImpl.java | 14 ++-- .../gitclient/SubmoduleUpdateCommand.java | 9 +-- .../plugins/gitclient/GitAPITestCase.java | 66 +++++++++++++++++-- 5 files changed, 81 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 617b6f0edf..bc6782c657 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -394,7 +394,7 @@ public void execute() throws GitException, InterruptedException { if (prune) args.add("--prune"); if (shallow) { - if (depth == null){ + if (depth == null) { depth = 1; } args.add("--depth=" + depth); @@ -1071,7 +1071,7 @@ public SubmoduleUpdateCommand submoduleUpdate() { String ref = null; Map submodBranch = new HashMap<>(); public Integer timeout; - public Integer depth = 1; + Integer depth = 1; public SubmoduleUpdateCommand recursive(boolean recursive) { this.recursive = recursive; @@ -1144,13 +1144,16 @@ else if (!referencePath.isDirectory()) args.add("--reference", ref); } if (shallow) { - if (depth == null){ + if (depth == null) { depth = 1; } - args.add("--depth=" + depth); + if (isAtLeastVersion(1, 8, 4, 0)) { + args.add("--depth=" + depth); + } else { + listener.getLogger().println("[WARNING] Git client older than 1.8.4 doesn't support shallow submodule updates. This flag is ignored."); + } } - // We need to call submodule update for each configured // submodule. Note that we can't reliably depend on the // getSubmodules() since it is possible "HEAD" doesn't exist, diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CloneCommand.java b/src/main/java/org/jenkinsci/plugins/gitclient/CloneCommand.java index 6c357cd8a7..3f2a0caa91 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CloneCommand.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CloneCommand.java @@ -109,7 +109,7 @@ public interface CloneCommand extends GitCommand { /** * When shallow cloning, allow for a depth to be set in cases where you need more than the immediate last commit. - * Has no effect if shallow is set to false (default) + * Has no effect if shallow is set to false (default). * * @param depth number of revisions to be included in shallow clone * @return a {@link org.jenkinsci.plugins.gitclient.CloneCommand} object. diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index b99ef489f3..aed432c660 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -2175,7 +2175,7 @@ public void submoduleClean(boolean recursive) throws GitException { } /** - * submoduleUpdate. + * Update submodules. * * @return a {@link org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand} object. */ @@ -2184,7 +2184,6 @@ public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand submoduleUpdate() return new org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand() { boolean recursive = false; boolean remoteTracking = false; - boolean shallow = false; String ref = null; @Override @@ -2217,12 +2216,17 @@ public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand timeout(Integer ti return this; } + @Override public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand shallow(boolean shallow) { - this.shallow = shallow; + if (shallow) { + listener.getLogger().println("[WARNING] JGit doesn't support shallow clone. This flag is ignored"); + } return this; } + @Override public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand depth(Integer depth) { + listener.getLogger().println("[WARNING] JGit doesn't support shallow clone and therefore depth is meaningless. This flag is ignored"); return this; } @@ -2241,10 +2245,6 @@ public void execute() throws GitException, InterruptedException { listener.getLogger().println("[ERROR] JGit doesn't support submodule update --reference yet."); throw new UnsupportedOperationException("not implemented yet"); } - if (shallow) { - listener.getLogger().println("[ERROR] JGit doesn't support shallow submodules yet."); - throw new UnsupportedOperationException("not implemented yet"); - } try (Repository repo = getRepository()) { SubmoduleUpdateCommand update = git(repo).submoduleUpdate(); diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/SubmoduleUpdateCommand.java b/src/main/java/org/jenkinsci/plugins/gitclient/SubmoduleUpdateCommand.java index e4f55c2df3..0216c4c698 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/SubmoduleUpdateCommand.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/SubmoduleUpdateCommand.java @@ -60,18 +60,19 @@ public interface SubmoduleUpdateCommand extends GitCommand { SubmoduleUpdateCommand timeout(Integer timeout); /** - * shallow. + * Only clone the most recent history, not preceding history. Depth of the + * shallow clone is controlled by the #depth method. * - * @param shallow a boolean. + * @param shallow boolean controlling whether the clone is shallow (requires git>=1.8.4) * @return a {@link org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand} object. */ SubmoduleUpdateCommand shallow(boolean shallow); /** * When shallow cloning, allow for a depth to be set in cases where you need more than the immediate last commit. - * Has no effect if shallow is set to false (default) + * Has no effect if shallow is set to false (default). * - * @param depth number of revisions to be included in shallow clone + * @param depth number of revisions to be included in shallow clone (requires git>=1.8.4) * @return a {@link org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand} object. */ SubmoduleUpdateCommand depth(Integer depth); diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index bcdc2c423d..39c2169a29 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -31,6 +31,7 @@ import java.io.StringWriter; import java.lang.reflect.Field; import java.nio.file.Files; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -2593,18 +2594,43 @@ public void test_submodule_update() throws Exception { assertTrue("modules/sshkeys does not exist", w.exists("modules/sshkeys")); } assertFixSubmoduleUrlsThrows(); + + String shallow = Paths.get(".git", "modules", "module", "1", "shallow").toString(); + assertFalse("shallow file existence: " + shallow, w.exists(shallow)); } - @NotImplementedInJGit public void test_submodule_update_shallow() throws Exception { - w.init(); - w.git.clone_().url(localMirror()).repositoryName("sub2_origin").execute(); - w.git.checkout().branch("tests/getRelativeSubmodule").ref("sub2_origin/tests/getRelativeSubmodule").deleteBranchIfExist(true).execute(); + WorkingArea remote = setupRepositoryWithSubmodule(); + w.git.clone_().url("file://" + remote.file("dir-repository").getAbsolutePath()).repositoryName("origin").execute(); + w.git.checkout().branch("master").ref("origin/master").execute(); w.git.submoduleInit(); w.git.submoduleUpdate().shallow(true).execute(); - final String shallow = ".git" + File.separator + "modules" + File.separator + "sub" + File.separator + "shallow"; - assertTrue("Shallow file does not exist: " + shallow, w.exists(shallow)); + boolean hasShallowSubmoduleSupport = w.git instanceof CliGitAPIImpl && w.cgit().isAtLeastVersion(1, 8, 4, 0); + + String shallow = Paths.get(".git", "modules", "submodule", "shallow").toString(); + assertEquals("shallow file existence: " + shallow, hasShallowSubmoduleSupport, w.exists(shallow)); + + int localSubmoduleCommits = w.cgit().subGit("submodule").revList("master").size(); + int remoteSubmoduleCommits = remote.cgit().subGit("dir-submodule").revList("master").size(); + assertEquals("submodule commit count didn't match", hasShallowSubmoduleSupport ? 1 : remoteSubmoduleCommits, localSubmoduleCommits); + } + + public void test_submodule_update_shallow_with_depth() throws Exception { + WorkingArea remote = setupRepositoryWithSubmodule(); + w.git.clone_().url("file://" + remote.file("dir-repository").getAbsolutePath()).repositoryName("origin").execute(); + w.git.checkout().branch("master").ref("origin/master").execute(); + w.git.submoduleInit(); + w.git.submoduleUpdate().shallow(true).depth(2).execute(); + + boolean hasShallowSubmoduleSupport = w.git instanceof CliGitAPIImpl && w.cgit().isAtLeastVersion(1, 8, 4, 0); + + String shallow = Paths.get(".git", "modules", "submodule", "shallow").toString(); + assertEquals("shallow file existence: " + shallow, hasShallowSubmoduleSupport, w.exists(shallow)); + + int localSubmoduleCommits = w.cgit().subGit("submodule").revList("master").size(); + int remoteSubmoduleCommits = remote.cgit().subGit("dir-submodule").revList("master").size(); + assertEquals("submodule commit count didn't match", hasShallowSubmoduleSupport ? 2 : remoteSubmoduleCommits, localSubmoduleCommits); } @NotImplementedInJGit @@ -4659,4 +4685,32 @@ private void withSystemLocaleReporting(String fileName, TestedCode code) throws interface TestedCode { void run() throws Exception; } + + private WorkingArea setupRepositoryWithSubmodule() throws Exception { + WorkingArea workingArea = new WorkingArea(); + + File repositoryDir = workingArea.file("dir-repository"); + File submoduleDir = workingArea.file("dir-submodule"); + + assertTrue("did not create dir " + repositoryDir.getName(), repositoryDir.mkdir()); + assertTrue("did not create dir " + submoduleDir.getName(), submoduleDir.mkdir()); + + WorkingArea submoduleWorkingArea = new WorkingArea(submoduleDir).init(); + + for (int commit = 1; commit <= 5; commit++) { + submoduleWorkingArea.touch("file", String.format("submodule content-%d", commit)); + submoduleWorkingArea.cgit().add("file"); + submoduleWorkingArea.cgit().commit(String.format("submodule commit-%d", commit)); + } + + WorkingArea repositoryWorkingArea = new WorkingArea(repositoryDir).init(); + + repositoryWorkingArea.commitEmpty("init"); + + repositoryWorkingArea.cgit().add("."); + repositoryWorkingArea.cgit().addSubmodule("file://" + submoduleDir.getAbsolutePath(), "submodule"); + repositoryWorkingArea.cgit().commit("submodule"); + + return workingArea; + } } From 73228e189fb3d6d19a161ca8c578c026de6e0c05 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Mon, 30 Jul 2018 20:46:27 +0200 Subject: [PATCH 147/226] Exclude httpcore, since it's already in the httpcomponents API plugin --- pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pom.xml b/pom.xml index 86b4aa3451..c07a638ee7 100644 --- a/pom.xml +++ b/pom.xml @@ -117,6 +117,11 @@ org.apache.httpcomponents httpclient + + + org.apache.httpcomponents + httpcore + com.jcraft From 76a1daa2d872f20893ccde87689049194895181b Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 30 Jul 2018 14:59:37 -0600 Subject: [PATCH 148/226] Update parent pom to 3.19 --- .mvn/extensions.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 510f24fbcd..a2d496cc2b 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -2,6 +2,6 @@ io.jenkins.tools.incrementals git-changelist-maven-extension - 1.0-beta-3 + 1.0-beta-4 diff --git a/pom.xml b/pom.xml index c07a638ee7..a6fe5fd2f1 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 3.17 + 3.19 From 595f977b85027bb87cdb15c7f4794c8651170bcf Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Thu, 26 Jul 2018 18:04:46 +0300 Subject: [PATCH 149/226] Add test that verifies invocation of ToolInstallers on master --- .../java/hudson/plugins/git/GitToolTest.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/test/java/hudson/plugins/git/GitToolTest.java b/src/test/java/hudson/plugins/git/GitToolTest.java index b7d2b53c09..69b6f96567 100644 --- a/src/test/java/hudson/plugins/git/GitToolTest.java +++ b/src/test/java/hudson/plugins/git/GitToolTest.java @@ -4,14 +4,20 @@ import hudson.model.Node; import hudson.model.TaskListener; import hudson.slaves.DumbSlave; +import hudson.tools.CommandInstaller; +import hudson.tools.InstallSourceProperty; import hudson.tools.ToolDescriptor; import hudson.util.StreamTaskListener; import java.io.IOException; +import java.util.Collections; import java.util.List; + import org.apache.commons.lang.SystemUtils; import org.jenkinsci.plugins.gitclient.JGitApacheTool; import org.jenkinsci.plugins.gitclient.JGitTool; import static org.junit.Assert.*; + +import org.junit.Assume; import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; @@ -43,6 +49,21 @@ public void testForNode() throws Exception { assertEquals(gitTool.getGitExe(), newTool.getGitExe()); } + @Test + public void shouldResolveToolsOnMaster() throws Exception { + Assume.assumeTrue(!hudson.remoting.Launcher.isWindows()); + TaskListener log = StreamTaskListener.fromStdout(); + GitTool t = new GitTool("myGit", null, Collections.singletonList( + new InstallSourceProperty(Collections.singletonList( + new CommandInstaller("master", "echo Hello", "TOOL_HOME") + )))); + t.getDescriptor().setInstallations(t); + + GitTool defaultTool = GitTool.getDefaultInstallation(); + GitTool resolved = (GitTool) defaultTool.translate(j.jenkins, new EnvVars(), TaskListener.NULL); + assertThat(resolved.getGitExe(), org.hamcrest.CoreMatchers.containsString("TOOL_HOME")); + } + @Test public void testForEnvironment() { EnvVars environment = new EnvVars(); From d14e339f0f9c1f711831ae59ec9fdeb053c51a22 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Tue, 31 Jul 2018 10:54:31 -0600 Subject: [PATCH 150/226] Move GitTool resolver test to separate file The Windows tests depend on JenkinsRule being used as a ClassRule in the GitToolTest. Rather than sacrifice test execution time (which on Windows is especially slow to start and stop JenkinsRule based tests), move the shouldResolveToolsOnMaster to a separate test class that can run its own JenkinsRule. Extends the test to run on Windows in addition to Linux. --- .../plugins/git/GitToolResolverTest.java | 43 +++++++++++++++++++ .../java/hudson/plugins/git/GitToolTest.java | 21 --------- 2 files changed, 43 insertions(+), 21 deletions(-) create mode 100644 src/test/java/hudson/plugins/git/GitToolResolverTest.java diff --git a/src/test/java/hudson/plugins/git/GitToolResolverTest.java b/src/test/java/hudson/plugins/git/GitToolResolverTest.java new file mode 100644 index 0000000000..c9b6a81fb2 --- /dev/null +++ b/src/test/java/hudson/plugins/git/GitToolResolverTest.java @@ -0,0 +1,43 @@ +package hudson.plugins.git; + +import hudson.EnvVars; +import hudson.model.TaskListener; +import hudson.tools.CommandInstaller; +import hudson.tools.InstallSourceProperty; +import hudson.util.StreamTaskListener; +import java.io.IOException; +import java.util.Collections; +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; + +public class GitToolResolverTest { + + @Rule + public JenkinsRule j = new JenkinsRule(); + + private GitTool gitTool; + + @Before + public void setUp() throws IOException { + GitTool.onLoaded(); + gitTool = GitTool.getDefaultInstallation(); + } + + @Test + public void shouldResolveToolsOnMaster() throws Exception { + TaskListener log = StreamTaskListener.fromStdout(); + GitTool t = new GitTool("myGit", null, Collections.singletonList( + new InstallSourceProperty(Collections.singletonList( + new CommandInstaller("master", "echo Hello", "TOOL_HOME") + )))); + t.getDescriptor().setInstallations(t); + + GitTool defaultTool = GitTool.getDefaultInstallation(); + GitTool resolved = (GitTool) defaultTool.translate(j.jenkins, new EnvVars(), TaskListener.NULL); + assertThat(resolved.getGitExe(), org.hamcrest.CoreMatchers.containsString("TOOL_HOME")); + } +} diff --git a/src/test/java/hudson/plugins/git/GitToolTest.java b/src/test/java/hudson/plugins/git/GitToolTest.java index 69b6f96567..b7d2b53c09 100644 --- a/src/test/java/hudson/plugins/git/GitToolTest.java +++ b/src/test/java/hudson/plugins/git/GitToolTest.java @@ -4,20 +4,14 @@ import hudson.model.Node; import hudson.model.TaskListener; import hudson.slaves.DumbSlave; -import hudson.tools.CommandInstaller; -import hudson.tools.InstallSourceProperty; import hudson.tools.ToolDescriptor; import hudson.util.StreamTaskListener; import java.io.IOException; -import java.util.Collections; import java.util.List; - import org.apache.commons.lang.SystemUtils; import org.jenkinsci.plugins.gitclient.JGitApacheTool; import org.jenkinsci.plugins.gitclient.JGitTool; import static org.junit.Assert.*; - -import org.junit.Assume; import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; @@ -49,21 +43,6 @@ public void testForNode() throws Exception { assertEquals(gitTool.getGitExe(), newTool.getGitExe()); } - @Test - public void shouldResolveToolsOnMaster() throws Exception { - Assume.assumeTrue(!hudson.remoting.Launcher.isWindows()); - TaskListener log = StreamTaskListener.fromStdout(); - GitTool t = new GitTool("myGit", null, Collections.singletonList( - new InstallSourceProperty(Collections.singletonList( - new CommandInstaller("master", "echo Hello", "TOOL_HOME") - )))); - t.getDescriptor().setInstallations(t); - - GitTool defaultTool = GitTool.getDefaultInstallation(); - GitTool resolved = (GitTool) defaultTool.translate(j.jenkins, new EnvVars(), TaskListener.NULL); - assertThat(resolved.getGitExe(), org.hamcrest.CoreMatchers.containsString("TOOL_HOME")); - } - @Test public void testForEnvironment() { EnvVars environment = new EnvVars(); From 29e97c4a3e0b8f6491154dbae8237a9ec9025918 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Tue, 31 Jul 2018 14:02:53 -0600 Subject: [PATCH 151/226] Add BatchCommandInstaller to shouldResolveToolsOnMaster test --- .../plugins/git/GitToolResolverTest.java | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/test/java/hudson/plugins/git/GitToolResolverTest.java b/src/test/java/hudson/plugins/git/GitToolResolverTest.java index c9b6a81fb2..db6f00b375 100644 --- a/src/test/java/hudson/plugins/git/GitToolResolverTest.java +++ b/src/test/java/hudson/plugins/git/GitToolResolverTest.java @@ -2,9 +2,11 @@ import hudson.EnvVars; import hudson.model.TaskListener; +import hudson.tools.AbstractCommandInstaller; +import hudson.tools.BatchCommandInstaller; import hudson.tools.CommandInstaller; import hudson.tools.InstallSourceProperty; -import hudson.util.StreamTaskListener; +import java.io.File; import java.io.IOException; import java.util.Collections; import static org.junit.Assert.*; @@ -29,15 +31,28 @@ public void setUp() throws IOException { @Test public void shouldResolveToolsOnMaster() throws Exception { - TaskListener log = StreamTaskListener.fromStdout(); + final String label = "master"; + final String command = "echo Hello"; + final String toolHome = "TOOL_HOME"; + AbstractCommandInstaller installer; + String expectedSubstring; + if (isWindows()) { + installer = new BatchCommandInstaller(label, command, toolHome); + expectedSubstring = System.getProperty("java.io.tmpdir", "C:\\Temp"); + } else { + installer = new CommandInstaller(label, command, toolHome); + expectedSubstring = toolHome; + } GitTool t = new GitTool("myGit", null, Collections.singletonList( - new InstallSourceProperty(Collections.singletonList( - new CommandInstaller("master", "echo Hello", "TOOL_HOME") - )))); + new InstallSourceProperty(Collections.singletonList(installer)))); t.getDescriptor().setInstallations(t); GitTool defaultTool = GitTool.getDefaultInstallation(); GitTool resolved = (GitTool) defaultTool.translate(j.jenkins, new EnvVars(), TaskListener.NULL); - assertThat(resolved.getGitExe(), org.hamcrest.CoreMatchers.containsString("TOOL_HOME")); + assertThat(resolved.getGitExe(), org.hamcrest.CoreMatchers.containsString(expectedSubstring)); + } + + private boolean isWindows() { + return File.pathSeparatorChar == ';'; } } From f062e589be1bf2ef49020f28c97579a3a9a43d8c Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Tue, 31 Jul 2018 20:33:36 -0600 Subject: [PATCH 152/226] Add @Issue annotations to CredentialsTest Reduce CredentialsTest differences between stable-2.7 and master branch --- .../plugins/gitclient/CredentialsTest.java | 28 +++++-------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index e6663d34fa..f9e2f6e9e8 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -42,6 +42,7 @@ import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import org.json.simple.JSONObject; import org.json.simple.JSONArray; @@ -353,6 +354,7 @@ private boolean testPeriodNotExpired() { } @Test + @Issue("JENKINS_50573") public void testFetchWithCredentials() throws URISyntaxException, GitException, InterruptedException, MalformedURLException, IOException { assumeTrue(testPeriodNotExpired()); File clonedFile = new File(repo, fileToCheck); @@ -402,27 +404,11 @@ public void testRemoteReferencesWithCredentials() throws Exception { assertThat(remoteReferences.keySet(), hasItems("refs/heads/master")); } - private String show(String name, String value) { - if (value != null && !value.isEmpty()) { - return " " + name + ": '" + value + "'"; - } - return ""; - } - - private String show(String name, File file) { - if (file != null) { - String homePath = HOME_DIR.getAbsolutePath(); - String filePath = file.getAbsolutePath(); - if (filePath.startsWith(homePath)) { - filePath = filePath.replace(homePath, "~"); - } - return " " + name + ": '" + filePath + "'"; - } - return ""; - } - - private String show(String name, char value) { - return " " + name + ": '" + value + "'"; + @Test + @Issue("JENKINS_50573") + public void isURIishRemote() throws Exception { + URIish uri = new URIish(gitRepoURL); + assertTrue("Should be remote but isn't: " + uri, uri.isRemote()); } private boolean isWindows() { From 2e284ec87e6b8b028f1fa1df6bcbc18da34447ae Mon Sep 17 00:00:00 2001 From: nre Date: Thu, 2 Aug 2018 18:42:15 +0200 Subject: [PATCH 153/226] Add option for updating submodules in parallel This change uses an ExecutorService to optionally update submodules in parallel. This can dramatically improving update times for repositories with lots of submodules. Since the CliGitAPIImpl class doesn't launch a single "git submodule update" command, but instead launches one command per submodule, we can't use the "--jobs" CLI argument for git, available since git 2.9.0. --- .../plugins/gitclient/CliGitAPIImpl.java | 30 ++++++++++++++++++- .../plugins/gitclient/JGitAPIImpl.java | 13 ++++++++ .../gitclient/SubmoduleUpdateCommand.java | 8 +++++ .../plugins/gitclient/GitAPITestCase.java | 17 +++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index bc6782c657..848b1cc1d6 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -58,6 +58,9 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; import java.util.regex.Matcher; @@ -1072,6 +1075,7 @@ public SubmoduleUpdateCommand submoduleUpdate() { Map submodBranch = new HashMap<>(); public Integer timeout; Integer depth = 1; + Integer threads = 1; public SubmoduleUpdateCommand recursive(boolean recursive) { this.recursive = recursive; @@ -1113,6 +1117,11 @@ public SubmoduleUpdateCommand depth(Integer depth) { return this; } + public SubmoduleUpdateCommand threads(Integer threads) { + this.threads = threads; + return this; + } + /** * @throws GitException if executing the Git command fails * @throws InterruptedException if called methods throw same exception @@ -1176,6 +1185,14 @@ else if (!referencePath.isDirectory()) // path. Pattern pattern = Pattern.compile(SUBMODULE_REMOTE_PATTERN_STRING, Pattern.MULTILINE); Matcher matcher = pattern.matcher(cfgOutput); + + ExecutorService executorService; + if (threads > 1) { + executorService = Executors.newFixedThreadPool(threads); + } else { + executorService = Executors.newSingleThreadExecutor(); + } + while (matcher.find()) { ArgumentListBuilder perModuleArgs = args.clone(); String sModuleName = matcher.group(1); @@ -1209,8 +1226,19 @@ else if (!referencePath.isDirectory()) String sModulePath = getSubmodulePath(sModuleName); perModuleArgs.add(sModulePath); - launchCommandWithCredentials(perModuleArgs, workspace, cred, urIish, timeout); + StandardCredentials finalCred = cred; + URIish finalUrIish = urIish; + executorService.submit(() -> { + try { + launchCommandWithCredentials(perModuleArgs, workspace, finalCred, finalUrIish, timeout); + } catch (InterruptedException e) { + throw new GitException("Interrupted while updating submodule for " + sModuleName); + } + }); } + + executorService.shutdown(); + executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); } }; } diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index aed432c660..327eb89575 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -2230,6 +2230,19 @@ public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand depth(Integer dept return this; } + @Override + public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand threads(Integer threads) { + // TODO: I have no idea if JGit can update submodules in parallel + // It might work, or it might blow up horribly. This probably depends on + // whether JGit relies on any global/shared state. Since I have no + // experience with JGit, I'm leaving this unimplemented for the time + // being. But if some brave soul wants to test this, feel free to provide + // an implementation similar to the one in the CliGitAPIImpl class using + // an ExecutorService. + listener.getLogger().println("[WARNING] JGit doesn't support updating submodules in parallel. This flag is ignored"); + return this; + } + @Override public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand useBranch(String submodule, String branchname) { return this; diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/SubmoduleUpdateCommand.java b/src/main/java/org/jenkinsci/plugins/gitclient/SubmoduleUpdateCommand.java index 0216c4c698..e952cba39c 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/SubmoduleUpdateCommand.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/SubmoduleUpdateCommand.java @@ -76,4 +76,12 @@ public interface SubmoduleUpdateCommand extends GitCommand { * @return a {@link org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand} object. */ SubmoduleUpdateCommand depth(Integer depth); + + /** + * Update submodules in parallel with the given number of threads. + * + * @param threads number of threads to use for updating submodules in parallel + * @return a {@link org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand} object. + */ + SubmoduleUpdateCommand threads(Integer threads); } diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 39c2169a29..1ab4175e7b 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -2633,6 +2633,23 @@ public void test_submodule_update_shallow_with_depth() throws Exception { assertEquals("submodule commit count didn't match", hasShallowSubmoduleSupport ? 2 : remoteSubmoduleCommits, localSubmoduleCommits); } + @NotImplementedInJGit + public void test_submodule_update_with_threads() throws Exception { + w.init(); + w.git.clone_().url(localMirror()).repositoryName("sub2_origin").execute(); + w.git.checkout().branch("tests/getSubmodules").ref("sub2_origin/tests/getSubmodules").deleteBranchIfExist(true).execute(); + w.git.submoduleInit(); + w.git.submoduleUpdate().threads(3).execute(); + + assertTrue("modules/firewall does not exist", w.exists("modules/firewall")); + assertTrue("modules/ntp does not exist", w.exists("modules/ntp")); + // JGit submodule implementation doesn't handle renamed submodules + if (w.igit() instanceof CliGitAPIImpl) { + assertTrue("modules/sshkeys does not exist", w.exists("modules/sshkeys")); + } + assertFixSubmoduleUrlsThrows(); + } + @NotImplementedInJGit public void test_trackingSubmoduleBranches() throws Exception { if (! ((CliGitAPIImpl)w.git).isAtLeastVersion(1,8,2,0)) { From a9147ad955c55e98972055fc92f327f92f201e53 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 3 Aug 2018 13:21:00 -0600 Subject: [PATCH 154/226] Use JGit 5.0.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a6fe5fd2f1..0473228709 100644 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,7 @@ -Dfile.encoding=${project.build.sourceEncoding} 2.60.3 8 - 5.0.1.201806211838-r + 5.0.2.201807311906-r From 41a906d066bb1148307f2e1af9e374ae08cf2366 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 4 Aug 2018 08:42:31 -0600 Subject: [PATCH 155/226] [maven-release-plugin] prepare release git-client-3.0.0-beta5 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 0473228709..e99359a9d7 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins git-client - ${revision}${changelist} + 3.0.0-beta5 hpi Jenkins Git client plugin @@ -38,7 +38,7 @@ scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git https://github.com/jenkinsci/${project.artifactId}-plugin - ${scmTag} + git-client-3.0.0-beta5 From 25eb79001e83e545333040e07ab035057af7759a Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 4 Aug 2018 08:42:39 -0600 Subject: [PATCH 156/226] [maven-release-plugin] prepare for next development iteration --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index e99359a9d7..6442eb4f2d 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins git-client - 3.0.0-beta5 + ${revision}${changelist} hpi Jenkins Git client plugin @@ -38,11 +38,11 @@ scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git https://github.com/jenkinsci/${project.artifactId}-plugin - git-client-3.0.0-beta5 + ${scmTag} - 3.0.0-beta5 + 3.0.0-beta6 -SNAPSHOT UTF-8 -Dfile.encoding=${project.build.sourceEncoding} From 4f1ebc72de5f036c5b9f2163a1152cf15c29e4dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sun, 5 Aug 2018 21:58:49 +0200 Subject: [PATCH 157/226] [JENKINS-52891] Always log the timeout for a CliGit command A timeout is always used for a cli git command and therefore should always be logged. Options a timeout may be set - timeout parameter for some commands - system property org.jenkinsci.plugins.gitclient.Git.timeOut - default of 10 minutes So far the timeout was only logged for commands where a) it cannot be customized b) it can and actually was customized Category a) some commands with correct default timeout logging so far > git --version # timeout=10 > git init ... # timeout=10 > git config ... # timeout=10 > git submodule init # timeout=10 Category b) commands with missing default timeout logging so far > git fetch ... > git checkout ... > git submodule update ... --- .../plugins/gitclient/CliGitAPIImpl.java | 5 ++- .../plugins/gitclient/GitAPITestCase.java | 39 +++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 848b1cc1d6..063f72a769 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -2102,11 +2102,12 @@ private String launchCommandIn(ArgumentListBuilder args, File workDir, EnvVars e /* GIT_SSH won't call the passphrase prompt script unless detached from controlling terminal */ args.prepend("setsid"); } - listener.getLogger().println(" > " + command + (timeout != null ? TIMEOUT_LOG_PREFIX + timeout : "")); + int usedTimeout = timeout == null ? TIMEOUT : timeout; + listener.getLogger().println(" > " + command + TIMEOUT_LOG_PREFIX + usedTimeout); Launcher.ProcStarter p = launcher.launch().cmds(args.toCommandArray()). envs(freshEnv).stdout(fos).stderr(err); if (workDir != null) p.pwd(workDir); - int status = p.start().joinWithTimeout(timeout != null ? timeout : TIMEOUT, TimeUnit.MINUTES, listener); + int status = p.start().joinWithTimeout(usedTimeout, TimeUnit.MINUTES, listener); String result = fos.toString(Charset.defaultCharset().toString()); if (status != 0) { diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 1ab4175e7b..33cfa1cf4e 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -478,6 +478,45 @@ private void assertBranchesNotExist(Set branches, String ... names) thro } } + @NotImplementedInJGit + public void test_clone_default_timeout_logging() throws Exception { + w.git.clone_().url(localMirror()).repositoryName("origin").execute(); + + cloneTimeout = CliGitAPIImpl.TIMEOUT; + assertCloneTimeout(); + } + + @NotImplementedInJGit + public void test_fetch_default_timeout_logging() throws Exception { + w.git.clone_().url(localMirror()).repositoryName("origin").execute(); + + w.git.fetch_().from(new URIish("origin"), null).execute(); + + fetchTimeout = CliGitAPIImpl.TIMEOUT; + assertFetchTimeout(); + } + + @NotImplementedInJGit + public void test_checkout_default_timeout_logging() throws Exception { + w.git.clone_().url(localMirror()).repositoryName("origin").execute(); + + w.git.checkout().ref("origin/master").execute(); + + checkoutTimeout = CliGitAPIImpl.TIMEOUT; + assertCheckoutTimeout(); + } + + @NotImplementedInJGit + public void test_submodule_update_default_timeout_logging() throws Exception { + w.git.clone_().url(localMirror()).repositoryName("origin").execute(); + w.git.checkout().ref("origin/tests/getSubmodules").execute(); + + w.git.submoduleUpdate().execute(); + + submoduleUpdateTimeout = CliGitAPIImpl.TIMEOUT; + assertSubmoduleUpdateTimeout(); + } + public void test_setAuthor() throws Exception { final String authorName = "Test Author"; final String authorEmail = "jenkins@example.com"; From cef5047b6274317ce86bc4db60a8207948f58d3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sun, 19 Aug 2018 10:58:55 +0200 Subject: [PATCH 158/226] Improve Revision implementation and tests implementation * no Guava required * use Java 8 features for improved clarity * fix wrong Javadoc * remove non-required {@inheritDoc} tests * reduce variable scope * follow naming conventions * fix parameter order when using assertEquals(expected, actual) * remove unused variables * misc minor improvements --- .../java/hudson/plugins/git/Revision.java | 32 ++---- .../java/hudson/plugins/git/RevisionTest.java | 108 +++++++++--------- 2 files changed, 62 insertions(+), 78 deletions(-) diff --git a/src/main/java/hudson/plugins/git/Revision.java b/src/main/java/hudson/plugins/git/Revision.java index 78ca91d818..e09f80d861 100644 --- a/src/main/java/hudson/plugins/git/Revision.java +++ b/src/main/java/hudson/plugins/git/Revision.java @@ -1,8 +1,7 @@ package hudson.plugins.git; -import com.google.common.base.Function; -import com.google.common.base.Joiner; -import com.google.common.collect.Iterables; +import static java.util.stream.Collectors.joining; + import hudson.Util; import org.eclipse.jgit.lib.ObjectId; import org.kohsuke.stapler.export.Exported; @@ -22,7 +21,7 @@ public class Revision implements java.io.Serializable, Cloneable { private static final long serialVersionUID = -7203898556389073882L; - ObjectId sha1; + ObjectId sha1; Collection branches; /** @@ -94,37 +93,26 @@ public void setBranches(Collection branches) { } /** - * containsBranchName. + * Returns whether the revision contains the specified branch. * - * @param name a {@link java.lang.String} object. - * @return true if this repository is bare + * @param name the name of the branch + * @return whether the revision contains the branch */ public boolean containsBranchName(String name) { - for (Branch b : branches) { - if (b.getName().equals(name)) { - return true; - } - } - return false; + return branches.stream().anyMatch(branch -> branch.getName().equals(name)); } - /** - * toString. - * - * @return a {@link java.lang.String} object. - */ + @Override public String toString() { final String revisionName = sha1 != null ? sha1.name() : "null"; StringBuilder s = new StringBuilder("Revision " + revisionName + " ("); if (branches != null) { - Joiner.on(", ").appendTo(s, - Iterables.transform(branches, from -> Util.fixNull(from.getName()))); + s.append(branches.stream().map(Branch::getName).map(Util::fixNull).collect(joining(", "))); } s.append(')'); return s.toString(); } - /** {@inheritDoc} */ @Override public Revision clone() { Revision clone; @@ -138,13 +126,11 @@ public Revision clone() { return clone; } - /** {@inheritDoc} */ @Override public int hashCode() { return sha1 != null ? 31 + sha1.hashCode() : 1; } - /** {@inheritDoc} */ @Override public boolean equals(Object obj) { if (!(obj instanceof Revision)) { diff --git a/src/test/java/hudson/plugins/git/RevisionTest.java b/src/test/java/hudson/plugins/git/RevisionTest.java index be4a6dba3f..49c18952f6 100644 --- a/src/test/java/hudson/plugins/git/RevisionTest.java +++ b/src/test/java/hudson/plugins/git/RevisionTest.java @@ -8,33 +8,33 @@ public class RevisionTest { - final String SHA1; - final ObjectId objectId; - final Revision revision1; + private final String sha1; + private final ObjectId objectId; + private final Revision revision1; - final Collection emptyCollection; - final Revision revision2; + private final Collection emptyCollection; + private final Revision revision2; - final String branchName; - final String SHA1a; - final Branch branch; - final Collection branchCollection; - final Revision revisionWithBranches; + private final String branchName; + private final String sha1a; + private final Branch branch; + private final Collection branchCollection; + private final Revision revisionWithBranches; public RevisionTest() { - this.SHA1 = "3725b67f3daa6621dd01356c96c08a1f85b90c61"; - this.objectId = ObjectId.fromString(SHA1); - this.revision1 = new Revision(objectId); - - this.emptyCollection = new ArrayList<>(); - this.revision2 = new Revision(objectId, emptyCollection); - - this.branchName = "origin/tests/getSubmodules"; - this.SHA1a = "9ac446c472a6433fe503d294ebb7d5691b590269"; - this.branch = new Branch(branchName, ObjectId.fromString(this.SHA1a)); - this.branchCollection = new ArrayList<>(); - this.branchCollection.add(this.branch); - this.revisionWithBranches = new Revision(ObjectId.fromString(this.SHA1a), branchCollection); + sha1 = "3725b67f3daa6621dd01356c96c08a1f85b90c61"; + objectId = ObjectId.fromString(sha1); + revision1 = new Revision(objectId); + + emptyCollection = new ArrayList<>(); + revision2 = new Revision(objectId, emptyCollection); + + branchName = "origin/tests/getSubmodules"; + sha1a = "9ac446c472a6433fe503d294ebb7d5691b590269"; + branch = new Branch(branchName, ObjectId.fromString(sha1a)); + branchCollection = new ArrayList<>(); + branchCollection.add(branch); + revisionWithBranches = new Revision(ObjectId.fromString(sha1a), branchCollection); } @Test @@ -42,7 +42,7 @@ public void testEquals() { assertEquals(revision1, revision1); assertNotEquals(revision1, null); assertNotEquals(null, revision1); - assertNotEquals(revision1, objectId); + assertNotEquals(objectId, revision1); assertEquals(revision1, revision2); revision2.setBranches(branchCollection); @@ -53,57 +53,55 @@ public void testEquals() { @Test public void testGetSha1() { - assertEquals(revision1.getSha1(), objectId); - assertEquals(revision2.getSha1(), objectId); + assertEquals(objectId, revision1.getSha1()); + assertEquals(objectId, revision2.getSha1()); } @Test public void testGetSha1String() { - assertEquals(revision1.getSha1String(), SHA1); - assertEquals(revision2.getSha1String(), SHA1); + assertEquals(sha1, revision1.getSha1String()); + assertEquals(sha1, revision2.getSha1String()); } @Test public void testSetSha1() { - final String newSHA1 = "b397392d6d00af263583edeaf8f7773a619d1cf8"; - final ObjectId newObjectId = ObjectId.fromString(newSHA1); + String newSha1 = "b397392d6d00af263583edeaf8f7773a619d1cf8"; + ObjectId newObjectId = ObjectId.fromString(newSha1); Revision rev = new Revision(objectId); - assertEquals(rev.getSha1(), objectId); + assertEquals(objectId, rev.getSha1()); + rev.setSha1(newObjectId); - assertEquals(rev.getSha1(), newObjectId); - assertEquals(rev.getSha1String(), newSHA1); + assertEquals(newObjectId, rev.getSha1()); + assertEquals(newSha1, rev.getSha1String()); + rev.setSha1(null); assertNull(rev.getSha1()); - assertEquals(rev.getSha1String(), ""); + assertEquals("", rev.getSha1String()); } @Test public void testGetBranches() { - Collection branches = revision1.getBranches(); - assertTrue(branches.isEmpty()); + assertEquals(0, revision1.getBranches().size()); - branches = revision2.getBranches(); - assertTrue(branches.isEmpty()); + assertEquals(0, revision2.getBranches().size()); - branches = revisionWithBranches.getBranches(); - assertFalse(branches.isEmpty()); + Collection branches = revisionWithBranches.getBranches(); assertTrue(branches.contains(branch)); - assertEquals(branches.size(), 1); + assertEquals(1, branches.size()); } @Test public void testSetBranches() { - final String newSHA1 = "b397392d6d00af263583edeaf8f7773a619d1cf8"; - final ObjectId newObjectId = ObjectId.fromString(newSHA1); Revision rev = new Revision(objectId); + rev.setBranches(emptyCollection); Collection branches = rev.getBranches(); - assertTrue(branches.isEmpty()); + assertEquals(0, branches.size()); + rev.setBranches(branchCollection); branches = rev.getBranches(); - assertFalse(branches.isEmpty()); assertTrue(branches.contains(branch)); - assertEquals(branches.size(), 1); + assertEquals(1, branches.size()); } @Test @@ -119,12 +117,14 @@ public void testContainsBranchName() { String mySHA1 = "aaaaaaaa72a6433fe503d294ebb7d5691b590269"; Branch myBranch = new Branch(myBranchName, ObjectId.fromString(mySHA1)); Collection branches = new ArrayList<>(); - Revision rev = new Revision(ObjectId.fromString(this.SHA1a), branches); + Revision rev = new Revision(ObjectId.fromString(sha1a), branches); assertFalse(rev.containsBranchName(myBranchName)); + branches.add(myBranch); rev.setBranches(branches); assertTrue(rev.containsBranchName(myBranchName)); assertFalse(rev.containsBranchName(branchName)); + branches.add(branch); rev.setBranches(branches); assertTrue(rev.containsBranchName(branchName)); @@ -132,9 +132,9 @@ public void testContainsBranchName() { @Test public void testToString() { - assertEquals("Revision " + SHA1 + " ()", revision1.toString()); - assertEquals("Revision " + SHA1 + " ()", revision2.toString()); - assertEquals("Revision " + SHA1a + " (" + branchName + ")", revisionWithBranches.toString()); + assertEquals("Revision " + sha1 + " ()", revision1.toString()); + assertEquals("Revision " + sha1 + " ()", revision2.toString()); + assertEquals("Revision " + sha1a + " (" + branchName + ")", revisionWithBranches.toString()); } @Test @@ -152,18 +152,16 @@ public void testToStringNullTwoArguments() { @Test public void testClone() { Revision revision1Clone = revision1.clone(); - assertEquals(revision1Clone.getSha1(), objectId); + assertEquals(objectId, revision1Clone.getSha1()); Revision revision2Clone = revision2.clone(); - assertEquals(revision2Clone.getSha1String(), SHA1); + assertEquals(sha1, revision2Clone.getSha1String()); Revision nullRevision = new Revision(null); Revision clonedRevision = nullRevision.clone(); - assertEquals(clonedRevision, nullRevision); + assertEquals(nullRevision, clonedRevision); - Collection branches = revisionWithBranches.getBranches(); Revision revisionWithBranchesClone = revisionWithBranches.clone(); - Collection branchesCloned = revisionWithBranchesClone.getBranches(); assertTrue(revisionWithBranchesClone.containsBranchName(branchName)); } From 41c2a08dbb49717ff4690168a8525969feada3f7 Mon Sep 17 00:00:00 2001 From: Adam Koch Date: Sun, 19 Aug 2018 17:11:28 -0500 Subject: [PATCH 159/226] Update surefire plugin version to 2.21.0 To address https://issues.jenkins-ci.org/browse/JENKINS-53121 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6442eb4f2d..e99bc1f9b9 100644 --- a/pom.xml +++ b/pom.xml @@ -253,7 +253,7 @@ maven-surefire-plugin - 2.20.1 + 2.21.0 maven-javadoc-plugin From 7784a02b0da88ee6ee0a0e46d7ffcd0dd969a543 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 19 Aug 2018 16:48:57 -0600 Subject: [PATCH 160/226] Use maven compiler plugin 3.8.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e99bc1f9b9..dfb2d36102 100644 --- a/pom.xml +++ b/pom.xml @@ -249,7 +249,7 @@ maven-compiler-plugin - 3.7.0 + 3.8.0 maven-surefire-plugin From 40f3f4cc164407b94eeaf0bddaa118ba31017b44 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 19 Aug 2018 16:50:28 -0600 Subject: [PATCH 161/226] Use maven javadoc plugin 3.0.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index dfb2d36102..8c1845bf6a 100644 --- a/pom.xml +++ b/pom.xml @@ -257,7 +257,7 @@ maven-javadoc-plugin - 3.0.0 + 3.0.1 From 4523f4adfd0f6dda3fec5b685af0ac23f8fc1128 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 18 Aug 2018 19:17:48 -0600 Subject: [PATCH 162/226] Use Hamcrest assertions for clearer code --- .../java/hudson/plugins/git/GitToolTest.java | 6 +- .../plugins/gitclient/GitAPITestCase.java | 60 +++++++++---------- .../jenkinsci/plugins/gitclient/PushTest.java | 25 +++++--- 3 files changed, 49 insertions(+), 42 deletions(-) diff --git a/src/test/java/hudson/plugins/git/GitToolTest.java b/src/test/java/hudson/plugins/git/GitToolTest.java index 8bb904b870..0d83e67a4d 100644 --- a/src/test/java/hudson/plugins/git/GitToolTest.java +++ b/src/test/java/hudson/plugins/git/GitToolTest.java @@ -11,6 +11,7 @@ import org.apache.commons.lang.SystemUtils; import org.jenkinsci.plugins.gitclient.JGitApacheTool; import org.jenkinsci.plugins.gitclient.JGitTool; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import org.junit.Before; import org.junit.ClassRule; @@ -69,10 +70,7 @@ public void testGetApplicableFromDescriptor() { GitTool.DescriptorImpl jgitDescriptor = (new JGitTool()).getDescriptor(); GitTool.DescriptorImpl jgitApacheDescriptor = (new JGitApacheTool()).getDescriptor(); List> toolDescriptors = gitDescriptor.getApplicableDescriptors(); - assertTrue("git tool descriptor not found in " + toolDescriptors, toolDescriptors.contains(gitDescriptor)); - assertTrue("jgit tool descriptor not found in " + toolDescriptors, toolDescriptors.contains(jgitDescriptor)); - assertTrue("jgitapache tool descriptor not found in " + toolDescriptors, toolDescriptors.contains(jgitApacheDescriptor)); - assertEquals("Wrong tool descriptor count in " + toolDescriptors, 3, toolDescriptors.size()); + assertThat(toolDescriptors, containsInAnyOrder(gitDescriptor, jgitDescriptor, jgitApacheDescriptor)); } } diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 33cfa1cf4e..213917d8f1 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -49,6 +49,7 @@ import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -982,6 +983,10 @@ private void assertExceptionMessageContains(GitException ge, String expectedSubs assertTrue("Expected '" + expectedSubstring + "' exception message, but was: " + actual, actual.contains(expectedSubstring)); } + private Collection getBranchNames(Collection branches) { + return branches.stream().map(p -> p.getName()).collect(Collectors.toList()); + } + public void test_fetch() throws Exception { /* Create a working repo containing a commit */ w.init(); @@ -995,7 +1000,7 @@ public void test_fetch() throws Exception { bare.init(true); w.git.setRemoteUrl("origin", bare.repoPath()); Set remoteBranchesEmpty = w.git.getRemoteBranches(); - assertEquals("Unexpected branch count", 0, remoteBranchesEmpty.size()); + assertThat(remoteBranchesEmpty, is(empty())); w.git.push("origin", "master"); ObjectId bareCommit1 = bare.git.getHeadRev(bare.repoPath(), "master"); assertEquals("bare != working", commit1, bareCommit1); @@ -1006,7 +1011,7 @@ public void test_fetch() throws Exception { ObjectId newAreaHead = newArea.head(); assertEquals("bare != newArea", bareCommit1, newAreaHead); Set remoteBranches1 = newArea.git.getRemoteBranches(); - assertEquals("Unexpected branch count in " + remoteBranches1, 2, remoteBranches1.size()); + assertThat(getBranchNames(remoteBranches1), hasItems("origin/master")); assertEquals(bareCommit1, newArea.git.getHeadRev(newArea.repoPath(), "refs/heads/master")); /* Commit a new change to the original repo */ @@ -1136,7 +1141,7 @@ public void test_push_tags() throws Exception { bare.init(true); w.git.setRemoteUrl("origin", bare.repoPath()); Set remoteBranchesEmpty = w.git.getRemoteBranches(); - assertEquals("Unexpected branch count", 0, remoteBranchesEmpty.size()); + assertThat(remoteBranchesEmpty, is(empty())); w.git.push("origin", "master"); ObjectId bareCommit1 = bare.git.getHeadRev(bare.repoPath(), "master"); assertEquals("bare != working", commit1, bareCommit1); @@ -1212,8 +1217,8 @@ public void test_fetch_needs_preceding_prune() throws Exception { w.git.add("file1"); w.git.commit("commit1"); ObjectId commit1 = w.head(); - assertEquals("Wrong branch count", 1, w.git.getBranches().size()); - assertTrue("Remote branches should not exist", w.git.getRemoteBranches().isEmpty()); + assertThat(getBranchNames(w.git.getBranches()), contains("master")); + assertThat(w.git.getRemoteBranches(), is(empty())); /* Prune when a remote is not yet defined */ try { @@ -1232,8 +1237,8 @@ public void test_fetch_needs_preceding_prune() throws Exception { w.git.push("origin", "master"); ObjectId bareCommit1 = bare.git.getHeadRev(bare.repoPath(), "master"); assertEquals("bare != working", commit1, bareCommit1); - assertEquals("Wrong branch count", 1, w.git.getBranches().size()); - assertTrue("Remote branches should not exist", w.git.getRemoteBranches().isEmpty()); + assertThat(getBranchNames(w.git.getBranches()), contains("master")); + assertThat(w.git.getRemoteBranches(), is(empty())); /* Create a branch in working repo named "parent" */ w.git.branch("parent"); @@ -1242,23 +1247,22 @@ public void test_fetch_needs_preceding_prune() throws Exception { w.git.add("file2"); w.git.commit("commit2"); ObjectId commit2 = w.head(); - assertEquals("Wrong branch count", 2, w.git.getBranches().size()); - assertTrue("Remote branches should not exist", w.git.getRemoteBranches().isEmpty()); + assertThat(getBranchNames(w.git.getBranches()), containsInAnyOrder("master", "parent")); + assertThat(w.git.getRemoteBranches(), is(empty())); /* Push branch named "parent" to bare repo */ w.git.push("origin", "parent"); ObjectId bareCommit2 = bare.git.getHeadRev(bare.repoPath(), "parent"); assertEquals("working parent != bare parent", commit2, bareCommit2); - assertEquals("Wrong branch count", 2, w.git.getBranches().size()); - assertTrue("Remote branches should not exist", w.git.getRemoteBranches().isEmpty()); + assertThat(getBranchNames(w.git.getBranches()), containsInAnyOrder("master", "parent")); + assertThat(w.git.getRemoteBranches(), is(empty())); /* Clone new working repo from bare repo */ WorkingArea newArea = clone(bare.repoPath()); ObjectId newAreaHead = newArea.head(); assertEquals("bare != newArea", bareCommit1, newAreaHead); Set remoteBranches = newArea.git.getRemoteBranches(); - assertBranchesExist(remoteBranches, "origin/master", "origin/parent", "origin/HEAD"); - assertEquals("Wrong count in " + remoteBranches, 3, remoteBranches.size()); + assertThat(getBranchNames(remoteBranches), containsInAnyOrder("origin/master", "origin/parent", "origin/HEAD")); /* Checkout parent in new working repo */ newArea.git.checkout("origin/parent", "parent"); @@ -1268,7 +1272,7 @@ public void test_fetch_needs_preceding_prune() throws Exception { /* Delete parent branch from w */ w.git.checkout("master"); w.cmd("git branch -D parent"); - assertEquals("Wrong branch count", 1, w.git.getBranches().size()); + assertThat(getBranchNames(w.git.getBranches()), contains("master")); /* Delete parent branch on bare repo*/ bare.cmd("git branch -D parent"); @@ -1287,7 +1291,7 @@ public void test_fetch_needs_preceding_prune() throws Exception { ObjectId bareCommit3 = bare.git.getHeadRev(bare.repoPath(), "parent/a"); assertEquals("parent/a != bare", commit3, bareCommit3); remoteBranches = bare.git.getRemoteBranches(); - assertEquals("Wrong count in " + remoteBranches, 0, remoteBranches.size()); + assertThat(remoteBranches, is(empty())); RefSpec defaultRefSpec = new RefSpec("+refs/heads/*:refs/remotes/origin/*"); List refSpecs = new ArrayList<>(); @@ -1338,7 +1342,7 @@ public void test_fetch_with_prune() throws Exception { w.git.add("file-master"); w.git.commit("master-commit"); ObjectId master = w.head(); - assertEquals("Wrong branch count", 1, w.git.getBranches().size()); + assertThat(getBranchNames(w.git.getBranches()), contains("master")); w.git.setRemoteUrl("origin", bare.repoPath()); w.git.push("origin", "master"); /* master branch is now on bare repo */ @@ -1348,7 +1352,7 @@ public void test_fetch_with_prune() throws Exception { w.git.add("file-branch1"); w.git.commit("branch1-commit"); ObjectId branch1 = w.head(); - assertEquals("Wrong branch count", 2, w.git.getBranches().size()); + assertThat(getBranchNames(w.git.getBranches()), containsInAnyOrder("master", "branch1")); w.git.push("origin", "branch1"); /* branch1 is now on bare repo */ w.git.checkout("master"); @@ -1357,16 +1361,15 @@ public void test_fetch_with_prune() throws Exception { w.git.add("file-branch2"); w.git.commit("branch2-commit"); ObjectId branch2 = w.head(); - assertEquals("Wrong branch count", 3, w.git.getBranches().size()); - assertTrue("Remote branches should not exist", w.git.getRemoteBranches().isEmpty()); + assertThat(getBranchNames(w.git.getBranches()), containsInAnyOrder("master", "branch1", "branch2")); + assertThat(w.git.getRemoteBranches(), is(empty())); w.git.push("origin", "branch2"); /* branch2 is now on bare repo */ /* Clone new working repo from bare repo */ WorkingArea newArea = clone(bare.repoPath()); ObjectId newAreaHead = newArea.head(); Set remoteBranches = newArea.git.getRemoteBranches(); - assertBranchesExist(remoteBranches, "origin/master", "origin/branch1", "origin/branch2", "origin/HEAD"); - assertEquals("Wrong count in " + remoteBranches, 4, remoteBranches.size()); + assertThat(getBranchNames(remoteBranches), containsInAnyOrder("origin/master", "origin/branch1", "origin/branch2", "origin/HEAD")); /* Remove branch1 from bare repo using original repo */ w.cmd("git push " + bare.repoPath() + " :branch1"); @@ -1379,26 +1382,21 @@ public void test_fetch_with_prune() throws Exception { newArea.cmd("git config fetch.prune false"); newArea.git.fetch_().from(new URIish(bare.repo.toString()), refSpecs).execute(); remoteBranches = newArea.git.getRemoteBranches(); - assertBranchesExist(remoteBranches, "origin/master", "origin/branch1", "origin/branch2", "origin/HEAD"); - assertEquals("Wrong count in " + remoteBranches, 4, remoteBranches.size()); + assertThat(getBranchNames(remoteBranches), containsInAnyOrder("origin/master", "origin/branch1", "origin/branch2", "origin/HEAD")); /* Fetch with prune should remove branch1 from newArea */ newArea.git.fetch_().from(new URIish(bare.repo.toString()), refSpecs).prune().execute(); remoteBranches = newArea.git.getRemoteBranches(); - assertBranchesExist(remoteBranches, "origin/master", "origin/branch2", "origin/HEAD"); + assertThat(getBranchNames(remoteBranches), containsInAnyOrder("origin/master", "origin/branch2", "origin/HEAD")); - /* Git 1.7.1 on Red Hat 6 does not prune branch1, don't fail the test + /* Git older than 1.7.9 (like 1.7.1 on Red Hat 6) does not prune branch1, don't fail the test * on that old git version. */ - int expectedBranchCount = 3; if (newArea.git instanceof CliGitAPIImpl && !w.cgit().isAtLeastVersion(1, 7, 9, 0)) { - expectedBranchCount = 4; - assertBranchesExist(remoteBranches, "origin/master", "origin/branch1", "origin/branch2", "origin/HEAD"); + assertThat(getBranchNames(remoteBranches), containsInAnyOrder("origin/master", "origin/branch1", "origin/branch2", "origin/HEAD")); } else { - assertBranchesExist(remoteBranches, "origin/master", "origin/branch2", "origin/HEAD"); - assertBranchesNotExist(remoteBranches, "origin/branch1"); + assertThat(getBranchNames(remoteBranches), containsInAnyOrder("origin/master", "origin/branch2", "origin/HEAD")); } - assertEquals("Wrong remote branch count", expectedBranchCount, remoteBranches.size()); } public void test_fetch_from_url() throws Exception { diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/PushTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/PushTest.java index 889ad5e965..1abdeed1ae 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/PushTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/PushTest.java @@ -8,6 +8,7 @@ import java.util.Collection; import java.util.List; import java.util.Random; +import java.util.stream.Collectors; import hudson.model.TaskListener; import hudson.plugins.git.Branch; @@ -15,7 +16,6 @@ import hudson.util.StreamTaskListener; import org.apache.commons.io.FileUtils; -import com.google.common.io.Files; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.transport.RefSpec; @@ -23,12 +23,15 @@ import org.junit.After; import org.junit.AfterClass; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import org.junit.Before; import org.junit.BeforeClass; +import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.junit.rules.TemporaryFolder; import org.junit.rules.TestName; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -69,6 +72,12 @@ public class PushTest { @Rule public TestName name = new TestName(); + @ClassRule + public static TemporaryFolder staticTemporaryFolder = new TemporaryFolder(); + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + public PushTest(String gitImpl, String branchName, String refSpec, Class expectedException) { this.gitImpl = gitImpl; this.branchName = branchName; @@ -142,7 +151,7 @@ public void createWorkingRepository() throws IOException, InterruptedException, hudson.EnvVars env = new hudson.EnvVars(); TaskListener listener = StreamTaskListener.fromStderr(); List refSpecs = new ArrayList<>(); - workingRepo = Files.createTempDir(); + workingRepo = temporaryFolder.newFolder(); workingGitClient = Git.with(listener, env).in(workingRepo).using(gitImpl).getClient(); workingGitClient.clone_() .url(bareRepo.getAbsolutePath()) @@ -170,7 +179,6 @@ public void verifyPushResultAndDeleteDirectory() throws GitException, Interrupte assertNotEquals(previousCommit, workingCommit); assertNotEquals(previousCommit, latestBareHead); } - FileUtils.deleteDirectory(workingRepo.getAbsoluteFile()); } @BeforeClass @@ -185,7 +193,7 @@ public static void createBareRepository() throws Exception { String gitImpl = gitImplementations[random.nextInt(gitImplementations.length)]; /* Create the bare repository */ - bareRepo = Files.createTempDir(); + bareRepo = staticTemporaryFolder.newFolder(); bareURI = new URIish(bareRepo.getAbsolutePath()); hudson.EnvVars env = new hudson.EnvVars(); TaskListener listener = StreamTaskListener.fromStderr(); @@ -193,7 +201,7 @@ public static void createBareRepository() throws Exception { bareGitClient.init_().workspace(bareRepo.getAbsolutePath()).bare(true).execute(); /* Clone the bare repository into a working copy */ - File cloneRepo = Files.createTempDir(); + File cloneRepo = staticTemporaryFolder.newFolder(); GitClient cloneGitClient = Git.with(listener, env).in(cloneRepo).using(gitImpl).getClient(); cloneGitClient.clone_() .url(bareRepo.getAbsolutePath()) @@ -239,12 +247,15 @@ protected void checkoutOldBranchAndCommitFile() throws GitException, Interrupted workingCommit = commitFileToCurrentBranch(); } + private Collection getBranchNames(List branches) { + return branches.stream().map(p -> p.getName()).collect(Collectors.toList()); + } + private ObjectId checkoutBranch(boolean useOldCommit) throws GitException, InterruptedException { /* Checkout branchName */ workingGitClient.checkoutBranch(branchName, "origin/" + branchName + (useOldCommit ? "^" : "")); List branches = workingGitClient.getBranchesContaining(branchName, false); - assertEquals("Wrong working branch count", 1, branches.size()); - assertEquals("Wrong working branch name", branchName, branches.get(0).getName()); + assertThat(getBranchNames(branches), contains(branchName)); return bareGitClient.getHeadRev(bareRepo.getAbsolutePath(), branchName); } From 49777046ef5178b6e3efab45f6b0a00ea5f4136e Mon Sep 17 00:00:00 2001 From: Vincent Latombe Date: Tue, 28 Aug 2018 12:25:52 +0200 Subject: [PATCH 163/226] [JENKINS-53279] Remove deprecated reference This fixes an issue reporting missing ServletException on agent side, as MasterComputer is pulling it, but FilePath isn't. --- .../org/jenkinsci/plugins/gitclient/AbstractGitAPIImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/AbstractGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/AbstractGitAPIImpl.java index b102d6244d..58b5aba98c 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/AbstractGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/AbstractGitAPIImpl.java @@ -1,11 +1,11 @@ package org.jenkinsci.plugins.gitclient; import com.cloudbees.plugins.credentials.common.StandardUsernameCredentials; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + +import hudson.FilePath; import hudson.ProxyConfiguration; import hudson.plugins.git.GitException; import hudson.remoting.Channel; -import jenkins.model.Jenkins.MasterComputer; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Repository; @@ -26,7 +26,7 @@ abstract class AbstractGitAPIImpl implements GitClient, Serializable { /** {@inheritDoc} */ public T withRepository(RepositoryCallback callable) throws IOException, InterruptedException { try (Repository repo = getRepository()) { - return callable.invoke(repo, MasterComputer.localChannel); + return callable.invoke(repo, FilePath.localChannel); } } From a85cd87d89753fa45df9f7a95ada769560a427e1 Mon Sep 17 00:00:00 2001 From: Ivan-Sinitsin Date: Wed, 29 Aug 2018 11:28:13 +0300 Subject: [PATCH 164/226] z/OS USS cli git enablement on master branch --- .../plugins/gitclient/CliGitAPIImpl.java | 99 +++++++++++++------ 1 file changed, 68 insertions(+), 31 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 063f72a769..0f25f63ae4 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -8,13 +8,10 @@ import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; -import hudson.EnvVars; -import hudson.FilePath; -import hudson.Launcher; +import hudson.*; import com.google.common.collect.Lists; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.Launcher.LocalLauncher; -import hudson.Util; import hudson.model.TaskListener; import hudson.plugins.git.Branch; import hudson.plugins.git.GitException; @@ -169,6 +166,10 @@ public class CliGitAPIImpl extends LegacyCompatibleGitAPIImpl { /* Package protected for testing */ final static String SUBMODULE_REMOTE_PATTERN_STRING = SUBMODULE_REMOTE_PATTERN_CONFIG_KEY + "\\s+[^\\s]+$"; + + /* Encoding charset for z/OS, only on z/OS USS platform + */ + private final String encoding; private void warnIfWindowsTemporaryDirNameHasSpaces() { if (!isWindows()) { return; @@ -252,7 +253,8 @@ protected CliGitAPIImpl(String gitExe, File workspace, this.listener = listener; this.gitExe = gitExe; this.environment = environment; - + this.encoding = ZosCheck() ? "IBM1047" : Charset.defaultCharset().toString(); + launcher = new LocalLauncher(IGitAPI.verbose?listener:TaskListener.NULL); } @@ -804,15 +806,15 @@ public void execute() throws GitException, InterruptedException { public void clean(boolean cleanSubmodule) throws GitException, InterruptedException { reset(true); String cmd = "-fdx"; - if (cleanSubmodule) cmd = "-ffdx"; - + if (cleanSubmodule) cmd = "-ffdx"; + launchCommand("clean", cmd); - } +} - /** - * Remove untracked files and directories, including files listed - * in the ignore rules. - * +/** + * Remove untracked files and directories, including files listed + * in the ignore rules. + * * @throws hudson.plugins.git.GitException if underlying git operation fails. * @throws java.lang.InterruptedException if interrupted. */ @@ -1816,7 +1818,7 @@ private String launchCommandWithCredentials(ArgumentListBuilder args, File workD private File createSshKeyFile(SSHUserPrivateKey sshUser) throws IOException, InterruptedException { File key = createTempFile("ssh", ".key"); - try (PrintWriter w = new PrintWriter(key, Charset.defaultCharset().toString())) { + try (PrintWriter w = new PrintWriter(key, this.encoding)) { List privateKeys = sshUser.getPrivateKeys(); for (String s : privateKeys) { w.println(s); @@ -1852,7 +1854,7 @@ private String quoteUnixCredentials(String str) { private File createWindowsSshAskpass(SSHUserPrivateKey sshUser) throws IOException { File ssh = createTempFile("pass", ".bat"); - try (PrintWriter w = new PrintWriter(ssh, Charset.defaultCharset().toString())) { + try (PrintWriter w = new PrintWriter(ssh, this.encoding)) { // avoid echoing command as part of the password w.println("@echo off"); // no surrounding double quotes on windows echo -- they are echoed too @@ -1865,7 +1867,7 @@ private File createWindowsSshAskpass(SSHUserPrivateKey sshUser) throws IOExcepti private File createUnixSshAskpass(SSHUserPrivateKey sshUser) throws IOException { File ssh = createTempFile("pass", ".sh"); - try (PrintWriter w = new PrintWriter(ssh, Charset.defaultCharset().toString())) { + try (PrintWriter w = new PrintWriter(ssh, this.encoding)) { w.println("#!/bin/sh"); w.println("echo '" + quoteUnixCredentials(Secret.toString(sshUser.getPassphrase())) + "'"); } @@ -1876,7 +1878,7 @@ private File createUnixSshAskpass(SSHUserPrivateKey sshUser) throws IOException /* Package protected for testability */ File createWindowsBatFile(String userName, String password) throws IOException { File askpass = createTempFile("pass", ".bat"); - try (PrintWriter w = new PrintWriter(askpass, Charset.defaultCharset().toString())) { + try (PrintWriter w = new PrintWriter(askpass, this.encoding)) { w.println("@set arg=%~1"); w.println("@if (%arg:~0,8%)==(Username) echo " + escapeWindowsCharsForUnquotedString(userName)); w.println("@if (%arg:~0,8%)==(Password) echo " + escapeWindowsCharsForUnquotedString(password)); @@ -1891,7 +1893,7 @@ private File createWindowsStandardAskpass(StandardUsernamePasswordCredentials cr private File createUnixStandardAskpass(StandardUsernamePasswordCredentials creds) throws IOException { File askpass = createTempFile("pass", ".sh"); - try (PrintWriter w = new PrintWriter(askpass, Charset.defaultCharset().toString())) { + try (PrintWriter w = new PrintWriter(askpass, this.encoding)) { w.println("#!/bin/sh"); w.println("case \"$1\" in"); w.println("Username*) echo '" + quoteUnixCredentials(creds.getUsername()) + "' ;;"); @@ -2023,8 +2025,8 @@ private File createWindowsGitSSH(File key, String user) throws IOException { File ssh = createTempFile("ssh", ".bat"); File sshexe = getSSHExecutable(); - - try (PrintWriter w = new PrintWriter(ssh, Charset.defaultCharset().toString())) { + + try (PrintWriter w = new PrintWriter(ssh, this.encoding)) { w.println("@echo off"); w.println("\"" + sshexe.getAbsolutePath() + "\" -i \"" + key.getAbsolutePath() +"\" -l \"" + user + "\" -o StrictHostKeyChecking=no %* "); } @@ -2032,11 +2034,15 @@ private File createWindowsGitSSH(File key, String user) throws IOException { return ssh; } + private static final boolean ZosCheck() { + return (File.pathSeparatorChar==':') && System.getProperty("os.name").equals("z/OS"); + } + private File createUnixGitSSH(File key, String user) throws IOException { File ssh = createTempFile("ssh", ".sh"); File ssh_copy = new File(ssh.toString() + "-copy"); boolean isCopied = false; - try (PrintWriter w = new PrintWriter(ssh, Charset.defaultCharset().toString())) { + try (PrintWriter w = new PrintWriter(ssh, this.encoding)) { w.println("#!/bin/sh"); // ${SSH_ASKPASS} might be ignored if ${DISPLAY} is not set w.println("if [ -z \"${DISPLAY}\" ]; then"); @@ -2046,7 +2052,7 @@ private File createUnixGitSSH(File key, String user) throws IOException { w.println("ssh -i \"" + key.getAbsolutePath() + "\" -l \"" + user + "\" -o StrictHostKeyChecking=no \"$@\""); } ssh.setExecutable(true, true); - //JENKINS-48258 git client plugin occasionally fails with "text file busy" error + //JENKINS-48258 git client plugin occasionally fails with "text file busy" error //The following creates a copy of the generated file and deletes the original //In case of a failure return the original and delete the copy String fromLocation = ssh.toString(); @@ -2067,12 +2073,12 @@ private File createUnixGitSSH(File key, String user) throws IOException { deleteTempFile(ssh_copy); } //Previous operation failed. Return original file - return ssh; - } - - return ssh_copy; + return ssh; } + return ssh_copy; +} + private String launchCommandIn(ArgumentListBuilder args, File workDir) throws GitException, InterruptedException { return launchCommandIn(args, workDir, environment); } @@ -2104,14 +2110,45 @@ private String launchCommandIn(ArgumentListBuilder args, File workDir, EnvVars e } int usedTimeout = timeout == null ? TIMEOUT : timeout; listener.getLogger().println(" > " + command + TIMEOUT_LOG_PREFIX + usedTimeout); - Launcher.ProcStarter p = launcher.launch().cmds(args.toCommandArray()). - envs(freshEnv).stdout(fos).stderr(err); - if (workDir != null) p.pwd(workDir); - int status = p.start().joinWithTimeout(usedTimeout, TimeUnit.MINUTES, listener); - String result = fos.toString(Charset.defaultCharset().toString()); + int status=0; + String result = ""; + String errorString = ""; + if(ZosCheck() == true) { + // Another behavior on z/OS required due to the race condition + Launcher.ProcStarter p = launcher.launch().cmds(args.toCommandArray()). + envs(freshEnv); + if (workDir != null) p.pwd(workDir); + p.readStdout().readStderr(); + Proc prc = p.start(); + + status = prc.joinWithTimeout(usedTimeout, TimeUnit.MINUTES, listener); + BufferedReader brStdout = new BufferedReader(new InputStreamReader(prc.getStdout())); + BufferedReader brStdErr = new BufferedReader(new InputStreamReader(prc.getStdout())); + + String stdout; + + while ((stdout = brStdout.readLine()) != null) { + result += stdout; + } + String stderr; + while ((stderr = brStdErr.readLine()) != null) { + errorString += stderr; + } + brStdErr.close(); + brStdout.close(); + } else { + // Original behaviour + Launcher.ProcStarter p = launcher.launch().cmds(args.toCommandArray()). + envs(freshEnv).stdout(fos).stderr(err); + if (workDir != null) p.pwd(workDir); + int status = p.start().joinWithTimeout(usedTimeout, TimeUnit.MINUTES, listener); + + result = fos.toString(Charset.defaultCharset().toString()); + errorString = err.toString(Charset.defaultCharset().toString()); + } if (status != 0) { - throw new GitException("Command \""+command+"\" returned status code " + status + ":\nstdout: " + result + "\nstderr: "+ err.toString(Charset.defaultCharset().toString())); + throw new GitException("Command \""+command+"\" returned status code " + status + ":\nstdout: " + result + "\nstderr: "+ errorString); } return result; From b89cf1c6ff297fd5ace99f4f3511b7823ae7b11f Mon Sep 17 00:00:00 2001 From: Ivan-Sinitsin Date: Wed, 29 Aug 2018 11:28:13 +0300 Subject: [PATCH 165/226] z/OS USS cli git enablement on master branch --- .../plugins/gitclient/CliGitAPIImpl.java | 99 +++++++++++++------ 1 file changed, 68 insertions(+), 31 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 063f72a769..0f25f63ae4 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -8,13 +8,10 @@ import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; -import hudson.EnvVars; -import hudson.FilePath; -import hudson.Launcher; +import hudson.*; import com.google.common.collect.Lists; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.Launcher.LocalLauncher; -import hudson.Util; import hudson.model.TaskListener; import hudson.plugins.git.Branch; import hudson.plugins.git.GitException; @@ -169,6 +166,10 @@ public class CliGitAPIImpl extends LegacyCompatibleGitAPIImpl { /* Package protected for testing */ final static String SUBMODULE_REMOTE_PATTERN_STRING = SUBMODULE_REMOTE_PATTERN_CONFIG_KEY + "\\s+[^\\s]+$"; + + /* Encoding charset for z/OS, only on z/OS USS platform + */ + private final String encoding; private void warnIfWindowsTemporaryDirNameHasSpaces() { if (!isWindows()) { return; @@ -252,7 +253,8 @@ protected CliGitAPIImpl(String gitExe, File workspace, this.listener = listener; this.gitExe = gitExe; this.environment = environment; - + this.encoding = ZosCheck() ? "IBM1047" : Charset.defaultCharset().toString(); + launcher = new LocalLauncher(IGitAPI.verbose?listener:TaskListener.NULL); } @@ -804,15 +806,15 @@ public void execute() throws GitException, InterruptedException { public void clean(boolean cleanSubmodule) throws GitException, InterruptedException { reset(true); String cmd = "-fdx"; - if (cleanSubmodule) cmd = "-ffdx"; - + if (cleanSubmodule) cmd = "-ffdx"; + launchCommand("clean", cmd); - } +} - /** - * Remove untracked files and directories, including files listed - * in the ignore rules. - * +/** + * Remove untracked files and directories, including files listed + * in the ignore rules. + * * @throws hudson.plugins.git.GitException if underlying git operation fails. * @throws java.lang.InterruptedException if interrupted. */ @@ -1816,7 +1818,7 @@ private String launchCommandWithCredentials(ArgumentListBuilder args, File workD private File createSshKeyFile(SSHUserPrivateKey sshUser) throws IOException, InterruptedException { File key = createTempFile("ssh", ".key"); - try (PrintWriter w = new PrintWriter(key, Charset.defaultCharset().toString())) { + try (PrintWriter w = new PrintWriter(key, this.encoding)) { List privateKeys = sshUser.getPrivateKeys(); for (String s : privateKeys) { w.println(s); @@ -1852,7 +1854,7 @@ private String quoteUnixCredentials(String str) { private File createWindowsSshAskpass(SSHUserPrivateKey sshUser) throws IOException { File ssh = createTempFile("pass", ".bat"); - try (PrintWriter w = new PrintWriter(ssh, Charset.defaultCharset().toString())) { + try (PrintWriter w = new PrintWriter(ssh, this.encoding)) { // avoid echoing command as part of the password w.println("@echo off"); // no surrounding double quotes on windows echo -- they are echoed too @@ -1865,7 +1867,7 @@ private File createWindowsSshAskpass(SSHUserPrivateKey sshUser) throws IOExcepti private File createUnixSshAskpass(SSHUserPrivateKey sshUser) throws IOException { File ssh = createTempFile("pass", ".sh"); - try (PrintWriter w = new PrintWriter(ssh, Charset.defaultCharset().toString())) { + try (PrintWriter w = new PrintWriter(ssh, this.encoding)) { w.println("#!/bin/sh"); w.println("echo '" + quoteUnixCredentials(Secret.toString(sshUser.getPassphrase())) + "'"); } @@ -1876,7 +1878,7 @@ private File createUnixSshAskpass(SSHUserPrivateKey sshUser) throws IOException /* Package protected for testability */ File createWindowsBatFile(String userName, String password) throws IOException { File askpass = createTempFile("pass", ".bat"); - try (PrintWriter w = new PrintWriter(askpass, Charset.defaultCharset().toString())) { + try (PrintWriter w = new PrintWriter(askpass, this.encoding)) { w.println("@set arg=%~1"); w.println("@if (%arg:~0,8%)==(Username) echo " + escapeWindowsCharsForUnquotedString(userName)); w.println("@if (%arg:~0,8%)==(Password) echo " + escapeWindowsCharsForUnquotedString(password)); @@ -1891,7 +1893,7 @@ private File createWindowsStandardAskpass(StandardUsernamePasswordCredentials cr private File createUnixStandardAskpass(StandardUsernamePasswordCredentials creds) throws IOException { File askpass = createTempFile("pass", ".sh"); - try (PrintWriter w = new PrintWriter(askpass, Charset.defaultCharset().toString())) { + try (PrintWriter w = new PrintWriter(askpass, this.encoding)) { w.println("#!/bin/sh"); w.println("case \"$1\" in"); w.println("Username*) echo '" + quoteUnixCredentials(creds.getUsername()) + "' ;;"); @@ -2023,8 +2025,8 @@ private File createWindowsGitSSH(File key, String user) throws IOException { File ssh = createTempFile("ssh", ".bat"); File sshexe = getSSHExecutable(); - - try (PrintWriter w = new PrintWriter(ssh, Charset.defaultCharset().toString())) { + + try (PrintWriter w = new PrintWriter(ssh, this.encoding)) { w.println("@echo off"); w.println("\"" + sshexe.getAbsolutePath() + "\" -i \"" + key.getAbsolutePath() +"\" -l \"" + user + "\" -o StrictHostKeyChecking=no %* "); } @@ -2032,11 +2034,15 @@ private File createWindowsGitSSH(File key, String user) throws IOException { return ssh; } + private static final boolean ZosCheck() { + return (File.pathSeparatorChar==':') && System.getProperty("os.name").equals("z/OS"); + } + private File createUnixGitSSH(File key, String user) throws IOException { File ssh = createTempFile("ssh", ".sh"); File ssh_copy = new File(ssh.toString() + "-copy"); boolean isCopied = false; - try (PrintWriter w = new PrintWriter(ssh, Charset.defaultCharset().toString())) { + try (PrintWriter w = new PrintWriter(ssh, this.encoding)) { w.println("#!/bin/sh"); // ${SSH_ASKPASS} might be ignored if ${DISPLAY} is not set w.println("if [ -z \"${DISPLAY}\" ]; then"); @@ -2046,7 +2052,7 @@ private File createUnixGitSSH(File key, String user) throws IOException { w.println("ssh -i \"" + key.getAbsolutePath() + "\" -l \"" + user + "\" -o StrictHostKeyChecking=no \"$@\""); } ssh.setExecutable(true, true); - //JENKINS-48258 git client plugin occasionally fails with "text file busy" error + //JENKINS-48258 git client plugin occasionally fails with "text file busy" error //The following creates a copy of the generated file and deletes the original //In case of a failure return the original and delete the copy String fromLocation = ssh.toString(); @@ -2067,12 +2073,12 @@ private File createUnixGitSSH(File key, String user) throws IOException { deleteTempFile(ssh_copy); } //Previous operation failed. Return original file - return ssh; - } - - return ssh_copy; + return ssh; } + return ssh_copy; +} + private String launchCommandIn(ArgumentListBuilder args, File workDir) throws GitException, InterruptedException { return launchCommandIn(args, workDir, environment); } @@ -2104,14 +2110,45 @@ private String launchCommandIn(ArgumentListBuilder args, File workDir, EnvVars e } int usedTimeout = timeout == null ? TIMEOUT : timeout; listener.getLogger().println(" > " + command + TIMEOUT_LOG_PREFIX + usedTimeout); - Launcher.ProcStarter p = launcher.launch().cmds(args.toCommandArray()). - envs(freshEnv).stdout(fos).stderr(err); - if (workDir != null) p.pwd(workDir); - int status = p.start().joinWithTimeout(usedTimeout, TimeUnit.MINUTES, listener); - String result = fos.toString(Charset.defaultCharset().toString()); + int status=0; + String result = ""; + String errorString = ""; + if(ZosCheck() == true) { + // Another behavior on z/OS required due to the race condition + Launcher.ProcStarter p = launcher.launch().cmds(args.toCommandArray()). + envs(freshEnv); + if (workDir != null) p.pwd(workDir); + p.readStdout().readStderr(); + Proc prc = p.start(); + + status = prc.joinWithTimeout(usedTimeout, TimeUnit.MINUTES, listener); + BufferedReader brStdout = new BufferedReader(new InputStreamReader(prc.getStdout())); + BufferedReader brStdErr = new BufferedReader(new InputStreamReader(prc.getStdout())); + + String stdout; + + while ((stdout = brStdout.readLine()) != null) { + result += stdout; + } + String stderr; + while ((stderr = brStdErr.readLine()) != null) { + errorString += stderr; + } + brStdErr.close(); + brStdout.close(); + } else { + // Original behaviour + Launcher.ProcStarter p = launcher.launch().cmds(args.toCommandArray()). + envs(freshEnv).stdout(fos).stderr(err); + if (workDir != null) p.pwd(workDir); + int status = p.start().joinWithTimeout(usedTimeout, TimeUnit.MINUTES, listener); + + result = fos.toString(Charset.defaultCharset().toString()); + errorString = err.toString(Charset.defaultCharset().toString()); + } if (status != 0) { - throw new GitException("Command \""+command+"\" returned status code " + status + ":\nstdout: " + result + "\nstderr: "+ err.toString(Charset.defaultCharset().toString())); + throw new GitException("Command \""+command+"\" returned status code " + status + ":\nstdout: " + result + "\nstderr: "+ errorString); } return result; From 21f368afd04dadb94458757108f934604834c208 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 31 Aug 2018 08:58:24 -0600 Subject: [PATCH 166/226] Use git-changelist-maven-extension 1.0-beta-6 --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index a2d496cc2b..d107aefa52 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -2,6 +2,6 @@ io.jenkins.tools.incrementals git-changelist-maven-extension - 1.0-beta-4 + 1.0-beta-6 From 7a1c345c09aadcd4c83396a0d3d6061f50937863 Mon Sep 17 00:00:00 2001 From: Ivan-Sinitsin Date: Mon, 3 Sep 2018 10:13:59 +0300 Subject: [PATCH 167/226] Findbugs cleanup --- .../jenkinsci/plugins/gitclient/CliGitAPIImpl.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 0f25f63ae4..f538e8fdfc 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -2123,18 +2123,22 @@ private String launchCommandIn(ArgumentListBuilder args, File workDir, EnvVars e Proc prc = p.start(); status = prc.joinWithTimeout(usedTimeout, TimeUnit.MINUTES, listener); - BufferedReader brStdout = new BufferedReader(new InputStreamReader(prc.getStdout())); - BufferedReader brStdErr = new BufferedReader(new InputStreamReader(prc.getStdout())); + BufferedReader brStdout = new BufferedReader(new InputStreamReader(prc.getStdout(),Charset.defaultCharset())); + BufferedReader brStdErr = new BufferedReader(new InputStreamReader(prc.getStderr(),Charset.defaultCharset())); String stdout; + StringBuffer buf = new StringBuffer(); while ((stdout = brStdout.readLine()) != null) { - result += stdout; + buf.append(stdout); } + result = buf.toString(); String stderr; + buf.setLength(0); while ((stderr = brStdErr.readLine()) != null) { - errorString += stderr; + buf.append(stderr); } + errorString = buf.toString(); brStdErr.close(); brStdout.close(); } else { From e767b04caa410590fe0919f93455ec7244a7fd93 Mon Sep 17 00:00:00 2001 From: Ivan-Sinitsin Date: Mon, 3 Sep 2018 10:37:15 +0300 Subject: [PATCH 168/226] EBCDIC charset for output --- .../java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index f538e8fdfc..aedc6ccf49 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -2123,8 +2123,8 @@ private String launchCommandIn(ArgumentListBuilder args, File workDir, EnvVars e Proc prc = p.start(); status = prc.joinWithTimeout(usedTimeout, TimeUnit.MINUTES, listener); - BufferedReader brStdout = new BufferedReader(new InputStreamReader(prc.getStdout(),Charset.defaultCharset())); - BufferedReader brStdErr = new BufferedReader(new InputStreamReader(prc.getStderr(),Charset.defaultCharset())); + BufferedReader brStdout = new BufferedReader(new InputStreamReader(prc.getStdout(),Charset.forName("IBM1047"))); + BufferedReader brStdErr = new BufferedReader(new InputStreamReader(prc.getStderr(),Charset.forName("IBM1047"))); String stdout; From bf7b1026c913eb72cca5b8089f4306c503732682 Mon Sep 17 00:00:00 2001 From: Ivan-Sinitsin Date: Mon, 3 Sep 2018 10:44:57 +0300 Subject: [PATCH 169/226] Duplicate declaration removed --- .../java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index aedc6ccf49..270aa36605 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -2146,7 +2146,7 @@ private String launchCommandIn(ArgumentListBuilder args, File workDir, EnvVars e Launcher.ProcStarter p = launcher.launch().cmds(args.toCommandArray()). envs(freshEnv).stdout(fos).stderr(err); if (workDir != null) p.pwd(workDir); - int status = p.start().joinWithTimeout(usedTimeout, TimeUnit.MINUTES, listener); + status = p.start().joinWithTimeout(usedTimeout, TimeUnit.MINUTES, listener); result = fos.toString(Charset.defaultCharset().toString()); errorString = err.toString(Charset.defaultCharset().toString()); From 057f12c30c9fc9992e67696e60e3da9a481a7fae Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 3 Sep 2018 10:26:52 -0600 Subject: [PATCH 170/226] Remove @AfterClass, it duplicates TemporaryFolder --- src/test/java/org/jenkinsci/plugins/gitclient/PushTest.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/PushTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/PushTest.java index 1abdeed1ae..a6c8af772d 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/PushTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/PushTest.java @@ -232,11 +232,6 @@ public static void createBareRepository() throws Exception { bareFirstCommit = bareGitClient.getHeadRev(bareRepo.getAbsolutePath(), "master"); } - @AfterClass - public static void removeBareRepository() throws IOException { - FileUtils.deleteDirectory(bareRepo); - } - protected void checkoutBranchAndCommitFile() throws GitException, InterruptedException, IOException { previousCommit = checkoutBranch(false); workingCommit = commitFileToCurrentBranch(); From 5051b3a94794c1b9d060e5e4381c713f3118c15f Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 3 Sep 2018 10:27:58 -0600 Subject: [PATCH 171/226] Remove unnecessary extra cleanup step TemporaryFolder already handles the cleanup. --- src/test/java/org/jenkinsci/plugins/gitclient/PushTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/PushTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/PushTest.java index a6c8af772d..0c5a1d58d1 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/PushTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/PushTest.java @@ -225,9 +225,6 @@ public static void createBareRepository() throws Exception { cloneGitClient.push().to(bareURI).ref("HEAD:" + branchName).execute(); } - /* Remove the clone */ - FileUtils.deleteDirectory(cloneRepo); - /* Remember the SHA1 of the first commit */ bareFirstCommit = bareGitClient.getHeadRev(bareRepo.getAbsolutePath(), "master"); } From cb0085f57b22f53019ecbf6f5d57ea4ac7dff052 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 3 Sep 2018 10:35:30 -0600 Subject: [PATCH 172/226] Use more concise call in getBranchNames --- .../java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java | 4 ++-- src/test/java/org/jenkinsci/plugins/gitclient/PushTest.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 213917d8f1..a4d510391c 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -49,7 +49,7 @@ import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; +import static java.util.stream.Collectors.toList; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -984,7 +984,7 @@ private void assertExceptionMessageContains(GitException ge, String expectedSubs } private Collection getBranchNames(Collection branches) { - return branches.stream().map(p -> p.getName()).collect(Collectors.toList()); + return branches.stream().map(Branch::getName).collect(toList()); } public void test_fetch() throws Exception { diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/PushTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/PushTest.java index 0c5a1d58d1..4e8340c492 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/PushTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/PushTest.java @@ -8,7 +8,7 @@ import java.util.Collection; import java.util.List; import java.util.Random; -import java.util.stream.Collectors; +import static java.util.stream.Collectors.toList; import hudson.model.TaskListener; import hudson.plugins.git.Branch; @@ -240,7 +240,7 @@ protected void checkoutOldBranchAndCommitFile() throws GitException, Interrupted } private Collection getBranchNames(List branches) { - return branches.stream().map(p -> p.getName()).collect(Collectors.toList()); + return branches.stream().map(Branch::getName).collect(toList()); } private ObjectId checkoutBranch(boolean useOldCommit) throws GitException, InterruptedException { From 615d9f2055fa3b5024224b291141b3dbb83071fa Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 3 Sep 2018 12:35:49 -0600 Subject: [PATCH 173/226] CONTRIBUTING: see SCM API coding style guidelines --- CONTRIBUTING.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b7ed38f339..665d30307d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,10 +27,12 @@ assure that you haven't introduced new findbugs warnings. # Code Style Guidelines -## Indentation +Use the [Jenkins SCM API coding style guide](https://github.com/jenkinsci/scm-api-plugin/blob/master/CONTRIBUTING.md#code-style-guidelines) for new code. -* Code formatting in the git client plugin varies between files. Recent additions have generally used the Netbeans "Format" right-click action to maintain consistency. Try to maintain reasonable consistency with the existing files. -* Please don't perform wholesale reformatting of a file without discussing with the current maintainers. +## Indentation and White Space + +* Code formatting in the git client plugin varies between files. Recent additions have generally used the Netbeans "Format" right-click action to maintain consistency. Try to maintain reasonable consistency with the existing files +* Please don't reformat a file without discussing with the current maintainers ## Maven POM file layout From 90b2b10706f45e050fdba259c0555e0cc8826d3b Mon Sep 17 00:00:00 2001 From: Ivan-Sinitsin Date: Tue, 4 Sep 2018 07:05:23 +0300 Subject: [PATCH 174/226] After PR review changes PR Review changes and fixes Whitespace cleanup --- .../plugins/gitclient/CliGitAPIImpl.java | 76 ++++++++++--------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 270aa36605..c81ef9cf46 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -8,10 +8,13 @@ import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; -import hudson.*; +import hudson.EnvVars; +import hudson.FilePath; +import hudson.Launcher; import com.google.common.collect.Lists; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.Launcher.LocalLauncher; +import hudson.Util; import hudson.model.TaskListener; import hudson.plugins.git.Branch; import hudson.plugins.git.GitException; @@ -22,6 +25,7 @@ import hudson.plugins.git.Revision; import hudson.util.ArgumentListBuilder; import hudson.util.Secret; +import hudson.Proc; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; @@ -167,7 +171,7 @@ public class CliGitAPIImpl extends LegacyCompatibleGitAPIImpl { final static String SUBMODULE_REMOTE_PATTERN_STRING = SUBMODULE_REMOTE_PATTERN_CONFIG_KEY + "\\s+[^\\s]+$"; - /* Encoding charset for z/OS, only on z/OS USS platform + /* Encoding charset for z/OS, only on z/OS USS platform */ private final String encoding; private void warnIfWindowsTemporaryDirNameHasSpaces() { @@ -806,15 +810,15 @@ public void execute() throws GitException, InterruptedException { public void clean(boolean cleanSubmodule) throws GitException, InterruptedException { reset(true); String cmd = "-fdx"; - if (cleanSubmodule) cmd = "-ffdx"; - + if (cleanSubmodule) cmd = "-ffdx"; + launchCommand("clean", cmd); -} + } -/** - * Remove untracked files and directories, including files listed - * in the ignore rules. - * + /** + * Remove untracked files and directories, including files listed + * in the ignore rules. + * * @throws hudson.plugins.git.GitException if underlying git operation fails. * @throws java.lang.InterruptedException if interrupted. */ @@ -1818,7 +1822,7 @@ private String launchCommandWithCredentials(ArgumentListBuilder args, File workD private File createSshKeyFile(SSHUserPrivateKey sshUser) throws IOException, InterruptedException { File key = createTempFile("ssh", ".key"); - try (PrintWriter w = new PrintWriter(key, this.encoding)) { + try (PrintWriter w = new PrintWriter(key, encoding)) { List privateKeys = sshUser.getPrivateKeys(); for (String s : privateKeys) { w.println(s); @@ -1854,7 +1858,7 @@ private String quoteUnixCredentials(String str) { private File createWindowsSshAskpass(SSHUserPrivateKey sshUser) throws IOException { File ssh = createTempFile("pass", ".bat"); - try (PrintWriter w = new PrintWriter(ssh, this.encoding)) { + try (PrintWriter w = new PrintWriter(ssh, encoding)) { // avoid echoing command as part of the password w.println("@echo off"); // no surrounding double quotes on windows echo -- they are echoed too @@ -1867,7 +1871,7 @@ private File createWindowsSshAskpass(SSHUserPrivateKey sshUser) throws IOExcepti private File createUnixSshAskpass(SSHUserPrivateKey sshUser) throws IOException { File ssh = createTempFile("pass", ".sh"); - try (PrintWriter w = new PrintWriter(ssh, this.encoding)) { + try (PrintWriter w = new PrintWriter(ssh, encoding)) { w.println("#!/bin/sh"); w.println("echo '" + quoteUnixCredentials(Secret.toString(sshUser.getPassphrase())) + "'"); } @@ -1878,7 +1882,7 @@ private File createUnixSshAskpass(SSHUserPrivateKey sshUser) throws IOException /* Package protected for testability */ File createWindowsBatFile(String userName, String password) throws IOException { File askpass = createTempFile("pass", ".bat"); - try (PrintWriter w = new PrintWriter(askpass, this.encoding)) { + try (PrintWriter w = new PrintWriter(askpass, encoding)) { w.println("@set arg=%~1"); w.println("@if (%arg:~0,8%)==(Username) echo " + escapeWindowsCharsForUnquotedString(userName)); w.println("@if (%arg:~0,8%)==(Password) echo " + escapeWindowsCharsForUnquotedString(password)); @@ -1893,7 +1897,7 @@ private File createWindowsStandardAskpass(StandardUsernamePasswordCredentials cr private File createUnixStandardAskpass(StandardUsernamePasswordCredentials creds) throws IOException { File askpass = createTempFile("pass", ".sh"); - try (PrintWriter w = new PrintWriter(askpass, this.encoding)) { + try (PrintWriter w = new PrintWriter(askpass, encoding)) { w.println("#!/bin/sh"); w.println("case \"$1\" in"); w.println("Username*) echo '" + quoteUnixCredentials(creds.getUsername()) + "' ;;"); @@ -2025,8 +2029,8 @@ private File createWindowsGitSSH(File key, String user) throws IOException { File ssh = createTempFile("ssh", ".bat"); File sshexe = getSSHExecutable(); - - try (PrintWriter w = new PrintWriter(ssh, this.encoding)) { + + try (PrintWriter w = new PrintWriter(ssh, encoding)) { w.println("@echo off"); w.println("\"" + sshexe.getAbsolutePath() + "\" -i \"" + key.getAbsolutePath() +"\" -l \"" + user + "\" -o StrictHostKeyChecking=no %* "); } @@ -2042,7 +2046,7 @@ private File createUnixGitSSH(File key, String user) throws IOException { File ssh = createTempFile("ssh", ".sh"); File ssh_copy = new File(ssh.toString() + "-copy"); boolean isCopied = false; - try (PrintWriter w = new PrintWriter(ssh, this.encoding)) { + try (PrintWriter w = new PrintWriter(ssh, encoding)) { w.println("#!/bin/sh"); // ${SSH_ASKPASS} might be ignored if ${DISPLAY} is not set w.println("if [ -z \"${DISPLAY}\" ]; then"); @@ -2052,7 +2056,7 @@ private File createUnixGitSSH(File key, String user) throws IOException { w.println("ssh -i \"" + key.getAbsolutePath() + "\" -l \"" + user + "\" -o StrictHostKeyChecking=no \"$@\""); } ssh.setExecutable(true, true); - //JENKINS-48258 git client plugin occasionally fails with "text file busy" error + //JENKINS-48258 git client plugin occasionally fails with "text file busy" error //The following creates a copy of the generated file and deletes the original //In case of a failure return the original and delete the copy String fromLocation = ssh.toString(); @@ -2073,12 +2077,12 @@ private File createUnixGitSSH(File key, String user) throws IOException { deleteTempFile(ssh_copy); } //Previous operation failed. Return original file - return ssh; + return ssh; + } + + return ssh_copy; } - return ssh_copy; -} - private String launchCommandIn(ArgumentListBuilder args, File workDir) throws GitException, InterruptedException { return launchCommandIn(args, workDir, environment); } @@ -2115,7 +2119,11 @@ private String launchCommandIn(ArgumentListBuilder args, File workDir, EnvVars e String result = ""; String errorString = ""; if(ZosCheck() == true) { - // Another behavior on z/OS required due to the race condition + /* Another behavior on z/OS required due to the race condition happening during transcoding of charset in + EBCDIC code page if CopyThread is used on IBM z/OS Java. For unclear reason, if we rely on Proc class consumption + of stdout and stderr with StreamCopyThread, then first several chars of a stream aren't get transcoded + Also, there is a need to pass a EBCDIC codepage conversion charset into input stream + */ Launcher.ProcStarter p = launcher.launch().cmds(args.toCommandArray()). envs(freshEnv); if (workDir != null) p.pwd(workDir); @@ -2123,24 +2131,22 @@ private String launchCommandIn(ArgumentListBuilder args, File workDir, EnvVars e Proc prc = p.start(); status = prc.joinWithTimeout(usedTimeout, TimeUnit.MINUTES, listener); - BufferedReader brStdout = new BufferedReader(new InputStreamReader(prc.getStdout(),Charset.forName("IBM1047"))); - BufferedReader brStdErr = new BufferedReader(new InputStreamReader(prc.getStderr(),Charset.forName("IBM1047"))); - - String stdout; - StringBuffer buf = new StringBuffer(); - while ((stdout = brStdout.readLine()) != null) { - buf.append(stdout); + String stdout; + String stderr; + try(BufferedReader brStdout = new BufferedReader(new InputStreamReader(prc.getStdout(),Charset.forName("IBM1047")))) { + while ((stdout = brStdout.readLine()) != null) { + buf.append(stdout); + } } result = buf.toString(); - String stderr; buf.setLength(0); - while ((stderr = brStdErr.readLine()) != null) { - buf.append(stderr); + try(BufferedReader brStdErr = new BufferedReader(new InputStreamReader(prc.getStderr(),Charset.forName("IBM1047")))) { + while ((stderr = brStdErr.readLine()) != null) { + buf.append(stderr); + } } errorString = buf.toString(); - brStdErr.close(); - brStdout.close(); } else { // Original behaviour Launcher.ProcStarter p = launcher.launch().cmds(args.toCommandArray()). From 9848c7d4e3fd90bd478a4111672b4b5eed820a13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Tue, 4 Sep 2018 22:53:17 +0200 Subject: [PATCH 175/226] Cleanup z/OS implementation * use defined encoding everywhere * share common code between original and z/OS implementation * name variables properly * cleanup formatting --- .../plugins/gitclient/CliGitAPIImpl.java | 106 +++++++++--------- 1 file changed, 52 insertions(+), 54 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index c81ef9cf46..f3ef55ced9 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -59,7 +59,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -145,6 +144,7 @@ public class CliGitAPIImpl extends LegacyCompatibleGitAPIImpl { private Map credentials = new HashMap<>(); private StandardCredentials defaultCredentials; private StandardCredentials lfsCredentials; + private final String encoding; /* git config --get-regex applies the regex to match keys, and returns all matches (including substring matches). * Thus, a config call: @@ -170,10 +170,6 @@ public class CliGitAPIImpl extends LegacyCompatibleGitAPIImpl { /* Package protected for testing */ final static String SUBMODULE_REMOTE_PATTERN_STRING = SUBMODULE_REMOTE_PATTERN_CONFIG_KEY + "\\s+[^\\s]+$"; - - /* Encoding charset for z/OS, only on z/OS USS platform - */ - private final String encoding; private void warnIfWindowsTemporaryDirNameHasSpaces() { if (!isWindows()) { return; @@ -251,15 +247,14 @@ private void getGitVersion() { * @param listener a {@link hudson.model.TaskListener} object. * @param environment a {@link hudson.EnvVars} object. */ - protected CliGitAPIImpl(String gitExe, File workspace, - TaskListener listener, EnvVars environment) { + protected CliGitAPIImpl(String gitExe, File workspace, TaskListener listener, EnvVars environment) { super(workspace); this.listener = listener; this.gitExe = gitExe; this.environment = environment; - this.encoding = ZosCheck() ? "IBM1047" : Charset.defaultCharset().toString(); - - launcher = new LocalLauncher(IGitAPI.verbose?listener:TaskListener.NULL); + this.encoding = isZos() ? "IBM1047" : Charset.defaultCharset().toString(); + + launcher = new LocalLauncher(IGitAPI.verbose ? listener : TaskListener.NULL); } /** {@inheritDoc} */ @@ -2038,10 +2033,6 @@ private File createWindowsGitSSH(File key, String user) throws IOException { return ssh; } - private static final boolean ZosCheck() { - return (File.pathSeparatorChar==':') && System.getProperty("os.name").equals("z/OS"); - } - private File createUnixGitSSH(File key, String user) throws IOException { File ssh = createTempFile("ssh", ".sh"); File ssh_copy = new File(ssh.toString() + "-copy"); @@ -2092,9 +2083,6 @@ private String launchCommandIn(ArgumentListBuilder args, File workDir, EnvVars e } private String launchCommandIn(ArgumentListBuilder args, File workDir, EnvVars env, Integer timeout) throws GitException, InterruptedException { - ByteArrayOutputStream fos = new ByteArrayOutputStream(); - // JENKINS-13356: capture the output of stderr separately - ByteArrayOutputStream err = new ByteArrayOutputStream(); EnvVars freshEnv = new EnvVars(env); // If we don't have credentials, but the requested URL requires them, @@ -2115,53 +2103,60 @@ private String launchCommandIn(ArgumentListBuilder args, File workDir, EnvVars e int usedTimeout = timeout == null ? TIMEOUT : timeout; listener.getLogger().println(" > " + command + TIMEOUT_LOG_PREFIX + usedTimeout); - int status=0; - String result = ""; - String errorString = ""; - if(ZosCheck() == true) { - /* Another behavior on z/OS required due to the race condition happening during transcoding of charset in - EBCDIC code page if CopyThread is used on IBM z/OS Java. For unclear reason, if we rely on Proc class consumption - of stdout and stderr with StreamCopyThread, then first several chars of a stream aren't get transcoded - Also, there is a need to pass a EBCDIC codepage conversion charset into input stream - */ - Launcher.ProcStarter p = launcher.launch().cmds(args.toCommandArray()). - envs(freshEnv); - if (workDir != null) p.pwd(workDir); + Launcher.ProcStarter p = launcher.launch().cmds(args.toCommandArray()).envs(freshEnv); + + if (workDir != null) { + p.pwd(workDir); + } + + int status; + String stdout; + String stderr; + + if (isZos()) { + // Another behavior on z/OS required due to the race condition happening during transcoding of charset in + // EBCDIC code page if CopyThread is used on IBM z/OS Java. For unclear reason, if we rely on Proc class consumption + // of stdout and stderr with StreamCopyThread, then first several chars of a stream aren't get transcoded. + // Also, there is a need to pass a EBCDIC codepage conversion charset into input stream. p.readStdout().readStderr(); - Proc prc = p.start(); - - status = prc.joinWithTimeout(usedTimeout, TimeUnit.MINUTES, listener); - StringBuffer buf = new StringBuffer(); - String stdout; - String stderr; - try(BufferedReader brStdout = new BufferedReader(new InputStreamReader(prc.getStdout(),Charset.forName("IBM1047")))) { - while ((stdout = brStdout.readLine()) != null) { - buf.append(stdout); + Proc process = p.start(); + + status = process.joinWithTimeout(usedTimeout, TimeUnit.MINUTES, listener); + + StringBuilder stdoutBuilder = new StringBuilder(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getStdout(), encoding))) { + String line; + while ((line = reader.readLine()) != null) { + stdoutBuilder.append(line); } } - result = buf.toString(); - buf.setLength(0); - try(BufferedReader brStdErr = new BufferedReader(new InputStreamReader(prc.getStderr(),Charset.forName("IBM1047")))) { - while ((stderr = brStdErr.readLine()) != null) { - buf.append(stderr); + stdout = stdoutBuilder.toString(); + + StringBuilder stderrBuilder = new StringBuilder(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getStderr(), encoding))) { + String line; + while ((line = reader.readLine()) != null) { + stderrBuilder.append(line); } } - errorString = buf.toString(); + stderr = stderrBuilder.toString(); } else { - // Original behaviour - Launcher.ProcStarter p = launcher.launch().cmds(args.toCommandArray()). - envs(freshEnv).stdout(fos).stderr(err); - if (workDir != null) p.pwd(workDir); + // JENKINS-13356: capture stdout and stderr separately + ByteArrayOutputStream stdoutStream = new ByteArrayOutputStream(); + ByteArrayOutputStream stderrStream = new ByteArrayOutputStream(); + + p.stdout(stdoutStream).stderr(stderrStream); status = p.start().joinWithTimeout(usedTimeout, TimeUnit.MINUTES, listener); - result = fos.toString(Charset.defaultCharset().toString()); - errorString = err.toString(Charset.defaultCharset().toString()); + stdout = stdoutStream.toString(encoding); + stderr = stderrStream.toString(encoding); } + if (status != 0) { - throw new GitException("Command \""+command+"\" returned status code " + status + ":\nstdout: " + result + "\nstderr: "+ errorString); + throw new GitException("Command \"" + command + "\" returned status code " + status + ":\nstdout: " + stdout + "\nstderr: "+ stderr); } - return result; + return stdout; } catch (GitException | InterruptedException e) { throw e; } catch (IOException e) { @@ -2169,7 +2164,6 @@ private String launchCommandIn(ArgumentListBuilder args, File workDir, EnvVars e } catch (Throwable t) { throw new GitException("Error performing git command", t); } - } /** @@ -3150,7 +3144,11 @@ public String getAllLogEntries(String branch) throws InterruptedException { /** inline ${@link hudson.Functions#isWindows()} to prevent a transient remote classloader issue */ private boolean isWindows() { - return File.pathSeparatorChar==';'; + return File.pathSeparatorChar == ';'; + } + + private boolean isZos() { + return File.pathSeparatorChar == ':' && System.getProperty("os.name").equals("z/OS"); } /* Return true if setsid program exists */ From 75920950e88e869394f982953bf571a127655b1d Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 11 Aug 2018 08:00:50 -0600 Subject: [PATCH 176/226] Move setRemoteUrl adjacent to repo init --- .../java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index a4d510391c..546134ba72 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -1338,12 +1338,12 @@ public void test_fetch_with_prune() throws Exception { /* master -> branch1 */ /* -> branch2 */ w.init(); + w.git.setRemoteUrl("origin", bare.repoPath()); w.touch("file-master", "file master content " + java.util.UUID.randomUUID().toString()); w.git.add("file-master"); w.git.commit("master-commit"); ObjectId master = w.head(); - assertThat(getBranchNames(w.git.getBranches()), contains("master")); - w.git.setRemoteUrl("origin", bare.repoPath()); + assertEquals("Wrong branch count", 1, w.git.getBranches().size()); w.git.push("origin", "master"); /* master branch is now on bare repo */ w.git.checkout("master"); From 83dd4f27f14294c10452bf19b85bff637f43765f Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 11 Aug 2018 08:03:38 -0600 Subject: [PATCH 177/226] Add @Issue references for 3 more tested bugs --- .../org/jenkinsci/plugins/gitclient/GitAPITestCase.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 546134ba72..4aaa6427c3 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -2839,11 +2839,12 @@ private boolean isJava6() { return false; } - /** - * core.symlinks is set to false by msysgit on Windows and by JGit - * 3.3.0 on all platforms. It is not set on Linux. Refer to - * JENKINS-21168, JENKINS-22376, and JENKINS-22391 for details. + /* + * core.symlinks is set to false by git for WIndows. + * It is not set on Linux. + * See also JENKINS-22376 and JENKINS-22391 */ + @Issue("JENKINS-21168") private void checkSymlinkSetting(WorkingArea area) throws IOException { String expected = SystemUtils.IS_OS_WINDOWS || (area.git instanceof JGitAPIImpl && isJava6()) ? "false" : ""; String symlinkValue = null; From cdb18904de8d928c3c71a49e83e0380ec5e7df75 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 11 Aug 2018 08:07:42 -0600 Subject: [PATCH 178/226] Remove Java 6 support from test - JDK 6 is dead --- .../org/jenkinsci/plugins/gitclient/GitAPITestCase.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 4aaa6427c3..3240445ccb 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -2832,13 +2832,6 @@ public void test_hasSubmodules() throws Exception { assertFixSubmoduleUrlsThrows(); } - private boolean isJava6() { - if (System.getProperty("java.version").startsWith("1.6")) { - return true; - } - return false; - } - /* * core.symlinks is set to false by git for WIndows. * It is not set on Linux. @@ -2846,7 +2839,7 @@ private boolean isJava6() { */ @Issue("JENKINS-21168") private void checkSymlinkSetting(WorkingArea area) throws IOException { - String expected = SystemUtils.IS_OS_WINDOWS || (area.git instanceof JGitAPIImpl && isJava6()) ? "false" : ""; + String expected = SystemUtils.IS_OS_WINDOWS ? "false" : ""; String symlinkValue = null; try { symlinkValue = w.cmd(true, "git config core.symlinks").trim(); From f1c5c6771a81517dcdf021d0b97eae044c344f7c Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 11 Aug 2018 11:01:01 -0600 Subject: [PATCH 179/226] Extract getBranchNames in test Better diagnostic message in the output (branch names only, not branch names and SHA-1 of HEAD of the branch) and easier to read. --- .../org/jenkinsci/plugins/gitclient/GitAPITestCase.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 3240445ccb..e67a271f17 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -465,15 +465,19 @@ private void check_remote_url(final String repositoryName) throws InterruptedExc assertTrue("remote URL has not been updated", remotes.contains(localMirror())); } + private Collection getBranchNames(Set branches) { + return Collections2.transform(branches, GitObject::getName); + } + private void assertBranchesExist(Set branches, String ... names) throws InterruptedException { - Collection branchNames = Collections2.transform(branches, GitObject::getName); + Collection branchNames = getBranchNames(branches); for (String name : names) { assertTrue(name + " branch not found in " + branchNames, branchNames.contains(name)); } } private void assertBranchesNotExist(Set branches, String ... names) throws InterruptedException { - Collection branchNames = Collections2.transform(branches, GitObject::getName); + Collection branchNames = getBranchNames(branches); for (String name : names) { assertFalse(name + " branch found in " + branchNames, branchNames.contains(name)); } From 184fc53777d078a135d8b983a0e427b12ba72650 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 11 Aug 2018 11:15:46 -0600 Subject: [PATCH 180/226] Remove unreferenced test variables --- .../java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index e67a271f17..1e3caf4113 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -1346,7 +1346,6 @@ public void test_fetch_with_prune() throws Exception { w.touch("file-master", "file master content " + java.util.UUID.randomUUID().toString()); w.git.add("file-master"); w.git.commit("master-commit"); - ObjectId master = w.head(); assertEquals("Wrong branch count", 1, w.git.getBranches().size()); w.git.push("origin", "master"); /* master branch is now on bare repo */ @@ -1355,7 +1354,6 @@ public void test_fetch_with_prune() throws Exception { w.touch("file-branch1", "file branch1 content " + java.util.UUID.randomUUID().toString()); w.git.add("file-branch1"); w.git.commit("branch1-commit"); - ObjectId branch1 = w.head(); assertThat(getBranchNames(w.git.getBranches()), containsInAnyOrder("master", "branch1")); w.git.push("origin", "branch1"); /* branch1 is now on bare repo */ @@ -1364,7 +1362,6 @@ public void test_fetch_with_prune() throws Exception { w.touch("file-branch2", "file branch2 content " + java.util.UUID.randomUUID().toString()); w.git.add("file-branch2"); w.git.commit("branch2-commit"); - ObjectId branch2 = w.head(); assertThat(getBranchNames(w.git.getBranches()), containsInAnyOrder("master", "branch1", "branch2")); assertThat(w.git.getRemoteBranches(), is(empty())); w.git.push("origin", "branch2"); /* branch2 is now on bare repo */ From c1930addf209a975090b33a40cebe9a1c05c35b5 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 11 Aug 2018 11:16:58 -0600 Subject: [PATCH 181/226] Simplify test refspec initialization --- .../java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 1e3caf4113..65f2aff711 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -1375,9 +1375,7 @@ public void test_fetch_with_prune() throws Exception { /* Remove branch1 from bare repo using original repo */ w.cmd("git push " + bare.repoPath() + " :branch1"); - RefSpec defaultRefSpec = new RefSpec("+refs/heads/*:refs/remotes/origin/*"); - List refSpecs = new ArrayList<>(); - refSpecs.add(defaultRefSpec); + List refSpecs = Arrays.asList(new RefSpec("+refs/heads/*:refs/remotes/origin/*")); /* Fetch without prune should leave branch1 in newArea */ newArea.cmd("git config fetch.prune false"); From 001c345a69b105798f3e6ffea49b8c7ae5352e45 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 8 Sep 2018 12:56:09 -0600 Subject: [PATCH 182/226] Remove redundant getBranchNames --- .../org/jenkinsci/plugins/gitclient/GitAPITestCase.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 65f2aff711..5d567c62ec 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -465,8 +465,8 @@ private void check_remote_url(final String repositoryName) throws InterruptedExc assertTrue("remote URL has not been updated", remotes.contains(localMirror())); } - private Collection getBranchNames(Set branches) { - return Collections2.transform(branches, GitObject::getName); + private Collection getBranchNames(Collection branches) { + return branches.stream().map(Branch::getName).collect(toList()); } private void assertBranchesExist(Set branches, String ... names) throws InterruptedException { @@ -987,10 +987,6 @@ private void assertExceptionMessageContains(GitException ge, String expectedSubs assertTrue("Expected '" + expectedSubstring + "' exception message, but was: " + actual, actual.contains(expectedSubstring)); } - private Collection getBranchNames(Collection branches) { - return branches.stream().map(Branch::getName).collect(toList()); - } - public void test_fetch() throws Exception { /* Create a working repo containing a commit */ w.init(); From 6c778e0a4acc4b26aab6573b2e1147e8187e5567 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 8 Sep 2018 12:57:14 -0600 Subject: [PATCH 183/226] Use hamcrest assertions in two more cases --- .../java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 5d567c62ec..43900771bd 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -472,14 +472,14 @@ private Collection getBranchNames(Collection branches) { private void assertBranchesExist(Set branches, String ... names) throws InterruptedException { Collection branchNames = getBranchNames(branches); for (String name : names) { - assertTrue(name + " branch not found in " + branchNames, branchNames.contains(name)); + assertThat(branchNames, hasItem(name)); } } private void assertBranchesNotExist(Set branches, String ... names) throws InterruptedException { Collection branchNames = getBranchNames(branches); for (String name : names) { - assertFalse(name + " branch found in " + branchNames, branchNames.contains(name)); + assertThat(branchNames, not(hasItem(name))); } } From 5a630b1bba290ef654da93f199a728aca20fee8a Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 10 Aug 2018 23:49:28 -0600 Subject: [PATCH 184/226] Use JGit's implementation of prune during fetch JGit 5.0.2 fixes the behavior of prune during fetch so that the alternative implementation is no longer required. --- pom.xml | 2 +- .../plugins/gitclient/JGitAPIImpl.java | 29 +------------------ .../plugins/gitclient/GitAPITestCase.java | 12 ++++---- 3 files changed, 8 insertions(+), 35 deletions(-) diff --git a/pom.xml b/pom.xml index 8c1845bf6a..bb781e6f3a 100644 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,7 @@ -Dfile.encoding=${project.build.sourceEncoding} 2.60.3 8 - 5.0.2.201807311906-r + 5.1.0.201808281540-m3 diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index 327eb89575..5c7553c361 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -551,8 +551,6 @@ public org.jenkinsci.plugins.gitclient.FetchCommand fetch_() { return new org.jenkinsci.plugins.gitclient.FetchCommand() { public URIish url; public List refspecs; - // JGit 3.3.0 thru 3.6.0 prune more branches than expected - // Refer to GitAPITestCase.test_fetch_with_prune() private boolean shouldPrune = false; public boolean tags = true; @@ -611,31 +609,6 @@ public void execute() throws GitException, InterruptedException { if (rs != null) allRefSpecs.add(rs); - if (shouldPrune) { - // since prune is broken in JGit, we go the trivial way: - // delete all refs matching the right side of the refspecs - // then fetch and let git recreate them. - List refs = git.branchList().setListMode(ListBranchCommand.ListMode.REMOTE).call(); - - List toDelete = new ArrayList<>(refs.size()); - - for (ListIterator it = refs.listIterator(); it.hasNext(); ) { - Ref branchRef = it.next(); - if (!branchRef.isSymbolic()) { // Don't delete HEAD and other symbolic refs - for (RefSpec rs : allRefSpecs) { - if (rs.matchDestination(branchRef)) { - toDelete.add(branchRef.getName()); - break; - } - } - } - } - if (!toDelete.isEmpty()) { - // we need force = true because usually not all remote branches will be merged into the current branch. - git.branchDelete().setForce(true).setBranchNames(toDelete.toArray(new String[toDelete.size()])).call(); - } - } - FetchCommand fetch = git.fetch(); fetch.setTagOpt(tags ? TagOpt.FETCH_TAGS : TagOpt.NO_TAGS); /* JGit 4.5 required a work around that the tags refspec had to be passed in addition to setting @@ -650,7 +623,7 @@ public void execute() throws GitException, InterruptedException { fetch.setCredentialsProvider(getProvider()); fetch.setRefSpecs(allRefSpecs); - // fetch.setRemoveDeletedRefs(shouldPrune); + fetch.setRemoveDeletedRefs(shouldPrune); fetch.call(); } catch (GitAPIException e) { diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java index 43900771bd..a895691465 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java @@ -1323,13 +1323,13 @@ public void test_fetch_timeout() throws Exception { } /** - * JGit 3.3.0 thru 3.6.0 "prune during fetch" prunes more remote - * branches than command line git prunes during fetch. This test - * should be used to evaluate future versions of JGit to see if - * pruning behavior more closely emulates command line git. - * - * This has been fixed using a workaround. + * JGit 3.3.0 thru 4.5.4 "prune during fetch" prunes more remote + * branches than command line git prunes during fetch. JGit 5.0.2 + * fixes the problem. + * Refer to https://bugs.eclipse.org/bugs/show_bug.cgi?id=533549 + * Refer to https://bugs.eclipse.org/bugs/show_bug.cgi?id=533806 */ + @Issue("JENKINS-26197") public void test_fetch_with_prune() throws Exception { WorkingArea bare = new WorkingArea(); bare.init(true); From 9f79fd9832da3bd6f00326d9e2d48e0b2fc06a37 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 9 Sep 2018 15:22:31 -0600 Subject: [PATCH 185/226] Use JGit 5.0.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bb781e6f3a..ad4ceabfea 100644 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,7 @@ -Dfile.encoding=${project.build.sourceEncoding} 2.60.3 8 - 5.1.0.201808281540-m3 + 5.0.3.201809091024-r From d92774a8fdc0f2f75e05067e33eb45f1c7ae5214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Mon, 6 Aug 2018 21:42:33 +0200 Subject: [PATCH 186/226] Make all instance variables private in all Command implementations * this is for consistency reasons * it has no effect on clients as the methods return type uses the respective command interface only --- .../plugins/gitclient/CliGitAPIImpl.java | 104 +++++++++--------- .../plugins/gitclient/JGitAPIImpl.java | 81 +++++++------- 2 files changed, 91 insertions(+), 94 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index f3ef55ced9..840fa7ec7c 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -333,13 +333,13 @@ public List getSubmodules( String treeIsh ) throws GitException, Int */ public FetchCommand fetch_() { return new FetchCommand() { - public URIish url; - public List refspecs; - public boolean prune; - public boolean shallow; - public Integer timeout; - public boolean tags = true; - public Integer depth = 1; + private URIish url; + private List refspecs; + private boolean prune; + private boolean shallow; + private Integer timeout; + private boolean tags = true; + private Integer depth = 1; public FetchCommand from(URIish remote, List refspecs) { this.url = remote; @@ -489,14 +489,14 @@ public void reset(boolean hard) throws GitException, InterruptedException { */ public CloneCommand clone_() { return new CloneCommand() { - String url; - String origin = "origin"; - String reference; - boolean shallow,shared; - Integer timeout; - boolean tags = true; - List refspecs; - Integer depth = 1; + private String url; + private String origin = "origin"; + private String reference; + private boolean shallow,shared; + private Integer timeout; + private boolean tags = true; + private List refspecs; + private Integer depth = 1; public CloneCommand url(String url) { this.url = url; @@ -647,12 +647,12 @@ else if (!referencePath.isDirectory()) */ public MergeCommand merge() { return new MergeCommand() { - public ObjectId rev; - public String comment; - public String strategy; - public String fastForwardMode; - public boolean squash; - public boolean commit = true; + private ObjectId rev; + private String comment; + private String strategy; + private String fastForwardMode; + private boolean squash; + private boolean commit = true; public MergeCommand setRevisionToMerge(ObjectId rev) { this.rev = rev; @@ -754,8 +754,8 @@ public void execute() throws GitException, InterruptedException { public InitCommand init_() { return new InitCommand() { - public String workspace; - public boolean bare; + private String workspace; + private boolean bare; public InitCommand workspace(String workspace) { this.workspace = workspace; @@ -942,10 +942,10 @@ public ChangelogCommand changelog() { /** Equivalent to the git-log raw format but using ISO 8601 date format - also prevent to depend on git CLI future changes */ public static final String RAW = "commit %H%ntree %T%nparent %P%nauthor %aN <%aE> %ai%ncommitter %cN <%cE> %ci%n%n%w(76,4,4)%s%n%n%b"; - final List revs = new ArrayList<>(); + private final List revs = new ArrayList<>(); - Integer n = null; - Writer out = null; + private Integer n = null; + private Writer out = null; @Override public ChangelogCommand excludes(String rev) { @@ -1068,15 +1068,15 @@ public void submoduleSync() throws GitException, InterruptedException { */ public SubmoduleUpdateCommand submoduleUpdate() { return new SubmoduleUpdateCommand() { - boolean recursive = false; - boolean remoteTracking = false; - boolean parentCredentials = false; - boolean shallow = false; - String ref = null; - Map submodBranch = new HashMap<>(); - public Integer timeout; - Integer depth = 1; - Integer threads = 1; + private boolean recursive = false; + private boolean remoteTracking = false; + private boolean parentCredentials = false; + private boolean shallow = false; + private String ref = null; + private Map submodBranch = new HashMap<>(); + private Integer timeout; + private Integer depth = 1; + private Integer threads = 1; public SubmoduleUpdateCommand recursive(boolean recursive) { this.recursive = recursive; @@ -2173,11 +2173,11 @@ private String launchCommandIn(ArgumentListBuilder args, File workDir, EnvVars e */ public PushCommand push() { return new PushCommand() { - public URIish remote; - public String refspec; - public boolean force; - public boolean tags; - public Integer timeout; + private URIish remote; + private String refspec; + private boolean force; + private boolean tags; + private Integer timeout; public PushCommand to(URIish remote) { this.remote = remote; @@ -2347,13 +2347,13 @@ public Set getRemoteBranches() throws GitException, InterruptedException public CheckoutCommand checkout() { return new CheckoutCommand() { - public String ref; - public String branch; - public boolean deleteBranch; - public List sparseCheckoutPaths = Collections.emptyList(); - public Integer timeout; - public String lfsRemote; - public StandardCredentials lfsCredentials; + private String ref; + private String branch; + private boolean deleteBranch; + private List sparseCheckoutPaths = Collections.emptyList(); + private Integer timeout; + private String lfsRemote; + private StandardCredentials lfsCredentials; public CheckoutCommand ref(String ref) { this.ref = ref; @@ -2600,11 +2600,11 @@ public List lsTree(String treeIsh, boolean recursive) throws GitExce */ public RevListCommand revList_() { return new RevListCommand() { - public boolean all; - public boolean nowalk; - public boolean firstParent; - public String refspec; - public List out; + private boolean all; + private boolean nowalk; + private boolean firstParent; + private String refspec; + private List out; public RevListCommand all() { return all(true); diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index 5c7553c361..5d574e7e06 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -254,11 +254,10 @@ private void doInit(String workspace, boolean bare) throws GitException { @Override public CheckoutCommand checkout() { return new CheckoutCommand() { - - public String ref; - public String branch; - public boolean deleteBranch; - public List sparseCheckoutPaths = Collections.emptyList(); + private String ref; + private String branch; + private boolean deleteBranch; + private List sparseCheckoutPaths = Collections.emptyList(); @Override public CheckoutCommand ref(String ref) { @@ -549,10 +548,10 @@ public boolean tagExists(String tagName) throws GitException { @Override public org.jenkinsci.plugins.gitclient.FetchCommand fetch_() { return new org.jenkinsci.plugins.gitclient.FetchCommand() { - public URIish url; - public List refspecs; + private URIish url; + private List refspecs; private boolean shouldPrune = false; - public boolean tags = true; + private boolean tags = true; @Override public org.jenkinsci.plugins.gitclient.FetchCommand from(URIish remote, List refspecs) { @@ -1067,11 +1066,11 @@ public void appendNote(String note, String namespace) throws GitException { @Override public ChangelogCommand changelog() { return new ChangelogCommand() { - Repository repo = getRepository(); - ObjectReader or = repo.newObjectReader(); - RevWalk walk = new RevWalk(or); - Writer out; - boolean hasIncludedRev = false; + private Repository repo = getRepository(); + private ObjectReader or = repo.newObjectReader(); + private RevWalk walk = new RevWalk(or); + private Writer out; + private boolean hasIncludedRev = false; @Override public ChangelogCommand excludes(String rev) { @@ -1313,13 +1312,13 @@ public void clean() throws GitException { public CloneCommand clone_() { return new CloneCommand() { - String url; - String remote = Constants.DEFAULT_REMOTE_NAME; - String reference; - Integer timeout; - boolean shared; - boolean tags = true; - List refspecs; + private String url; + private String remote = Constants.DEFAULT_REMOTE_NAME; + private String reference; + private Integer timeout; + private boolean shared; + private boolean tags = true; + private List refspecs; @Override public CloneCommand url(String url) { @@ -1495,13 +1494,12 @@ else if (!referencePath.isDirectory()) @Override public MergeCommand merge() { return new MergeCommand() { - - ObjectId rev; - MergeStrategy strategy; - FastForwardMode fastForwardMode; - boolean squash; - boolean commit = true; - String comment; + private ObjectId rev; + private MergeStrategy strategy; + private FastForwardMode fastForwardMode; + private boolean squash; + private boolean commit = true; + private String comment; @Override public MergeCommand setRevisionToMerge(ObjectId rev) { @@ -1592,9 +1590,8 @@ public void execute() throws GitException, InterruptedException { @Override public InitCommand init_() { return new InitCommand() { - - public String workspace; - public boolean bare; + private String workspace; + private boolean bare; @Override public InitCommand workspace(String workspace) { @@ -1814,10 +1811,10 @@ private Set listRemoteBranches(String remote) throws NotSupportedExcepti @Override public PushCommand push() { return new PushCommand() { - public URIish remote; - public String refspec; - public boolean force; - public boolean tags; + private URIish remote; + private String refspec; + private boolean force; + private boolean tags; @Override public PushCommand to(URIish remote) { @@ -1939,11 +1936,11 @@ private String fixRefSpec(Repository repository) throws IOException { public RevListCommand revList_() { return new RevListCommand() { - public boolean all; - public boolean nowalk; - public boolean firstParent; - public String refspec; - public List out; + private boolean all; + private boolean nowalk; + private boolean firstParent; + private String refspec; + private List out; @Override public RevListCommand all() { @@ -2155,9 +2152,9 @@ public void submoduleClean(boolean recursive) throws GitException { @Override public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand submoduleUpdate() { return new org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand() { - boolean recursive = false; - boolean remoteTracking = false; - String ref = null; + private boolean recursive = false; + private boolean remoteTracking = false; + private String ref = null; @Override public org.jenkinsci.plugins.gitclient.SubmoduleUpdateCommand recursive(boolean recursive) { From 2dd0ebcc1745c8759d0b98c819414782a5431247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Mon, 6 Aug 2018 21:56:51 +0200 Subject: [PATCH 187/226] Use @Override on all implemented methods in all Command implementations * this is for consistency reasons (with JGitAPIImpl and in general) --- .../plugins/gitclient/CliGitAPIImpl.java | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 840fa7ec7c..bccc27114a 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -341,41 +341,49 @@ public FetchCommand fetch_() { private boolean tags = true; private Integer depth = 1; + @Override public FetchCommand from(URIish remote, List refspecs) { this.url = remote; this.refspecs = refspecs; return this; } + @Override public FetchCommand tags(boolean tags) { this.tags = tags; return this; } + @Override public FetchCommand prune() { return prune(true); } + @Override public FetchCommand prune(boolean prune) { this.prune = prune; return this; } + @Override public FetchCommand shallow(boolean shallow) { this.shallow = shallow; return this; } + @Override public FetchCommand timeout(Integer timeout) { this.timeout = timeout; return this; } + @Override public FetchCommand depth(Integer depth) { this.depth = depth; return this; } + @Override public void execute() throws GitException, InterruptedException { listener.getLogger().println( "Fetching upstream changes from " + url); @@ -498,16 +506,19 @@ public CloneCommand clone_() { private List refspecs; private Integer depth = 1; + @Override public CloneCommand url(String url) { this.url = url; return this; } + @Override public CloneCommand repositoryName(String name) { this.origin = name; return this; } + @Override public CloneCommand shared() { return shared(true); } @@ -518,6 +529,7 @@ public CloneCommand shared(boolean shared) { return this; } + @Override public CloneCommand shallow() { return shallow(true); } @@ -528,36 +540,43 @@ public CloneCommand shallow(boolean shallow) { return this; } + @Override public CloneCommand noCheckout() { //this.noCheckout = true; Since the "clone" command has been replaced with init + fetch, the --no-checkout option is always satisfied return this; } + @Override public CloneCommand tags(boolean tags) { this.tags = tags; return this; } + @Override public CloneCommand reference(String reference) { this.reference = reference; return this; } + @Override public CloneCommand timeout(Integer timeout) { this.timeout = timeout; return this; } + @Override public CloneCommand depth(Integer depth) { this.depth = depth; return this; } + @Override public CloneCommand refspecs(List refspecs) { this.refspecs = new ArrayList<>(refspecs); return this; } + @Override public void execute() throws GitException, InterruptedException { URIish urIish = null; @@ -654,36 +673,43 @@ public MergeCommand merge() { private boolean squash; private boolean commit = true; + @Override public MergeCommand setRevisionToMerge(ObjectId rev) { this.rev = rev; return this; } + @Override public MergeCommand setStrategy(MergeCommand.Strategy strategy) { this.strategy = strategy.toString(); return this; } + @Override public MergeCommand setGitPluginFastForwardMode(MergeCommand.GitPluginFastForwardMode fastForwardMode) { this.fastForwardMode = fastForwardMode.toString(); return this; } + @Override public MergeCommand setSquash(boolean squash) { this.squash = squash; return this; } + @Override public MergeCommand setMessage(String comment) { this.comment = comment; return this; } + @Override public MergeCommand setCommit(boolean commit) { this.commit = commit; return this; } + @Override public void execute() throws GitException, InterruptedException { ArgumentListBuilder args = new ArgumentListBuilder(); args.add("merge"); @@ -727,11 +753,13 @@ public RebaseCommand rebase() { return new RebaseCommand() { private String upstream; + @Override public RebaseCommand setUpstream(String upstream) { this.upstream = upstream; return this; } + @Override public void execute() throws GitException, InterruptedException { try { ArgumentListBuilder args = new ArgumentListBuilder(); @@ -757,16 +785,19 @@ public InitCommand init_() { private String workspace; private boolean bare; + @Override public InitCommand workspace(String workspace) { this.workspace = workspace; return this; } + @Override public InitCommand bare(boolean bare) { this.bare = bare; return this; } + @Override public void execute() throws GitException, InterruptedException { /* Match JGit - create directory if it does not exist */ /* Multi-branch pipeline assumes init() creates directory */ @@ -1078,46 +1109,55 @@ public SubmoduleUpdateCommand submoduleUpdate() { private Integer depth = 1; private Integer threads = 1; + @Override public SubmoduleUpdateCommand recursive(boolean recursive) { this.recursive = recursive; return this; } + @Override public SubmoduleUpdateCommand remoteTracking(boolean remoteTracking) { this.remoteTracking = remoteTracking; return this; } + @Override public SubmoduleUpdateCommand parentCredentials(boolean parentCredentials) { this.parentCredentials = parentCredentials; return this; } + @Override public SubmoduleUpdateCommand ref(String ref) { this.ref = ref; return this; } + @Override public SubmoduleUpdateCommand useBranch(String submodule, String branchname) { this.submodBranch.put(submodule, branchname); return this; } + @Override public SubmoduleUpdateCommand timeout(Integer timeout) { this.timeout = timeout; return this; } + @Override public SubmoduleUpdateCommand shallow(boolean shallow) { this.shallow = shallow; return this; } + @Override public SubmoduleUpdateCommand depth(Integer depth) { this.depth = depth; return this; } + @Override public SubmoduleUpdateCommand threads(Integer threads) { this.threads = threads; return this; @@ -1127,6 +1167,7 @@ public SubmoduleUpdateCommand threads(Integer threads) { * @throws GitException if executing the Git command fails * @throws InterruptedException if called methods throw same exception */ + @Override public void execute() throws GitException, InterruptedException { // Initialize the submodules to ensure that the git config // contains the URLs from .gitmodules. @@ -2179,16 +2220,19 @@ public PushCommand push() { private boolean tags; private Integer timeout; + @Override public PushCommand to(URIish remote) { this.remote = remote; return this; } + @Override public PushCommand ref(String refspec) { this.refspec = refspec; return this; } + @Override public PushCommand force() { return force(true); } @@ -2199,16 +2243,19 @@ public PushCommand force(boolean force) { return this; } + @Override public PushCommand tags(boolean tags) { this.tags = tags; return this; } + @Override public PushCommand timeout(Integer timeout) { this.timeout = timeout; return this; } + @Override public void execute() throws GitException, InterruptedException { ArgumentListBuilder args = new ArgumentListBuilder(); args.add("push", remote.toPrivateASCIIString()); @@ -2355,31 +2402,37 @@ public CheckoutCommand checkout() { private String lfsRemote; private StandardCredentials lfsCredentials; + @Override public CheckoutCommand ref(String ref) { this.ref = ref; return this; } + @Override public CheckoutCommand branch(String branch) { this.branch = branch; return this; } + @Override public CheckoutCommand deleteBranchIfExist(boolean deleteBranch) { this.deleteBranch = deleteBranch; return this; } + @Override public CheckoutCommand sparseCheckoutPaths(List sparseCheckoutPaths) { this.sparseCheckoutPaths = sparseCheckoutPaths == null ? Collections.emptyList() : sparseCheckoutPaths; return this; } + @Override public CheckoutCommand timeout(Integer timeout) { this.timeout = timeout; return this; } + @Override public CheckoutCommand lfsRemote(String lfsRemote) { this.lfsRemote = lfsRemote; return this; @@ -2403,6 +2456,7 @@ private void interruptThisCheckout() throws InterruptedException { throw new InterruptedException(interruptMessage); } + @Override public void execute() throws GitException, InterruptedException { /* File.lastModified() limited by file system time, several * popular Linux file systems only have 1 second granularity. @@ -2606,6 +2660,7 @@ public RevListCommand revList_() { private String refspec; private List out; + @Override public RevListCommand all() { return all(true); } @@ -2615,6 +2670,8 @@ public RevListCommand all(boolean all) { this.all = all; return this; } + + @Override public RevListCommand nowalk(boolean nowalk) { // --no-walk wasn't introduced until v1.5.3 if (isAtLeastVersion(1, 5, 3, 0)) { @@ -2623,6 +2680,7 @@ public RevListCommand nowalk(boolean nowalk) { return this; } + @Override public RevListCommand firstParent() { return firstParent(true); } @@ -2633,16 +2691,19 @@ public RevListCommand firstParent(boolean firstParent) { return this; } + @Override public RevListCommand to(List revs){ this.out = revs; return this; } + @Override public RevListCommand reference(String reference){ this.refspec = reference; return this; } + @Override public void execute() throws GitException, InterruptedException { ArgumentListBuilder args = new ArgumentListBuilder("rev-list"); From 08ef5a9cee53a39edbb154b02a430a67cf8d95d2 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 19 Sep 2018 14:35:10 -0600 Subject: [PATCH 188/226] Use equalisverifier 2.5.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ad4ceabfea..b3958d1c85 100644 --- a/pom.xml +++ b/pom.xml @@ -165,7 +165,7 @@ nl.jqno.equalsverifier equalsverifier - 2.4.8 + 2.5.2 test From 2cdb4b8d32525d0239a3aea0dcc614e5c00267d6 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 19 Sep 2018 14:36:11 -0600 Subject: [PATCH 189/226] Use http client library 4.5.5-3.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b3958d1c85..57aa4ddffc 100644 --- a/pom.xml +++ b/pom.xml @@ -205,7 +205,7 @@ org.jenkins-ci.plugins apache-httpcomponents-client-4-api - 4.5.3-2.0 + 4.5.5-3.0 org.objenesis From 7ff03bedefaaec07f68aca20d31f8f96ae030ef4 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 19 Sep 2018 14:38:06 -0600 Subject: [PATCH 190/226] Use JGit 5.1.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 57aa4ddffc..df2227e5f8 100644 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,7 @@ -Dfile.encoding=${project.build.sourceEncoding} 2.60.3 8 - 5.0.3.201809091024-r + 5.1.1.201809181055-r From 1529e261eb1f588597de7d479107960fc751b0ba Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 19 Sep 2018 14:41:37 -0600 Subject: [PATCH 191/226] Use parent pom 3.22 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index df2227e5f8..bc49db28aa 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 3.19 + 3.22 From 3cb4534f04e989b286a84af076a2d22501dacaa9 Mon Sep 17 00:00:00 2001 From: Ivan-Sinitsin Date: Wed, 26 Sep 2018 08:46:32 +0300 Subject: [PATCH 192/226] Getting rid of static constant in encoding --- .../java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index bccc27114a..9fb4987c7a 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -252,7 +252,8 @@ protected CliGitAPIImpl(String gitExe, File workspace, TaskListener listener, En this.listener = listener; this.gitExe = gitExe; this.environment = environment; - this.encoding = isZos() ? "IBM1047" : Charset.defaultCharset().toString(); + this.encoding = isZos() && System.getProperty("ibm.system.encoding")!=null ? + Charset.forName(System.getProperty("ibm.system.encoding")).toString() : Charset.defaultCharset().toString(); launcher = new LocalLauncher(IGitAPI.verbose ? listener : TaskListener.NULL); } From 197fd4866a9c579bdf00ecf9a00fa6cce65bad89 Mon Sep 17 00:00:00 2001 From: Baptiste Mathus Date: Wed, 26 Sep 2018 10:44:35 +0200 Subject: [PATCH 193/226] Update to latest parent pom and incrementals-tools --- .mvn/extensions.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index d107aefa52..94863e605b 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -2,6 +2,6 @@ io.jenkins.tools.incrementals git-changelist-maven-extension - 1.0-beta-6 + 1.0-beta-7 diff --git a/pom.xml b/pom.xml index bc49db28aa..10fca9b638 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 3.22 + 3.23 From 42bd2dd15565648bf6dea58f2e851095f2b04f33 Mon Sep 17 00:00:00 2001 From: Ivan-Sinitsin Date: Wed, 26 Sep 2018 18:14:33 +0300 Subject: [PATCH 194/226] Pull review changes --- .../org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 9fb4987c7a..b8575568cb 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -252,8 +252,12 @@ protected CliGitAPIImpl(String gitExe, File workspace, TaskListener listener, En this.listener = listener; this.gitExe = gitExe; this.environment = environment; - this.encoding = isZos() && System.getProperty("ibm.system.encoding")!=null ? - Charset.forName(System.getProperty("ibm.system.encoding")).toString() : Charset.defaultCharset().toString(); + + if( isZos() && System.getProperty("ibm.system.encoding") != null ) { + this.encoding = Charset.forName(System.getProperty("ibm.system.encoding")).toString(); + } else { + this.encoding = Charset.defaultCharset().toString(); + } launcher = new LocalLauncher(IGitAPI.verbose ? listener : TaskListener.NULL); } From 28b618b8a661b8fc3912d7990b8786aacef3b037 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 26 Sep 2018 11:16:42 -0600 Subject: [PATCH 195/226] Update README Launch a CI build --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2f18e3bc45..192c34de55 100644 --- a/README.md +++ b/README.md @@ -36,4 +36,4 @@ To Do * Evaluate [pull requests](https://github.com/jenkinsci/git-client-plugin/pulls) * Fix [bugs](https://issues.jenkins-ci.org/secure/IssueNavigator.jspa?mode=hide&reset=true&jqlQuery=project+%3D+JENKINS+AND+status+in+%28Open%2C+"In+Progress"%2C+Reopened%29+AND+component+%3D+git-client-plugin) * Create infrastructure to detect [files opened during a unit test](https://issues.jenkins-ci.org/browse/JENKINS-19994) and left open at exit from test -* Complete more of the JGit implementation +* Complete more JGit implementation From 6d3ef7b85a079b2e8c5e06368b949d98efb06970 Mon Sep 17 00:00:00 2001 From: Joseph Petersen Date: Mon, 8 Oct 2018 00:06:54 +0200 Subject: [PATCH 196/226] set file permissions to allow use of openssh on windows --- .../plugins/gitclient/CliGitAPIImpl.java | 84 ++++++++++++++++++- .../CliGitAPIWindowsFilePermissionsTest.java | 78 +++++++++++++++++ 2 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIWindowsFilePermissionsTest.java diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index b8575568cb..5e59dedbc0 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -46,13 +46,20 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.attribute.AclEntry; +import java.nio.file.attribute.AclEntryPermission; +import java.nio.file.attribute.AclEntryType; +import java.nio.file.attribute.AclFileAttributeView; import java.nio.file.attribute.FileAttribute; import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.PosixFilePermissions; +import java.nio.file.attribute.UserPrincipal; +import java.nio.file.attribute.UserPrincipalLookupService; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -127,6 +134,29 @@ public class CliGitAPIImpl extends LegacyCompatibleGitAPIImpl { * ssh configurations). */ private static final boolean CALL_SETSID; + + /** + * Needed file permission for OpenSSH client that is made by Windows, + * this will remove unwanted users and inherited permissions + * which is required when the git client is using the SSH to clone + * + * The ssh client that the git client ships ignores file permission on Windows + * Which the PowerShell team at Microsoft decided to fix in their port of OpenSSH + */ + static final EnumSet ACL_ENTRY_PERMISSIONS = EnumSet.of( + AclEntryPermission.READ_DATA, + AclEntryPermission.WRITE_DATA, + AclEntryPermission.APPEND_DATA, + AclEntryPermission.READ_NAMED_ATTRS, + AclEntryPermission.WRITE_NAMED_ATTRS, + AclEntryPermission.EXECUTE, + AclEntryPermission.READ_ATTRIBUTES, + AclEntryPermission.WRITE_ATTRIBUTES, + AclEntryPermission.DELETE, + AclEntryPermission.READ_ACL, + AclEntryPermission.SYNCHRONIZE + ); + static { acceptSelfSignedCertificates = Boolean.getBoolean(GitClient.class.getName() + ".untrustedSSL"); CALL_SETSID = setsidExists() && USE_SETSID; @@ -1869,10 +1899,62 @@ private File createSshKeyFile(SSHUserPrivateKey sshUser) throws IOException, Int w.println(s); } } - new FilePath(key).chmod(0400); + if (launcher.isUnix()) { + new FilePath(key).chmod(0400); + } else { + fixSshKeyOnWindows(key); + } + return key; } + /* package protected for testability */ + void fixSshKeyOnWindows(File key) throws GitException { + if (launcher.isUnix()) return; + + Path file = Paths.get(key.toURI()); + + AclFileAttributeView fileAttributeView = Files.getFileAttributeView(file, AclFileAttributeView.class); + if (fileAttributeView == null) return; + + String username = getWindowsUserName(fileAttributeView); + if (StringUtils.isBlank(username)) return; + + try { + UserPrincipalLookupService userPrincipalLookupService = file.getFileSystem().getUserPrincipalLookupService(); + UserPrincipal userPrincipal = userPrincipalLookupService.lookupPrincipalByName(username); + AclEntry aclEntry = AclEntry.newBuilder() + .setType(AclEntryType.ALLOW) + .setPrincipal(userPrincipal) + .setPermissions(ACL_ENTRY_PERMISSIONS) + .build(); + fileAttributeView.setAcl(Collections.singletonList(aclEntry)); + } catch (IOException | UnsupportedOperationException e) { + throw new GitException("Error updating file permission for \"" + key.getAbsolutePath() + "\""); + } + } + + /* package protected for testability */ + String getWindowsUserName(AclFileAttributeView aclFileAttributeView) { + if (launcher.isUnix()) return ""; + + try { + return aclFileAttributeView.getOwner().getName(); + } catch (IOException ignored) { + String username = System.getenv("USERNAME"); + if (StringUtils.isBlank(username)) return ""; + + String domain = System.getenv("USERDOMAIN"); + if (StringUtils.isNotBlank(domain) && !username.endsWith("$")) { + username = domain + "\\" + username; + } else if (username.endsWith("$")) { + username = "BUILTIN\\Administrators"; + } + + return username; + } + } + /* package protected for testability */ String escapeWindowsCharsForUnquotedString(String str) { // Quote special characters for Windows Batch Files diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIWindowsFilePermissionsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIWindowsFilePermissionsTest.java new file mode 100644 index 0000000000..37cdb0ab96 --- /dev/null +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIWindowsFilePermissionsTest.java @@ -0,0 +1,78 @@ +package org.jenkinsci.plugins.gitclient; + +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.AclEntry; +import java.nio.file.attribute.AclEntryType; +import java.nio.file.attribute.AclFileAttributeView; +import java.nio.file.attribute.UserPrincipal; +import java.nio.file.attribute.UserPrincipalLookupService; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; + +public class CliGitAPIWindowsFilePermissionsTest { + + private CliGitAPIImpl cliGit; + private File file; + private AclFileAttributeView fileAttributeView; + private UserPrincipal userPrincipal; + private String username; + + @Before + public void beforeEach() throws Exception { + assumeTrue(isWindows()); + cliGit = new CliGitAPIImpl("git", new File("."), null, null); + file = cliGit.createTempFile("permission", ".suff"); + Path path = Paths.get(file.toURI()); + fileAttributeView = Files.getFileAttributeView(path, AclFileAttributeView.class); + assertNotNull(fileAttributeView); + UserPrincipalLookupService userPrincipalLookupService = path.getFileSystem().getUserPrincipalLookupService(); + assertNotNull(userPrincipalLookupService); + username = cliGit.getWindowsUserName(fileAttributeView); + assertNotNull(username); + userPrincipal = userPrincipalLookupService.lookupPrincipalByName(username); + assertNotNull(userPrincipal); + assertEquals(userPrincipal, fileAttributeView.getOwner()); + } + + @Test + public void test_windows_file_permission_is_set_correctly() throws Exception { + cliGit.fixSshKeyOnWindows(file); + assertEquals(1, fileAttributeView.getAcl().size()); + AclEntry aclEntry = fileAttributeView.getAcl().get(0); + assertTrue(aclEntry.flags().isEmpty()); + assertEquals(CliGitAPIImpl.ACL_ENTRY_PERMISSIONS, aclEntry.permissions()); + assertEquals(userPrincipal, aclEntry.principal()); + assertEquals(AclEntryType.ALLOW, aclEntry.type()); + } + + @Test + public void test_windows_file_permission_are_incorrect() throws Exception { + // By default files include System and builtin administrators + assertNotSame(1, fileAttributeView.getAcl().size()); + for (AclEntry entry : fileAttributeView.getAcl()) { + if (entry.principal().equals(userPrincipal)) { + assertNotSame(CliGitAPIImpl.ACL_ENTRY_PERMISSIONS, entry.permissions()); + } + } + } + + @Test + public void test_windows_username_lookup() { + assertEquals(username, userPrincipal.getName()); + } + + /** inline ${@link hudson.Functions#isWindows()} to prevent a transient remote classloader issue */ + private boolean isWindows() { + return File.pathSeparatorChar == ';'; + } +} From 0362ebda4f8818c4afe92eac81b65e93ceb6bbe2 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Tue, 16 Oct 2018 13:22:22 -0600 Subject: [PATCH 197/226] Use parent pom 3.25 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 10fca9b638..3d1d46e508 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 3.23 + 3.25 From 8319103b4f0339c88a8c3fb988a7ea7aee12efe3 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Tue, 16 Oct 2018 18:27:51 -0600 Subject: [PATCH 198/226] Update pom.xml --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3d1d46e508..1bb7502741 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 3.25 + 3.25 From 7915cf0daf514e75738dac7c23acc7a807d0803f Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Tue, 16 Oct 2018 18:28:13 -0600 Subject: [PATCH 199/226] Update pom.xml --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1bb7502741..3d1d46e508 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 3.25 + 3.25 From a88ab7781a86bc22a2ea37c47a4468e54b5e1054 Mon Sep 17 00:00:00 2001 From: Name From Git-Plugin-Test Date: Thu, 18 Oct 2018 14:12:52 +0200 Subject: [PATCH 200/226] CD-155 truncate commit log in change page now optional --- .gitignore | 3 +++ pom.xml | 2 +- .../java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index ddf4940128..e7e1a8903e 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ tags # emacs backup files *~ /nbproject/ + +# Mac OSX +.DS_Store \ No newline at end of file diff --git a/pom.xml b/pom.xml index 10fca9b638..7080508596 100644 --- a/pom.xml +++ b/pom.xml @@ -205,7 +205,7 @@ org.jenkins-ci.plugins apache-httpcomponents-client-4-api - 4.5.5-3.0 + 4.5.5-2.1 org.objenesis diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index b8575568cb..13f6ef4831 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -977,7 +977,7 @@ public ChangelogCommand changelog() { return new ChangelogCommand() { /** Equivalent to the git-log raw format but using ISO 8601 date format - also prevent to depend on git CLI future changes */ - public static final String RAW = "commit %H%ntree %T%nparent %P%nauthor %aN <%aE> %ai%ncommitter %cN <%cE> %ci%n%n%w(76,4,4)%s%n%n%b"; + public static final String RAW = "commit %H%ntree %T%nparent %P%nauthor %aN <%aE> %ai%ncommitter %cN <%cE> %ci%n%n%w(0,4,4)%s%n%n%b"; private final List revs = new ArrayList<>(); private Integer n = null; From 530dc780e19f14fa92f63c3ddb8ed5b1ff199452 Mon Sep 17 00:00:00 2001 From: Name From Git-Plugin-Test Date: Fri, 19 Oct 2018 18:46:22 +0200 Subject: [PATCH 201/226] JENKINS-29977 Changing CLI git client format for changelog --- .../plugins/gitclient/CliGitAPIImpl.java | 2 +- .../plugins/gitclient/GitClientTest.java | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 13f6ef4831..aa19a4cd82 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -977,7 +977,7 @@ public ChangelogCommand changelog() { return new ChangelogCommand() { /** Equivalent to the git-log raw format but using ISO 8601 date format - also prevent to depend on git CLI future changes */ - public static final String RAW = "commit %H%ntree %T%nparent %P%nauthor %aN <%aE> %ai%ncommitter %cN <%cE> %ci%n%n%w(0,4,4)%s%n%n%b"; + public static final String RAW = "commit %H%ntree %T%nparent %P%nauthor %aN <%aE> %ai%ncommitter %cN <%cE> %ci%n%n%w(0,4,4)%B%n%n"; private final List revs = new ArrayList<>(); private Integer n = null; diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java index 25a33d047d..5e19d303fd 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java @@ -257,6 +257,36 @@ private String randomEmail(String name) { return name.replaceAll(" ", ".") + "@middle.earth"; } + @Test + @Issue("JENKINS-297799") + public void testChangelongVeryLong() throws Exception { + + final String gitMessage = + "Uno Dos Tres Cuatro cinco Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut " + + "posuere tellus eu efficitur tristique. In iaculis neque in dolor vulputate" + + "sollicitudin eget a quam. Donec finibus sapien quis lectus euismod facilisis. Integer" + + "massa purus, scelerisque id iaculis ut, blandit vitae velit. Pellentesque lobortis" + + "aliquet felis, vel laoreet ipsum tincidunt at. Mauris tellus est, cursus vitae ex" + + "eget, venenatis auctor eros. Sed sagittis porta odio. Donec ut interdum massa. Aliquam" + + "sagittis, mi sit amet sollicitudin elementum, velit quam eleifend nisl, in rhoncus" + + "felis nibh eu nibh. Class aptent taciti sociosqu ad litora torquent per conubia " + + "nostra, per inceptos himenaeos." + + "\nseis\n" + + "\nasfasfasfasf\n" + ; + final String content = String.format("A random UUID: %s\n", UUID.randomUUID().toString()); + ObjectId message = commitFile("One-File.txt", content, gitMessage); + + ChangelogCommand changelog = gitClient.changelog(); + StringWriter changelogStringWriter = new StringWriter(); + changelog.includes(message).to(changelogStringWriter).execute(); + assertThat(changelogStringWriter.toString(), containsString("Ut posuere")); + assertThat(changelogStringWriter.toString(), containsString("conubia nostra")); + + + } + + @Test @Issue("JENKINS-39832") // Diagnostics of ChangelogCommand were insufficient public void testChangelogExceptionMessage() throws Exception { From 27a1e6abe3a0954c3ede0cb6483fd52940310da8 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 29 Sep 2018 20:22:32 -0600 Subject: [PATCH 202/226] Test Jenkins 2.121.3 instead of 2.121.1 --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index beffbfdf56..09a28a145e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,6 +1,6 @@ #!groovy // build both versions, retry test failures -buildPlugin(jenkinsVersions: [null, '2.121.1'], +buildPlugin(jenkinsVersions: [null, '2.121.3'], findbugs: [run:true, archive:true, unstableTotalAll: '0'], failFast: false) From ca1b9eca39de6754eaab3f171f6d79ac999b7052 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 20 Oct 2018 02:49:45 -0600 Subject: [PATCH 203/226] Use IOUtils to read process stderr/stdout into string The CheckNull annotation on the Proc.getStderr() and Proc.getStdout() calls requires a findbugs suppression in this case because the preceding call to readStderr() and readStdout() assures that the return value will not be null. --- .../plugins/gitclient/CliGitAPIImpl.java | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 5e59dedbc0..dab53f7696 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -28,6 +28,7 @@ import hudson.Proc; import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; @@ -2210,6 +2211,17 @@ private String launchCommandIn(ArgumentListBuilder args, File workDir, EnvVars e return launchCommandIn(args, workDir, environment, TIMEOUT); } + @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "earlier readStderr()/readStdout() call prevents null return") + private String readProcessIntoString(Proc process, String encoding, boolean useStderr) + throws IOException, UnsupportedEncodingException { + if (useStderr) { + /* process.getStderr reference is the findbugs warning to be suppressed */ + return IOUtils.toString(process.getStderr(), encoding); + } + /* process.getStdout reference is the findbugs warning to be suppressed */ + return IOUtils.toString(process.getStdout(), encoding); + } + private String launchCommandIn(ArgumentListBuilder args, File workDir, EnvVars env, Integer timeout) throws GitException, InterruptedException { EnvVars freshEnv = new EnvVars(env); @@ -2251,23 +2263,8 @@ private String launchCommandIn(ArgumentListBuilder args, File workDir, EnvVars e status = process.joinWithTimeout(usedTimeout, TimeUnit.MINUTES, listener); - StringBuilder stdoutBuilder = new StringBuilder(); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getStdout(), encoding))) { - String line; - while ((line = reader.readLine()) != null) { - stdoutBuilder.append(line); - } - } - stdout = stdoutBuilder.toString(); - - StringBuilder stderrBuilder = new StringBuilder(); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getStderr(), encoding))) { - String line; - while ((line = reader.readLine()) != null) { - stderrBuilder.append(line); - } - } - stderr = stderrBuilder.toString(); + stdout = readProcessIntoString(process, encoding, false); + stderr = readProcessIntoString(process, encoding, true); } else { // JENKINS-13356: capture stdout and stderr separately ByteArrayOutputStream stdoutStream = new ByteArrayOutputStream(); From 823c887de25a70e9b8b1ff6fe5c7d68610299847 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 20 Oct 2018 02:40:23 -0600 Subject: [PATCH 204/226] Remove unused imports from Netrc --- src/main/java/org/jenkinsci/plugins/gitclient/Netrc.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/Netrc.java b/src/main/java/org/jenkinsci/plugins/gitclient/Netrc.java index 8b92a66587..6b12fb3e14 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/Netrc.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/Netrc.java @@ -2,11 +2,9 @@ import edu.umd.cs.findbugs.annotations.NonNull; import hudson.plugins.git.GitException; -import hudson.util.IOUtils; import java.io.BufferedReader; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.Charset; From 38c51d58c5a33580160466bf73ad4887939d7d79 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 20 Oct 2018 02:44:14 -0600 Subject: [PATCH 205/226] Use apache commons-io IOUtils, not deprecated Hudson.IOUtils --- src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index 5d574e7e06..8981dec25e 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -21,7 +21,6 @@ import hudson.plugins.git.GitLockFailedException; import hudson.plugins.git.IndexEntry; import hudson.plugins.git.Revision; -import hudson.util.IOUtils; import java.io.File; import java.io.FileNotFoundException; @@ -47,6 +46,7 @@ import javax.annotation.Nullable; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang.time.FastDateFormat; import org.eclipse.jgit.api.AddNoteCommand; import org.eclipse.jgit.api.CommitCommand; From fd2cef09564aeada65215c04647eae76dacf9193 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 19 Oct 2018 20:40:58 -0600 Subject: [PATCH 206/226] Use equalsverifier 3.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3d1d46e508..784e9ebbbf 100644 --- a/pom.xml +++ b/pom.xml @@ -165,7 +165,7 @@ nl.jqno.equalsverifier equalsverifier - 2.5.2 + 3.0 test From 3486cf819e025ce29f7d9f00f037e92918a17350 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Fri, 19 Oct 2018 20:09:37 -0600 Subject: [PATCH 207/226] Use JGit 5.1.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 784e9ebbbf..e8e283fb14 100644 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,7 @@ -Dfile.encoding=${project.build.sourceEncoding} 2.60.3 8 - 5.1.1.201809181055-r + 5.1.2.201810061102-r From 5521e7da1bd03a8f0fc78615e77b2d803db131a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sat, 6 Oct 2018 11:54:38 +0200 Subject: [PATCH 208/226] Replace Hudson's deprecated IOUtils Based on https://ci.jenkins.io/job/Infra/job/deprecated-usage-in-plugins/job/master/lastSuccessfulBuild/artifact/output/usage-by-plugin.html --- src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index 5d574e7e06..8981dec25e 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -21,7 +21,6 @@ import hudson.plugins.git.GitLockFailedException; import hudson.plugins.git.IndexEntry; import hudson.plugins.git.Revision; -import hudson.util.IOUtils; import java.io.File; import java.io.FileNotFoundException; @@ -47,6 +46,7 @@ import javax.annotation.Nullable; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang.time.FastDateFormat; import org.eclipse.jgit.api.AddNoteCommand; import org.eclipse.jgit.api.CommitCommand; From c159c0b0e11d343f31c16e2300128666bf6603e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Sun, 21 Oct 2018 13:01:15 +0200 Subject: [PATCH 209/226] Remove all unused Apache HttpClient contrib classes Based on https://ci.jenkins.io/job/Infra/job/deprecated-usage-in-plugins/job/master/lastSuccessfulBuild/artifact/output/usage-by-plugin.html The classes got obsolete with commit f0e20a4fef7d851ccb57cd6832a8fe8353d28866, when switching to the modern Apache HttpComponents API. --- pom.xml | 1 - .../ssl/EasySSLProtocolSocketFactory.java | 222 ------------------ .../contrib/ssl/EasyX509TrustManager.java | 113 --------- 3 files changed, 336 deletions(-) delete mode 100644 src/main/java/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java delete mode 100644 src/main/java/org/apache/commons/httpclient/contrib/ssl/EasyX509TrustManager.java diff --git a/pom.xml b/pom.xml index 3d1d46e508..3ecd702f0c 100644 --- a/pom.xml +++ b/pom.xml @@ -266,7 +266,6 @@ org.apache.maven.plugins maven-javadoc-plugin - org.apache.commons.httpclient.contrib.ssl param,return,throws,link false diff --git a/src/main/java/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java b/src/main/java/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java deleted file mode 100644 index 2bf07daf3c..0000000000 --- a/src/main/java/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * $HeadURL$ - * $Revision$ - * $Date$ - * - * ==================================================================== - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - * - */ - -package org.apache.commons.httpclient.contrib.ssl; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketAddress; -import java.net.UnknownHostException; - -import javax.net.SocketFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; - -import org.apache.commons.httpclient.ConnectTimeoutException; -import org.apache.commons.httpclient.HttpClientError; -import org.apache.commons.httpclient.params.HttpConnectionParams; -import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - *

    - * EasySSLProtocolSocketFactory can be used to create SSL {@link java.net.Socket}s - * that accept self-signed certificates. - *

    - *

    - * This socket factory SHOULD NOT be used for productive systems - * due to security reasons, unless it is a concious decision and - * you are perfectly aware of security implications of accepting - * self-signed certificates - *

    - * - *

    - * Example of using custom protocol socket factory for a specific host: - *

    - *     Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
    - *
    - *     URI uri = new URI("https://localhost/", true);
    - *     // use relative url only
    - *     GetMethod httpget = new GetMethod(uri.getPathQuery());
    - *     HostConfiguration hc = new HostConfiguration();
    - *     hc.setHost(uri.getHost(), uri.getPort(), easyhttps);
    - *     HttpClient client = new HttpClient();
    - *     client.executeMethod(hc, httpget);
    - *     
    - *

    - * Example of using custom protocol socket factory per default instead of the standard one: - *

    - *     Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
    - *     Protocol.registerProtocol("https", easyhttps);
    - *
    - *     HttpClient client = new HttpClient();
    - *     GetMethod httpget = new GetMethod("https://localhost/");
    - *     client.executeMethod(httpget);
    - *     
    - * - * @author Oleg Kalnichevski - * - *

    - * DISCLAIMER: HttpClient developers DO NOT actively support this component. - * The component is provided as a reference material, which may be inappropriate - * for use without additional customization. - *

    - */ -public class EasySSLProtocolSocketFactory implements SecureProtocolSocketFactory { - - /** Log object for this class. */ - private static final Log LOG = LogFactory.getLog(EasySSLProtocolSocketFactory.class); - - private SSLContext sslcontext = null; - - /** - * Constructor for EasySSLProtocolSocketFactory. - */ - public EasySSLProtocolSocketFactory() { - super(); - } - - private static SSLContext createEasySSLContext() { - try { - SSLContext context = SSLContext.getInstance("SSL"); - context.init( - null, - new TrustManager[] {new EasyX509TrustManager(null)}, - null); - return context; - } catch (Exception e) { - LOG.error(e.getMessage(), e); - throw new HttpClientError(e.toString()); - } - } - - private SSLContext getSSLContext() { - if (this.sslcontext == null) { - this.sslcontext = createEasySSLContext(); - } - return this.sslcontext; - } - - /** {@inheritDoc} */ - public Socket createSocket( - String host, - int port, - InetAddress clientHost, - int clientPort) - throws IOException, UnknownHostException { - - return getSSLContext().getSocketFactory().createSocket( - host, - port, - clientHost, - clientPort - ); - } - - /** - * {@inheritDoc} - * - * Attempts to get a new socket connection to the given host within the given time limit. - *

    - * To circumvent the limitations of older JREs that do not support connect timeout a - * controller thread is executed. The controller thread attempts to create a new socket - * within the given limit of time. If socket constructor does not return until the - * timeout expires, the controller terminates and throws an {@link ConnectTimeoutException} - *

    - */ - public Socket createSocket( - final String host, - final int port, - final InetAddress localAddress, - final int localPort, - final HttpConnectionParams params - ) throws IOException, UnknownHostException, ConnectTimeoutException { - if (params == null) { - throw new IllegalArgumentException("Parameters may not be null"); - } - int timeout = params.getConnectionTimeout(); - SocketFactory socketfactory = getSSLContext().getSocketFactory(); - if (timeout == 0) { - return socketfactory.createSocket(host, port, localAddress, localPort); - } else { - Socket socket = socketfactory.createSocket(); - SocketAddress localaddr = new InetSocketAddress(localAddress, localPort); - SocketAddress remoteaddr = new InetSocketAddress(host, port); - socket.bind(localaddr); - socket.connect(remoteaddr, timeout); - return socket; - } - } - - /** {@inheritDoc} */ - public Socket createSocket(String host, int port) - throws IOException, UnknownHostException { - return getSSLContext().getSocketFactory().createSocket( - host, - port - ); - } - - /** {@inheritDoc} */ - public Socket createSocket( - Socket socket, - String host, - int port, - boolean autoClose) - throws IOException, UnknownHostException { - return getSSLContext().getSocketFactory().createSocket( - socket, - host, - port, - autoClose - ); - } - - /** {@inheritDoc} */ - @SuppressFBWarnings(value = "EQ_GETCLASS_AND_CLASS_CONSTANT", - justification = "Implementation provided by Apache, never inherited") - public boolean equals(Object obj) { - return ((obj != null) && obj.getClass().equals(EasySSLProtocolSocketFactory.class)); - } - - /** - * hashCode. - * - * @return a int. - */ - public int hashCode() { - return EasySSLProtocolSocketFactory.class.hashCode(); - } - -} diff --git a/src/main/java/org/apache/commons/httpclient/contrib/ssl/EasyX509TrustManager.java b/src/main/java/org/apache/commons/httpclient/contrib/ssl/EasyX509TrustManager.java deleted file mode 100644 index 63e640a911..0000000000 --- a/src/main/java/org/apache/commons/httpclient/contrib/ssl/EasyX509TrustManager.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * ==================================================================== - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - * - */ - -package org.apache.commons.httpclient.contrib.ssl; - -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - *

    - * EasyX509TrustManager unlike default {@link javax.net.ssl.X509TrustManager} accepts - * self-signed certificates. - *

    - * This trust manager SHOULD NOT be used for productive systems - * due to security reasons, unless it is a concious decision and - * you are perfectly aware of security implications of accepting - * self-signed certificates - * - *

    - * DISCLAIMER: HttpClient developers DO NOT actively support this component. - * The component is provided as a reference material, which may be inappropriate - * for use without additional customization. - * - * @author Adrian Sutton - * @author Oleg Kalnichevski - */ -public class EasyX509TrustManager implements X509TrustManager -{ - private X509TrustManager standardTrustManager = null; - - /** Log object for this class. */ - private static final Log LOG = LogFactory.getLog(EasyX509TrustManager.class); - - /** - * Constructor for EasyX509TrustManager. - * - * @param keystore a {@link java.security.KeyStore} object. - * @throws java.security.NoSuchAlgorithmException if requested algorithm is not available - * @throws java.security.KeyStoreException if KeyStore operations fail - */ - public EasyX509TrustManager(KeyStore keystore) throws NoSuchAlgorithmException, KeyStoreException { - super(); - TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - factory.init(keystore); - TrustManager[] trustmanagers = factory.getTrustManagers(); - if (trustmanagers.length == 0) { - throw new NoSuchAlgorithmException("no trust manager found"); - } - this.standardTrustManager = (X509TrustManager)trustmanagers[0]; - } - - /** {@inheritDoc} */ - public void checkClientTrusted(X509Certificate[] certificates,String authType) throws CertificateException { - standardTrustManager.checkClientTrusted(certificates,authType); - } - - /** {@inheritDoc} */ - public void checkServerTrusted(X509Certificate[] certificates,String authType) throws CertificateException { - if ((certificates != null) && LOG.isDebugEnabled()) { - LOG.debug("Server certificate chain:"); - for (int i = 0; i < certificates.length; i++) { - LOG.debug("X509Certificate[" + i + "]=" + certificates[i]); - } - } - if ((certificates != null) && (certificates.length == 1)) { - certificates[0].checkValidity(); - } else { - standardTrustManager.checkServerTrusted(certificates,authType); - } - } - - /** - * getAcceptedIssuers. - * - * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers() - * @return an array of {@link java.security.cert.X509Certificate} objects. - */ - public X509Certificate[] getAcceptedIssuers() { - return this.standardTrustManager.getAcceptedIssuers(); - } -} From 3e4e7e71d67203efb69a1c997b4809c73d9f479e Mon Sep 17 00:00:00 2001 From: Name From Git-Plugin-Test Date: Mon, 22 Oct 2018 11:48:56 +0200 Subject: [PATCH 210/226] JENKINS-29977 bumping httpcomponenets version to 3.0 and git-client to RC --- pom.xml | 4 ++-- .../org/jenkinsci/plugins/gitclient/GitClientTest.java | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 7080508596..c527fc92a2 100644 --- a/pom.xml +++ b/pom.xml @@ -43,7 +43,7 @@ 3.0.0-beta6 - -SNAPSHOT + -rc1791.3a94dfffd1fc UTF-8 -Dfile.encoding=${project.build.sourceEncoding} 2.60.3 @@ -205,7 +205,7 @@ org.jenkins-ci.plugins apache-httpcomponents-client-4-api - 4.5.5-2.1 + 4.5.5-3.0 org.objenesis diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java index 5e19d303fd..0d55f41df2 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java @@ -259,10 +259,18 @@ private String randomEmail(String name) { @Test @Issue("JENKINS-297799") + /** + * Changelog was formatted on word boundary prior to + * 72 characters with git client plugin 2.0+ when using CLI git. + * Was not truncated by git client plugin using JGit (And Apache version). + * Rely on caller to truncate first line if desired. + * Matching change will be included in git plugin 4.0.0 + * to retain existing truncation behavior. + */ public void testChangelongVeryLong() throws Exception { final String gitMessage = - "Uno Dos Tres Cuatro cinco Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut " + + "Uno Dos Tres Cuatro Cinco Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut " + "posuere tellus eu efficitur tristique. In iaculis neque in dolor vulputate" + "sollicitudin eget a quam. Donec finibus sapien quis lectus euismod facilisis. Integer" + "massa purus, scelerisque id iaculis ut, blandit vitae velit. Pellentesque lobortis" + From 760252f2e550dc9f5752acc67a2af27d053f0989 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 3 Nov 2018 21:44:36 -0600 Subject: [PATCH 211/226] Fix credentials test reporting failures Use a JenkinsRule for every test instead of using a single JenkinsRule for all the tests. This will dramatically slow test performance. --- .../java/org/jenkinsci/plugins/gitclient/CredentialsTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index f9e2f6e9e8..4df0f4910a 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -61,8 +61,8 @@ public class CredentialsTest { // Required for credentials use - @ClassRule - public static final JenkinsRule j = new JenkinsRule(); + @Rule + public final JenkinsRule j = new JenkinsRule(); private final String gitImpl; private final String gitRepoURL; From 76dade9186720cefa354cc0e9c718853d63ef9a9 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 4 Nov 2018 04:02:10 -0700 Subject: [PATCH 212/226] Allow more time for credentials tests The switch from a single JenkinsRule instance at the class level to a JenkinsRule per credentials test slows the individual tests but should allow more total tests to be executed because the 180 second JenkinsRule timeout won't be reached inside any single JenkinsRule test. Still want to limit the total execution time of the CredentialsTest class to not exceed 3 minutes. Otherwise, total test execution time becomes too long. --- .../java/org/jenkinsci/plugins/gitclient/CredentialsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index 4df0f4910a..91788b6202 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -350,7 +350,7 @@ private void addCredential() throws IOException { * @return true if another test should be allowed to start */ private boolean testPeriodNotExpired() { - return (System.currentTimeMillis() - firstTestStartTime) < ((180 - 120) * 1000L); + return (System.currentTimeMillis() - firstTestStartTime) < ((180 - 30) * 1000L); } @Test From 819061502224c027efca9165f9cd2db8cb30ac05 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 3 Nov 2018 21:19:09 -0600 Subject: [PATCH 213/226] Use parent pom 3.26 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b298291fd0..0c2fd79f5d 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 3.25 + 3.26 From be227a74d21642c57d95bcf1ab710c920967bef1 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 4 Nov 2018 13:38:35 -0700 Subject: [PATCH 214/226] Use JGit 5.1.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0c2fd79f5d..5f59816025 100644 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,7 @@ -Dfile.encoding=${project.build.sourceEncoding} 2.60.3 8 - 5.1.2.201810061102-r + 5.1.3.201810200350-r From 8b8bb32197c37c2e544f614cf2153378ec4d8218 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 4 Nov 2018 13:42:16 -0700 Subject: [PATCH 215/226] Use equalsverifier 3.0.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5f59816025..b94ec877af 100644 --- a/pom.xml +++ b/pom.xml @@ -165,7 +165,7 @@ nl.jqno.equalsverifier equalsverifier - 3.0 + 3.0.2 test From 07f6ca1c3c3c19997278d4c61712c748d377f604 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 4 Nov 2018 13:49:56 -0700 Subject: [PATCH 216/226] Use objenesis 3.0.1 in GitAPITestCase --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b94ec877af..7c552fb738 100644 --- a/pom.xml +++ b/pom.xml @@ -210,7 +210,7 @@ org.objenesis objenesis - 2.6 + 3.0.1 test From 6717c57e5e5f522767ebd3eed3414cb092478a70 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sun, 4 Nov 2018 14:17:42 -0700 Subject: [PATCH 217/226] Use surefire plugin 2.22.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7c552fb738..7358c2b279 100644 --- a/pom.xml +++ b/pom.xml @@ -253,7 +253,7 @@ maven-surefire-plugin - 2.21.0 + 2.22.1 maven-javadoc-plugin From 698f25691afe5ace24e9a5e03d67cb2c20656ed3 Mon Sep 17 00:00:00 2001 From: Jose Blas Camacho Taboada Date: Mon, 5 Nov 2018 11:26:11 +0100 Subject: [PATCH 218/226] JENKINS-29977 bumping httpcomponenets version to 3.0 and git-client to RC --- .../java/org/jenkinsci/plugins/gitclient/GitClientTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java index 0d55f41df2..cb39953db1 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java @@ -258,7 +258,7 @@ private String randomEmail(String name) { } @Test - @Issue("JENKINS-297799") + @Issue("JENKINS-29977") /** * Changelog was formatted on word boundary prior to * 72 characters with git client plugin 2.0+ when using CLI git. @@ -267,7 +267,7 @@ private String randomEmail(String name) { * Matching change will be included in git plugin 4.0.0 * to retain existing truncation behavior. */ - public void testChangelongVeryLong() throws Exception { + public void testChangelogVeryLong() throws Exception { final String gitMessage = "Uno Dos Tres Cuatro Cinco Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut " + From f99e5ab3e790ed9c7697af81f1e602c1653fb9c3 Mon Sep 17 00:00:00 2001 From: Jose Blas Camacho Taboada Date: Mon, 5 Nov 2018 12:26:27 +0100 Subject: [PATCH 219/226] JENKINS-29977 changing back changelist to SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c527fc92a2..10fca9b638 100644 --- a/pom.xml +++ b/pom.xml @@ -43,7 +43,7 @@ 3.0.0-beta6 - -rc1791.3a94dfffd1fc + -SNAPSHOT UTF-8 -Dfile.encoding=${project.build.sourceEncoding} 2.60.3 From 7176a6bcd2fb9143b739750f1a859fcfdcc343b4 Mon Sep 17 00:00:00 2001 From: Jose Blas Camacho Taboada Date: Mon, 5 Nov 2018 12:43:09 +0100 Subject: [PATCH 220/226] JENKINS-29977 removing trailing newlinex from CLIGitImpl, no need for that with %B instead of %b --- .../java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index aa19a4cd82..149185bee8 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -977,7 +977,7 @@ public ChangelogCommand changelog() { return new ChangelogCommand() { /** Equivalent to the git-log raw format but using ISO 8601 date format - also prevent to depend on git CLI future changes */ - public static final String RAW = "commit %H%ntree %T%nparent %P%nauthor %aN <%aE> %ai%ncommitter %cN <%cE> %ci%n%n%w(0,4,4)%B%n%n"; + public static final String RAW = "commit %H%ntree %T%nparent %P%nauthor %aN <%aE> %ai%ncommitter %cN <%cE> %ci%n%n%w(0,4,4)%B"; private final List revs = new ArrayList<>(); private Integer n = null; From efe41358e07c451dca487da6fb9b401ba172a6c4 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 5 Nov 2018 07:17:31 -0700 Subject: [PATCH 221/226] Add another JENKINS-29977 test --- pom.xml | 6 ++ .../plugins/gitclient/GitClientTest.java | 55 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/pom.xml b/pom.xml index 7358c2b279..2a460bd677 100644 --- a/pom.xml +++ b/pom.xml @@ -186,6 +186,12 @@ 2.4 test + + org.apache.commons + commons-text + 1.6 + test + com.google.code.findbugs jsr305 diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java index cb39953db1..060b3b6d7b 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java @@ -1834,4 +1834,59 @@ public void testGetTags_ThreeTags() throws Exception { Set result = gitClient.getTags(); assertThat(result, containsInAnyOrder(expectedTag, expectedTag2, expectedTag3)); } + + private String truncateAtWord(String src, int maxLength) { + java.text.BreakIterator breakIterator = java.text.BreakIterator.getWordInstance(); + breakIterator.setText(src); + return src.substring(0, breakIterator.preceding(maxLength + 1)).trim(); + } + + private String wrapAtWord(String src, int maxLength) { + return org.apache.commons.text.WordUtils.wrap(src, maxLength); + } + + private String padLinesWithSpaces(String src, int spacePadCount) { + char[] paddingArray = new char[spacePadCount]; + Arrays.fill(paddingArray, ' '); + String padding = new String(paddingArray); + return padding + src.replace("\n", "\n" + padding).trim(); + } + + @Test + @Issue("JENKINS-29977") + public void testChangelogFirstLineTruncation() throws Exception { + // 1 2 3 4 5 6 7 8 + // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 + final String longFirstLine = + "The first line of this commit message is longer than 72 characters to show JENKINS-29977"; + final String longBody = + "The body of this commit message is also longer than 72 characters though that is not part of JENKINS-29977"; + // Intentionally randomize whether the commit message body ends with a newline character + final String commitMessage = longFirstLine + "\n\n" + longBody + (random.nextBoolean() ? "\n" : ""); + final ObjectId commit = commitOneFile(commitMessage); + ChangelogCommand changelog = gitClient.changelog(); + StringWriter changelogStringWriter = new StringWriter(); + changelog.includes(commit).to(changelogStringWriter).execute(); + + final String truncatedFirstLine = truncateAtWord(longFirstLine, 72) + "\n"; + final String truncatedBody = truncateAtWord(longBody, 72) + "\n"; + + final String wrappedFirstLine = wrapAtWord(longFirstLine, 72); + final String wrappedBody = wrapAtWord(longBody, 72); + + // Truncated lines are NOT included in the changelog + assertThat(changelogStringWriter.toString(), not(containsString(truncatedFirstLine))); + assertThat(changelogStringWriter.toString(), not(containsString(truncatedBody))); + + // Wrapped lines are NOT included in the changelog + assertThat(changelogStringWriter.toString(), not(containsString(padLinesWithSpaces(wrappedFirstLine, 4)))); + assertThat(changelogStringWriter.toString(), not(containsString(padLinesWithSpaces(wrappedBody, 4)))); + + // Unmodified lines are included in the changelog + assertThat(changelogStringWriter.toString(), containsString(longFirstLine)); + assertThat(changelogStringWriter.toString(), containsString(longBody)); + + // Entire unmodified commit message is included in the changelog + assertThat(changelogStringWriter.toString(), containsString(padLinesWithSpaces(commitMessage, 4))); + } } From ba34cca4fbd11b26fee1e7f2f2914a28fa088a79 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 5 Nov 2018 07:35:06 -0700 Subject: [PATCH 222/226] Fix some GitClientTest white space --- .../java/org/jenkinsci/plugins/gitclient/GitClientTest.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java index 060b3b6d7b..5a80cc2321 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/GitClientTest.java @@ -260,7 +260,7 @@ private String randomEmail(String name) { @Test @Issue("JENKINS-29977") /** - * Changelog was formatted on word boundary prior to + * Changelog was formatted on word boundary prior to * 72 characters with git client plugin 2.0+ when using CLI git. * Was not truncated by git client plugin using JGit (And Apache version). * Rely on caller to truncate first line if desired. @@ -290,11 +290,8 @@ public void testChangelogVeryLong() throws Exception { changelog.includes(message).to(changelogStringWriter).execute(); assertThat(changelogStringWriter.toString(), containsString("Ut posuere")); assertThat(changelogStringWriter.toString(), containsString("conubia nostra")); - - } - @Test @Issue("JENKINS-39832") // Diagnostics of ChangelogCommand were insufficient public void testChangelogExceptionMessage() throws Exception { From dcaa6e14b30712673a0604d148bf2eabe16d4920 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 30 Sep 2017 11:41:57 -0600 Subject: [PATCH 223/226] [JENKINS-47514] Avoid shell escaping password characters Use cat (Linux) and type (Windows) of files rather than echo of strings to send username and password to the git ssh commands to reduce the risk and complication of shell escaping username and password text provided by end users. --- .../plugins/gitclient/CliGitAPIImpl.java | 123 +++++++----- .../gitclient/CliGitAPIImplAuthTest.java | 178 ------------------ 2 files changed, 71 insertions(+), 230 deletions(-) delete mode 100644 src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplAuthTest.java diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 2d2c1a56f7..a35003a1bd 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -1795,8 +1795,10 @@ private String launchCommandWithCredentials(ArgumentListBuilder args, File workD File key = null; File ssh = null; - File pass = null; File askpass = null; + File usernameFile = null; + File passwordFile = null; + File passphrase = null; EnvVars env = environment; if (!PROMPT_FOR_AUTHENTICATION && isAtLeastVersion(2, 3, 0, 0)) { env = new EnvVars(env); @@ -1817,18 +1819,19 @@ private String launchCommandWithCredentials(ArgumentListBuilder args, File workD if (userName == null) { userName = sshUser.getUsername(); } + passphrase = createPassphraseFile(sshUser); if (launcher.isUnix()) { ssh = createUnixGitSSH(key, userName); - pass = createUnixSshAskpass(sshUser); + askpass = createUnixSshAskpass(sshUser, passphrase); } else { ssh = createWindowsGitSSH(key, userName); - pass = createWindowsSshAskpass(sshUser); + askpass = createWindowsSshAskpass(sshUser, passphrase); } env = new EnvVars(env); env.put("GIT_SSH", ssh.getAbsolutePath()); env.put("GIT_SSH_VARIANT", "ssh"); - env.put("SSH_ASKPASS", pass.getAbsolutePath()); + env.put("SSH_ASKPASS", askpass.getAbsolutePath()); // supply a dummy value for DISPLAY if not already present // or else ssh will not invoke SSH_ASKPASS @@ -1840,10 +1843,12 @@ private String launchCommandWithCredentials(ArgumentListBuilder args, File workD StandardUsernamePasswordCredentials userPass = (StandardUsernamePasswordCredentials) credentials; listener.getLogger().println("using GIT_ASKPASS to set credentials " + userPass.getDescription()); + usernameFile = createUsernameFile(userPass); + passwordFile = createPasswordFile(userPass); if (launcher.isUnix()) { - askpass = createUnixStandardAskpass(userPass); + askpass = createUnixStandardAskpass(userPass, usernameFile, passwordFile); } else { - askpass = createWindowsStandardAskpass(userPass); + askpass = createWindowsStandardAskpass(userPass, usernameFile, passwordFile); } env = new EnvVars(env); @@ -1885,10 +1890,12 @@ private String launchCommandWithCredentials(ArgumentListBuilder args, File workD } catch (IOException e) { throw new GitException("Failed to setup credentials", e); } finally { - deleteTempFile(pass); deleteTempFile(key); deleteTempFile(ssh); deleteTempFile(askpass); + deleteTempFile(passphrase); + deleteTempFile(usernameFile); + deleteTempFile(passwordFile); } } @@ -1956,82 +1963,96 @@ String getWindowsUserName(AclFileAttributeView aclFileAttributeView) { } } - /* package protected for testability */ - String escapeWindowsCharsForUnquotedString(String str) { - // Quote special characters for Windows Batch Files - // See: http://stackoverflow.com/questions/562038/escaping-double-quotes-in-batch-script - // See: http://ss64.com/nt/syntax-esc.html - String quoted = str.replace("%", "%%") - .replace("^", "^^") - .replace(" ", "^ ") - .replace("\t", "^\t") - .replace("\\", "^\\") - .replace("&", "^&") - .replace("|", "^|") - .replace("\"", "^\"") - .replace(">", "^>") - .replace("<", "^<"); - return quoted; - } - - private String quoteUnixCredentials(String str) { - // Assumes string will be used inside of single quotes, as it will - // only replace "'" substrings. - return str.replace("'", "'\\''"); - } - - private File createWindowsSshAskpass(SSHUserPrivateKey sshUser) throws IOException { - File ssh = createTempFile("pass", ".bat"); + /* Escape all double quotes in filename, then surround filename in double quotes. + * Only useful to prepare filename for reference from a DOS batch file. + */ + private String windowsArgEncodeFileName(String filename) { + if (filename.contains("\"")) { + filename = filename.replaceAll("\"", "^\""); + } + return "\"" + filename + "\""; + } + + private File createWindowsSshAskpass(SSHUserPrivateKey sshUser, @NonNull File passphrase) throws IOException { + File ssh = File.createTempFile("pass", ".bat"); try (PrintWriter w = new PrintWriter(ssh, encoding)) { // avoid echoing command as part of the password w.println("@echo off"); - // no surrounding double quotes on windows echo -- they are echoed too - w.println("echo " + escapeWindowsCharsForUnquotedString(Secret.toString(sshUser.getPassphrase()))); + w.println("type " + windowsArgEncodeFileName(passphrase.getAbsolutePath())); w.flush(); } ssh.setExecutable(true, true); return ssh; } - private File createUnixSshAskpass(SSHUserPrivateKey sshUser) throws IOException { + /* Escape all single quotes in filename, then surround filename in single quotes. + * Only useful to prepare filename for reference from a shell script. + */ + private String unixArgEncodeFileName(String filename) { + if (filename.contains("'")) { + filename = filename.replaceAll("'", "\\'"); + } + return "'" + filename + "'"; + } + + private File createUnixSshAskpass(SSHUserPrivateKey sshUser, @NonNull File passphrase) throws IOException { File ssh = createTempFile("pass", ".sh"); try (PrintWriter w = new PrintWriter(ssh, encoding)) { w.println("#!/bin/sh"); - w.println("echo '" + quoteUnixCredentials(Secret.toString(sshUser.getPassphrase())) + "'"); + w.println("cat " + unixArgEncodeFileName(passphrase.getAbsolutePath())); } ssh.setExecutable(true, true); return ssh; } - /* Package protected for testability */ - File createWindowsBatFile(String userName, String password) throws IOException { + private File createWindowsStandardAskpass(StandardUsernamePasswordCredentials creds, File usernameFile, File passwordFile) throws IOException { File askpass = createTempFile("pass", ".bat"); try (PrintWriter w = new PrintWriter(askpass, encoding)) { w.println("@set arg=%~1"); - w.println("@if (%arg:~0,8%)==(Username) echo " + escapeWindowsCharsForUnquotedString(userName)); - w.println("@if (%arg:~0,8%)==(Password) echo " + escapeWindowsCharsForUnquotedString(password)); + w.println("@if (%arg:~0,8%)==(Username) type " + windowsArgEncodeFileName(usernameFile.getAbsolutePath())); + w.println("@if (%arg:~0,8%)==(Password) type " + windowsArgEncodeFileName(passwordFile.getAbsolutePath())); } askpass.setExecutable(true, true); return askpass; } - private File createWindowsStandardAskpass(StandardUsernamePasswordCredentials creds) throws IOException { - return createWindowsBatFile(creds.getUsername(), Secret.toString(creds.getPassword())); - } - - private File createUnixStandardAskpass(StandardUsernamePasswordCredentials creds) throws IOException { + private File createUnixStandardAskpass(StandardUsernamePasswordCredentials creds, File usernameFile, File passwordFile) throws IOException { File askpass = createTempFile("pass", ".sh"); try (PrintWriter w = new PrintWriter(askpass, encoding)) { w.println("#!/bin/sh"); w.println("case \"$1\" in"); - w.println("Username*) echo '" + quoteUnixCredentials(creds.getUsername()) + "' ;;"); - w.println("Password*) echo '" + quoteUnixCredentials(Secret.toString(creds.getPassword())) + "' ;;"); + w.println("Username*) cat " + unixArgEncodeFileName(usernameFile.getAbsolutePath()) + " ;;"); + w.println("Password*) cat " + unixArgEncodeFileName(passwordFile.getAbsolutePath()) + " ;;"); w.println("esac"); } askpass.setExecutable(true, true); return askpass; } + private File createPassphraseFile(SSHUserPrivateKey sshUser) throws IOException { + File passphraseFile = createTempFile("phrase", ".txt"); + try (PrintWriter w = new PrintWriter(passphraseFile, "UTF-8")) { + w.println(Secret.toString(sshUser.getPassphrase())); + } + return passphraseFile; + } + + private File createUsernameFile(StandardUsernamePasswordCredentials userPass) throws IOException { + File usernameFile = createTempFile("username", ".txt"); + try (PrintWriter w = new PrintWriter(usernameFile, "UTF-8")) { + w.println(userPass.getUsername()); + } + return usernameFile; + } + + private File createPasswordFile(StandardUsernamePasswordCredentials userPass) throws IOException { + File passwordFile = createTempFile("password", ".txt"); + try (PrintWriter w = new PrintWriter(passwordFile, "UTF-8")) { + w.println(Secret.toString(userPass.getPassword())); + } + return passwordFile; + } + private String getPathToExe(String userGitExe) { userGitExe = userGitExe.toLowerCase(); @@ -2284,10 +2305,8 @@ private String launchCommandIn(ArgumentListBuilder args, File workDir, EnvVars e return stdout; } catch (GitException | InterruptedException e) { throw e; - } catch (IOException e) { - throw new GitException("Error performing command: " + command, e); - } catch (Throwable t) { - throw new GitException("Error performing git command", t); + } catch (Throwable e) { + throw new GitException("Error performing git command: " + command, e); } } diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplAuthTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplAuthTest.java deleted file mode 100644 index 282ac524d1..0000000000 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPIImplAuthTest.java +++ /dev/null @@ -1,178 +0,0 @@ -package org.jenkinsci.plugins.gitclient; - -import hudson.EnvVars; -import hudson.Launcher; -import hudson.model.TaskListener; -import hudson.util.ArgumentListBuilder; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.Arrays; -import java.util.Random; -import java.util.concurrent.TimeUnit; -import static org.hamcrest.Matchers.hasItems; -import org.junit.Before; -import org.junit.Test; -import static org.junit.Assert.*; - -/** - * CliGitAPIImpl authorization specific tests. - * - * @author Mark Waite - */ -public class CliGitAPIImplAuthTest { - - private final Launcher launcher = new Launcher.LocalLauncher(TaskListener.NULL); - - private final Random random = new Random(); - - private final String[] CARET_SPECIALS = {"^", "&", "\\", "<", ">", "|", " ", "\"", "\t"}; - private final String[] PERCENT_SPECIALS = {"%"}; - - private CliGitAPIImpl git; - - @Before - public void setUp() { - git = new CliGitAPIImpl("git", new File("."), TaskListener.NULL, new EnvVars()); - } - - @Test - public void testQuotedUsernamePasswordCredentials() throws Exception { - assertEquals("", quoteCredentials("")); - for (String special : CARET_SPECIALS) { - String expected = expectedQuoting(special); - assertEquals(expected, quoteCredentials(special)); - checkWindowsCommandOutput(special); - assertEquals(expected + expected, quoteCredentials(special + special)); - checkWindowsCommandOutput(special + special); - } - for (String special : PERCENT_SPECIALS) { - String expected = expectedQuoting(special); - assertEquals(expected, quoteCredentials(special)); - checkWindowsCommandOutput(special); - assertEquals(expected + expected, quoteCredentials(special + special)); - checkWindowsCommandOutput(special + special); - } - for (String startSpecial : CARET_SPECIALS) { - for (String endSpecial : PERCENT_SPECIALS) { - for (String middle : randomStrings()) { - String source = startSpecial + middle + endSpecial; - String expected = expectedQuoting(source); - assertEquals(expected, quoteCredentials(source)); - checkWindowsCommandOutput(source); - assertEquals(expected + expected, quoteCredentials(source + source)); - checkWindowsCommandOutput(source + source); - } - } - } - for (String startSpecial : PERCENT_SPECIALS) { - for (String endSpecial : CARET_SPECIALS) { - for (String middle : randomStrings()) { - String source = startSpecial + middle + endSpecial; - String expected = expectedQuoting(source); - assertEquals(expected, quoteCredentials(source)); - checkWindowsCommandOutput(source); - assertEquals(expected + expected, quoteCredentials(source + source)); - checkWindowsCommandOutput(source + source); - } - } - } - for (String startSpecial : PERCENT_SPECIALS) { - for (String endSpecial : PERCENT_SPECIALS) { - for (String middle : randomStrings()) { - String source = startSpecial + middle + endSpecial; - String expected = expectedQuoting(source); - assertEquals(expected, quoteCredentials(source)); - checkWindowsCommandOutput(source); - assertEquals(expected + expected, quoteCredentials(source + source)); - checkWindowsCommandOutput(source + source); - } - } - } - } - - private String quoteCredentials(String password) { - return git.escapeWindowsCharsForUnquotedString(password); - } - - private String expectedQuoting(String password) { - for (String needsCaret : CARET_SPECIALS) { - password = password.replace(needsCaret, "^" + needsCaret); - } - for (String needsPercent : PERCENT_SPECIALS) { - password = password.replace(needsPercent, "%" + needsPercent); - } - return password; - } - - private void checkWindowsCommandOutput(String password) throws Exception { - if (!isWindows() || password == null || password.trim().isEmpty()) { - /* ArgumentListBuilder can't pass spaces or tabs as arguments */ - return; - } - String userName = "git"; - File batFile = git.createWindowsBatFile(userName, password); - assertTrue(batFile.exists()); - ArgumentListBuilder args = new ArgumentListBuilder(batFile.getAbsolutePath(), "Password"); - String[] output = run(args); - assertThat(Arrays.asList(output), hasItems(password)); - if (batFile.delete() == false) { - /* Retry delete only once */ - Thread.sleep(501); /* Wait up to 0.5 second for Windows virus scanners, etc. */ - assertTrue("Failed retry of delete test batch file", batFile.delete()); - } - assertFalse(batFile.exists()); - } - - private String[] run(ArgumentListBuilder args) throws IOException, InterruptedException { - String[] output; - ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); - ByteArrayOutputStream bytesErr = new ByteArrayOutputStream(); - Launcher.ProcStarter p = launcher.launch().cmds(args).envs(new EnvVars()).stdout(bytesOut).stderr(bytesErr).pwd(new File(".")); - int status = p.start().joinWithTimeout(1, TimeUnit.MINUTES, TaskListener.NULL); - String result = bytesOut.toString("UTF-8"); - if (bytesErr.size() > 0) { - result = result + "\nstderr not empty:\n" + bytesErr.toString("UTF-8"); - } - output = result.split("[\\n\\r]"); - assertEquals(args.toString() + " command failed and reported '" + Arrays.toString(output) + "'", 0, status); - return output; - } - - /* Strings may contain ' ' but should not contain other escaped chars */ - private final String[] sourceData = { - "ЁЂЃЄЅ", - "Miloš Šafařík", - "ЌЍЎЏАБВГД", - "ЕЖЗИЙКЛМНОПРСТУФ", - "фхцчшщъыьэюя", - "الإطلاق", - "1;DROP TABLE users", - "C:", - "' OR '1'='1", - "He said, \"Hello!\", didn't he?", - "ZZ:", - "Roses are \u001b[0;31mred\u001b[0m" - }; - - private String randomString() { - int index = random.nextInt(sourceData.length); - return sourceData[index]; - } - - private String[] randomStrings() { - if (TEST_ALL_CREDENTIALS) { - return sourceData; - } - int index = random.nextInt(sourceData.length); - return new String[]{sourceData[index]}; - } - - private boolean isWindows() { - return File.pathSeparatorChar == ';'; - } - - /* If not in a Jenkins job, then default to run all credentials tests. */ - private static final String NOT_JENKINS = System.getProperty("JOB_NAME") == null ? "true" : "false"; - private static final boolean TEST_ALL_CREDENTIALS = Boolean.valueOf(System.getProperty("TEST_ALL_CREDENTIALS", NOT_JENKINS)); -} From 158b74c0a752dabc7c3d267ce654bcdf869d8425 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 10 Nov 2018 10:14:39 -0700 Subject: [PATCH 224/226] Do not use workspace as Linux temp path if '%' in name The Linux based ssh commands perform expansion of '%' in arguments to ssh, even if the '%' character is in the name of the file or directory. --- .../java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index a35003a1bd..7c04467ec3 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -1719,6 +1719,9 @@ File createTempFile(String prefix, String suffix) throws IOException { return createTempFileInSystemDir(prefix, suffix); } return Files.createTempFile(tmpPath, prefix, suffix).toFile(); + } else if (workspaceTmp.getAbsolutePath().contains("%")) { + /* Avoid Linux expansion of % in ssh arguments */ + return createTempFileInSystemDir(prefix, suffix); } // Unix specific if (workspaceTmp.getAbsolutePath().contains("`")) { From 975ef67d3a9d789947d4a78d30f0bea715e538f1 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 10 Nov 2018 10:21:40 -0700 Subject: [PATCH 225/226] Adapt credentials test for CLI git shallow clone Command line git shallow clone is only workable with command line git 1.9 and newer. Earlier versions cause strange behaviors in the plugin. Rather than complicate things with spurious failures on older command line git implementations (like CentOS 6 and CentOS 7). --- .../plugins/gitclient/CredentialsTest.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java index 8649cdfe59..1a44a93146 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java @@ -202,6 +202,14 @@ private static boolean isCredentialsSupported() throws IOException, InterruptedE return cli.isAtLeastVersion(1, 7, 9, 0); } + private boolean isShallowCloneSupported(String implementation, GitClient gitClient) throws IOException, InterruptedException { + if (!implementation.equals("git")) { + return false; + } + CliGitAPIImpl cli = (CliGitAPIImpl) gitClient; + return cli.isAtLeastVersion(1, 9, 0, 0); + } + @Parameterized.Parameters(name = "{2}-{1}-{0}-{5}") public static Collection gitRepoUrls() throws MalformedURLException, FileNotFoundException, IOException, InterruptedException, ParseException { List repos = new ArrayList<>(); @@ -301,13 +309,13 @@ public static Collection gitRepoUrls() throws MalformedURLException, FileNotFoun return TEST_ALL_CREDENTIALS ? repos : repos.subList(0, Math.min(repos.size(), 6)); } - private void doFetch(String source) throws InterruptedException, URISyntaxException { + private void doFetch(String source) throws Exception { /* Save some bandwidth with shallow clone for CliGit, not yet available for JGit */ URIish sourceURI = new URIish(source); List refSpecs = new ArrayList<>(); refSpecs.add(new RefSpec("+refs/heads/master:refs/remotes/origin/master")); FetchCommand cmd = git.fetch_().from(sourceURI, refSpecs).tags(false); - if (gitImpl.equals("git")) { + if (isShallowCloneSupported(gitImpl, git)) { // Reduce network transfer by using shallow clone // JGit does not support shallow clone cmd.shallow(true).depth(1); @@ -344,7 +352,7 @@ private boolean testPeriodNotExpired() { @Test @Issue("JENKINS_50573") - public void testFetchWithCredentials() throws URISyntaxException, GitException, InterruptedException, MalformedURLException, IOException { + public void testFetchWithCredentials() throws Exception { assumeTrue(testPeriodNotExpired()); File clonedFile = new File(repo, fileToCheck); git.init_().workspace(repo.getAbsolutePath()).execute(); From ac5f9c8192727a08b56e317068af7cde2358d676 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 10 Nov 2018 13:16:31 -0700 Subject: [PATCH 226/226] Fix README formatting of build example --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 192c34de55..b2bc2c3fbd 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,11 @@ Code coverage reporting is written to `target/site/jacoco/` by the maven command Building the Plugin =================== +``` $ java -version # Requires Java 1.8 $ mvn -version # Requires Apache Maven 3.5.0 or later $ mvn clean install +``` To Do =====