Hi all!
I have a big trouble with deleting issues. I only can't delete issue that has subtasks. I have some listeners that set up on some delete events (IssueDeletedEvent, IssueLinkDeletedEvent and PreDeleteEvent). Processes in them are not simple but clearly - update custom field in subtask only or update custom field in task/subtask. Listener starts its work if the event was thrown by subtask.
When I try to delete subtask is no problem, but when I try to delete task (that has subtasks of course) - appears window with information that timeout was exceeded.
When I disable code part that responsible for update custom field value all works fine.
May be who met this problem and knows how to resolve this?
And what order of deleting issue? A can't find this information in web, it will very helpful for me.
Thanks!
/*
Event: IssueLinkDeleted
Note:
Update two custom fields cfOne and cfTwo
fields are collections with options
Field values in epic contain all field values in tasks
Field values in task contain all field values in subtask
Field values mutable only in subtasks
Create and delete link events set up only to subtasks
All ids was replaced by patterns
*/
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.customfields.option.Option
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.link.IssueLinkManager
import com.atlassian.jira.issue.link.IssueLink
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import org.apache.log4j.Level
import org.apache.log4j.Logger
class Managers {
static final CustomFieldManager CUSTOM_FIELD_MANAGER = ComponentAccessor.getCustomFieldManager()
static final IssueLinkManager ISSUE_LINK_MANAGER = ComponentAccessor.getIssueLinkManager()
static final IssueManager ISSUE_MANAGER = ComponentAccessor.getIssueManager()
}
class Ids {
static final Long ONE_CF_ID = 11111L // custom field
static final Long TWO_CF_ID = 11111L // custom field
static final String SUBTASK_ISSUE_TYPE_ID = "11111"
static final Long EPIC_LINK_ID = 11111L
static final Long SUB_TASK_ISSUE_LINK_TYPE_ID = 11111L
}
Logger log = Logger.getLogger("!!!")
log.setLevel(Level.DEBUG)
IssueLink issueLink = event.getIssueLink()
Issue epic = null;
if (issueLink.getIssueLinkType().getId() == Ids.SUB_TASK_ISSUE_LINK_TYPE_ID) {
// link between task and subtask (subtask is removed)
Issue task = issueLink.getSourceObject();
epic = getEpicByTask(task);
} else if (issueLink.getIssueLinkType().getId() == Ids.EPIC_LINK_ID) {
// link between epic and task (task is removed)
epic = issueLink.getSourceObject();
}
if (epic) {
log.debug("EPIC_KEY = ${epic.getKey()}")
Set<Option> cfOneNewValues = updateTasksAndGetAllOptionsFromTasks(epic, Ids.ONE_CF_ID, log)
Set<Option> cfTwoNewValues = updateTasksAndGetAllOptionsFromTasks(epic, Ids.TWO_CF_ID, log)
updateEpic(epic, Ids.ONE_CF_ID, cfOneNewValues)
updateEpic(epic, Ids.TWO_CF_ID, cfTwoNewValues)
}
log.debug("script end")
private Issue getEpicByTask(Issue task) {
if (task) {
List<IssueLink> inwards = Managers.ISSUE_LINK_MANAGER.getInwardLinks(task.getId())
for (IssueLink link : inwards) {
log.debug(link)
Long currentLinkId = link.getIssueLinkType().getId()
if (currentLinkId == Ids.EPIC_LINK_ID) {
return link.getSourceObject()
}
}
}
return null;
}
private Set<Option> updateTasksAndGetAllOptionsFromTasks(Issue epic, Long cfId, Logger log) {
Set<Option> options = new HashSet<>()
List<IssueLink> links = Managers.ISSUE_LINK_MANAGER.getOutwardLinks(epic.getId())
for (IssueLink link : links) {
Long currentLinkId = link.getIssueLinkType().getId()
if (currentLinkId == Ids.EPIC_LINK_ID) {
Issue task = link.getDestinationObject()
log.debug("FOUND TASK ${task}")
CustomField cfObj = Managers.CUSTOM_FIELD_MANAGER.getCustomFieldObject(cfId)
Set<Option> prevVal = task.getCustomFieldValue(cfObj) as Set<Option>
Set<Option> newVal = getFieldOptionsFromSubtasks(task, cfId, Ids.SUB_TASK_ISSUE_LINK_TYPE_ID, log)
log.debug("NEW TASK VALUE BY SUBTASK ${newVal}")
if (prevVal != newVal) {
cfObj.updateValue(null, task, new ModifiedValue(prevVal, newVal), new DefaultIssueChangeHolder())
}
options.addAll(newVal)
}
}
return options
}
private Set<Option> getFieldOptionsFromSubtasks(Issue issue, Long cfId, Long linkId, Logger log) {
Set<Option> options = new HashSet<>()
List<IssueLink> links = Managers.ISSUE_LINK_MANAGER.getOutwardLinks(issue.getId())
for (IssueLink link : links) {
Long currentLinkId = link.getIssueLinkType().getId()
if (currentLinkId == linkId) {
Issue child = link.getDestinationObject()
Set<Option> cfValues = child.getCustomFieldValue(Managers.CUSTOM_FIELD_MANAGER.getCustomFieldObject(cfId)) as Set<Option>
if (cfValues) {
options.addAll(cfValues)
}
}
}
return options
}
private void updateEpic(Issue epic, Long cfId, Set<Option> values) {
CustomField customField = Managers.CUSTOM_FIELD_MANAGER.getCustomFieldObject(cfId)
Set<Option> prevVal = epic.getCustomFieldValue(customField) as Set<Option>
if (prevVal != values) {
customField.updateValue(null, epic, new ModifiedValue(prevVal, values), new DefaultIssueChangeHolder())
}
}