Skip to content

Commit

Permalink
Use status from->to to pick a transition to apply to an issue
Browse files Browse the repository at this point in the history
  • Loading branch information
marko-bekhta committed Nov 28, 2024
1 parent 99bb1a8 commit 3bb733d
Show file tree
Hide file tree
Showing 11 changed files with 91 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -310,10 +310,10 @@ interface StatusesValueMapping extends ValueMapping {
Optional<String> deletedResolution();

/**
* @return The id of the transition to apply to get the "Close" transition when
* closing the issue deleted upstream before archiving it.
* @return The status name to transition the issue to when handling an issue
* deleted/moved upstream before archiving it.
*/
Optional<String> deletedTransition();
Optional<String> deletedStatus();

/**
* @return A map where the {@code key} is the upstream status name, and the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraRemoteLink;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraSimpleObject;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraTransition;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraTransitions;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraUser;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraVersion;

Expand Down Expand Up @@ -145,6 +146,10 @@ JiraIssues find(@QueryParam("jql") String query, @QueryParam("startAt") int star
@Path("/issue/{issueKey}/transitions")
void transition(@PathParam("issueKey") String issueKey, JiraTransition transition);

@GET
@Path("/issue/{issueKey}/transitions")
JiraTransitions availableTransitions(String issueKey);

@PUT
@Path("/issue/{issueKey}/archive")
void archive(@PathParam("issueKey") String issueKey);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraRemoteLink;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraSimpleObject;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraTransition;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraTransitions;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraUser;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraVersion;

Expand Down Expand Up @@ -250,6 +251,11 @@ public void transition(String issueKey, JiraTransition transition) {
withRetry(() -> delegate.transition(issueKey, transition));
}

@Override
public JiraTransitions availableTransitions(String issueKey) {
return withRetry(() -> delegate.availableTransitions(issueKey));
}

@Override
public void archive(String issueKey) {
withRetry(() -> delegate.archive(issueKey));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
package org.hibernate.infra.replicate.jira.service.jira.handler;

import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.regex.Pattern;

import org.hibernate.infra.replicate.jira.JiraConfig;
import org.hibernate.infra.replicate.jira.service.jira.HandlerProjectContext;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraComment;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraIssue;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraIssueTransition;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraSimpleObject;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraTextContent;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraTransitions;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraUser;
import org.hibernate.infra.replicate.jira.service.reporting.FailureCollector;
import org.hibernate.infra.replicate.jira.service.reporting.ReportingConfig;
Expand Down Expand Up @@ -92,21 +96,29 @@ protected Optional<String> issueType(String sourceId) {
}, mappedValues.defaultValue()));
}

protected Optional<String> statusToTransition(String sourceId) {
JiraConfig.ValueMapping mappedValues = context.projectGroup().statuses();
return Optional.ofNullable(JiraStaticFieldMappingCache.status(context.projectGroupName(), sourceId, pk -> {
Map<String, String> mapping = context.projectGroup().statuses().mapping();
if (!mapping.isEmpty()) {
return mapping;
}
protected Optional<String> statusToTransition(String from, String to, Supplier<Optional<String>> transitionFinder) {
return Optional.ofNullable(JiraStaticFieldMappingCache.status(context.projectGroupName(),
"%s->%s".formatted(from, to), tk -> transitionFinder.get().orElse(null)));
}

// Otherwise we'll try to use REST to get the info and match, but that may not
// necessarily work fine
List<JiraSimpleObject> source = context.sourceJiraClient().getStatues();
List<JiraSimpleObject> destination = context.destinationJiraClient().getStatues();
protected Optional<String> findRequiredTransitionId(String downstreamStatus, JiraIssue destIssue) {
if (downstreamStatus != null) {
List<JiraIssueTransition> jiraTransitions = null;
try {
JiraTransitions transitions = context.destinationJiraClient().availableTransitions(destIssue.key);
jiraTransitions = transitions.transitions;
} catch (Exception e) {
failureCollector.warning("Failed to find a transition for %s".formatted(destIssue.key), e);
jiraTransitions = Collections.emptyList();
}
for (JiraIssueTransition transition : jiraTransitions) {
if (transition.to != null && downstreamStatus.equalsIgnoreCase(transition.to.name)) {
return Optional.of(transition.id);
}
}
}

return createMapping(source, destination);
}, mappedValues.defaultValue()));
return Optional.empty();
}

protected Optional<String> linkType(String sourceId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ protected void applyTransition(JiraIssue sourceIssue, String destinationKey) {

protected void applyTransition(JiraIssue sourceIssue, JiraIssue destIssue, String destinationKey) {
Set<String> statusesToIgnore = context.projectGroup().statuses().ignoreTransitionCondition()
.getOrDefault(sourceIssue.fields.status.name.toLowerCase(Locale.ROOT).replace(' ', '-'), Set.of());
.getOrDefault(sourceIssue.fields.status.name.toLowerCase(Locale.ROOT), Set.of());
if (statusesToIgnore.contains(destIssue.fields.status.name.toLowerCase(Locale.ROOT))) {
// no need to apply the transition :)
return;
}
prepareTransition(sourceIssue).ifPresent(
prepareTransition(sourceIssue.fields.status, destIssue).ifPresent(
jiraTransition -> context.destinationJiraClient().transition(destinationKey, jiraTransition));
}

Expand Down Expand Up @@ -213,8 +213,18 @@ private JiraUser toUser(String value) {
return new JiraUser(context.projectGroup().users().mappedPropertyName(), value);
}

private Optional<JiraTransition> prepareTransition(JiraIssue sourceIssue) {
return statusToTransition(sourceIssue.fields.status.id).map(JiraTransition::new);
protected Optional<JiraTransition> prepareTransition(JiraSimpleObject sourceStatus, JiraIssue destIssue) {
String downstreamStatus = context.projectGroup().statuses().mapping()
.get(sourceStatus.name.toLowerCase(Locale.ROOT));
return prepareTransition(downstreamStatus, destIssue);
}

protected Optional<JiraTransition> prepareTransition(String downstreamStatus, JiraIssue destIssue) {
return Optional
.ofNullable(statusToTransition(destIssue.fields.status.name, downstreamStatus,
() -> findRequiredTransitionId(downstreamStatus, destIssue))
.orElseGet(() -> findRequiredTransitionId(downstreamStatus, destIssue).orElse(null)))
.map(JiraTransition::new);
}

protected Optional<JiraIssueLink> prepareParentLink(String destinationKey, JiraIssue sourceIssue) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraTransition;
import org.hibernate.infra.replicate.jira.service.reporting.ReportingConfig;

public class JiraIssueDeleteEventHandler extends JiraEventHandler {
public class JiraIssueDeleteEventHandler extends JiraIssueAbstractEventHandler {
private final String key;

public JiraIssueDeleteEventHandler(ReportingConfig reportingConfig, HandlerProjectContext context, Long id,
Expand Down Expand Up @@ -70,7 +70,7 @@ private void handleDeletedMovedIssue(String type) {

context.destinationJiraClient().update(destinationKey, updated);

prepareTransition()
prepareTransition(issue)
.ifPresent(transition -> context.destinationJiraClient().transition(destinationKey, transition));

context.destinationJiraClient().archive(destinationKey);
Expand All @@ -80,11 +80,12 @@ private void handleDeletedMovedIssue(String type) {
}
}

private Optional<JiraTransition> prepareTransition() {
Optional<String> deletedTransition = context.projectGroup().statuses().deletedTransition();
if (deletedTransition.isPresent()) {
private Optional<JiraTransition> prepareTransition(JiraIssue issue) {
Optional<String> deletedStatus = context.projectGroup().statuses().deletedStatus();
if (deletedStatus.isPresent()) {
prepareTransition(deletedStatus.get(), issue);
JiraTransition transition = new JiraTransition();
transition.transition = new JiraIssueTransition(deletedTransition.get());
transition.transition = new JiraIssueTransition(deletedStatus.get());

Optional<String> deletedResolution = context.projectGroup().statuses().deletedResolution();
deletedResolution.ifPresent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ public static String issueType(String projectGroup, String sourceId,
return issueType.computeIfAbsent(projectGroup, onMissing).getOrDefault(sourceId, defaultValue);
}

public static String status(String projectGroup, String sourceId, Function<String, Map<String, String>> onMissing,
String defaultValue) {
return status.computeIfAbsent(projectGroup, onMissing).getOrDefault(sourceId, defaultValue);
public static String status(String projectGroup, String transitionKey, Function<String, String> onMissing) {
return status.computeIfAbsent(projectGroup, pg -> new ConcurrentHashMap<>()).computeIfAbsent(transitionKey,
onMissing);
}

public static String linkType(String projectGroup, String sourceId, Function<String, Map<String, String>> onMissing,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package org.hibernate.infra.replicate.jira.service.jira.model.rest;

import org.hibernate.infra.replicate.jira.service.jira.model.JiraBaseObject;

public class JiraIssueTransition extends JiraBaseObject {
public String id;
public class JiraIssueTransition extends JiraSimpleObject {
public JiraSimpleObject to;

public JiraIssueTransition() {
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.hibernate.infra.replicate.jira.service.jira.model.rest;

import java.util.List;

import org.hibernate.infra.replicate.jira.service.jira.model.JiraBaseObject;

public class JiraTransitions extends JiraBaseObject {
public List<JiraIssueTransition> transitions;
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraIssueLink;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraIssueLinkTypes;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraIssueResponse;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraIssueTransition;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraIssues;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraRemoteLink;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraSimpleObject;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraTransition;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraTransitions;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraUser;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraVersion;

Expand Down Expand Up @@ -190,6 +192,18 @@ public void transition(String issueKey, JiraTransition transition) {
// do nothing
}

@Override
public JiraTransitions availableTransitions(String issueKey) {
JiraTransitions transitions = new JiraTransitions();
JiraIssueTransition transition = new JiraIssueTransition();
transition.name = "To To Do";
transition.id = "100";
transition.to = new JiraSimpleObject("1234");
transition.to.name = "To Do";
transitions.transitions = List.of(transition);
return transitions;
}

@Override
public void archive(String issueKey) {
// do nothing
Expand Down
3 changes: 3 additions & 0 deletions src/test/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ jira.project-group."hibernate".destination.api-uri=http://localhost:8081/api/jir
jira.project-group."hibernate".destination.api-user.email=user-name
jira.project-group."hibernate".destination.api-user.token=user-token
jira.project-group."hibernate".issue-link-types.default-value=10050

jira.project-group."hibernate".statuses.mapping."to\u0020do"=to do

jira.project-group."hibernate".projects.JIRATEST1.security.secret=not-a-secret
jira.project-group."hibernate".projects.JIRATEST1.project-id=10323
jira.project-group."hibernate".projects.JIRATEST1.project-key=JIRATEST2
Expand Down

0 comments on commit 3bb733d

Please sign in to comment.