Automate Epic Custom Field Sum


Sum up the total of custom field values of all related epic issues, including sub-tasks.


There is a project that has a custom field named as "Cost". This custom field is available for all issue types. When an issue or sub-task is created or updated, you can define value of "Cost" field. If the issue or sub-task is related with an epic, "Cost" field of the epic is automatically calculated and the result is the sum of all related issues and sub-tasks "Cost" fields.

Good to Know

  • This script can bet set as a listener for "Issue created" and "Issue updated". So once an issue is created or updated sum field value will be recalculated.
  • Issues related with an epic are the ones that are child of the epic or child of those issues. To do this, the JQL "linkedissue" is used, but is needed to get rid of the epic issue itself.


Jira Jira

//Epic Link Custom Field ID final epicLinkCf = get("/rest/api/2/field") .asObject(List) .body .find { (it as Map).name == 'Epic Link' } as Map //Number Custom Field ID final numberCf = get("/rest/api/2/field") .asObject(List) .body .find { (it as Map).name == '' } as Map def issueFields = get("/rest/api/2/issue/$issue.key") .asObject(Map) .body .fields as Map //If issue has no parent or is not related with an epic, the script will not be executed def issueParent = issueFields.find { it.key == 'parent' }?.value as Map def epicKey = issueFields.find { it.key == }?.value if (!epicKey && !issueParent) { return } //If the issue is sub-task, Epic Key is obtained from the parent issue if (issueParent) { def parentIssueField = get("/rest/api/2/issue/$issueParent.key") .asObject(Map) .body .fields as Map epicKey = parentIssueField.find { it.key == }.value } //Obtain all related epic issues, including sub-tasks def allChildIssues = get("/rest/api/2/search") .queryString('jql', "linkedissue = $epicKey") .header('Content-Type', 'application/json') .asObject(Map) .body .issues as List def sum = 0 def issues = allChildIssues.findAll { it.key != epicKey } issues.each { def fields = get("/rest/api/2/issue/$it.key") .header('Content-Type', 'application/json') .asObject(Map) .body .fields as Map def numberCfValue = fields[] ?: 0 sum += numberCfValue as Integer } put("/rest/api/2/issue/$epicKey") .header("Content-Type", "application/json") .body([ fields: [ ( sum ] ]).asString()
Discovered an issue? Report it here

Suggested for you