diff --git a/release-tools/src/main/java/org/springframework/data/release/issues/jira/Jira.java b/release-tools/src/main/java/org/springframework/data/release/issues/jira/Jira.java index f73b7ad..86b043b 100644 --- a/release-tools/src/main/java/org/springframework/data/release/issues/jira/Jira.java +++ b/release-tools/src/main/java/org/springframework/data/release/issues/jira/Jira.java @@ -309,12 +309,12 @@ class Jira implements JiraConnector { return; } - JiraIssue jiraIssue = JiraIssue.create().assignTo(jiraProperties.getCredentials()); + JiraIssueUpdate editMeta = JiraIssueUpdate.create().assignTo(jiraProperties.getUsername()); logger.log("Ticket", "Self-assignment of %s", ticket); try { - operations.exchange(ISSUE_TEMPLATE, HttpMethod.POST, new HttpEntity(jiraIssue, httpHeaders), String.class, + operations.exchange(ISSUE_TEMPLATE, HttpMethod.PUT, new HttpEntity(editMeta, httpHeaders), String.class, parameters).getBody(); } catch (HttpClientErrorException e) { logger.warn("Ticket", "Self-assignment of %s failed with status ", ticket, e.getStatusCode()); diff --git a/release-tools/src/main/java/org/springframework/data/release/issues/jira/JiraIssue.java b/release-tools/src/main/java/org/springframework/data/release/issues/jira/JiraIssue.java index 591e8c9..0814a66 100644 --- a/release-tools/src/main/java/org/springframework/data/release/issues/jira/JiraIssue.java +++ b/release-tools/src/main/java/org/springframework/data/release/issues/jira/JiraIssue.java @@ -86,29 +86,6 @@ class JiraIssue { && fields.hasSummary(Tracker.releaseTicketSummary(moduleIteration)); } - /** - * Assign to the user specified in {@link Credentials}. - * - * @param credentials must not be {@literal null}. - * @return - */ - public JiraIssue assignTo(Credentials credentials) { - return assignTo(credentials.getUsername()); - } - - /** - * Assign the ticket to {@code username}. - * - * @param username must not be empty and not {@literal null}. - * @return - */ - public JiraIssue assignTo(String username) { - - Assert.hasText(username, "Username must not be empty!"); - getFields().setAssignee(JiraUser.from(username)); - return this; - } - /** * Set the project to {@code projectKey}. * diff --git a/release-tools/src/main/java/org/springframework/data/release/issues/jira/JiraIssueUpdate.java b/release-tools/src/main/java/org/springframework/data/release/issues/jira/JiraIssueUpdate.java new file mode 100644 index 0000000..9c59a3e --- /dev/null +++ b/release-tools/src/main/java/org/springframework/data/release/issues/jira/JiraIssueUpdate.java @@ -0,0 +1,78 @@ +package org.springframework.data.release.issues.jira; + +import lombok.NonNull; +import lombok.Value; + +import java.io.IOException; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.springframework.util.Assert; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +/** + * Value object to represent a Jira issue update via {@code PUT} with {@code update} fields. + * + * @author Mark Paluch + */ +@Value +class JiraIssueUpdate { + + private final Map update; + + private JiraIssueUpdate(Map update) { + this.update = update; + } + + /** + * Create an empty {@link JiraIssueUpdate}. + * + * @return + */ + public static JiraIssueUpdate create() { + return new JiraIssueUpdate(Collections.emptyMap()); + } + + /** + * Assign the issue to {@code userId}. + * + * @param userId must not be {@literal null} or empty. + * @return + */ + public JiraIssueUpdate assignTo(String userId) { + + Assert.hasText(userId, "UserId must not be null or empty!"); + + Map update = new LinkedHashMap<>(this.update); + update.put("assignee", new AssignTo(userId)); + + return new JiraIssueUpdate(update); + } + + /** + * Serializes as [ {"set": "value"} ] + */ + @Value + @JsonSerialize(using = SetSerializer.class) + static class AssignTo { + final @NonNull String value; + } + + static class SetSerializer extends JsonSerializer { + + @Override + public void serialize(AssignTo value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + + gen.writeStartArray(); + + gen.writeObject(Collections.singletonMap("set", Collections.singletonMap("name", value.getValue()))); + + gen.writeEndArray(); + } + } +} diff --git a/release-tools/src/test/java/org/springframework/data/release/issues/jira/JiraConnectorIntegrationTests.java b/release-tools/src/test/java/org/springframework/data/release/issues/jira/JiraConnectorIntegrationTests.java index d5f904a..9cfe0ef 100644 --- a/release-tools/src/test/java/org/springframework/data/release/issues/jira/JiraConnectorIntegrationTests.java +++ b/release-tools/src/test/java/org/springframework/data/release/issues/jira/JiraConnectorIntegrationTests.java @@ -54,12 +54,12 @@ import com.github.tomakehurst.wiremock.junit.WireMockRule; */ public class JiraConnectorIntegrationTests extends AbstractIntegrationTests { - public static final String CREATE_ISSUE_URI = "/rest/api/2/issue"; - public static final String CREATE_VERSION_URI = "/rest/api/2/version"; - public static final String SEARCH_URI = "/rest/api/2/search"; - public static final String PROJECT_VERSION_URI = "/rest/api/2/project/%s/version"; - public static final String PROJECT_COMPONENTS_URI = "/rest/api/2/project/%s/components"; - public static final ModuleIteration REST_HOPPER_RC1 = ReleaseTrains.HOPPER.getModuleIteration(Iteration.RC1, "REST"); + static final String CREATE_ISSUE_URI = "/rest/api/2/issue"; + static final String CREATE_VERSION_URI = "/rest/api/2/version"; + static final String SEARCH_URI = "/rest/api/2/search"; + static final String PROJECT_VERSION_URI = "/rest/api/2/project/%s/version"; + static final String PROJECT_COMPONENTS_URI = "/rest/api/2/project/%s/components"; + static final ModuleIteration REST_HOPPER_RC1 = ReleaseTrains.HOPPER.getModuleIteration(Iteration.RC1, "REST"); @Rule public WireMockRule mockService = new WireMockRule( wireMockConfig().port(8888).fileSource(new ClasspathFileSource("integration/jira"))); @@ -265,7 +265,7 @@ public class JiraConnectorIntegrationTests extends AbstractIntegrationTests { } /** - * @see #5 + * @see #5, #54 */ @Test public void assignTicketToMe() { @@ -273,13 +273,13 @@ public class JiraConnectorIntegrationTests extends AbstractIntegrationTests { mockService.stubFor(get(urlPathMatching("/rest/api/2/issue/DATAREDIS-302")).// willReturn(json("existingTicket.json"))); - mockService.stubFor(post(urlPathMatching("/rest/api/2/issue/DATAREDIS-302")).// + mockService.stubFor(put(urlPathMatching("/rest/api/2/issue/DATAREDIS-302")).// willReturn(aResponse().withStatus(204))); - jira.assignTicketToMe(new Ticket("DATAREDIS-99999", "", null)); + jira.assignTicketToMe(new Ticket("DATAREDIS-302", "", null)); - verify(postRequestedFor(urlPathMatching("/rest/api/2/issue/DATAREDIS-302")) - .withRequestBody(equalToJson("{\"fields\":{\"assignee\":{\"name\":\"dummy\"}}}"))); + verify(putRequestedFor(urlPathMatching("/rest/api/2/issue/DATAREDIS-302")) + .withRequestBody(equalToJson("{\"update\":{\"assignee\":[ {\"set\":{\"name\":\"dummy\"}} ] }}"))); } /**