diff --git a/pom.xml b/pom.xml
index e3e846e34..515b630a4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
org.jenkins-ci.plugins
plugin
- 4.88
+ 5.19
@@ -33,8 +33,9 @@
999999-SNAPSHOT
jenkinsci/${project.artifactId}-plugin
2.2.0
- 2.440.3
- true
+
+ 2.504
+ ${jenkins.baseline}.1
false
@@ -42,8 +43,8 @@
io.jenkins.tools.bom
- bom-2.440.x
- 3234.v5ca_5154341ef
+ bom-${jenkins.baseline}.x
+ 4948.vcf1d17350668
pom
import
@@ -59,6 +60,10 @@
io.jenkins.plugins
caffeine-api
+
+ io.jenkins.plugins
+ commons-lang3-api
+
io.jenkins.plugins
ionicons-api
@@ -83,12 +88,6 @@
org.jenkins-ci.plugins.workflow
workflow-support
-
- com.github.tomakehurst
- wiremock-jre8-standalone
- 2.35.2
- test
-
io.jenkins
configuration-as-code
@@ -107,7 +106,7 @@
org.awaitility
awaitility
- 4.2.2
+ 4.3.0
test
@@ -137,6 +136,12 @@
mockito-core
test
+
+ org.wiremock
+ wiremock-standalone
+ 3.13.1
+ test
+
diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/ApiRateLimitChecker.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/ApiRateLimitChecker.java
index 57ce199ad..41f0deb8f 100644
--- a/src/main/java/org/jenkinsci/plugins/github_branch_source/ApiRateLimitChecker.java
+++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/ApiRateLimitChecker.java
@@ -1,7 +1,6 @@
package org.jenkinsci.plugins.github_branch_source;
import edu.umd.cs.findbugs.annotations.NonNull;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.Util;
import hudson.model.TaskListener;
import hudson.util.LogTaskListener;
@@ -12,13 +11,12 @@
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.StringUtils;
import org.jenkinsci.plugins.github.config.GitHubServerConfig;
import org.kohsuke.github.GHRateLimit;
import org.kohsuke.github.GitHub;
import org.kohsuke.github.RateLimitChecker;
-@SuppressFBWarnings("DMI_RANDOM_USED_ONLY_ONCE") // https://github.com/spotbugs/spotbugs/issues/1539
public enum ApiRateLimitChecker {
/** Attempt to evenly distribute GitHub API requests. */
diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/Connector.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/Connector.java
index 0973951c5..d6a30fc14 100644
--- a/src/main/java/org/jenkinsci/plugins/github_branch_source/Connector.java
+++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/Connector.java
@@ -75,7 +75,7 @@
import jenkins.util.SystemProperties;
import okhttp3.Cache;
import okhttp3.OkHttpClient;
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.StringUtils;
import org.jenkinsci.plugins.gitclient.GitClient;
import org.jenkinsci.plugins.github.config.GitHubServerConfig;
import org.kohsuke.github.GHAppInstallationToken;
diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/Endpoint.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/Endpoint.java
index 8c6539002..0669a5444 100644
--- a/src/main/java/org/jenkinsci/plugins/github_branch_source/Endpoint.java
+++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/Endpoint.java
@@ -42,7 +42,7 @@
import java.util.logging.Logger;
import jenkins.model.Jenkins;
import jenkins.scm.api.SCMName;
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.StringUtils;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.github.GitHub;
diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/FillErrorResponse.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/FillErrorResponse.java
index c2513a629..3d030fbf6 100644
--- a/src/main/java/org/jenkinsci/plugins/github_branch_source/FillErrorResponse.java
+++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/FillErrorResponse.java
@@ -1,13 +1,12 @@
package org.jenkinsci.plugins.github_branch_source;
import hudson.Util;
+import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletResponse;
import jenkins.model.Jenkins;
import org.kohsuke.stapler.HttpResponse;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
// TODO replace with corresponding core functionality once Jenkins core has JENKINS-42443
class FillErrorResponse extends IOException implements HttpResponse {
@@ -20,8 +19,7 @@ public FillErrorResponse(String message, boolean clearList) {
}
@Override
- public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node)
- throws IOException, ServletException {
+ public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException {
rsp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
rsp.setContentType("text/html;charset=UTF-8");
rsp.setHeader("X-Jenkins-Select-Error", clearList ? "clear" : "retain");
diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubAppCredentials.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubAppCredentials.java
index 4dc65d3f8..d2a2886e3 100644
--- a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubAppCredentials.java
+++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubAppCredentials.java
@@ -103,7 +103,6 @@ public class GitHubAppCredentials extends BaseStandardCredentials implements Sta
private String apiUri;
- @SuppressFBWarnings(value = "IS2_INCONSISTENT_SYNC", justification = "#withOwner locking only for #byOwner")
@Deprecated
private String owner;
diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubConfiguration.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubConfiguration.java
index 5360b3d8e..f06c109b2 100644
--- a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubConfiguration.java
+++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubConfiguration.java
@@ -41,8 +41,8 @@
import jenkins.model.GlobalConfiguration;
import jenkins.model.Jenkins;
import net.sf.json.JSONObject;
-import org.apache.commons.lang.StringUtils;
-import org.kohsuke.stapler.StaplerRequest;
+import org.apache.commons.lang3.StringUtils;
+import org.kohsuke.stapler.StaplerRequest2;
@Extension
public class GitHubConfiguration extends GlobalConfiguration {
@@ -60,7 +60,7 @@ public GitHubConfiguration() {
}
@Override
- public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+ public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
req.bindJSON(this, json);
return true;
}
diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubOrgMetadataAction.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubOrgMetadataAction.java
index 37c170ecf..284f00f69 100644
--- a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubOrgMetadataAction.java
+++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubOrgMetadataAction.java
@@ -32,7 +32,7 @@
import java.io.ObjectStreamException;
import java.util.Objects;
import jenkins.scm.api.metadata.AvatarMetadataAction;
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.StringUtils;
import org.kohsuke.github.GHUser;
import org.kohsuke.stapler.Stapler;
@@ -76,7 +76,7 @@ public String getAvatarImageOf(String size) {
String image = avatarIconClassNameImageOf(getAvatarIconClassName(), size);
return image != null
? image
- : (Stapler.getCurrentRequest().getContextPath()
+ : (Stapler.getCurrentRequest2().getContextPath()
+ Hudson.RESOURCE_PATH
+ "/plugin/github-branch-source/images/"
+ "/github-logo.svg");
diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubRepositoryInfo.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubRepositoryInfo.java
index db74b0720..9302e863f 100644
--- a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubRepositoryInfo.java
+++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubRepositoryInfo.java
@@ -24,13 +24,13 @@
package org.jenkinsci.plugins.github_branch_source;
-import static org.apache.commons.lang.StringUtils.removeEnd;
+import static org.apache.commons.lang3.StringUtils.removeEnd;
import static org.jenkinsci.plugins.github_branch_source.GitHubSCMSource.GITHUB_COM;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.net.MalformedURLException;
import java.net.URL;
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.StringUtils;
/**
* Used to compute values for GitHubSCMSource from a user-specified repository URL.
diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMBuilder.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMBuilder.java
index 44bd2ee37..962b9707e 100644
--- a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMBuilder.java
+++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMBuilder.java
@@ -32,7 +32,6 @@
import com.cloudbees.plugins.credentials.domains.URIRequirementBuilder;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.model.Item;
import hudson.model.Queue;
import hudson.plugins.git.GitSCM;
@@ -49,7 +48,7 @@
import jenkins.scm.api.SCMRevision;
import jenkins.scm.api.SCMSourceOwner;
import jenkins.scm.api.mixin.TagSCMHead;
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.transport.RefSpec;
import org.jenkinsci.plugins.github.config.GitHubServerConfig;
@@ -59,7 +58,6 @@
*
* @since 2.2.0
*/
-@SuppressFBWarnings("DMI_RANDOM_USED_ONLY_ONCE") // https://github.com/spotbugs/spotbugs/issues/1539
public class GitHubSCMBuilder extends GitSCMBuilder {
private static final Random ENTROPY = new Random();
diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMFileSystem.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMFileSystem.java
index cdecf79ea..e3bd1a01e 100644
--- a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMFileSystem.java
+++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMFileSystem.java
@@ -46,7 +46,7 @@
import jenkins.scm.api.SCMRevision;
import jenkins.scm.api.SCMSource;
import jenkins.scm.api.SCMSourceDescriptor;
-import org.apache.commons.lang.time.FastDateFormat;
+import org.apache.commons.lang3.time.FastDateFormat;
import org.kohsuke.github.GHCommit;
import org.kohsuke.github.GHRef;
import org.kohsuke.github.GHRepository;
diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMNavigator.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMNavigator.java
index 4e35ad913..d188b2af1 100644
--- a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMNavigator.java
+++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMNavigator.java
@@ -39,6 +39,7 @@
import hudson.AbortException;
import hudson.Extension;
import hudson.ExtensionList;
+import hudson.Functions;
import hudson.RestrictedSince;
import hudson.Util;
import hudson.console.HyperlinkNote;
@@ -90,7 +91,7 @@
import jenkins.scm.impl.trait.WildcardSCMHeadFilterTrait;
import jenkins.util.SystemProperties;
import net.jcip.annotations.GuardedBy;
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.StringUtils;
import org.jenkins.ui.icon.Icon;
import org.jenkins.ui.icon.IconFormat;
import org.jenkins.ui.icon.IconSet;
@@ -1041,50 +1042,60 @@ public void visitSources(SCMSourceObserver observer) throws IOException, Interru
continue; // ignore repos in other orgs when using GHMyself
}
- if (repo.isArchived() && gitHubSCMNavigatorContext.isExcludeArchivedRepositories()) {
- witness.record(repo.getName(), false);
- listener.getLogger()
- .println(GitHubConsoleNote.create(
- System.currentTimeMillis(),
- String.format(
- "Skipping repository %s because it is archived",
- repo.getName())));
-
- } else if (!topicMatches(gitHubSCMNavigatorContext, repo, listener.getLogger())) {
- // exclude repositories which are missing one or more of the specified topics
- witness.record(repo.getName(), false);
- } else if (!repo.isPrivate() && gitHubSCMNavigatorContext.isExcludePublicRepositories()) {
- witness.record(repo.getName(), false);
- listener.getLogger()
- .println(GitHubConsoleNote.create(
- System.currentTimeMillis(),
- String.format(
- "Skipping repository %s because it is public",
- repo.getName())));
- } else if (repo.isPrivate() && gitHubSCMNavigatorContext.isExcludePrivateRepositories()) {
- witness.record(repo.getName(), false);
- listener.getLogger()
- .println(GitHubConsoleNote.create(
- System.currentTimeMillis(),
- String.format(
- "Skipping repository %s because it is private",
- repo.getName())));
- } else if (gitHubSCMNavigatorContext.isExcludeForkedRepositories()
- && repo.getSource() != null) {
- witness.record(repo.getName(), false);
+ try {
+ if (repo.isArchived() && gitHubSCMNavigatorContext.isExcludeArchivedRepositories()) {
+ witness.record(repo.getName(), false);
+ listener.getLogger()
+ .println(GitHubConsoleNote.create(
+ System.currentTimeMillis(),
+ String.format(
+ "Skipping repository %s because it is archived",
+ repo.getName())));
+
+ } else if (!topicMatches(gitHubSCMNavigatorContext, repo, listener.getLogger())) {
+ // exclude repositories which are missing one or more of the specified topics
+ witness.record(repo.getName(), false);
+ } else if (!repo.isPrivate()
+ && gitHubSCMNavigatorContext.isExcludePublicRepositories()) {
+ witness.record(repo.getName(), false);
+ listener.getLogger()
+ .println(GitHubConsoleNote.create(
+ System.currentTimeMillis(),
+ String.format(
+ "Skipping repository %s because it is public",
+ repo.getName())));
+ } else if (repo.isPrivate()
+ && gitHubSCMNavigatorContext.isExcludePrivateRepositories()) {
+ witness.record(repo.getName(), false);
+ listener.getLogger()
+ .println(GitHubConsoleNote.create(
+ System.currentTimeMillis(),
+ String.format(
+ "Skipping repository %s because it is private",
+ repo.getName())));
+ } else if (gitHubSCMNavigatorContext.isExcludeForkedRepositories()
+ && repo.getSource() != null) {
+ witness.record(repo.getName(), false);
+ listener.getLogger()
+ .println(GitHubConsoleNote.create(
+ System.currentTimeMillis(),
+ String.format(
+ "Skipping repository %s because it is a fork",
+ repo.getName())));
+ } else if (request.process(repo.getName(), sourceFactory, null, witness)) {
+ listener.getLogger()
+ .println(GitHubConsoleNote.create(
+ System.currentTimeMillis(),
+ String.format(
+ "%d repositories were processed (query completed)",
+ witness.getCount())));
+ }
+ } catch (IOException e) {
listener.getLogger()
.println(GitHubConsoleNote.create(
System.currentTimeMillis(),
- String.format(
- "Skipping repository %s because it is a fork",
- repo.getName())));
- } else if (request.process(repo.getName(), sourceFactory, null, witness)) {
- listener.getLogger()
- .println(GitHubConsoleNote.create(
- System.currentTimeMillis(),
- String.format(
- "%d repositories were processed (query completed)",
- witness.getCount())));
+ String.format("Error while processing repository %s", repo.getName())));
+ Functions.printStackTrace(e, listener.getLogger());
}
}
listener.getLogger()
@@ -1124,48 +1135,60 @@ public void visitSources(SCMSourceObserver observer) throws IOException, Interru
repositories = org.listRepositories(100);
}
for (GHRepository repo : repositories) {
- if (repo.isArchived() && gitHubSCMNavigatorContext.isExcludeArchivedRepositories()) {
- // exclude archived repositories
- witness.record(repo.getName(), false);
- listener.getLogger()
- .println(GitHubConsoleNote.create(
- System.currentTimeMillis(),
- String.format(
- "Skipping repository %s because it is archived", repo.getName())));
- } else if (!topicMatches(gitHubSCMNavigatorContext, repo, listener.getLogger())) {
- // exclude repositories which are missing one or more of the specified topics
- witness.record(repo.getName(), false);
- } else if (!repo.isPrivate() && gitHubSCMNavigatorContext.isExcludePublicRepositories()) {
- witness.record(repo.getName(), false);
- listener.getLogger()
- .println(GitHubConsoleNote.create(
- System.currentTimeMillis(),
- String.format(
- "Skipping repository %s because it is public", repo.getName())));
+ try {
+ if (repo.isArchived() && gitHubSCMNavigatorContext.isExcludeArchivedRepositories()) {
+ // exclude archived repositories
+ witness.record(repo.getName(), false);
+ listener.getLogger()
+ .println(GitHubConsoleNote.create(
+ System.currentTimeMillis(),
+ String.format(
+ "Skipping repository %s because it is archived",
+ repo.getName())));
+ } else if (!topicMatches(gitHubSCMNavigatorContext, repo, listener.getLogger())) {
+ // exclude repositories which are missing one or more of the specified topics
+ witness.record(repo.getName(), false);
+ } else if (!repo.isPrivate() && gitHubSCMNavigatorContext.isExcludePublicRepositories()) {
+ witness.record(repo.getName(), false);
+ listener.getLogger()
+ .println(GitHubConsoleNote.create(
+ System.currentTimeMillis(),
+ String.format(
+ "Skipping repository %s because it is public",
+ repo.getName())));
- } else if (repo.isPrivate() && gitHubSCMNavigatorContext.isExcludePrivateRepositories()) {
- witness.record(repo.getName(), false);
- listener.getLogger()
- .println(GitHubConsoleNote.create(
- System.currentTimeMillis(),
- String.format(
- "Skipping repository %s because it is private", repo.getName())));
+ } else if (repo.isPrivate() && gitHubSCMNavigatorContext.isExcludePrivateRepositories()) {
+ witness.record(repo.getName(), false);
+ listener.getLogger()
+ .println(GitHubConsoleNote.create(
+ System.currentTimeMillis(),
+ String.format(
+ "Skipping repository %s because it is private",
+ repo.getName())));
- } else if (gitHubSCMNavigatorContext.isExcludeForkedRepositories()
- && repo.getSource() != null) {
- witness.record(repo.getName(), false);
- listener.getLogger()
- .println(GitHubConsoleNote.create(
- System.currentTimeMillis(),
- String.format(
- "Skipping repository %s because it is a fork", repo.getName())));
- } else if (request.process(repo.getName(), sourceFactory, null, witness)) {
+ } else if (gitHubSCMNavigatorContext.isExcludeForkedRepositories()
+ && repo.getSource() != null) {
+ witness.record(repo.getName(), false);
+ listener.getLogger()
+ .println(GitHubConsoleNote.create(
+ System.currentTimeMillis(),
+ String.format(
+ "Skipping repository %s because it is a fork",
+ repo.getName())));
+ } else if (request.process(repo.getName(), sourceFactory, null, witness)) {
+ listener.getLogger()
+ .println(GitHubConsoleNote.create(
+ System.currentTimeMillis(),
+ String.format(
+ "%d repositories were processed (query completed)",
+ witness.getCount())));
+ }
+ } catch (IOException e) {
listener.getLogger()
.println(GitHubConsoleNote.create(
System.currentTimeMillis(),
- String.format(
- "%d repositories were processed (query completed)",
- witness.getCount())));
+ String.format("Error while processing repository %s", repo.getName())));
+ Functions.printStackTrace(e, listener.getLogger());
}
}
listener.getLogger()
@@ -1753,7 +1776,7 @@ public String getIconFilePathPattern() {
/** {@inheritDoc} */
@Override
public String getIconClassName() {
- return "icon-github-scm-navigator";
+ return "symbol-logo-github plugin-ionicons-api";
}
/** {@inheritDoc} */
diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource.java
index 6b1583df9..ac1c480fc 100644
--- a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource.java
+++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource.java
@@ -26,8 +26,8 @@
import static hudson.Functions.isWindows;
import static hudson.model.Items.XSTREAM2;
-import static org.apache.commons.lang.StringUtils.isBlank;
-import static org.apache.commons.lang.StringUtils.removeEnd;
+import static org.apache.commons.lang3.StringUtils.isBlank;
+import static org.apache.commons.lang3.StringUtils.removeEnd;
import static org.jenkinsci.plugins.github_branch_source.Connector.isCredentialValid;
import static org.jenkinsci.plugins.github_branch_source.GitHubSCMBuilder.API_V3;
import static org.jenkinsci.plugins.github_branch_source.GitHubSCMBuilder.HTTPS;
@@ -58,6 +58,7 @@
import hudson.util.FormValidation;
import hudson.util.ListBoxModel;
import hudson.util.LogTaskListener;
+import jakarta.servlet.http.HttpServletResponse;
import java.io.Closeable;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -85,7 +86,6 @@
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import javax.servlet.http.HttpServletResponse;
import jenkins.model.Jenkins;
import jenkins.plugins.git.AbstractGitSCMSource;
import jenkins.plugins.git.GitTagSCMRevision;
@@ -117,7 +117,7 @@
import jenkins.scm.impl.trait.Selection;
import jenkins.scm.impl.trait.WildcardSCMHeadFilterTrait;
import jenkins.util.SystemProperties;
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.lib.Constants;
import org.jenkinsci.Symbol;
import org.jenkinsci.plugins.github.config.GitHubServerConfig;
@@ -1053,6 +1053,19 @@ public GHPermissionType fetch(String username) throws IOException, InterruptedEx
}
});
+ if (request.isFetchPRs()) {
+ // JENKINS-56996 / JENKINS-73791
+ // PRs are one the most error prone areas for scans
+ // Branches and tags are contained only the current repo, PRs go across forks
+ // FileNotFoundException can occur in a number of situations
+ // When this happens, it is not ideal behavior but it is better to let the PR be
+ // orphaned
+ // and the orphan strategy control the result than for this error to stop scanning
+ // (For Org scanning this is particularly important.)
+ // If some more general IO exception is thrown, we will still fail.
+ validatePullRequests(request);
+ }
+
if (request.isFetchBranches()
&& !request.isComplete()
&& this.shouldRetrieve(observer, event, BranchSCMHead.class)) {
@@ -1067,6 +1080,7 @@ public GHPermissionType fetch(String username) throws IOException, InterruptedEx
HyperlinkNote.encodeTo(
resolvedRepositoryUrl + "/tree/" + branchName, branchName));
BranchSCMHead head = new BranchSCMHead(branchName);
+
if (request.process(
head,
new SCMRevisionImpl(head, branch.getSHA1()),
@@ -1081,8 +1095,6 @@ public SCMSourceCriteria.Probe create(
}
},
new CriteriaWitness(listener))) {
- listener.getLogger()
- .format("%n %d branches were processed (query completed)%n", count);
break;
}
}
@@ -1095,18 +1107,6 @@ public SCMSourceCriteria.Probe create(
int count = 0;
int errorCount = 0;
Map> strategies = request.getPRStrategies();
-
- // JENKINS-56996
- // PRs are one the most error prone areas for scans
- // Branches and tags are contained only the current repo, PRs go across forks
- // FileNotFoundException can occur in a number of situations
- // When this happens, it is not ideal behavior but it is better to let the PR be
- // orphaned
- // and the orphan strategy control the result than for this error to stop scanning
- // (For Org scanning this is particularly important.)
- // If some more general IO exception is thrown, we will still fail.
-
- validatePullRequests(request);
for (final GHPullRequest pr : request.getPullRequests()) {
int number = pr.getNumber();
try {
@@ -2134,7 +2134,6 @@ public FormValidation doValidateRepositoryUrlAndCredentials(
} catch (IllegalArgumentException e) {
return FormValidation.error(e, e.getMessage());
}
-
StandardCredentials credentials =
Connector.lookupScanCredentials(context, info.getApiUri(), credentialsId, info.getRepoOwner());
StringBuilder sb = new StringBuilder();
@@ -2571,17 +2570,24 @@ public void observe(GHPullRequest pr) {
GHUser user = null;
try {
user = pr.getUser();
- if (users.containsKey(user.getLogin())) {
- // looked up this user already
- user = users.get(user.getLogin());
+ String login = user.getLogin();
+ if ("copilot".equalsIgnoreCase(login)) {
+ ContributorMetadataAction contributor =
+ new ContributorMetadataAction("copilot", "copilot", "copilot@unknown.user");
+ pullRequestContributorCache.put(number, contributor);
+ users.put("copilot", user);
+ } else {
+ if (users.containsKey(login)) {
+ // looked up this user already
+ user = users.get(login);
+ }
+ ContributorMetadataAction contributor =
+ new ContributorMetadataAction(login, user.getName(), user.getEmail());
+ // store the populated user record now that we have it
+ pullRequestContributorCache.put(number, contributor);
+ users.put(login, user);
}
- ContributorMetadataAction contributor =
- new ContributorMetadataAction(user.getLogin(), user.getName(), user.getEmail());
- pullRequestContributorCache.put(number, contributor);
- // store the populated user record now that we have it
- users.put(user.getLogin(), user);
} catch (FileNotFoundException e) {
- // If file not found for user, warn but keep going
request.listener()
.getLogger()
.format(
diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/PullRequestSCMRevision.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/PullRequestSCMRevision.java
index 9931447a9..afce906e5 100644
--- a/src/main/java/org/jenkinsci/plugins/github_branch_source/PullRequestSCMRevision.java
+++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/PullRequestSCMRevision.java
@@ -32,7 +32,7 @@
import jenkins.scm.api.mixin.ChangeRequestCheckoutStrategy;
import jenkins.scm.api.mixin.ChangeRequestSCMHead2;
import jenkins.scm.api.mixin.ChangeRequestSCMRevision;
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.StringUtils;
import org.kohsuke.stapler.export.Exported;
/** Revision of a pull request. */
@@ -58,7 +58,7 @@ public PullRequestSCMRevision(
this.mergeHash = mergeHash;
}
- @SuppressFBWarnings({"SE_PRIVATE_READ_RESOLVE_NOT_INHERITED", "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE"})
+ @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE")
private Object readResolve() {
if (getTarget() == null) {
// fix an instance prior to the type migration, thankfully we have all the required info
diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/SSHCheckoutTrait.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/SSHCheckoutTrait.java
index 67ecdad4b..de6a6d00f 100644
--- a/src/main/java/org/jenkinsci/plugins/github_branch_source/SSHCheckoutTrait.java
+++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/SSHCheckoutTrait.java
@@ -47,7 +47,7 @@
import jenkins.scm.api.trait.SCMSourceContext;
import jenkins.scm.api.trait.SCMSourceTrait;
import jenkins.scm.api.trait.SCMSourceTraitDescriptor;
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.StringUtils;
import org.jenkinsci.Symbol;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
diff --git a/src/test/java/org/jenkinsci/plugins/github_branch_source/EndpointTest.java b/src/test/java/org/jenkinsci/plugins/github_branch_source/EndpointTest.java
index b470e6fc3..9693adbfb 100644
--- a/src/test/java/org/jenkinsci/plugins/github_branch_source/EndpointTest.java
+++ b/src/test/java/org/jenkinsci/plugins/github_branch_source/EndpointTest.java
@@ -10,13 +10,13 @@
import hudson.Util;
import hudson.model.UnprotectedRootAction;
import hudson.security.csrf.CrumbExclusion;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import jenkins.model.Jenkins;
import org.htmlunit.FailingHttpStatusCodeException;
import org.htmlunit.HttpMethod;
@@ -31,8 +31,8 @@
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.MockAuthorizationStrategy;
import org.jvnet.hudson.test.TestExtension;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
import org.xml.sax.SAXException;
public class EndpointTest {
@@ -103,7 +103,7 @@ private String appendCrumb(String url) {
}
private String getCrumb() {
- return Functions.getCrumbRequestField() + "=" + Functions.getCrumb(null);
+ return Functions.getCrumbRequestField() + "=" + Functions.getCrumb((StaplerRequest2) null);
}
private Page post(String relative, String userName) throws Exception {
@@ -116,8 +116,8 @@ private Page post(String relative, String userName) throws Exception {
final WebRequest request = new WebRequest(new URL(client.getContextPath() + relative), HttpMethod.POST);
request.setAdditionalHeader("Accept", client.getBrowserVersion().getHtmlAcceptHeader());
- request.setRequestParameters(
- Arrays.asList(new NameValuePair(Functions.getCrumbRequestField(), Functions.getCrumb(null))));
+ request.setRequestParameters(Arrays.asList(
+ new NameValuePair(Functions.getCrumbRequestField(), Functions.getCrumb((StaplerRequest2) null))));
return client.getPage(request);
}
@@ -141,7 +141,7 @@ public String getUrlName() {
return "testroot";
}
- public void doIndex(StaplerRequest request, StaplerResponse response) throws IOException {
+ public void doIndex(StaplerRequest2 request, StaplerResponse2 response) throws IOException {
visited = true;
response.getWriter().println("OK");
}
diff --git a/src/test/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMBuilderTest.java b/src/test/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMBuilderTest.java
index 1f1ef4d95..1b39e0f4c 100644
--- a/src/test/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMBuilderTest.java
+++ b/src/test/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMBuilderTest.java
@@ -20,6 +20,7 @@
import com.cloudbees.plugins.credentials.SystemCredentialsProvider;
import com.cloudbees.plugins.credentials.domains.Domain;
import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl;
+import hudson.model.Descriptor;
import hudson.plugins.git.GitSCM;
import hudson.plugins.git.Revision;
import hudson.plugins.git.UserRemoteConfig;
@@ -82,7 +83,7 @@ public void createGitHubSCMSourceForTest(boolean configuredByUrl, String repoUrl
}
@Before
- public void setUp() throws IOException {
+ public void setUp() throws IOException, Descriptor.FormException {
owner = j.createProject(WorkflowMultiBranchProject.class);
Credentials userPasswordCredential = new UsernamePasswordCredentialsImpl(
CredentialsScope.GLOBAL, "user-pass", null, "git-user", "git-secret");
diff --git a/src/test/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMNavigatorTest.java b/src/test/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMNavigatorTest.java
index 4a501b6a0..f2b8d395a 100644
--- a/src/test/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMNavigatorTest.java
+++ b/src/test/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMNavigatorTest.java
@@ -37,6 +37,7 @@
import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
+import hudson.model.Descriptor;
import hudson.model.Item;
import hudson.model.TaskListener;
import hudson.model.User;
@@ -46,6 +47,7 @@
import hudson.security.SecurityRealm;
import hudson.util.ListBoxModel;
import hudson.util.LogTaskListener;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -75,8 +77,16 @@ public class GitHubSCMNavigatorTest extends AbstractGitHubWireMockTest {
@Mock
private SCMSourceOwner scmSourceOwner;
- private BaseStandardCredentials credentials = new UsernamePasswordCredentialsImpl(
- CredentialsScope.GLOBAL, "authenticated-user", null, "git-user", "git-secret");
+ private BaseStandardCredentials credentials;
+
+ {
+ try {
+ credentials = new UsernamePasswordCredentialsImpl(
+ CredentialsScope.GLOBAL, "authenticated-user", null, "git-user", "git-secret");
+ } catch (Descriptor.FormException e) {
+ throw new RuntimeException(e);
+ }
+ }
private GitHubSCMNavigator navigator;
@@ -451,6 +461,42 @@ public void appliesFilters() throws Exception {
assertEquals(projectNames, Collections.singleton("yolo"));
}
+ @Test
+ public void fetchBadRepo() throws Exception {
+ final Set projectNames = new HashSet<>();
+ final SCMSourceObserver observer = new SCMSourceObserver() {
+ @NonNull
+ @Override
+ public SCMSourceOwner getContext() {
+ return scmSourceOwner;
+ }
+
+ @NonNull
+ @Override
+ public TaskListener getListener() {
+ return new LogTaskListener(Logger.getAnonymousLogger(), Level.INFO);
+ }
+
+ @NonNull
+ @Override
+ public ProjectObserver observe(@NonNull String projectName) throws IllegalArgumentException, IOException {
+ if ("basic".equalsIgnoreCase(projectName)) {
+ throw new IOException("Failed to get repo basic");
+ }
+ projectNames.add(projectName);
+ return new NoOpProjectObserver();
+ }
+
+ @Override
+ public void addAttribute(@NonNull String key, @Nullable Object value)
+ throws IllegalArgumentException, ClassCastException {}
+ };
+
+ navigator.visitSources(SCMSourceObserver.filter(observer, "basic", "yolo"));
+
+ assertThat(projectNames, containsInAnyOrder("yolo"));
+ }
+
@Test
public void fetchActions() throws Exception {
assertThat(
diff --git a/src/test/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMProbeTest.java b/src/test/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMProbeTest.java
index 63917dacd..545600ddc 100644
--- a/src/test/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMProbeTest.java
+++ b/src/test/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMProbeTest.java
@@ -4,7 +4,6 @@
import static org.junit.Assert.*;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
-import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer;
import com.github.tomakehurst.wiremock.http.RequestMethod;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder;
@@ -32,10 +31,8 @@ public class GitHubSCMProbeTest {
public WireMockRule githubApi = factory.getRule(WireMockConfiguration.options()
.dynamicPort()
.usingFilesUnderClasspath("cache_failure")
- .extensions(ResponseTemplateTransformer.builder()
- .global(true)
- .maxCacheEntries(0L)
- .build()));
+ .globalTemplating(true)
+ .withMaxTemplateCacheEntries(0L));
private GitHubSCMProbe probe;
diff --git a/src/test/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSourceTest.java b/src/test/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSourceTest.java
index 1a58db43e..77666a076 100644
--- a/src/test/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSourceTest.java
+++ b/src/test/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSourceTest.java
@@ -375,6 +375,11 @@ public boolean isHead(@NonNull Probe probe, @NonNull TaskListener listener) thro
@Test
public void fetchSmokes_badUser() throws Exception {
+ source.setTraits(Arrays.asList(
+ new BranchDiscoveryTrait(true, false),
+ new ForkPullRequestDiscoveryTrait(
+ EnumSet.of(ChangeRequestCheckoutStrategy.MERGE),
+ new ForkPullRequestDiscoveryTrait.TrustContributors())));
// make it so PR-2 returns a file not found for user
githubApi.stubFor(get(urlMatching("(/api/v3)?/repos/cloudbeers/yolo/pulls/2"))
.inScenario("Pull Request Merge Hash")