diff --git a/docs/Home.md b/docs/Home.md index 40f98947b..afc29860a 100644 --- a/docs/Home.md +++ b/docs/Home.md @@ -32,6 +32,8 @@ scripts, including [[tests for DSL scripts|Testing DSL Scripts]] and [[IDE Suppo Browse the Jenkins issue tracker to see any [open issues](https://issues.jenkins-ci.org/issues/?filter=15140). ## Release Notes +* 1.80.0 (July 1 2022) + * Don't destroy credentials when re-creating organization folders ([GH-1251](https://github.com/jenkinsci/job-dsl-plugin/pull/1251) [JENKINS-44681](https://issues.jenkins.io/browse/JENKINS-44681)) * 1.79.0 (April 14 2022) * Allow using classes not supported by `structs` for `DescribableContext` ([GH-1202](https://github.com/jenkinsci/job-dsl-plugin/pull/1202) [JENKINS-57435](https://issues.jenkins-ci.org/browse/JENKINS-57435)) ** Note that this has the potential to be unsafe and can lead to source-controlled secrets. Please be **very cautious** when embedding secrets into source control! diff --git a/job-dsl-plugin/build.gradle b/job-dsl-plugin/build.gradle index 492fe9cd6..1da18c142 100644 --- a/job-dsl-plugin/build.gradle +++ b/job-dsl-plugin/build.gradle @@ -109,6 +109,7 @@ dependencies { compile(project(':job-dsl-core')) { exclude group: 'org.jvnet.hudson', module:'xstream' } + implementation 'org.jenkins-ci.plugins:branch-api:2.4.0' implementation 'org.jenkins-ci.plugins:cloudbees-folder:5.14' implementation 'org.jenkins-ci.plugins:structs:1.19' implementation 'org.jenkins-ci.plugins:script-security:1.54' @@ -123,5 +124,5 @@ dependencies { testImplementation 'io.jenkins:configuration-as-code:1.15:tests' testImplementation 'org.jenkins-ci.plugins:matrix-auth:1.3' testImplementation 'org.jenkins-ci.plugins:nested-view:1.14' - testImplementation 'org.jenkins-ci.plugins:credentials:2.1.10' + testImplementation 'org.jenkins-ci.plugins:credentials:2.1.11' } diff --git a/job-dsl-plugin/src/main/groovy/javaposse/jobdsl/plugin/JenkinsJobManagement.java b/job-dsl-plugin/src/main/groovy/javaposse/jobdsl/plugin/JenkinsJobManagement.java index e2eeeb716..e595b5767 100644 --- a/job-dsl-plugin/src/main/groovy/javaposse/jobdsl/plugin/JenkinsJobManagement.java +++ b/job-dsl-plugin/src/main/groovy/javaposse/jobdsl/plugin/JenkinsJobManagement.java @@ -39,6 +39,7 @@ import javaposse.jobdsl.dsl.NameNotProvidedException; import javaposse.jobdsl.dsl.UserContent; import javaposse.jobdsl.plugin.ExtensionPointHelper.DslExtension; +import jenkins.branch.OrganizationFolder; import jenkins.model.DirectlyModifiableTopLevelItemGroup; import jenkins.model.Jenkins; import jenkins.model.ModifiableTopLevelItemGroup; @@ -587,17 +588,25 @@ private void renameJob(Job from, String to) throws IOException { } private void mergeCredentials(AbstractItem item, javaposse.jobdsl.dsl.Item dslItem) { + Optional> maybeProperty = Optional.empty(); if (item instanceof Folder) { Folder folder = (Folder) item; - Optional> maybeProperty = + maybeProperty = folder.getProperties().stream() .filter(p -> p instanceof FolderCredentialsProperty) .findFirst(); - if (maybeProperty.isPresent()) { - LOGGER.log(Level.FINE, format("Merging credentials for %s", item.getName())); - DslItemConfigurer.mergeCredentials(maybeProperty.get(), dslItem); - } + } + if (item instanceof OrganizationFolder) { + OrganizationFolder folder = (OrganizationFolder) item; + maybeProperty = + folder.getProperties().stream() + .filter(p -> p instanceof FolderCredentialsProperty) + .findFirst(); + } + if (maybeProperty.isPresent()) { + LOGGER.log(Level.FINE, format("Merging credentials for %s", item.getName())); + DslItemConfigurer.mergeCredentials(maybeProperty.get(), dslItem); } } diff --git a/job-dsl-plugin/src/test/groovy/javaposse/jobdsl/plugin/JenkinsJobManagementSpec.groovy b/job-dsl-plugin/src/test/groovy/javaposse/jobdsl/plugin/JenkinsJobManagementSpec.groovy index 705c5457f..3d77fd634 100644 --- a/job-dsl-plugin/src/test/groovy/javaposse/jobdsl/plugin/JenkinsJobManagementSpec.groovy +++ b/job-dsl-plugin/src/test/groovy/javaposse/jobdsl/plugin/JenkinsJobManagementSpec.groovy @@ -1,5 +1,6 @@ package javaposse.jobdsl.plugin +import jenkins.branch.OrganizationFolder import com.cloudbees.hudson.plugins.folder.AbstractFolder import com.cloudbees.hudson.plugins.folder.AbstractFolderProperty import com.cloudbees.hudson.plugins.folder.AbstractFolderPropertyDescriptor @@ -641,7 +642,7 @@ class JenkinsJobManagementSpec extends Specification { e.message == 'Type of item "my-job" does not match existing type, item type can not be changed' } - def 'createOrUpdateConfig should preserve credentials if they exist on a folder'() { + def 'createOrUpdateConfig should preserve credentials if they exist on a Folder'() { setup: Folder folder = jenkinsRule.createProject(Folder, 'folder') folder.addProperty(createCredentialProperty()) @@ -654,7 +655,7 @@ class JenkinsJobManagementSpec extends Specification { actual.properties.size() == 1 } - def 'createOrUpdateConfig should ignore other properties on the folder'() { + def 'createOrUpdateConfig should ignore other properties on the Folder'() { setup: Folder folder = jenkinsRule.createProject(Folder, 'folder') folder.addProperty(new FakeProperty()) @@ -667,6 +668,43 @@ class JenkinsJobManagementSpec extends Specification { actual.properties.size() == 0 } + def 'createOrUpdateConfig should preserve credentials if they exist on an OrganizationFolder'() { + setup: + OrganizationFolder folder = jenkinsRule.createProject(OrganizationFolder, 'org') + // `OrganizationFolder`s include a lot of existing metadata that is appended, regardless of how few we already + // set, so we should calculate expected as the default computed properties + int defaultProperties = folder.properties.size() + + def property = createCredentialProperty() + folder.addProperty(property) + + when: + jobManagement.createOrUpdateConfig(createItem('org', '/organizationfolder.xml'), false) + + then: + def actualItem = jenkinsRule.jenkins.getItem('org') + def actual = (AbstractFolder) actualItem + actual.properties.size() == defaultProperties + 1 + } + + def 'createOrUpdateConfig should ignore other properties on the OrganizationFolder'() { + setup: + OrganizationFolder folder = jenkinsRule.createProject(OrganizationFolder, 'org') + // `OrganizationFolder`s include a lot of existing metadata that is appended, regardless of how few we already + // set, so we should calculate expected as the default computed properties + int defaultProperties = folder.properties.size() + + folder.addProperty(new FakeProperty()) + + when: + jobManagement.createOrUpdateConfig(createItem('org', '/organizationfolder.xml'), false) + folder.writeConfigDotXml(System.out) + + then: + def actual = jenkinsRule.jenkins.getItem('org') + actual.properties.size() == defaultProperties + } + def 'createOrUpdateView should work if view type changes'() { setup: jenkinsRule.jenkins.addView(new AllView('foo')) diff --git a/job-dsl-plugin/src/test/resources/organizationfolder.xml b/job-dsl-plugin/src/test/resources/organizationfolder.xml new file mode 100644 index 000000000..8105f9dcb --- /dev/null +++ b/job-dsl-plugin/src/test/resources/organizationfolder.xml @@ -0,0 +1,9 @@ + + + + + false + + + +