Skip to content
Open

Dev #368

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,17 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Setup Java JDK
uses: actions/setup-java@v2.3.1
uses: actions/setup-java@v4
with:
java-version: 11
distribution: 'adopt'
java-version: 17
distribution: 'temurin'

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
Expand All @@ -57,17 +57,17 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
# - name: Autobuild
# uses: github/codeql-action/autobuild@v2
# uses: github/codeql-action/autobuild@v3

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun

# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language

- name: Build with Maven
run: mvn -DskipTests=true -V -ntp install

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3
4 changes: 2 additions & 2 deletions .github/workflows/jenkins-security-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ permissions:

jobs:
security-scan:
uses: jenkins-infra/jenkins-security-scan/.github/workflows/jenkins-security-scan.yaml@v2
uses: jenkins-infra/jenkins-security-scan/.github/workflows/jenkins-security-scan.yaml@v2.2.1
with:
java-cache: 'maven' # Optionally enable use of a build dependency cache. Specify 'maven' or 'gradle' as appropriate.
# java-version: 21 # Optionally specify what version of Java to set up for the build, or remove to use a recent default.
java-version: 17 # Specify Java 17 to match the project requirements
10 changes: 7 additions & 3 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
/*
See the documentation for more options:
https://github.com/jenkins-infra/pipeline-library/
*/
buildPlugin(
forkCount: '1C', // run this number of tests in parallel for faster feedback. If the number terminates with a 'C', the value will be multiplied by the number of available CPU cores
useContainerAgent: true, // Set to `false` if you need to use Docker for containerized tests
configurations: [
[platform: 'linux', jdk: 17],
[platform: 'linux', jdk: 21],
[platform: 'windows', jdk: 17],
])

])
15 changes: 3 additions & 12 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@
<!-- https://www.jenkins.io/doc/developer/plugin-development/choosing-jenkins-baseline/ -->
<jenkins.baseline>2.440</jenkins.baseline>
<jenkins.version>${jenkins.baseline}.3</jenkins.version>
<powermock.version>2.0.0</powermock.version>
<hpi.compatibleSinceVersion>2.9.0</hpi.compatibleSinceVersion>
<jenkins.java.level>17</jenkins.java.level>
</properties>

<name>Bitbucket Push and Pull Request Plugin</name>
<description>Bitbucket plugin for Jenkins v2.138.2 or later, allowing push and pull requests</description>
<description>Bitbucket plugin for Jenkins allowing push and pull requests</description>

<licenses>
<license>
Expand Down Expand Up @@ -192,13 +191,6 @@
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>

</dependencies>

<url>https://github.com/jenkinsci/bitbucket-push-and-pull-request-plugin</url>
Expand All @@ -213,13 +205,13 @@
<repositories>
<repository>
<id>repo.jenkins-ci.org</id>
<url>https://repo.jenkins.io/public/</url>
<url>https://repo.jenkins-ci.org/public/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>repo.jenkins-ci.org</id>
<url>https://repo.jenkins.io/public/</url>
<url>https://repo.jenkins-ci.org/public/</url>
</pluginRepository>
</pluginRepositories>

Expand All @@ -243,5 +235,4 @@
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
import org.eclipse.jgit.transport.URIish;

/**
*
*
* @author cdelmonte
*
*/
Expand Down Expand Up @@ -92,7 +92,7 @@
List<URIish> remoteScmUrls = bitbucketAction.getScmUrls().stream().map(makeUrl)
.filter(Objects::nonNull).collect(Collectors.toList());

try (ACLContext ctx = ACL.as(ACL.SYSTEM)) {
try (ACLContext ctx = ACL.as2(ACL.SYSTEM2)) {
if (globalConfig.isSingleJobSet()) {
try {
Job job = (Job) Jenkins.get().getItemByFullName(globalConfig.getSingleJob());
Expand Down Expand Up @@ -159,82 +159,80 @@
return;
}

Predicate<URIish> checkSCM = (url) -> scm instanceof GitSCM && matchGitScm(scm, url);
Predicate<URIish> checkSCM = url -> scm instanceof GitSCM && matchGitScm(scm, url);

if (remotes.stream().anyMatch(checkSCM) && !scmTriggered.contains(scm)) {
scmTriggered.add(scm);

try {
jobTrigger.bitbucketTrigger.onPost(bitbucketEvent, bitbucketAction, scm, observable);
return;

} catch (Exception e) {
logger.log(Level.WARNING, "Error: {0}", e.getMessage());
}
}

logger.log(Level.FINE, "{0} SCM doesn't match remote repo {1} or it was already triggered.",
new Object[] { job.getName(), remotes.stream().map(URIish::toString).collect(Collectors.joining(", ")) });

}));
}

private static class Trigger {
public final BitBucketPPRTrigger bitbucketTrigger;
final Optional<SCMTriggerItem> scmTriggerItem;

public Trigger(BitBucketPPRTrigger bitbucketTrigger, Optional<SCMTriggerItem> item) {
this.bitbucketTrigger = bitbucketTrigger;
this.scmTriggerItem = item;
}
}

private boolean mPJobShouldNotBeTriggered(Job<?, ?> job, BitBucketPPRHookEvent bitbucketEvent,
BitBucketPPRAction bitbucketAction) {

if (job.getDisplayName() != null) {
String displayName = job.getDisplayName();
String sourceBranchName = bitbucketAction.getSourceBranch();
String targetBranchName = bitbucketAction.getTargetBranch();

logger.log(Level.FINEST,
"Bitbucket event is : {0}, Job Name : {1}, sourceBranchName: {2}, targetBranchName: {3}",
new String[] {
bitbucketEvent.getAction(), displayName, sourceBranchName,
targetBranchName });

if (PULL_REQUEST_MERGED.equalsIgnoreCase(bitbucketEvent.getAction())) {
return !displayName.equalsIgnoreCase(targetBranchName);
}

if (PULL_REQUEST_SERVER_MERGED.equalsIgnoreCase(bitbucketEvent.getAction())) {
return !displayName.equalsIgnoreCase(targetBranchName);
}

if (sourceBranchName != null) {
return !displayName.equalsIgnoreCase(sourceBranchName);
}

if (REPOSITORY_CLOUD_PUSH.equalsIgnoreCase(bitbucketEvent.getAction())
&& targetBranchName != null) {
return !displayName.equals(targetBranchName);
}

if (REPOSITORY_SERVER_PUSH.equalsIgnoreCase(bitbucketEvent.getAction())
&& targetBranchName != null) {
return !displayName.equals(targetBranchName);
}
}

return true;
}

private Optional<BitBucketPPRTrigger> getBitBucketTrigger(Job<?, ?> job) {
if (job instanceof ParameterizedJobMixIn.ParameterizedJob) {
ParameterizedJobMixIn.ParameterizedJob<?, ?> pJob =
(ParameterizedJobMixIn.ParameterizedJob<?, ?>) job;
if (job instanceof ParameterizedJobMixIn.ParameterizedJob<?, ?> pJob) {

Check warning on line 233 in src/main/java/io/jenkins/plugins/bitbucketpushandpullrequest/BitBucketPPRJobProbe.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 162-233 are not covered by tests

return pJob.getTriggers().values().stream().filter(BitBucketPPRTrigger.class::isInstance)
return pJob.getTriggers().values().stream().filter(BitBucketPPRTrigger.class::isInstance)
.findFirst().map(BitBucketPPRTrigger.class::cast);
}
return Optional.empty();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
/*******************************************************************************
* The MIT License
*
*
* Copyright (C) 2018, CloudBees, Inc.
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
Expand All @@ -26,7 +26,7 @@


public interface BitBucketPPRPollResultListener {
public void onPollSuccess(PollingResult pollingResult);
void onPollSuccess(PollingResult pollingResult);

public void onPollError(Throwable throwable);
void onPollError(Throwable throwable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,23 @@
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.logging.Logger;
import javax.annotation.CheckForNull;

import edu.umd.cs.findbugs.annotations.NonNull;
import io.jenkins.plugins.bitbucketpushandpullrequest.action.*;
import org.apache.commons.jelly.XMLOutput;
import org.eclipse.jgit.transport.URIish;
import org.jenkinsci.Symbol;
import org.jenkinsci.plugins.plaincredentials.StringCredentials;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.QueryParameter;
import com.cloudbees.plugins.credentials.CredentialsMatchers;
import com.cloudbees.plugins.credentials.common.StandardCredentials;
import com.cloudbees.plugins.credentials.common.StandardListBoxModel;
import com.cloudbees.plugins.credentials.domains.DomainRequirement;
import hudson.Extension;
import hudson.Util;
import hudson.console.AnnotatedLargeText;
Expand All @@ -54,7 +52,6 @@
import hudson.model.Job;
import hudson.model.Queue;
import hudson.model.Run;
import hudson.model.Build;
import hudson.model.queue.QueueTaskFuture;
import hudson.plugins.git.RevisionParameterAction;
import hudson.scm.PollingResult;
Expand All @@ -65,7 +62,6 @@
import hudson.util.ListBoxModel;
import hudson.util.SequentialExecutionQueue;
import io.jenkins.plugins.bitbucketpushandpullrequest.cause.BitBucketPPRTriggerCause;
import io.jenkins.plugins.bitbucketpushandpullrequest.common.BitBucketPPRUtils;
import io.jenkins.plugins.bitbucketpushandpullrequest.event.BitBucketPPREventContext;
import io.jenkins.plugins.bitbucketpushandpullrequest.event.BitBucketPPREventFactory;
import io.jenkins.plugins.bitbucketpushandpullrequest.event.BitBucketPPREventType;
Expand Down Expand Up @@ -152,213 +148,213 @@

@Override
public void onPollSuccess(PollingResult pollingResult) {
matchingFilters.stream()
matchingFilters
.forEach(
filter -> {
try {
BitBucketPPRTriggerCause cause =
filter.getCause(getLogFile(), bitbucketAction, bitbucketEvent);
if (shouldScheduleJob(filter, pollingResult, bitbucketAction)) {
scheduleJob(cause, bitbucketAction, scmTrigger, observable, filter);
}
} catch (Throwable e) {
logger.warning(
String.format(
"During the polling process an exception was thrown: %s.",
e.getMessage()));
e.printStackTrace();
}
});
}

@Override
public void onPollError(Throwable e) {
logger.warning(String.format("Called onPollError: %s.", e.getMessage()));
e.printStackTrace();
}
});

try {
getDescriptor().queue.execute(bitbucketPollingRunnable);
} catch (Throwable e) {
logger.warning(
String.format(
"Error: cannot add the BB PPR polling runnable to the Jenkins' SequentialExecutionQueue queue: %s",
e.getMessage()));
e.printStackTrace();
}

} else {
logger.warning("Triggers are not configured.");
}
}

private void checkLocalPropagationUrl(BitBucketPPRAction bitBucketPPRAction) {

if (bitBucketPPRAction == null) {
return;
}

if (!isEmpty(propagationUrl)) {
BitBucketPPRActionAbstract bitBucketPPRActionAbstract =
(BitBucketPPRActionAbstract) bitBucketPPRAction;
bitBucketPPRActionAbstract.setPropagationUrl(propagationUrl);
}
}

private boolean shouldScheduleJob(
BitBucketPPRTriggerFilter filter,
PollingResult pollingResult,
BitBucketPPRAction bitbucketAction) {
logger.finest(
String.format(
"Should schedule job: %s and (polling result has changes: %s or trigger also if there aren't changes: %s)",
filter.shouldScheduleJob(bitbucketAction),
pollingResult.hasChanges(),
filter.shouldTriggerAlsoIfNothingChanged()));

return filter.shouldScheduleJob(bitbucketAction)
&& (pollingResult.hasChanges() || filter.shouldTriggerAlsoIfNothingChanged());
}

private void scheduleJob(
BitBucketPPRTriggerCause cause,
BitBucketPPRAction bitbucketAction,
SCM scmTrigger,
BitBucketPPRObservable observable,
BitBucketPPRTriggerFilter filter)
throws URISyntaxException {

// Jenkins will take all instances of QueueAction from this job and will try to compare these
// instances
// to all instances of QueueAction from all other pending jobs
// while calling scheduleBuild2 (see hudson.model.Queue.scheduleInternal)
// So we need RevisionParameterAction to distinguish THIS job from all other pending jobs in
// queue

Queue.Item item =
ParameterizedJobMixIn.scheduleBuild2(
job,
5,
new CauseAction(cause),
bitbucketAction,
new RevisionParameterAction(
bitbucketAction.getLatestCommit(),
new URIish(bitbucketAction.getScmUrls().get(0))));

logger.info(String.format("Commit passed to git: %s", bitbucketAction.getLatestCommit()));

QueueTaskFuture<? extends Run<?, ?>> f =
item != null ? (QueueTaskFuture) item.getFuture() : null;

if (f == null) return;

try {
Run<?, ?> startedBuild = (Run<?, ?>) f.waitForStart();
Run<?, ?> startedBuild = f.waitForStart();

logger.info(String.format("Triggering %s # %d", job.getName(), startedBuild.getNumber()));

observable.notifyObservers(
BitBucketPPREventFactory.createEvent(
BitBucketPPREventType.BUILD_STARTED,
new BitBucketPPREventContext(
this, bitbucketAction, scmTrigger, startedBuild, filter)));

Run<?, ?> run = (Run<?, ?>) f.get();
Run<?, ?> run = f.get();

if (f.isDone()) {
observable.notifyObservers(
BitBucketPPREventFactory.createEvent(
BitBucketPPREventType.BUILD_FINISHED,
new BitBucketPPREventContext(this, bitbucketAction, scmTrigger, run, filter)));
}

} catch (InterruptedException | ExecutionException e) {
logger.warning(e.getMessage());
e.printStackTrace();
} catch (Throwable e) {
e.printStackTrace();
}
}

File getLogFile() {
if (job == null) return null;
return new File(job.getRootDir(), BITBUCKET_POLLING_LOG);
}

@Override
public Collection<? extends hudson.model.Action> getProjectActions() {
return Collections.singleton(new BitBucketPPRWebHookPollingAction());
}

@Override
public DescriptorImpl getDescriptor() {
return (DescriptorImpl) super.getDescriptor();
}

public List<BitBucketPPRTriggerFilter> getTriggers() {
return triggers;
}

/** Action object for {@link BitBucketPPRProject}. Used to display the polling log. */
public class BitBucketPPRWebHookPollingAction implements hudson.model.Action {
public Job<?, ?> getOwner() {
return job;
}

@Override
public String getIconFileName() {
return "clipboard.png";
}

@Override
public String getDisplayName() {
return "BitBucket Push and Pull Request Hook Log";
}

@Override
public String getUrlName() {
return "BitBucketPPRPollLog";
}

public String getLog() throws Exception {
return Util.loadFile(getLogFile(), StandardCharsets.UTF_8);
}

/** Writes the annotated log to the given output. */
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
value = "RV_RETURN_VALUE_IGNORED",
justification = "I know what I'm doing")
public void writeLogTo(XMLOutput out) throws Exception {
new AnnotatedLargeText<BitBucketPPRWebHookPollingAction>(
getLogFile(), Charset.defaultCharset(), true, this)
new AnnotatedLargeText<>(
getLogFile(), Charset.defaultCharset(), true, this)
.writeHtmlTo(0, out.asWriter());
}
}

@Symbol("bitBucketTrigger")
@Extension
public static class DescriptorImpl extends TriggerDescriptor {
private final SequentialExecutionQueue queue =
new SequentialExecutionQueue(Jenkins.MasterComputer.threadPoolForRemoting);

public ListBoxModel doFillCredentialsIdItems(
@AncestorInPath Item context,
@QueryParameter String remote,
@QueryParameter String credentialsId) {

if (context == null && !Jenkins.get().hasPermission(Jenkins.ADMINISTER)
|| context != null && !context.hasPermission(Item.EXTENDED_READ)) {
return new StandardListBoxModel().includeCurrentValue(credentialsId);
}

return new StandardListBoxModel()
.includeEmptyValue()
.includeMatchingAs(
ACL.SYSTEM,
ACL.SYSTEM2,
context,
StandardCredentials.class,
Collections.<DomainRequirement>emptyList(),
Collections.emptyList(),

Check warning on line 357 in src/main/java/io/jenkins/plugins/bitbucketpushandpullrequest/BitBucketPPRTrigger.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 151-357 are not covered by tests
CredentialsMatchers.always())
.includeCurrentValue(credentialsId);
}
Expand All @@ -370,6 +366,7 @@
&& item instanceof ParameterizedJobMixIn.ParameterizedJob;
}

@NonNull
@Override
public String getDisplayName() {
return "Build with BitBucket Push and Pull Request Plugin";
Expand Down
Loading
Loading