From 990a259b6a759e6ea670542ffbc9587c8b15addc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Dec 2025 18:40:42 +0000 Subject: [PATCH 1/4] feat: add failIfAlreadyExists flag to version creator --- .../plugins/jira/JiraVersionCreator.java | 15 +++++++++++- .../jira/JiraVersionCreatorBuilder.java | 15 +++++++++++- .../hudson/plugins/jira/VersionCreator.java | 24 +++++++++++++++---- .../jira/JiraVersionCreator/config.jelly | 3 +++ .../help-failIfAlreadyExists.html | 4 ++++ .../JiraVersionCreatorBuilder/config.jelly | 3 +++ .../help-failIfAlreadyExists.html | 4 ++++ src/main/webapp/help-version-create.html | 2 +- .../plugins/jira/VersionCreatorTest.java | 22 +++++++++++++++++ 9 files changed, 85 insertions(+), 7 deletions(-) create mode 100644 src/main/resources/hudson/plugins/jira/JiraVersionCreator/help-failIfAlreadyExists.html create mode 100644 src/main/resources/hudson/plugins/jira/JiraVersionCreatorBuilder/help-failIfAlreadyExists.html diff --git a/src/main/java/hudson/plugins/jira/JiraVersionCreator.java b/src/main/java/hudson/plugins/jira/JiraVersionCreator.java index 7b8ffc7eb..e893ccf31 100644 --- a/src/main/java/hudson/plugins/jira/JiraVersionCreator.java +++ b/src/main/java/hudson/plugins/jira/JiraVersionCreator.java @@ -11,6 +11,7 @@ import hudson.tasks.Publisher; import net.sf.json.JSONObject; import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.StaplerRequest2; /** @@ -24,6 +25,7 @@ public class JiraVersionCreator extends Notifier { private String jiraVersion; private String jiraProjectKey; + private boolean failIfAlreadyExists = true; @DataBoundConstructor public JiraVersionCreator(String jiraVersion, String jiraProjectKey) { @@ -52,9 +54,20 @@ public void setJiraProjectKey(String jiraProjectKey) { this.jiraProjectKey = jiraProjectKey; } + public boolean isFailIfAlreadyExists() { + return failIfAlreadyExists; + } + + @DataBoundSetter + public void setFailIfAlreadyExists(boolean failIfAlreadyExists) { + this.failIfAlreadyExists = failIfAlreadyExists; + } + @Override public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) { - return new VersionCreator().perform(build.getProject(), jiraVersion, jiraProjectKey, build, listener); + VersionCreator versionCreator = new VersionCreator(); + versionCreator.setFailIfAlreadyExists(failIfAlreadyExists); + return versionCreator.perform(build.getProject(), jiraVersion, jiraProjectKey, build, listener); } @Override diff --git a/src/main/java/hudson/plugins/jira/JiraVersionCreatorBuilder.java b/src/main/java/hudson/plugins/jira/JiraVersionCreatorBuilder.java index c88a797cd..1714e5349 100644 --- a/src/main/java/hudson/plugins/jira/JiraVersionCreatorBuilder.java +++ b/src/main/java/hudson/plugins/jira/JiraVersionCreatorBuilder.java @@ -12,6 +12,7 @@ import net.sf.json.JSONObject; import org.jenkinsci.Symbol; import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.StaplerRequest2; /** @@ -25,6 +26,7 @@ public class JiraVersionCreatorBuilder extends Builder implements SimpleBuildSte private String jiraVersion; private String jiraProjectKey; + private boolean failIfAlreadyExists = true; @DataBoundConstructor public JiraVersionCreatorBuilder(String jiraVersion, String jiraProjectKey) { @@ -53,9 +55,20 @@ public void setJiraProjectKey(String jiraProjectKey) { this.jiraProjectKey = jiraProjectKey; } + public boolean isFailIfAlreadyExists() { + return failIfAlreadyExists; + } + + @DataBoundSetter + public void setFailIfAlreadyExists(boolean failIfAlreadyExists) { + this.failIfAlreadyExists = failIfAlreadyExists; + } + @Override public void perform(Run run, EnvVars env, TaskListener listener) { - new VersionCreator().perform(run.getParent(), jiraVersion, jiraProjectKey, run, listener); + VersionCreator versionCreator = new VersionCreator(); + versionCreator.setFailIfAlreadyExists(failIfAlreadyExists); + versionCreator.perform(run.getParent(), jiraVersion, jiraProjectKey, run, listener); } @Override diff --git a/src/main/java/hudson/plugins/jira/VersionCreator.java b/src/main/java/hudson/plugins/jira/VersionCreator.java index d35ec6ae2..8fea85fd0 100644 --- a/src/main/java/hudson/plugins/jira/VersionCreator.java +++ b/src/main/java/hudson/plugins/jira/VersionCreator.java @@ -12,6 +12,7 @@ import java.util.List; import java.util.Optional; import java.util.logging.Logger; +import org.kohsuke.stapler.DataBoundSetter; /** * Performs an action which creates new Jira version. @@ -20,6 +21,17 @@ class VersionCreator { private static final Logger LOGGER = Logger.getLogger(VersionCreator.class.getName()); + private boolean failIfAlreadyExists = true; + + @DataBoundSetter + public void setFailIfAlreadyExists(boolean failIfAlreadyExists) { + this.failIfAlreadyExists = failIfAlreadyExists; + } + + public boolean isFailIfAlreadyExists() { + return failIfAlreadyExists; + } + protected boolean perform( Job project, String jiraVersion, String jiraProjectKey, Run build, TaskListener listener) { String realVersion = null; @@ -42,13 +54,17 @@ protected boolean perform( List existingVersions = Optional.ofNullable(session.getVersions(realProjectKey)).orElse(Collections.emptyList()); - // past logic to fail the build if the version already exists + // check if version already exists if (existingVersions.stream().anyMatch(v -> v.getName().equals(finalRealVersion))) { listener.getLogger().println(Messages.JiraVersionCreator_VersionExists(realVersion, realProjectKey)); - if (listener instanceof BuildListener) { - ((BuildListener) listener).finished(Result.FAILURE); + if (failIfAlreadyExists) { + if (listener instanceof BuildListener) { + ((BuildListener) listener).finished(Result.FAILURE); + } + return false; } - return false; + // version exists but we don't fail the build + return true; } listener.getLogger().println(Messages.JiraVersionCreator_CreatingVersion(realVersion, realProjectKey)); diff --git a/src/main/resources/hudson/plugins/jira/JiraVersionCreator/config.jelly b/src/main/resources/hudson/plugins/jira/JiraVersionCreator/config.jelly index 6cff006ec..c35f0ccc0 100644 --- a/src/main/resources/hudson/plugins/jira/JiraVersionCreator/config.jelly +++ b/src/main/resources/hudson/plugins/jira/JiraVersionCreator/config.jelly @@ -6,4 +6,7 @@ + + + \ No newline at end of file diff --git a/src/main/resources/hudson/plugins/jira/JiraVersionCreator/help-failIfAlreadyExists.html b/src/main/resources/hudson/plugins/jira/JiraVersionCreator/help-failIfAlreadyExists.html new file mode 100644 index 000000000..1b85e84c8 --- /dev/null +++ b/src/main/resources/hudson/plugins/jira/JiraVersionCreator/help-failIfAlreadyExists.html @@ -0,0 +1,4 @@ +
+ When checked (default), the build will fail if the version already exists in Jira. + When unchecked, the build will continue successfully even if the version already exists. +
\ No newline at end of file diff --git a/src/main/resources/hudson/plugins/jira/JiraVersionCreatorBuilder/config.jelly b/src/main/resources/hudson/plugins/jira/JiraVersionCreatorBuilder/config.jelly index 6cff006ec..c35f0ccc0 100644 --- a/src/main/resources/hudson/plugins/jira/JiraVersionCreatorBuilder/config.jelly +++ b/src/main/resources/hudson/plugins/jira/JiraVersionCreatorBuilder/config.jelly @@ -6,4 +6,7 @@ + + + \ No newline at end of file diff --git a/src/main/resources/hudson/plugins/jira/JiraVersionCreatorBuilder/help-failIfAlreadyExists.html b/src/main/resources/hudson/plugins/jira/JiraVersionCreatorBuilder/help-failIfAlreadyExists.html new file mode 100644 index 000000000..1b85e84c8 --- /dev/null +++ b/src/main/resources/hudson/plugins/jira/JiraVersionCreatorBuilder/help-failIfAlreadyExists.html @@ -0,0 +1,4 @@ +
+ When checked (default), the build will fail if the version already exists in Jira. + When unchecked, the build will continue successfully even if the version already exists. +
\ No newline at end of file diff --git a/src/main/webapp/help-version-create.html b/src/main/webapp/help-version-create.html index f38b8a54e..2b8de2e14 100644 --- a/src/main/webapp/help-version-create.html +++ b/src/main/webapp/help-version-create.html @@ -1,3 +1,3 @@
- Creates a new version in Jira in the project with the given key. If the version already exists, the build will fail. + Creates a new version in Jira in the project with the given key. By default, if the version already exists, the build will fail. This behavior can be changed by unchecking the "Fail if version already exists" option.
diff --git a/src/test/java/hudson/plugins/jira/VersionCreatorTest.java b/src/test/java/hudson/plugins/jira/VersionCreatorTest.java index 4f237acfb..b897ad5dd 100644 --- a/src/test/java/hudson/plugins/jira/VersionCreatorTest.java +++ b/src/test/java/hudson/plugins/jira/VersionCreatorTest.java @@ -147,4 +147,26 @@ void buildDidNotFailWhenVersionExists() throws IOException, InterruptedException versionCreator.perform(project, JIRA_VER_PARAM, JIRA_PRJ_PARAM, build, listener); verify(session, times(0)).addVersion(any(), any()); } + + @Test + void buildDoesNotFailWhenVersionExistsAndFailIfAlreadyExistsIsFalse() + throws IOException, InterruptedException, RestClientException { + when(build.getEnvironment(listener)).thenReturn(env); + when(site.getSession(any())).thenReturn(session); + when(session.getVersions(JIRA_PRJ)).thenReturn(Arrays.asList(existingVersion)); + + // Set failIfAlreadyExists to false + versionCreator.setFailIfAlreadyExists(false); + + boolean result = versionCreator.perform(project, JIRA_VER, JIRA_PRJ, build, listener); + + // Verify that addVersion is not called (because version already exists) + verify(session, times(0)).addVersion(any(), any()); + // Verify the message is logged + verify(logger, times(1)).println(Messages.JiraVersionCreator_VersionExists(JIRA_VER, JIRA_PRJ)); + // Verify build is NOT failed + verify(listener, times(0)).finished(Result.FAILURE); + // Verify the perform method returns true + assertThat(result, is(true)); + } } From 6862d342362ff20e8d3a206b441e0880920f6a39 Mon Sep 17 00:00:00 2001 From: Radek Antoniuk Date: Wed, 17 Dec 2025 01:30:48 +0100 Subject: [PATCH 2/4] handle null from XStream readResolve and refactor to fluent interface --- CONTRIBUTING.md | 8 +-- README.md | 11 ++-- .../plugins/jira/JiraVersionCreator.java | 20 +++++-- .../jira/JiraVersionCreatorBuilder.java | 14 ++++- .../hudson/plugins/jira/VersionCreator.java | 33 +++++++----- .../plugins/jira/VersionCreatorTest.java | 54 +++++++++++-------- 6 files changed, 88 insertions(+), 52 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 13e79499e..d46ce3932 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,6 +4,7 @@ General rules: - check the [general Jenkins development guide](https://www.jenkins.io/doc/developer/book/) - make sure to provide tests +- when adding new fields, make sure to [include backward-compatibility](https://www.jenkins.io/doc/developer/persistence/backward-compatibility/) and tests for that - mark the Pull Request as _draft_ initially, to make sure all the checks pass correctly, then convert it to non-draft. ## Setting up your environment @@ -22,15 +23,14 @@ brew install pre-commit && pre-commit install --install-hooks Use [docker-compose](./docker-compose.yml) to run a local Jenkins instance with the plugin installed. The configuration includes local volumes for both: Jenkins and ssh-agent, so you can easily test the plugin in a clean environment. -```bash ### Atlassian sources import -To resolve some binary compatibility issues [JENKINS-48357](https://issues.jenkins-ci.org/browse/JENKINS-48357), +To resolve [some binary compatibility issues](https://github.com/jenkinsci/jira-plugin/pull/140), the sources from the artifact [com.atlassian.httpclient:atlassian-httpclient-plugin:0.23](https://packages.atlassian.com/maven-external/com/atlassian/httpclient/atlassian-httpclient-plugin/0.23.0/) has been imported in the project to have control over http(s) protocol transport layer. The downloaded sources didn't have any license headers but based on the [pom](https://packages.atlassian.com/maven-external/com/atlassian/httpclient/atlassian-httpclient-plugin/0.23.0/atlassian-httpclient-plugin-0.23.0.pom) -sources are Apache License (see pom in src/main/resources/atlassian-httpclient-plugin-0.23.0.pom) +sources are Apache License (see pom in src/main/resources/atlassian-httpclient-plugin-0.23.0.pom) ### Testing @@ -38,4 +38,4 @@ There is a [Jira Cloud](https://jenkins-jira-plugin.atlassian.net/) test instanc ### Releasing the plugin -Make sure you have your `~/.m2/settings.xml` configured accordingly - refer to [releasing Jenkins plugins](https://www.jenkins.io/doc/developer/publishing/releasing/). +See [releasing Jenkins plugins](https://www.jenkins.io/doc/developer/publishing/releasing-manually/). diff --git a/README.md b/README.md index 878118007..5aaadaa82 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,9 @@ [![Jenkins CI](https://ci.jenkins.io/buildStatus/icon?job=Plugins/jira-plugin/master)](https://ci.jenkins.io/job/Plugins/job/jira-plugin/) [![Contributors](https://img.shields.io/github/contributors/jenkinsci/jira-plugin.svg)](https://github.com/jenkinsci/jira-plugin/graphs/contributors) -See user documentation at [https://jenkinsci.github.io/jira-plugin/](https://jenkinsci.github.io/jira-plugin/) +1. See user documentation at [https://jenkinsci.github.io/jira-plugin/](https://jenkinsci.github.io/jira-plugin/). +1. Use [Declarative pipelines](https://www.jenkins.io/doc/book/pipeline/#declarative-versus-scripted-pipeline-syntax). +1. Check [jira plugin steps reference](https://www.jenkins.io/doc/pipeline/steps/jira/). ## i18n @@ -22,10 +24,3 @@ See user documentation at [https://jenkinsci.github.io/jira-plugin/](https://jen This plugin uses [CrowdIn platform](https://jenkins.crowdin.com/jira-plugin) as the frontend to manage translations. If you would like to contribute translation of this plugin in your language, you're most welcome! For details, see [jenkins.io CrowdIn introduction](https://www.jenkins.io/doc/developer/crowdin/translating-plugins/). -## Contributing - -There have been many developers involved in the development of this plugin and there are many downstream users who depend on it. Tests help us assure that we're delivering a reliable plugin and that we've communicated our intent to other developers in a way that they can detect when they run tests. - -- each change should be covered by appropriate unit tests -- in case it is not testable via a unit test, it should be tested against a real Jira instance - possibly both Jira Server and Jira Cloud. There is a [Jira Cloud test instance](https://jenkins-jira-plugin.atlassian.net/) that we are using for testing the plugin releases - let us know in the Pull Request in case you need access for testing - diff --git a/src/main/java/hudson/plugins/jira/JiraVersionCreator.java b/src/main/java/hudson/plugins/jira/JiraVersionCreator.java index e893ccf31..1d2b29955 100644 --- a/src/main/java/hudson/plugins/jira/JiraVersionCreator.java +++ b/src/main/java/hudson/plugins/jira/JiraVersionCreator.java @@ -18,14 +18,15 @@ * A build step which creates new Jira version * * @author Artem Koshelev artkoshelev@gmail.com - * @deprecated Replaced by {@link JiraVersionCreatorBuilder}. Read its description to see why. - * Kept for backward compatibility. + * @deprecated Replaced by {@link JiraVersionCreatorBuilder}. Read its + * description to see why. Kept for backward compatibility. */ @Deprecated public class JiraVersionCreator extends Notifier { + private String jiraVersion; private String jiraProjectKey; - private boolean failIfAlreadyExists = true; + private Boolean failIfAlreadyExists = true; @DataBoundConstructor public JiraVersionCreator(String jiraVersion, String jiraProjectKey) { @@ -67,7 +68,9 @@ public void setFailIfAlreadyExists(boolean failIfAlreadyExists) { public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) { VersionCreator versionCreator = new VersionCreator(); versionCreator.setFailIfAlreadyExists(failIfAlreadyExists); - return versionCreator.perform(build.getProject(), jiraVersion, jiraProjectKey, build, listener); + versionCreator.setJiraVersion(jiraVersion); + versionCreator.setJiraProjectKey(jiraProjectKey); + return versionCreator.perform(build.getProject(), build, listener); } @Override @@ -75,6 +78,14 @@ public BuildStepDescriptor getDescriptor() { return DESCRIPTOR; } + protected Object readResolve() { + if (failIfAlreadyExists == null) { + setFailIfAlreadyExists(true); + } + + return this; + } + @Extension public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); @@ -103,5 +114,6 @@ public String getDisplayName() { public String getHelpFile() { return "/plugin/jira/help-version-create.html"; } + } } diff --git a/src/main/java/hudson/plugins/jira/JiraVersionCreatorBuilder.java b/src/main/java/hudson/plugins/jira/JiraVersionCreatorBuilder.java index 1714e5349..2f5183a93 100644 --- a/src/main/java/hudson/plugins/jira/JiraVersionCreatorBuilder.java +++ b/src/main/java/hudson/plugins/jira/JiraVersionCreatorBuilder.java @@ -26,7 +26,7 @@ public class JiraVersionCreatorBuilder extends Builder implements SimpleBuildSte private String jiraVersion; private String jiraProjectKey; - private boolean failIfAlreadyExists = true; + private Boolean failIfAlreadyExists = true; @DataBoundConstructor public JiraVersionCreatorBuilder(String jiraVersion, String jiraProjectKey) { @@ -59,6 +59,14 @@ public boolean isFailIfAlreadyExists() { return failIfAlreadyExists; } + protected Object readResolve() { + if (failIfAlreadyExists == null) { + setFailIfAlreadyExists(true); + } + + return this; + } + @DataBoundSetter public void setFailIfAlreadyExists(boolean failIfAlreadyExists) { this.failIfAlreadyExists = failIfAlreadyExists; @@ -68,7 +76,9 @@ public void setFailIfAlreadyExists(boolean failIfAlreadyExists) { public void perform(Run run, EnvVars env, TaskListener listener) { VersionCreator versionCreator = new VersionCreator(); versionCreator.setFailIfAlreadyExists(failIfAlreadyExists); - versionCreator.perform(run.getParent(), jiraVersion, jiraProjectKey, run, listener); + versionCreator.setJiraVersion(jiraVersion); + versionCreator.setJiraProjectKey(jiraProjectKey); + versionCreator.perform(run.getParent(), run, listener); } @Override diff --git a/src/main/java/hudson/plugins/jira/VersionCreator.java b/src/main/java/hudson/plugins/jira/VersionCreator.java index 8fea85fd0..a0e28d8c1 100644 --- a/src/main/java/hudson/plugins/jira/VersionCreator.java +++ b/src/main/java/hudson/plugins/jira/VersionCreator.java @@ -1,5 +1,10 @@ package hudson.plugins.jira; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.logging.Logger; + import static org.apache.commons.lang.StringUtils.isEmpty; import hudson.model.BuildListener; @@ -8,11 +13,6 @@ import hudson.model.Run; import hudson.model.TaskListener; import hudson.plugins.jira.extension.ExtendedVersion; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.logging.Logger; -import org.kohsuke.stapler.DataBoundSetter; /** * Performs an action which creates new Jira version. @@ -23,17 +23,27 @@ class VersionCreator { private boolean failIfAlreadyExists = true; - @DataBoundSetter - public void setFailIfAlreadyExists(boolean failIfAlreadyExists) { + private String jiraVersion; + + private String jiraProjectKey; + + public VersionCreator setFailIfAlreadyExists(boolean failIfAlreadyExists) { this.failIfAlreadyExists = failIfAlreadyExists; + return this; } - public boolean isFailIfAlreadyExists() { - return failIfAlreadyExists; + public VersionCreator setJiraVersion(String jiraVersion) { + this.jiraVersion = jiraVersion; + return this; + } + + public VersionCreator setJiraProjectKey(String jiraProjectKey) { + this.jiraProjectKey = jiraProjectKey; + return this; } protected boolean perform( - Job project, String jiraVersion, String jiraProjectKey, Run build, TaskListener listener) { + Job project, Run build, TaskListener listener) { String realVersion = null; String realProjectKey = null; @@ -75,9 +85,6 @@ protected boolean perform( listener.fatalError("Unable to add version %s to Jira project %s", realVersion, realProjectKey, e)); } - if (listener instanceof BuildListener) { - ((BuildListener) listener).finished(Result.FAILURE); - } return false; } diff --git a/src/test/java/hudson/plugins/jira/VersionCreatorTest.java b/src/test/java/hudson/plugins/jira/VersionCreatorTest.java index b897ad5dd..41a2f0cef 100644 --- a/src/test/java/hudson/plugins/jira/VersionCreatorTest.java +++ b/src/test/java/hudson/plugins/jira/VersionCreatorTest.java @@ -1,35 +1,37 @@ package hudson.plugins.jira; +import java.io.IOException; +import java.io.PrintStream; +import java.util.Arrays; + import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; +import org.joda.time.DateTime; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; import static org.mockito.ArgumentMatchers.any; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.Mockito; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.stubbing.Answer; import com.atlassian.jira.rest.client.api.RestClientException; + import hudson.EnvVars; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.BuildListener; import hudson.model.Result; import hudson.plugins.jira.extension.ExtendedVersion; -import java.io.IOException; -import java.io.PrintStream; -import java.util.Arrays; -import org.joda.time.DateTime; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; -import org.mockito.stubbing.Answer; @ExtendWith(MockitoExtension.class) class VersionCreatorTest { @@ -96,7 +98,9 @@ void callsJiraWithSpecifiedParameters() throws InterruptedException, IOException // for new version, verify the addVersion method is called when(session.getVersions(JIRA_PRJ)).thenReturn(null); - boolean result = versionCreator.perform(project, JIRA_VER, JIRA_PRJ, build, listener); + versionCreator.setJiraProjectKey(JIRA_PRJ); + versionCreator.setJiraVersion(JIRA_VER); + boolean result = versionCreator.perform(project, build, listener); verify(session, times(1)).addVersion(versionCaptor.capture(), projectCaptor.capture()); assertThat(projectCaptor.getValue(), is(JIRA_PRJ)); assertThat(versionCaptor.getValue(), is(JIRA_VER)); @@ -106,7 +110,9 @@ void callsJiraWithSpecifiedParameters() throws InterruptedException, IOException // for existing version, verify the addVersion method is not called reset(session); when(session.getVersions(JIRA_PRJ)).thenReturn(Arrays.asList(existingVersion)); - result = versionCreator.perform(project, JIRA_VER, JIRA_PRJ, build, listener); + versionCreator.setJiraProjectKey(JIRA_PRJ); + versionCreator.setJiraVersion(JIRA_VER); + result = versionCreator.perform(project, build, listener); verify(session, times(0)).addVersion(versionCaptor.capture(), projectCaptor.capture()); verify(logger, times(1)).println(Messages.JiraVersionCreator_VersionExists(JIRA_VER, JIRA_PRJ)); verify(listener).finished(Result.FAILURE); @@ -120,7 +126,9 @@ void expandsEnvParameters() throws InterruptedException, IOException, RestClient // for new version, verify the addVersion method is called when(session.getVersions(JIRA_PRJ)).thenReturn(null); - boolean result = versionCreator.perform(project, JIRA_VER_PARAM, JIRA_PRJ_PARAM, build, listener); + versionCreator.setJiraProjectKey(JIRA_PRJ_PARAM); + versionCreator.setJiraVersion(JIRA_VER_PARAM); + boolean result = versionCreator.perform(project, build, listener); verify(session, times(1)).addVersion(versionCaptor.capture(), projectCaptor.capture()); assertThat(projectCaptor.getValue(), is(JIRA_PRJ)); assertThat(versionCaptor.getValue(), is(JIRA_VER)); @@ -129,7 +137,9 @@ void expandsEnvParameters() throws InterruptedException, IOException, RestClient // for existing version, verify the addVersion method is called reset(session); when(session.getVersions(JIRA_PRJ)).thenReturn(Arrays.asList(existingVersion)); - result = versionCreator.perform(project, JIRA_VER_PARAM, JIRA_PRJ_PARAM, build, listener); + versionCreator.setJiraProjectKey(JIRA_PRJ_PARAM); + versionCreator.setJiraVersion(JIRA_VER_PARAM); + result = versionCreator.perform(project, build, listener); verify(session, times(0)).addVersion(versionCaptor.capture(), projectCaptor.capture()); verify(logger, times(1)).println(Messages.JiraVersionCreator_VersionExists(JIRA_VER, JIRA_PRJ)); verify(listener).finished(Result.FAILURE); @@ -143,8 +153,9 @@ void buildDidNotFailWhenVersionExists() throws IOException, InterruptedException new ExtendedVersion(null, ANY_ID, JIRA_VER, null, false, true, ANY_DATE, ANY_DATE); when(site.getSession(any())).thenReturn(session); when(session.getVersions(JIRA_PRJ)).thenReturn(Arrays.asList(releasedVersion)); - - versionCreator.perform(project, JIRA_VER_PARAM, JIRA_PRJ_PARAM, build, listener); + versionCreator.setJiraProjectKey(JIRA_PRJ_PARAM); + versionCreator.setJiraVersion(JIRA_VER_PARAM); + versionCreator.perform(project, build, listener); verify(session, times(0)).addVersion(any(), any()); } @@ -157,8 +168,9 @@ void buildDoesNotFailWhenVersionExistsAndFailIfAlreadyExistsIsFalse() // Set failIfAlreadyExists to false versionCreator.setFailIfAlreadyExists(false); - - boolean result = versionCreator.perform(project, JIRA_VER, JIRA_PRJ, build, listener); + versionCreator.setJiraProjectKey(JIRA_PRJ); + versionCreator.setJiraVersion(JIRA_VER); + boolean result = versionCreator.perform(project, build, listener); // Verify that addVersion is not called (because version already exists) verify(session, times(0)).addVersion(any(), any()); From cb32f707580019432a98ac0ff5841fba726c8dac Mon Sep 17 00:00:00 2001 From: Radek Antoniuk Date: Wed, 17 Dec 2025 02:05:24 +0100 Subject: [PATCH 3/4] chore: spotless:apply --- .../plugins/jira/JiraVersionCreator.java | 3 +- .../jira/JiraVersionCreatorBuilder.java | 2 +- .../hudson/plugins/jira/VersionCreator.java | 14 ++++---- .../plugins/jira/VersionCreatorTest.java | 32 +++++++++---------- 4 files changed, 23 insertions(+), 28 deletions(-) diff --git a/src/main/java/hudson/plugins/jira/JiraVersionCreator.java b/src/main/java/hudson/plugins/jira/JiraVersionCreator.java index 1d2b29955..0ef45ef66 100644 --- a/src/main/java/hudson/plugins/jira/JiraVersionCreator.java +++ b/src/main/java/hudson/plugins/jira/JiraVersionCreator.java @@ -82,7 +82,7 @@ protected Object readResolve() { if (failIfAlreadyExists == null) { setFailIfAlreadyExists(true); } - + return this; } @@ -114,6 +114,5 @@ public String getDisplayName() { public String getHelpFile() { return "/plugin/jira/help-version-create.html"; } - } } diff --git a/src/main/java/hudson/plugins/jira/JiraVersionCreatorBuilder.java b/src/main/java/hudson/plugins/jira/JiraVersionCreatorBuilder.java index 2f5183a93..11ab242f6 100644 --- a/src/main/java/hudson/plugins/jira/JiraVersionCreatorBuilder.java +++ b/src/main/java/hudson/plugins/jira/JiraVersionCreatorBuilder.java @@ -63,7 +63,7 @@ protected Object readResolve() { if (failIfAlreadyExists == null) { setFailIfAlreadyExists(true); } - + return this; } diff --git a/src/main/java/hudson/plugins/jira/VersionCreator.java b/src/main/java/hudson/plugins/jira/VersionCreator.java index a0e28d8c1..d7e80903e 100644 --- a/src/main/java/hudson/plugins/jira/VersionCreator.java +++ b/src/main/java/hudson/plugins/jira/VersionCreator.java @@ -1,10 +1,5 @@ package hudson.plugins.jira; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.logging.Logger; - import static org.apache.commons.lang.StringUtils.isEmpty; import hudson.model.BuildListener; @@ -13,6 +8,10 @@ import hudson.model.Run; import hudson.model.TaskListener; import hudson.plugins.jira.extension.ExtendedVersion; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.logging.Logger; /** * Performs an action which creates new Jira version. @@ -26,7 +25,7 @@ class VersionCreator { private String jiraVersion; private String jiraProjectKey; - + public VersionCreator setFailIfAlreadyExists(boolean failIfAlreadyExists) { this.failIfAlreadyExists = failIfAlreadyExists; return this; @@ -42,8 +41,7 @@ public VersionCreator setJiraProjectKey(String jiraProjectKey) { return this; } - protected boolean perform( - Job project, Run build, TaskListener listener) { + protected boolean perform(Job project, Run build, TaskListener listener) { String realVersion = null; String realProjectKey = null; diff --git a/src/test/java/hudson/plugins/jira/VersionCreatorTest.java b/src/test/java/hudson/plugins/jira/VersionCreatorTest.java index 41a2f0cef..91788001d 100644 --- a/src/test/java/hudson/plugins/jira/VersionCreatorTest.java +++ b/src/test/java/hudson/plugins/jira/VersionCreatorTest.java @@ -1,37 +1,35 @@ package hudson.plugins.jira; -import java.io.IOException; -import java.io.PrintStream; -import java.util.Arrays; - import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; -import org.joda.time.DateTime; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentCaptor; import static org.mockito.ArgumentMatchers.any; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.Mockito; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import org.mockito.junit.jupiter.MockitoExtension; -import org.mockito.stubbing.Answer; import com.atlassian.jira.rest.client.api.RestClientException; - import hudson.EnvVars; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.BuildListener; import hudson.model.Result; import hudson.plugins.jira.extension.ExtendedVersion; +import java.io.IOException; +import java.io.PrintStream; +import java.util.Arrays; +import org.joda.time.DateTime; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.stubbing.Answer; @ExtendWith(MockitoExtension.class) class VersionCreatorTest { @@ -99,7 +97,7 @@ void callsJiraWithSpecifiedParameters() throws InterruptedException, IOException // for new version, verify the addVersion method is called when(session.getVersions(JIRA_PRJ)).thenReturn(null); versionCreator.setJiraProjectKey(JIRA_PRJ); - versionCreator.setJiraVersion(JIRA_VER); + versionCreator.setJiraVersion(JIRA_VER); boolean result = versionCreator.perform(project, build, listener); verify(session, times(1)).addVersion(versionCaptor.capture(), projectCaptor.capture()); assertThat(projectCaptor.getValue(), is(JIRA_PRJ)); @@ -111,7 +109,7 @@ void callsJiraWithSpecifiedParameters() throws InterruptedException, IOException reset(session); when(session.getVersions(JIRA_PRJ)).thenReturn(Arrays.asList(existingVersion)); versionCreator.setJiraProjectKey(JIRA_PRJ); - versionCreator.setJiraVersion(JIRA_VER); + versionCreator.setJiraVersion(JIRA_VER); result = versionCreator.perform(project, build, listener); verify(session, times(0)).addVersion(versionCaptor.capture(), projectCaptor.capture()); verify(logger, times(1)).println(Messages.JiraVersionCreator_VersionExists(JIRA_VER, JIRA_PRJ)); From 93f4a31f5a00e4ae21b6a7bbcc353e677478433d Mon Sep 17 00:00:00 2001 From: Radek Antoniuk Date: Wed, 17 Dec 2025 14:02:46 +0100 Subject: [PATCH 4/4] add tests for failIfAlreadyExists flag in JiraVersionCreatorBuilder --- .../jira/JiraVersionCreatorBuilderTest.java | 63 ++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/test/java/hudson/plugins/jira/JiraVersionCreatorBuilderTest.java b/src/test/java/hudson/plugins/jira/JiraVersionCreatorBuilderTest.java index 669822e0e..591bedca5 100644 --- a/src/test/java/hudson/plugins/jira/JiraVersionCreatorBuilderTest.java +++ b/src/test/java/hudson/plugins/jira/JiraVersionCreatorBuilderTest.java @@ -1,9 +1,15 @@ package hudson.plugins.jira; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import hudson.model.Result; +import hudson.util.XStream2; import java.util.Collections; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; @@ -11,6 +17,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.WithoutJenkins; import org.jvnet.hudson.test.junit.jupiter.WithJenkins; class JiraVersionCreatorBuilderTest { @@ -19,6 +26,8 @@ class JiraVersionCreatorBuilderTest { private JiraSession session; + private final XStream2 xStream2 = new XStream2(); + @BeforeEach void createMocks() { site = mock(JiraSite.class); @@ -38,4 +47,56 @@ void testPipelineWithJiraSite(JenkinsRule r) throws Exception { WorkflowRun b = r.buildAndAssertStatus(Result.SUCCESS, job); r.assertLogContains("[Jira] Creating version Version in project project-key.", b); } + + @Test + @WithoutJenkins + void readResolveSetsFailIfAlreadyExistsWhenMissingInConfig() { + String xml = """ + + 1.0 + PROJ + + """; + JiraVersionCreatorBuilder builder = (JiraVersionCreatorBuilder) xStream2.fromXML(xml); + + assertTrue(builder.isFailIfAlreadyExists()); + + xml = """ + + 1.2 + PROJ + + """; + JiraVersionCreator notifier = (JiraVersionCreator) xStream2.fromXML(xml); + + assertThat(notifier.getJiraProjectKey(), is("PROJ")); + assertThat(notifier.getJiraVersion(), is("1.2")); + assertTrue(notifier.isFailIfAlreadyExists()); + } + + @Test + @WithoutJenkins + void readResolvePresentInConfig() { + String xml = """ + + 1.0 + PROJ + false + + """; + JiraVersionCreatorBuilder builder = (JiraVersionCreatorBuilder) xStream2.fromXML(xml); + + assertFalse(builder.isFailIfAlreadyExists()); + + xml = """ + + 1.0 + PROJ + false + + """; + JiraVersionCreator notifier = (JiraVersionCreator) xStream2.fromXML(xml); + + assertFalse(notifier.isFailIfAlreadyExists()); + } }