diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index c3a5cba..85d6c71 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java: [11,17,21] + java: [17,21] steps: - uses: actions/checkout@v4 - name: Set up JDK ${{ matrix.java }} @@ -53,7 +53,7 @@ jobs: SONAR_TOKEN: ${{ secrets.SONARCLOUD_TOKEN }} SONAR_ORGANIZATION: ${{ secrets.SONARCLOUD_ORGANIZATION }} - uses: actions/upload-artifact@v4 - if: matrix.java == '11' && success() + if: matrix.java == '17' && success() with: path: target/dependency-track.hpi name: dependency-track.hpi diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3829b25..09f56b9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,7 +23,7 @@ jobs: - name: Set up JDK uses: actions/setup-java@v4 with: - java-version: 11 + java-version: 17 distribution: 'zulu' cache: 'maven' server-id: 'maven.jenkins-ci.org' diff --git a/CHANGELOG.md b/CHANGELOG.md index 97d9c28..7300336 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased ### ⚠ Breaking +- require Jenkins 2.479.1 or newer +- require Java 17 or newer (required since Jenkins 2.479.1) + ### ⭐ New Features ### 🐞 Bugs Fixed diff --git a/Jenkinsfile b/Jenkinsfile index d3e6b65..98f5eb0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,4 @@ #!/usr/bin/env groovy /* `buildPlugin` step provided by: https://github.com/jenkins-infra/pipeline-library */ -buildPlugin(jdkVersions: [11], platforms:['linux']) +buildPlugin(jdkVersions: [17], platforms:['linux']) diff --git a/pom.xml b/pom.xml index c61e904..4d59c01 100644 --- a/pom.xml +++ b/pom.xml @@ -6,14 +6,14 @@ org.jenkins-ci.plugins plugin - 4.88 + 5.3 dependency-track OWASP Dependency-Track Plugin - 5.1.1-SNAPSHOT + 6.0.0-SNAPSHOT hpi 2018 @@ -37,9 +37,9 @@ - 2.440.1 + 2.479.1 3.0.0 - 1836.vccda_4a_122a_a_e + 1850.va_a_8c31d3158b_ 1.15.3 UTF-8 UTF-8 @@ -85,7 +85,7 @@ initialize - v20.13.1 + v22.11.0 https://repo.jenkins-ci.org/nodejs-dist/ https://repo.jenkins-ci.org/api/npm/npm/ ${project.build.directory} @@ -476,7 +476,7 @@ org.jenkins-ci.plugins credentials - 1378.v81ef4269d764 + 1389.vd7a_b_f5fa_50a_2 org.jenkins-ci.plugins @@ -486,12 +486,12 @@ io.jenkins.plugins okhttp-api - 4.11.0-172.vda_da_1feeb_c6e + 4.11.0-181.v1de5b_83857df org.springframework.retry spring-retry - 1.3.4 + 2.0.0 io.jenkins diff --git a/src/main/java/org/jenkinsci/plugins/DependencyTrack/ApiClient.java b/src/main/java/org/jenkinsci/plugins/DependencyTrack/ApiClient.java index 6f96484..ba0c18d 100644 --- a/src/main/java/org/jenkinsci/plugins/DependencyTrack/ApiClient.java +++ b/src/main/java/org/jenkinsci/plugins/DependencyTrack/ApiClient.java @@ -28,7 +28,6 @@ import java.util.Base64; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import okhttp3.MediaType; @@ -204,7 +203,7 @@ private List getProjectsPaged(final int page) throws ApiClientException return JSONArray.fromObject(response.body().string()).stream() .map(JSONObject.class::cast) .map(ProjectParser::parse) - .collect(Collectors.toList()); + .toList(); } return List.of(); } catch (IOException e) { @@ -355,7 +354,7 @@ public void updateProjectProperties(@NonNull final String projectUuid, @NonNull final var updates = new JSONObject(); final var tags = properties.getTags().stream() .map(tag -> Map.of("name", tag)) - .collect(Collectors.toList()); + .toList(); // overwrite tags if needed if (!tags.isEmpty()) { updates.element("tags", tags); diff --git a/src/main/java/org/jenkinsci/plugins/DependencyTrack/DependencyTrackPublisher.java b/src/main/java/org/jenkinsci/plugins/DependencyTrack/DependencyTrackPublisher.java index c23bd14..15879b8 100644 --- a/src/main/java/org/jenkinsci/plugins/DependencyTrack/DependencyTrackPublisher.java +++ b/src/main/java/org/jenkinsci/plugins/DependencyTrack/DependencyTrackPublisher.java @@ -343,11 +343,11 @@ public void perform(@NonNull final Run run, @NonNull final FilePath worksp if (synchronous && StringUtils.isNotBlank(uploadResult.getToken())) { final var resultActions = publishAnalysisResult(logger, apiClient, uploadResult.getToken(), run, effectiveProjectName, effectiveProjectVersion); if (thresholds.hasValues()) { - final var resultAction = resultActions.get(0).map(ResultAction.class::cast).get(); + final var resultAction = resultActions.findingsAction; evaluateRiskGates(run, logger, resultAction.getSeverityDistribution(), thresholds); } - if (resultActions.get(1).isPresent()) { - final var violationsAction = resultActions.get(1).map(ViolationsRunAction.class::cast).get(); + if (resultActions.violationsAction != null) { + final var violationsAction = resultActions.violationsAction; evaluateViolations(run, logger, violationsAction.getViolations()); } } @@ -356,7 +356,7 @@ public void perform(@NonNull final Run run, @NonNull final FilePath worksp } } - private List> publishAnalysisResult(final ConsoleLogger logger, final ApiClient apiClient, final String token, final Run build, final String effectiveProjectName, final String effectiveProjectVersion) throws InterruptedException, ApiClientException, AbortException { + private PublishAnalysisResult publishAnalysisResult(final ConsoleLogger logger, final ApiClient apiClient, final String token, final Run build, final String effectiveProjectName, final String effectiveProjectVersion) throws InterruptedException, ApiClientException, AbortException { final long timeout = System.currentTimeMillis() + (60000L * getEffectivePollingTimeout()); final long interval = 1000L * getEffectivePollingInterval(); logger.log(Messages.Builder_Polling()); @@ -399,8 +399,7 @@ private List> publishAnalysisResult(final ConsoleLogger log linkAction.setProjectVersion(effectiveProjectVersion); build.addOrReplaceAction(linkAction); - // replace with record when using Java 17 - return List.of(Optional.of(findingsAction), Optional.ofNullable(violationsAction)); + return new PublishAnalysisResult(findingsAction, violationsAction); } private void evaluateRiskGates(final Run build, final ConsoleLogger logger, final SeverityDistribution currentDistribution, final Thresholds thresholds) throws AbortException { @@ -636,4 +635,6 @@ private String lookupProjectId(final ConsoleLogger logger, final ApiClient apiCl } return projectIdCache; } + + private static record PublishAnalysisResult(@NonNull ResultAction findingsAction, @Nullable ViolationsRunAction violationsAction) {} } diff --git a/src/main/java/org/jenkinsci/plugins/DependencyTrack/DescriptorImpl.java b/src/main/java/org/jenkinsci/plugins/DependencyTrack/DescriptorImpl.java index 7b84022..a557b9c 100644 --- a/src/main/java/org/jenkinsci/plugins/DependencyTrack/DescriptorImpl.java +++ b/src/main/java/org/jenkinsci/plugins/DependencyTrack/DescriptorImpl.java @@ -53,7 +53,7 @@ import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.QueryParameter; -import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerRequest2; import org.kohsuke.stapler.verb.POST; import static org.jenkinsci.plugins.DependencyTrack.model.Permissions.*; @@ -176,7 +176,7 @@ public ListBoxModel doFillProjectIdItems(@QueryParameter final String dependency final List options = apiClient.getProjects().stream() .map(p -> new ListBoxModel.Option(p.getName().concat(" ").concat(Optional.ofNullable(p.getVersion()).orElse(StringUtils.EMPTY)).trim(), p.getUuid())) .sorted(Comparator.comparing(o -> o.name)) - .collect(Collectors.toList()); + .toList(); projects.add(new ListBoxModel.Option(Messages.Publisher_ProjectList_Placeholder(), StringUtils.EMPTY)); projects.addAll(options); } catch (ApiClientException e) { @@ -338,15 +338,9 @@ private FormValidation checkTeamPermissions(final ApiClient apiClient, final Str } sb.append(""); switch (worst) { - case OK: - sb.insert(0, Messages.Publisher_ConnectionTest_Success(poweredBy)); - break; - case WARNING: - sb.insert(0, Messages.Publisher_ConnectionTest_Warning(poweredBy)); - break; - case ERROR: - sb.insert(0, Messages.Publisher_ConnectionTest_Error(poweredBy)); - break; + case OK -> sb.insert(0, Messages.Publisher_ConnectionTest_Success(poweredBy)); + case WARNING -> sb.insert(0, Messages.Publisher_ConnectionTest_Warning(poweredBy)); + case ERROR -> sb.insert(0, Messages.Publisher_ConnectionTest_Error(poweredBy)); } return FormValidation.respond(worst, String.format("
%s
", worst.name().toLowerCase(Locale.ENGLISH), sb)); } @@ -360,7 +354,7 @@ private FormValidation checkTeamPermissions(final ApiClient apiClient, final Str * @throws FormException an exception validating form input */ @Override - public boolean configure(final StaplerRequest req, final JSONObject formData) throws Descriptor.FormException { + public boolean configure(final StaplerRequest2 req, final JSONObject formData) throws Descriptor.FormException { req.bindJSON(this, formData); save(); return super.configure(req, formData); diff --git a/src/main/java/org/jenkinsci/plugins/DependencyTrack/FindingParser.java b/src/main/java/org/jenkinsci/plugins/DependencyTrack/FindingParser.java index b7b12c4..3684eca 100644 --- a/src/main/java/org/jenkinsci/plugins/DependencyTrack/FindingParser.java +++ b/src/main/java/org/jenkinsci/plugins/DependencyTrack/FindingParser.java @@ -19,7 +19,6 @@ import java.util.List; import java.util.Optional; import java.util.function.Predicate; -import java.util.stream.Collectors; import lombok.experimental.UtilityClass; import net.sf.json.JSONArray; import net.sf.json.JSONNull; @@ -87,7 +86,7 @@ private List parseAliases(JSONObject json, String vulnId) { .map(alias::getString) .filter(Predicate.not(vulnId::equalsIgnoreCase))) .distinct() - .collect(Collectors.toList()) + .toList() : null; } } diff --git a/src/main/java/org/jenkinsci/plugins/DependencyTrack/JobAction.java b/src/main/java/org/jenkinsci/plugins/DependencyTrack/JobAction.java index d7b8c5a..9829189 100644 --- a/src/main/java/org/jenkinsci/plugins/DependencyTrack/JobAction.java +++ b/src/main/java/org/jenkinsci/plugins/DependencyTrack/JobAction.java @@ -20,7 +20,6 @@ import java.util.Comparator; import java.util.List; import java.util.Objects; -import java.util.stream.Collectors; import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; @@ -65,7 +64,7 @@ public JSONArray getSeverityDistributionTrend() { .sorted(Comparator.naturalOrder()) .map(run -> run.getAction(ResultAction.class)).filter(Objects::nonNull) .map(ResultAction::getSeverityDistribution) - .collect(Collectors.toList()); + .toList(); return JSONArray.fromObject(severityDistributions); } diff --git a/src/main/java/org/jenkinsci/plugins/DependencyTrack/ProjectParser.java b/src/main/java/org/jenkinsci/plugins/DependencyTrack/ProjectParser.java index 2997317..697ef3d 100644 --- a/src/main/java/org/jenkinsci/plugins/DependencyTrack/ProjectParser.java +++ b/src/main/java/org/jenkinsci/plugins/DependencyTrack/ProjectParser.java @@ -17,7 +17,6 @@ import java.time.LocalDateTime; import java.util.List; -import java.util.stream.Collectors; import lombok.experimental.UtilityClass; import net.sf.json.JSONArray; import net.sf.json.JSONObject; @@ -58,6 +57,6 @@ private List parseTags(JSONArray tagArray) { return tagArray.stream() .map(o -> getKeyOrNull((JSONObject) o, "name")) .filter(StringUtils::isNotBlank) - .collect(Collectors.toList()); + .toList(); } } diff --git a/src/main/java/org/jenkinsci/plugins/DependencyTrack/ProjectProperties.java b/src/main/java/org/jenkinsci/plugins/DependencyTrack/ProjectProperties.java index 0b50582..d79bd8e 100644 --- a/src/main/java/org/jenkinsci/plugins/DependencyTrack/ProjectProperties.java +++ b/src/main/java/org/jenkinsci/plugins/DependencyTrack/ProjectProperties.java @@ -101,10 +101,10 @@ public List getTags() { @DataBoundSetter @SuppressWarnings("unchecked") public void setTags(final Object value) { - if (value instanceof String) { - setTagsIntern((String) value); - } else if (value instanceof String[]) { - setTagsIntern((String[]) value); + if (value instanceof String string) { + setTagsIntern(string); + } else if (value instanceof String[] strings) { + setTagsIntern(strings); } else if (value instanceof Collection && areAllElementsOfType((Collection) value, String.class)) { setTagsIntern((Collection) value); } else if (value == null) { @@ -169,7 +169,7 @@ private List normalizeTags(final Collection values) { .map(String::toLowerCase) .distinct() .sorted() - .collect(Collectors.toList()); + .toList(); } @Extension diff --git a/src/main/java/org/jenkinsci/plugins/DependencyTrack/ViolationParser.java b/src/main/java/org/jenkinsci/plugins/DependencyTrack/ViolationParser.java index ae7bcf5..9c6ed62 100644 --- a/src/main/java/org/jenkinsci/plugins/DependencyTrack/ViolationParser.java +++ b/src/main/java/org/jenkinsci/plugins/DependencyTrack/ViolationParser.java @@ -16,7 +16,6 @@ package org.jenkinsci.plugins.DependencyTrack; import java.util.List; -import java.util.stream.Collectors; import lombok.experimental.UtilityClass; import net.sf.json.JSONArray; import net.sf.json.JSONObject; @@ -32,7 +31,7 @@ List parse(final String jsonResponse) { return jsonArray.stream() .map(JSONObject.class::cast) .map(ViolationParser::parseViolation) - .collect(Collectors.toList()); + .toList(); } private Violation parseViolation(JSONObject json) { diff --git a/src/main/java/org/jenkinsci/plugins/DependencyTrack/ViolationsJobAction.java b/src/main/java/org/jenkinsci/plugins/DependencyTrack/ViolationsJobAction.java index 8b2c9d6..4224593 100644 --- a/src/main/java/org/jenkinsci/plugins/DependencyTrack/ViolationsJobAction.java +++ b/src/main/java/org/jenkinsci/plugins/DependencyTrack/ViolationsJobAction.java @@ -82,7 +82,7 @@ public JSONArray getViolationsTrend() { item.putIfAbsent(ViolationState.FAIL.name().toLowerCase(), 0); return item; }) - .collect(Collectors.toList()); + .toList(); return JSONArray.fromObject(distributions); } diff --git a/src/test/java/org/jenkinsci/plugins/DependencyTrack/DescriptorImplTest.java b/src/test/java/org/jenkinsci/plugins/DependencyTrack/DescriptorImplTest.java index 44bffa0..5415caf 100644 --- a/src/test/java/org/jenkinsci/plugins/DependencyTrack/DescriptorImplTest.java +++ b/src/test/java/org/jenkinsci/plugins/DependencyTrack/DescriptorImplTest.java @@ -47,7 +47,7 @@ import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.MockAuthorizationStrategy; import org.jvnet.hudson.test.junit.jupiter.WithJenkins; -import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerRequest2; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @@ -384,7 +384,7 @@ void getDependencyTrackPollingTimeoutTest() { @Test void configureTest() throws Descriptor.FormException { - StaplerRequest req = mock(StaplerRequest.class); + var req = mock(StaplerRequest2.class); JSONObject formData = new JSONObject() .element("dependencyTrackUrl", "https://foo.bar/") .element("dependencyTrackApiKey", "api-key") diff --git a/src/test/java/org/jenkinsci/plugins/DependencyTrack/ProjectPropertiesTest.java b/src/test/java/org/jenkinsci/plugins/DependencyTrack/ProjectPropertiesTest.java index 7b1704f..1cdcc5c 100644 --- a/src/test/java/org/jenkinsci/plugins/DependencyTrack/ProjectPropertiesTest.java +++ b/src/test/java/org/jenkinsci/plugins/DependencyTrack/ProjectPropertiesTest.java @@ -52,7 +52,7 @@ void testSetTags() { uut.setTags(new String[]{"tag2", "tag1"}); assertThat(uut.getTags()).containsExactly("tag1", "tag2"); - uut.setTags(Stream.of("TAG2", "tag2").collect(Collectors.toList())); + uut.setTags(Stream.of("TAG2", "tag2").toList()); assertThat(uut.getTags()).containsExactly("tag2"); uut.setTags(Stream.of("TAG2", "tag2").collect(Collectors.toSet()));