Why do my listeners on delete events interfere to delete issues?

Dmitrii March 16, 2021

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())
}
}

2 answers

0 votes
Nic Brough -Adaptavist-
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
March 17, 2021

If you're going to delete issues (recommendation - don't, certainly not automatically, but that's not the point of your question), you must stagger the issue/subtask delete.

Sub-tasks have to have a parent issue, stripping their parent away breaks in many "interesting" ways.  You must delete them before touching the parent.

0 votes
Mario Carabelli March 17, 2021

I didn't ahve this problem in the past so I can'T point you to a solution directly but this sounds like there is an exception thrown somewhere in your code if you delete a task with subtasks, which leads to your timeout. Most likely your listeners on your subtasks somehow assume logically that there is a (parent-)task present and if you try to delete it this assumptions fails (by throwing an exception that the "task-value" cant be NULL, or something similar. 

To troubleshoot and find the problem I would enable logging for your listeners (https://docs.adaptavist.com/sfj/set-logging-to-help-debug-your-scripts-11993359.html), trigger the timeout and then check your logs at the time of your test for exceptions related to your problem.

Dmitrii March 17, 2021

I have been using logging and I have no errors or exception there. I also thought that a parent of subtask doesn't exist more and the problem in that, but when listener starts - the parent exists (I had checked that by logs).

Mario Carabelli March 17, 2021

mhh that is strange. Do you mind sharing your code? Maybe a second pair of eyes sees the error.

Dmitrii March 17, 2021
/*

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 = 31510L // custom field
static final Long TWO_CF_ID = 35916L // 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())
}
}
Dmitrii March 17, 2021
/*

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 = 31510L // custom field
static final Long TWO_CF_ID = 35916L // 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())
}
}
Dmitrii March 17, 2021
/*

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())
}
}
Dmitrii March 17, 2021
/*

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;
}

Dmitrii March 17, 2021

I add listener code. Want to add that this problem is meeting in another listeners and each has some delete event and lines contained function with update custom field values. If I remove line that responsible for update custom field then I can delete a task

Mario Carabelli March 20, 2021

I tried but unfortunately I cant find the Error. Maybe you should reconsider your approach like Nic mentioned.

 a

Suggest an answer

Log in or Sign up to answer