From 8255bde2a361de32ffc72f69568e7cecd1350348 Mon Sep 17 00:00:00 2001 From: Ronny Perinke <23166289+sephiroth-j@users.noreply.github.com> Date: Thu, 28 Nov 2024 21:01:58 +0100 Subject: [PATCH] Support variables in project properties fixes JENKINS-74822 --- CHANGELOG.md | 2 ++ README.md | 2 ++ .../DependencyTrackPublisher.java | 25 ++++++++++++++++--- .../ProjectProperties/help-description.html | 1 + .../help-description_de.html | 1 + .../ProjectProperties/help-group.html | 1 + .../ProjectProperties/help-group_de.html | 1 + .../ProjectProperties/help-parentId.html | 1 + .../ProjectProperties/help-parentId_de.html | 1 + .../ProjectProperties/help-parentName.html | 1 + .../ProjectProperties/help-parentName_de.html | 1 + .../ProjectProperties/help-parentVersion.html | 1 + .../help-parentVersion_de.html | 1 + .../ProjectProperties/help-swidTagId.html | 1 + .../ProjectProperties/help-swidTagId_de.html | 1 + .../ProjectProperties/help-tags.html | 1 + .../ProjectProperties/help-tags_de.html | 1 + .../DependencyTrackPublisherTest.java | 23 ++++++++++++++--- 18 files changed, 58 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97d9c28b..7a4bf880 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ## Unreleased ### ⚠ Breaking ### ⭐ New Features +- Support variables in project properties ([JENKINS-74822](https://issues.jenkins.io/browse/JENKINS-74822)) + ### 🐞 Bugs Fixed ## v5.1.0 - 2024-09-20 diff --git a/README.md b/README.md index f6f411c8..f0daf925 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,8 @@ Once configured with a valid URL and API key, simply configure a job to publish - description - ID of parent project (for Dependency-Track v4.7 and newer) + The use of environment variables in the form `${VARIABLE}` is supported here. + **Override global settings**: Allows to override global settings for "Auto Create Projects", "Dependency-Track URL", "Dependency-Track Frontend URL", "API key", "Polling Interval" and the various timeouts. ### Thresholds diff --git a/src/main/java/org/jenkinsci/plugins/DependencyTrack/DependencyTrackPublisher.java b/src/main/java/org/jenkinsci/plugins/DependencyTrack/DependencyTrackPublisher.java index c23bd14d..043edac2 100644 --- a/src/main/java/org/jenkinsci/plugins/DependencyTrack/DependencyTrackPublisher.java +++ b/src/main/java/org/jenkinsci/plugins/DependencyTrack/DependencyTrackPublisher.java @@ -32,6 +32,7 @@ import hudson.tasks.Recorder; import hudson.util.Secret; import java.util.Optional; +import java.util.stream.Collectors; import jenkins.model.RunAction2; import jenkins.tasks.SimpleBuildStep; import lombok.AccessLevel; @@ -320,10 +321,11 @@ public void perform(@NonNull final Run run, @NonNull final FilePath worksp final String effectiveUrl = getEffectiveUrl(); final String effectiveApiKey = getEffectiveApiKey(run); + final ProjectProperties effectiveProjectProperties = expandProjectProperties(env); logger.log(Messages.Builder_Publishing(effectiveUrl, effectiveArtifact)); final ApiClient apiClient = clientFactory.create(effectiveUrl, effectiveApiKey, logger, getEffectiveConnectionTimeout(), getEffectiveReadTimeout()); final UploadResult uploadResult = apiClient.upload(projectId, effectiveProjectName, effectiveProjectVersion, - artifactFilePath, effectiveAutocreate, projectProperties); + artifactFilePath, effectiveAutocreate, effectiveProjectProperties); if (!uploadResult.isSuccess()) { throw new AbortException(Messages.Builder_Upload_Failed()); @@ -337,7 +339,7 @@ public void perform(@NonNull final Run run, @NonNull final FilePath worksp logger.log(Messages.Builder_Success(String.format("%s/projects/%s", getEffectiveFrontendUrl(), StringUtils.isNotBlank(projectId) ? projectId : StringUtils.EMPTY))); - updateProjectProperties(logger, apiClient, effectiveProjectName, effectiveProjectVersion); + updateProjectProperties(logger, apiClient, effectiveProjectName, effectiveProjectVersion, effectiveProjectProperties); final var thresholds = getThresholds(); if (synchronous && StringUtils.isNotBlank(uploadResult.getToken())) { @@ -609,7 +611,7 @@ private Thresholds getThresholds() { return thresholds; } - private void updateProjectProperties(final ConsoleLogger logger, final ApiClient apiClient, final String effectiveProjectName, final String effectiveProjectVersion) throws ApiClientException { + private void updateProjectProperties(final ConsoleLogger logger, final ApiClient apiClient, final String effectiveProjectName, final String effectiveProjectVersion, final ProjectProperties effectiveProjectProperties) throws ApiClientException { // check whether there are settings other than those of the parent project. // the parent project is set during upload. boolean doUpdateProject = projectProperties != null && ( // noformat @@ -621,7 +623,7 @@ private void updateProjectProperties(final ConsoleLogger logger, final ApiClient if (doUpdateProject) { logger.log(Messages.Builder_Project_Update()); final String id = lookupProjectId(logger, apiClient, effectiveProjectName, effectiveProjectVersion); - apiClient.updateProjectProperties(id, projectProperties); + apiClient.updateProjectProperties(id, effectiveProjectProperties); } } @@ -636,4 +638,19 @@ private String lookupProjectId(final ConsoleLogger logger, final ApiClient apiCl } return projectIdCache; } + + private ProjectProperties expandProjectProperties(final EnvVars env) { + if (projectProperties != null) { + final var expandedProperties = new ProjectProperties(); + Optional.ofNullable(projectProperties.getDescription()).map(env::expand).ifPresent(expandedProperties::setDescription); + Optional.ofNullable(projectProperties.getGroup()).map(env::expand).ifPresent(expandedProperties::setGroup); + Optional.ofNullable(projectProperties.getParentId()).map(env::expand).ifPresent(expandedProperties::setParentId); + Optional.ofNullable(projectProperties.getParentName()).map(env::expand).ifPresent(expandedProperties::setParentName); + Optional.ofNullable(projectProperties.getParentVersion()).map(env::expand).ifPresent(expandedProperties::setParentVersion); + Optional.ofNullable(projectProperties.getSwidTagId()).map(env::expand).ifPresent(expandedProperties::setSwidTagId); + expandedProperties.setTags(projectProperties.getTags().stream().map(env::expand).collect(Collectors.toList())); + return expandedProperties; + } + return null; + } } diff --git a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-description.html b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-description.html index e89bacb5..b1d6e67c 100644 --- a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-description.html +++ b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-description.html @@ -1,3 +1,4 @@
The description to be set for the project. +

The value can contain environment variables in the form of ${VARIABLE_NAME} which are resolved.

diff --git a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-description_de.html b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-description_de.html index efd0c88e..918a51af 100644 --- a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-description_de.html +++ b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-description_de.html @@ -1,3 +1,4 @@
Die Beschreibung, die für das Projekt gesetzt werden soll. +

Der Wert kann Umgebungsvariablen in Form von ${VARIABLE_NAME} enthalten, die aufgelöst werden.

diff --git a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-group.html b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-group.html index db03b758..3f25c014 100644 --- a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-group.html +++ b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-group.html @@ -1,3 +1,4 @@
Specifies the value of "Namespace / Group / Vendor" to be set for the project. +

The value can contain environment variables in the form of ${VARIABLE_NAME} which are resolved.

diff --git a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-group_de.html b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-group_de.html index dde5b454..6db920c8 100644 --- a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-group_de.html +++ b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-group_de.html @@ -1,3 +1,4 @@
Wert für "Namensraum / Gruppe / Hersteller", der für das Projekt gesetzt werden soll. +

Der Wert kann Umgebungsvariablen in Form von ${VARIABLE_NAME} enthalten, die aufgelöst werden.

diff --git a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentId.html b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentId.html index 10f6cab2..d5267bcb 100644 --- a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentId.html +++ b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentId.html @@ -1,3 +1,4 @@
The ID (UUID) of the parent project. +

The value can contain environment variables in the form of ${VARIABLE_NAME} which are resolved.

diff --git a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentId_de.html b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentId_de.html index f23996e7..36d24d38 100644 --- a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentId_de.html +++ b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentId_de.html @@ -1,3 +1,4 @@
Die ID (UUID) des übergeordneten Projekts. +

Der Wert kann Umgebungsvariablen in Form von ${VARIABLE_NAME} enthalten, die aufgelöst werden.

diff --git a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentName.html b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentName.html index b1e95159..b3bb46bf 100644 --- a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentName.html +++ b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentName.html @@ -1,3 +1,4 @@
The name of the parent project. +

The value can contain environment variables in the form of ${VARIABLE_NAME} which are resolved.

diff --git a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentName_de.html b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentName_de.html index 3425a878..f35458e6 100644 --- a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentName_de.html +++ b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentName_de.html @@ -1,3 +1,4 @@
Der Name des übergeordneten Projekts. +

Der Wert kann Umgebungsvariablen in Form von ${VARIABLE_NAME} enthalten, die aufgelöst werden.

diff --git a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentVersion.html b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentVersion.html index d3a732b1..29b14070 100644 --- a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentVersion.html +++ b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentVersion.html @@ -1,3 +1,4 @@
The version of the parent project. +

The value can contain environment variables in the form of ${VARIABLE_NAME} which are resolved.

diff --git a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentVersion_de.html b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentVersion_de.html index a7240e60..c9f7ca3f 100644 --- a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentVersion_de.html +++ b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-parentVersion_de.html @@ -1,3 +1,4 @@
Die Version des übergeordneten Projekts. +

Der Wert kann Umgebungsvariablen in Form von ${VARIABLE_NAME} enthalten, die aufgelöst werden.

diff --git a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-swidTagId.html b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-swidTagId.html index f49ab9f2..5a3315e8 100644 --- a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-swidTagId.html +++ b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-swidTagId.html @@ -1,3 +1,4 @@
Specifies the SWID Tag ID to be set for the project. +

The value can contain environment variables in the form of ${VARIABLE_NAME} which are resolved.

diff --git a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-swidTagId_de.html b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-swidTagId_de.html index 5be64b82..baef5bb8 100644 --- a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-swidTagId_de.html +++ b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-swidTagId_de.html @@ -1,3 +1,4 @@
Wert für "SWID Tag ID", der für das Projekt gesetzt werden soll. +

Der Wert kann Umgebungsvariablen in Form von ${VARIABLE_NAME} enthalten, die aufgelöst werden.

diff --git a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-tags.html b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-tags.html index 6f1090bd..05143cd1 100644 --- a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-tags.html +++ b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-tags.html @@ -1,4 +1,5 @@
Specifies the list of tags to be set for the project. Separate multiple tags with spaces or put each tag on a separate line.

All tags are automatically lowercased!

+

The tag-value can contain environment variables in the form of ${VARIABLE_NAME} which are resolved.

diff --git a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-tags_de.html b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-tags_de.html index cb6d430e..a5c79995 100644 --- a/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-tags_de.html +++ b/src/main/resources/org/jenkinsci/plugins/DependencyTrack/ProjectProperties/help-tags_de.html @@ -1,4 +1,5 @@
Gibt die Liste der Tags an, die für das Projekt gesetzt werden sollen. Trennen Sie mehrere Tags durch Leerzeichen oder eine eigene Zeile.

Alle Tags werden automatisch kleingeschrieben!

+

Der Tag-Wert kann Umgebungsvariablen in Form von ${VARIABLE_NAME} enthalten, die aufgelöst werden.

diff --git a/src/test/java/org/jenkinsci/plugins/DependencyTrack/DependencyTrackPublisherTest.java b/src/test/java/org/jenkinsci/plugins/DependencyTrack/DependencyTrackPublisherTest.java index 4e81fd52..78c4cff7 100644 --- a/src/test/java/org/jenkinsci/plugins/DependencyTrack/DependencyTrackPublisherTest.java +++ b/src/test/java/org/jenkinsci/plugins/DependencyTrack/DependencyTrackPublisherTest.java @@ -49,6 +49,7 @@ import org.junit.jupiter.api.io.TempDir; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.junit.jupiter.WithJenkins; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; @@ -173,7 +174,7 @@ void testPerformAsync(@TempDir Path tmpWork) throws IOException { uut.setProjectProperties(props); uut.setUnstableTotalCritical(1); - when(client.upload(eq("uuid-1"), isNull(), isNull(), any(FilePath.class), eq(false), eq(props))) + when(client.upload(eq("uuid-1"), isNull(), isNull(), any(FilePath.class), eq(false), any(ProjectProperties.class))) .thenReturn(new UploadResult(true)) .thenReturn(new UploadResult(false)); @@ -314,7 +315,13 @@ void testPerformSyncWithoutProjectId(@TempDir Path tmpWork) throws IOException { tmp.createNewFile(); FilePath workDir = new FilePath(tmpWork.toFile()); final var props = new ProjectProperties(); - props.setDescription("description"); + props.setDescription("description. ${my.var}"); + props.setTags(List.of("tag1", "${my.var}")); + props.setSwidTagId("swidTagId. ${my.var}"); + props.setGroup("group. ${my.var}"); + props.setParentId("parentId. ${my.var}"); + props.setParentName("parentName. ${my.var}"); + props.setParentVersion("parentVersion. ${my.var}"); DependencyTrackPublisher uut = new DependencyTrackPublisher(tmp.getName(), true, clientFactory); uut.setProjectName("name-1"); uut.setProjectVersion("version-1"); @@ -323,7 +330,7 @@ void testPerformSyncWithoutProjectId(@TempDir Path tmpWork) throws IOException { uut.setProjectProperties(props); final var team = Team.builder().name("test-team").permissions(Set.of(VIEW_POLICY_VIOLATION.toString())).build(); - when(client.upload(isNull(), eq("name-1"), eq("version-1"), any(FilePath.class), eq(true), eq(props))).thenReturn(new UploadResult(true, "token-1")); + when(client.upload(isNull(), eq("name-1"), eq("version-1"), any(FilePath.class), eq(true), any(ProjectProperties.class))).thenReturn(new UploadResult(true, "token-1")); when(client.isTokenBeingProcessed("token-1")).thenReturn(Boolean.TRUE).thenReturn(Boolean.FALSE); when(client.getFindings("uuid-1")).thenReturn(List.of()); when(client.getTeamPermissions()).thenReturn(team); @@ -336,7 +343,15 @@ void testPerformSyncWithoutProjectId(@TempDir Path tmpWork) throws IOException { verify(client).getFindings("uuid-1"); verify(client).getTeamPermissions(); verify(client).getViolations("uuid-1"); - verify(client).updateProjectProperties("uuid-1", props); + var propsCaptor = ArgumentCaptor.forClass(ProjectProperties.class); + verify(client).updateProjectProperties(eq("uuid-1"), propsCaptor.capture()); + assertThat(propsCaptor.getValue().getDescription()).isEqualTo("description. my.value"); + assertThat(propsCaptor.getValue().getTags()).containsExactlyInAnyOrder("tag1", "my.value"); + assertThat(propsCaptor.getValue().getSwidTagId()).isEqualTo("swidTagId. my.value"); + assertThat(propsCaptor.getValue().getGroup()).isEqualTo("group. my.value"); + assertThat(propsCaptor.getValue().getParentId()).isEqualTo("parentId. my.value"); + assertThat(propsCaptor.getValue().getParentName()).isEqualTo("parentName. my.value"); + assertThat(propsCaptor.getValue().getParentVersion()).isEqualTo("parentVersion. my.value"); verify(client).lookupProject("name-1", "version-1"); }