Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,29 @@
import com.atlassian.jira.rest.client.api.domain.IssueField;
import hudson.Extension;
import hudson.cli.CLICommand;
import hudson.model.Item;
import hudson.model.Job;
import hudson.model.ParameterDefinition;
import hudson.model.ParameterValue;
import hudson.model.ParametersDefinitionProperty;
import hudson.plugins.jira.JiraSession;
import hudson.plugins.jira.JiraSite;
import hudson.plugins.jira.Messages;
import hudson.util.ListBoxModel;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeoutException;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.jenkinsci.Symbol;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerRequest2;
import org.kohsuke.stapler.interceptor.RequirePOST;

public class JiraIssueParameterDefinition extends ParameterDefinition {
private static final long serialVersionUID = 3927562542249244416L;
Expand All @@ -54,7 +61,7 @@
@Override
public ParameterValue createValue(StaplerRequest2 req) {
String[] values = req.getParameterValues(getName());
if (values == null || values.length != 1) {
if (values == null || values.length != 1 || values[0].isEmpty()) {
return null;
}

Expand All @@ -75,7 +82,10 @@
public List<JiraIssueParameterDefinition.Result> getIssues()
throws IOException, TimeoutException, RestClientException {
Job<?, ?> job = Stapler.getCurrentRequest2().findAncestorObject(Job.class);
return getIssues(job);

Check warning on line 85 in src/main/java/hudson/plugins/jira/listissuesparameter/JiraIssueParameterDefinition.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 85 is not covered by tests
}

List<JiraIssueParameterDefinition.Result> getIssues(Job<?, ?> job) {
JiraSite site = JiraSite.get(job);
if (site == null) {
throw new IllegalStateException(
Expand Down Expand Up @@ -122,6 +132,25 @@
public String getDisplayName() {
return "Jira Issue Parameter";
}

@RequirePOST
public ListBoxModel doFillValueItems(@AncestorInPath Job<?, ?> job, @QueryParameter String name) {
ListBoxModel items = new ListBoxModel();
if (job.hasPermission(Item.BUILD)) {
ParametersDefinitionProperty prop = job.getProperty(ParametersDefinitionProperty.class);
if (prop != null) {

Check warning on line 141 in src/main/java/hudson/plugins/jira/listissuesparameter/JiraIssueParameterDefinition.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 141 is only partially covered, one branch is missing
ParameterDefinition def = prop.getParameterDefinition(name);
if (def instanceof JiraIssueParameterDefinition jiraIssueDef) {

Check warning on line 143 in src/main/java/hudson/plugins/jira/listissuesparameter/JiraIssueParameterDefinition.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 143 is only partially covered, one branch is missing
List<Result> issueValues = jiraIssueDef.getIssues(job);
issueValues.forEach(it -> items.add(it.key + ": " + it.summary, it.key));
}
}
}
if (items.isEmpty()) {
items.add(Messages.JiraIssueParameterDefinition_NoIssueMatchedSearch(), "");
}
return items;
}
}

public static class Result {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,28 @@
import com.atlassian.jira.rest.client.api.domain.Version;
import hudson.Extension;
import hudson.cli.CLICommand;
import hudson.model.Item;
import hudson.model.Job;
import hudson.model.ParameterDefinition;
import hudson.model.ParameterValue;
import hudson.model.ParametersDefinitionProperty;
import hudson.plugins.jira.JiraSession;
import hudson.plugins.jira.JiraSite;
import hudson.plugins.jira.Messages;
import hudson.util.ListBoxModel;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import net.sf.json.JSONObject;
import org.jenkinsci.Symbol;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerRequest2;
import org.kohsuke.stapler.interceptor.RequirePOST;

public class JiraVersionParameterDefinition extends ParameterDefinition {
private static final long serialVersionUID = 4232979892748310160L;
Expand Down Expand Up @@ -50,7 +57,7 @@
@Override
public ParameterValue createValue(StaplerRequest2 req) {
String[] values = req.getParameterValues(getName());
if (values == null || values.length != 1) {
if (values == null || values.length != 1 || values[0].isEmpty()) {
return null;
}
return new JiraVersionParameterValue(getName(), values[0]);
Expand All @@ -69,7 +76,10 @@

public List<JiraVersionParameterDefinition.Result> getVersions() throws IOException, RestClientException {
Job<?, ?> contextJob = Stapler.getCurrentRequest2().findAncestorObject(Job.class);
return getVersions(contextJob);
}

List<JiraVersionParameterDefinition.Result> getVersions(Job<?, ?> contextJob) {
JiraSite site = JiraSite.get(contextJob);
if (site == null) {
throw new IllegalStateException(
Expand Down Expand Up @@ -173,6 +183,25 @@
public String getDisplayName() {
return "Jira Release Version Parameter";
}

@RequirePOST
public ListBoxModel doFillVersionItems(@AncestorInPath Job<?, ?> job, @QueryParameter String name) {
ListBoxModel items = new ListBoxModel();
if (job.hasPermission(Item.BUILD)) {
ParametersDefinitionProperty prop = job.getProperty(ParametersDefinitionProperty.class);
if (prop != null) {

Check warning on line 192 in src/main/java/hudson/plugins/jira/versionparameter/JiraVersionParameterDefinition.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 192 is only partially covered, one branch is missing
ParameterDefinition def = prop.getParameterDefinition(name);
if (def instanceof JiraVersionParameterDefinition jiraVersionDef) {

Check warning on line 194 in src/main/java/hudson/plugins/jira/versionparameter/JiraVersionParameterDefinition.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 194 is only partially covered, one branch is missing
List<JiraVersionParameterDefinition.Result> issueValues = jiraVersionDef.getVersions(job);
issueValues.forEach(it -> items.add(it.name));
}
}
}
if (items.isEmpty()) {
items.add(Messages.JiraVersionParameterDefinition_NoVersionsMatchedSearch(), "");
}
return items;
}
}

public static class Result {
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/hudson/plugins/jira/Messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,5 @@ ErrorCommentingIssues=[Jira] Could not comment on some issues: {0}
JiraSite.threadExecutorMinimunSize = Thread Executor Size must be at least {0} (higher values are recommended)
JiraSite.timeoutMinimunValue = Connection timeout must be at least {0}
JiraSite.readTimeoutMinimunValue = Read timeout must be at least {0}
JiraIssueParameterDefinition.NoIssueMatchedSearch = No issues matched the search
JiraVersionParameterDefinition.NoVersionsMatchedSearch = No version matched the search
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,12 @@ limitations under the License.
<!-- this is the page fragment displayed when triggering a new build -->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<j:set var="escapeEntryTitleAndDescription" value="false"/>
<f:entry title="${h.escape(it.name)}" description="${it.formattedDescription}">
<!-- this div is required because of ParametersDefinitionProperty.java#117 -->
<div name="parameter">
<input type="hidden" name="name" value="${it.name}"/>
<j:choose>
<j:when test="${it.issues == null or it.issues.size() == 0}">
<!-- no tags at all -->
${%No issues matched the search.}<br/>
${%If you trigger the build, it will likely fail.}
</j:when>
<j:otherwise>
<!-- everything is fine, we can display the drop-down list to the user -->
<select name="value">
<j:forEach var="issue" items="${it.issues}">
<option value="${issue.key}">${issue.key}: ${issue.summary}</option>
</j:forEach>
</select>
</j:otherwise>
</j:choose>
</div>
</f:entry>
<j:set var="escapeEntryTitleAndDescription" value="false"/>
<j:set var="descriptor" value="${it.descriptor}"/>
<f:entry field="value" title="${h.escape(it.name)}" description="${it.formattedDescription}">
<div name="parameter">
<input type="hidden" name="name" value="${it.name}"/>
<f:select/>
</div>
</f:entry>
</j:jelly>
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<j:set var="escapeEntryTitleAndDescription" value="false"/>
<f:entry title="${h.escape(it.name)}">
<f:textbox name="${it.name}" value="${it.issue}" />
<j:set var="readOnlyMode" value="true"/>
<f:textbox name="${it.name}" value="${it.value}"/>
</f:entry>
</j:jelly>
Original file line number Diff line number Diff line change
@@ -1,26 +1,12 @@
<!-- this is the page fragment displayed when triggering a new build -->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<j:set var="escapeEntryTitleAndDescription" value="false"/>
<f:entry title="${h.escape(it.name)}" description="${it.formattedDescription}">
<!-- this div is required because of ParametersDefinitionProperty.java#117 -->
<div name="parameter">
<input type="hidden" name="name" value="${it.name}"/>
<j:choose>
<j:when test="${it.versions == null or it.versions.size() == 0}">
<!-- no tags at all -->
${%No versions found meeting your filter criteria.}<br/>
${%If you trigger the build, it will likely fail.}
</j:when>
<j:otherwise>
<!-- everything is fine, we can display the drop-down list to the user -->
<select name="version">
<j:forEach var="version" items="${it.versions}">
<option value="${version.name}">${version.name}</option>
</j:forEach>
</select>
</j:otherwise>
</j:choose>
</div>
</f:entry>
<j:set var="escapeEntryTitleAndDescription" value="false"/>
<j:set var="descriptor" value="${it.descriptor}"/>
<f:entry field="version" title="${h.escape(it.name)}" description="${it.formattedDescription}">
<div name="parameter">
<input type="hidden" name="name" value="${it.name}"/>
<f:select/>
</div>
</f:entry>
</j:jelly>
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<j:set var="escapeEntryTitleAndDescription" value="false"/>
<f:entry title="${h.escape(it.name)}">
<f:textbox name="${it.name}" value="${it.version}" />
<j:set var="readOnlyMode" value="true"/>
<f:textbox name="${it.name}" value="${it.version}"/>
</f:entry>
</j:jelly>
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package hudson.plugins.jira.listissuesparameter;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import com.atlassian.jira.rest.client.api.domain.Issue;
import hudson.model.Item;
import hudson.model.Job;
import hudson.model.ParameterValue;
import hudson.model.ParametersDefinitionProperty;
import hudson.plugins.jira.Messages;
import hudson.util.ListBoxModel;
import java.util.List;
import java.util.stream.Stream;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.NullSource;
import org.kohsuke.stapler.StaplerRequest2;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class JiraIssueParameterDefinitionTest {

private JiraIssueParameterDefinition definition =
new JiraIssueParameterDefinition("PARAM_NAME", "desc", "jqlQuery");

static Stream<Arguments> createValueInvalidParameters() {
return Stream.of(
Arguments.of((Object) new String[] {}),
Arguments.of((Object) new String[] {"a", "b"}),
Arguments.of((Object) new String[] {""}));
}

@ParameterizedTest
@NullSource
@MethodSource("createValueInvalidParameters")
void shouldCreateNullParameterForInvalidValues(String[] values, @Mock StaplerRequest2 req) {
when(req.getParameterValues(any())).thenReturn(values);

ParameterValue result = definition.createValue(req);

assertNull(result);
}

@Test
void shouldCreateValue(@Mock StaplerRequest2 req) {
when(req.getParameterValues(any())).thenReturn(new String[] {"value"});

ParameterValue result = definition.createValue(req);

assertNotNull(result);
assertEquals("PARAM_NAME", result.getName());
assertEquals("value", result.getValue());
}

@Nested
class DescriptorImplTest {

private JiraIssueParameterDefinition.DescriptorImpl uut = new JiraIssueParameterDefinition.DescriptorImpl();

@Test
void shouldFillValueItems(
@Mock Job<?, ?> job,
@Mock ParametersDefinitionProperty propertyDef,
@Mock JiraIssueParameterDefinition paramDef,
@Mock Issue issue) {
when(job.hasPermission(Item.BUILD)).thenReturn(true);
when(job.getProperty(ParametersDefinitionProperty.class)).thenReturn(propertyDef);
when(propertyDef.getParameterDefinition("PARAM_NAME")).thenReturn(paramDef);
when(issue.getKey()).thenReturn("JIRA-1234");
when(issue.getSummary()).thenReturn("Summary");
JiraIssueParameterDefinition.Result item = new JiraIssueParameterDefinition.Result(issue, null);
when(paramDef.getIssues(any())).thenReturn(List.of(item));

ListBoxModel result = uut.doFillValueItems(job, "PARAM_NAME");

assertThat(result, hasSize(1));
ListBoxModel.Option option = result.get(0);
assertEquals("JIRA-1234", option.value);
assertEquals("JIRA-1234: Summary", option.name);
verify(job).hasPermission(Item.BUILD);
}

@Test
void shouldNotFillValueItemsIfPermissionMissing(@Mock Job<?, ?> job) {
ListBoxModel result = uut.doFillValueItems(job, "PARAM_NAME");

assertThat(result, hasSize(1));
ListBoxModel.Option option = result.get(0);
assertEquals("", option.value);
assertEquals(Messages.JiraIssueParameterDefinition_NoIssueMatchedSearch(), option.name);
verify(job).hasPermission(Item.BUILD);

Check warning

Code scanning / Jenkins Security Scan

Result of hasPermission call is ignored Warning test

The result of the call is ignored
}

@Test
void shouldHaveNoSearchMatchesItemIfSearchMatchesNoItem(
@Mock Job<?, ?> job,
@Mock ParametersDefinitionProperty propertyDef,
@Mock JiraIssueParameterDefinition paramDef,
@Mock Issue issue) {
when(job.hasPermission(Item.BUILD)).thenReturn(true);
when(job.getProperty(ParametersDefinitionProperty.class)).thenReturn(propertyDef);
when(propertyDef.getParameterDefinition("PARAM_NAME")).thenReturn(paramDef);

ListBoxModel result = uut.doFillValueItems(job, "PARAM_NAME");

assertThat(result, hasSize(1));
ListBoxModel.Option option = result.get(0);
assertEquals("", option.value);
assertEquals(Messages.JiraIssueParameterDefinition_NoIssueMatchedSearch(), option.name);
verify(job).hasPermission(Item.BUILD);

Check warning

Code scanning / Jenkins Security Scan

Result of hasPermission call is ignored Warning test

The result of the call is ignored
}
}
}
Loading
Loading