Skip to content

Commit

Permalink
Handling of Epic labels and links
Browse files Browse the repository at this point in the history
  • Loading branch information
marko-bekhta committed Oct 25, 2024
1 parent 47cc44b commit 3c3690a
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 2 deletions.
31 changes: 30 additions & 1 deletion src/main/java/org/hibernate/infra/replicate/jira/JiraConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ interface JiraProjectGroup {
* Mapping of upstream issue types to downstream ones. Please make sure to
* review your project scheme to see which issue types are available.
*/
ValueMapping issueTypes();
IssueTypeValueMapping issueTypes();

/**
* Depending on your downstream JIRA permission schema configuration, Service
Expand Down Expand Up @@ -234,6 +234,35 @@ interface IssueLinkTypeValueMapping extends ValueMapping {
String parentLinkType();
}

interface IssueTypeValueMapping extends ValueMapping {
/**
* @return the name of the custom field that represents the epic link field.
* Apparently there is no clean way to attach issues to an epic, and a
* possible workaround is to use the custom filed (that differs from
* instance to instance) that represents the Epic link key.
* <p>
* A possible alternative could've been <a href=
* "https://developer.atlassian.com/server/jira/platform/rest/v10000/api-group-epic/#api-agile-1-0-epic-epicidorkey-issue-post">Move
* issues to a specific epic</a> but it might not be available on all
* instance types.
* <p>
* If value is not provided in the configuration, then tickets will not
* be linked to epics during the sync.
*/
Optional<String> epicLinkKeyCustomFieldName();

/**
* @return The name of a custom field that represents the "epic name" i.e.
* epic-short-label in the upstream (source) Jira instance.
*/
Optional<String> epicLinkSourceLabelCustomFieldName();
/**
* @return The name of a custom field that represents the "epic name" i.e.
* epic-short-label in the downstream (destination) Jira instance.
*/
Optional<String> epicLinkDestinationLabelCustomFieldName();
}

interface UserValueMapping extends ValueMapping {
/**
* @return the name of the property to apply the assignee value to. With Jira
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.util.Objects;
import java.util.Optional;

import org.hibernate.infra.replicate.jira.JiraConfig;
import org.hibernate.infra.replicate.jira.service.jira.HandlerProjectContext;
import org.hibernate.infra.replicate.jira.service.jira.client.JiraRestException;
import org.hibernate.infra.replicate.jira.service.jira.model.rest.JiraFields;
Expand Down Expand Up @@ -128,6 +129,24 @@ protected JiraIssue issueToCreate(JiraIssue sourceIssue) {
destinationIssue.fields.assignee = JiraUser.unassigned(context.projectGroup().users().mappedPropertyName());
}

if (!isSubTaskIssue(sourceIssue.fields.issuetype) && sourceIssue.fields.parent != null) {
if (isEpicIssue(sourceIssue.fields.parent.fields.issuetype)) {
JiraConfig.IssueTypeValueMapping issueTypes = context.projectGroup().issueTypes();
issueTypes.epicLinkKeyCustomFieldName().ifPresent(epicLinkCustomFieldName -> destinationIssue.fields
.properties().put(epicLinkCustomFieldName, toDestinationKey(sourceIssue.fields.parent.key)));
}
}
if (isEpicIssue(sourceIssue.fields.issuetype)) {
// Try to set an epic label ... obviously it is a custom field >_< ...
JiraConfig.IssueTypeValueMapping issueTypes = context.projectGroup().issueTypes();
Object sourceEpicLabel = issueTypes.epicLinkSourceLabelCustomFieldName()
.map(sourceIssue.fields.properties()::get).orElse(sourceIssue.fields.summary);

issueTypes.epicLinkDestinationLabelCustomFieldName()
.ifPresent(epicLinkDestinationLabelCustomFieldName -> destinationIssue.fields.properties()
.put(epicLinkDestinationLabelCustomFieldName, sourceEpicLabel));
}

return destinationIssue;
}

Expand All @@ -140,7 +159,10 @@ private Optional<JiraTransition> prepareTransition(JiraIssue sourceIssue) {
}

protected Optional<JiraIssueLink> prepareParentLink(String destinationKey, JiraIssue sourceIssue) {
if (sourceIssue.fields.parent != null) {
// we only add a link for sub-tasks (the ones that have a corresponding types).
// Issues assigned to an epic, can also have a parent.
// but for those we won't add an extra link:
if (sourceIssue.fields.parent != null && isSubTaskIssue(sourceIssue.fields.issuetype)) {
String parent = toDestinationKey(sourceIssue.fields.parent.key);
// we don't really need it, but as usual we are making sure that the issue is
// available downstream:
Expand All @@ -164,6 +186,20 @@ protected Optional<JiraIssueLink> prepareParentLink(String destinationKey, JiraI
}
}

private boolean isSubTaskIssue(JiraSimpleObject issueType) {
if (issueType == null) {
return false;
}
return Boolean.parseBoolean(Objects.toString(issueType.properties().get("subtask"), null));
}

private boolean isEpicIssue(JiraSimpleObject issueType) {
if (issueType == null) {
return false;
}
return "epic".equalsIgnoreCase(issueType.name);
}

private String prepareDescriptionQuote(JiraIssue issue) {
URI issueUri = createJiraIssueUri(issue);

Expand Down

0 comments on commit 3c3690a

Please sign in to comment.