Skip to content

Commit

Permalink
Adds auto-favoriting exclusion for workflow libraries
Browse files Browse the repository at this point in the history
Without testing if a remote URL is a match for the buildData it might log
an error when testing a specific commit against the wrong git repository:
Unexpected error when retrieving changeset
hudson.plugins.git.GitException: Error: git whatchanged --no-abbrev ...
Should fix JENKINS-43400.

Fixing the previous behavior leads to auto-favoriting the author of the
last commit for the workflow library for all builds that contains the
workflow library.

Bumps supported Jenkins to 2.289.3, required by pipeline-groovy-lib.

pipeline-groovy-lib contains duplicate code from deprecated plugin
workflow-cps-global-lib-plugin. Could not add support for both plugins due
the java package being the same.
  • Loading branch information
froque committed Jul 3, 2023
1 parent df62488 commit 9a6c4f2
Show file tree
Hide file tree
Showing 6 changed files with 318 additions and 44 deletions.
2 changes: 1 addition & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
buildPlugin(useContainerAgent: true, configurations: [
[ platform: "linux", jdk: "8" ],
[ platform: "windows", jdk: "8" ],
[ platform: "linux", jdk: "11", jenkins: "2.222.3" ]
[ platform: "linux", jdk: "11" ]
])
41 changes: 9 additions & 32 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<properties>
<java.level>8</java.level>
<!-- jenkins -->
<jenkins.version>2.176.4</jenkins.version>
<jenkins.version>2.289.3</jenkins.version>
<!-- security spotbugs -->
<spotbugs.failOnError>false</spotbugs.failOnError>
</properties>
Expand Down Expand Up @@ -54,14 +54,6 @@
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>git</artifactId>
<version>3.6.0</version>
<exclusions>
<!-- Upper bound dependencies error fix -->
<exclusion>
<groupId>org.jenkins-ci</groupId>
<artifactId>annotation-indexer</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
Expand All @@ -70,7 +62,6 @@
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>branch-api</artifactId>
<version>2.0.11</version>
</dependency>
<dependency>
<groupId>org.jvnet.hudson.plugins</groupId>
Expand All @@ -81,26 +72,18 @@
<dependency>
<groupId>org.jenkinsci.plugins</groupId>
<artifactId>pipeline-model-definition</artifactId>
<version>1.2.2</version>
<scope>test</scope>
<exclusions>
<!-- Pulled by JTH -->
<exclusion>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Upper bound dependencies error fix -->
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
<groupId>io.jenkins.plugins</groupId>
<artifactId>pipeline-groovy-lib</artifactId>
<version>591.v3a_7f422b_d058</version>
<optional>true</optional>
</dependency>
<!-- Upper bound dependencies error fix -->
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>command-launcher</artifactId>
<version>1.3</version>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Expand All @@ -109,17 +92,11 @@
<dependencies>
<dependency>
<groupId>io.jenkins.tools.bom</groupId>
<artifactId>bom-2.176.x</artifactId>
<version>9</version>
<artifactId>bom-2.289.x</artifactId>
<version>1500.ve4d05cd32975</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
package io.jenkins.blueocean.autofavorite;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import javax.annotation.CheckForNull;

import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import hudson.EnvVars;
import hudson.Extension;
import hudson.FilePath;
Expand All @@ -17,27 +29,28 @@
import hudson.plugins.git.GitSCM;
import hudson.plugins.git.GitTool;
import hudson.plugins.git.Revision;
import hudson.plugins.git.UserRemoteConfig;
import hudson.plugins.git.util.BuildData;
import hudson.scm.SCM;
import hudson.scm.SCMRevisionState;
import hudson.util.LogTaskListener;
import io.jenkins.blueocean.autofavorite.user.FavoritingUserProperty;
import jenkins.branch.MultiBranchProject;
import jenkins.model.Jenkins;
import jenkins.plugins.git.GitSCMSource;
import jenkins.scm.api.SCMSource;
import org.apache.commons.io.IOUtils;
import org.eclipse.jgit.errors.MissingObjectException;
import org.jenkinsci.plugins.gitclient.Git;
import org.jenkinsci.plugins.gitclient.GitClient;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;

import javax.annotation.CheckForNull;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jenkinsci.plugins.workflow.libs.FolderLibraries;
import org.jenkinsci.plugins.workflow.libs.GlobalLibraries;
import org.jenkinsci.plugins.workflow.libs.LibrariesAction;
import org.jenkinsci.plugins.workflow.libs.LibraryConfiguration;
import org.jenkinsci.plugins.workflow.libs.LibraryRecord;
import org.jenkinsci.plugins.workflow.libs.LibraryRetriever;
import org.jenkinsci.plugins.workflow.libs.SCMSourceRetriever;

@Extension
public class FavoritingScmListener extends SCMListener {
Expand Down Expand Up @@ -65,7 +78,23 @@ public void onCheckout(Run<?, ?> build, SCM scm, FilePath workspace, TaskListene
return;
}

BuildData buildData = build.getAction(BuildData.class);
final List<String> urls = ((GitSCM) scm).getUserRemoteConfigs().stream()
.map(UserRemoteConfig::getUrl)
.collect(Collectors.toList());

final List<BuildData> buildDataList = build.getActions(BuildData.class);
BuildData buildData = buildDataList.stream()
.filter(bd -> !Sets.intersection(Sets.newHashSet(urls), bd.remoteUrls).isEmpty())
.findFirst()
.orElse(null);

if (Jenkins.get().getPlugin("pipeline-groovy-lib") != null) {
if (shouldSkipLibrariesRepository(build, urls)) {
LOGGER.fine("Remote repository is for a Workflow Library. Skipping auto favoriting.");
return;
}
}

if (buildData == null) {
LOGGER.fine("No Git Build Data is present. Favoriting cannot be run.");
return;
Expand Down Expand Up @@ -135,6 +164,51 @@ public void onCheckout(Run<?, ?> build, SCM scm, FilePath workspace, TaskListene
}
}

private boolean shouldSkipLibrariesRepository(final Run<?, ?> build, final List<String> urls) {
final LibrariesAction librariesAction = build.getAction(LibrariesAction.class);
if (librariesAction != null && !librariesAction.getLibraries().isEmpty()) {
for (final LibraryRecord libraryRecord : librariesAction.getLibraries()) {
final String name = libraryRecord.getName();

if (libraryMatchesUrls(urls, name, GlobalLibraries.get().getLibraries())) {
return true;
}

final MultiBranchProject<?, ?> multiBranchProject = (MultiBranchProject<?, ?>) ((WorkflowRun) build).getParent().getParent();
for (Object property : multiBranchProject.getProperties()) {
if (property instanceof FolderLibraries) {
FolderLibraries folderLibraries = (FolderLibraries) property;
final List<LibraryConfiguration> libraryConfigurations = folderLibraries.getLibraries();
if (libraryMatchesUrls(urls, name, libraryConfigurations)) {
return true;
}
}
}
}
}
return false;
}

private boolean libraryMatchesUrls(final List<String> urls, final String name, final List<LibraryConfiguration> libraryConfigurations) {
for (final LibraryConfiguration library : libraryConfigurations) {
if (library.getName().equals(name)) {
final LibraryRetriever retriever = library.getRetriever();
if (retriever instanceof SCMSourceRetriever) {
final SCMSourceRetriever scmSourceRetriever = (SCMSourceRetriever) retriever;
final SCMSource scmSource = scmSourceRetriever.getScm();
if (scmSource instanceof GitSCMSource) {
final GitSCMSource gitSCMSource = (GitSCMSource) scmSource;
final String remote = gitSCMSource.getRemote();
if (urls.contains(remote)) {
return true;
}
}
}
}
}
return false;
}

private GitChangeSet getChangeSet(GitSCM scm, FilePath workspace, Revision lastBuiltRevision, TaskListener listener) throws IOException, InterruptedException {
Git gitBuilder = Git.with(listener, new EnvVars())
.in(workspace);
Expand Down
Loading

0 comments on commit 9a6c4f2

Please sign in to comment.