ScriptRunner - transition all parent issues when child issue transitions

Janene Pappas
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
September 26, 2019

I'm using Scriptrunner for Jira Cloud. I've found the post function to transition a parent when a subtask transitions, but I would like the entire hierarchy to transition as well - Sub-task, Story and Epic. I'm not finding how to get the parent of any issue type except Sub-task. 


def transitionID = '21' // My global In Progress transition ID
def parentKey = 0
if (((Map) issue.fields.issuetype)?.name == 'Sub-task') {
parentKey = issue.fields.parent.key
} else {
What goes here?
}
// The rest call to transition the issue
def result = post("/rest/api/2/issue/${parentKey}/transitions")
.header("Content-Type", "application/json")
.body([transition: [id: transitionID]])
.asObject(Map)

// Check if the issue was transitioned correctly
// Log out the issues updated or which failed to update
if (result.status == 204) {
logger.info("The ${parentKey} issue was also transitioned by the post function.")
} else {
logger.warn("The post function failed to transition the ${parentKey}issue. ${result.status}: ${result.body}")
}

Obviously a WIP but help with this part would be appreciated 

2 answers

1 accepted

0 votes
Answer accepted
fran garcia gomera
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
September 27, 2019

A task, story name it what you want don't have a parent, they can have epic link to relate them with the epic they belong to.

Jira works with only three levels of issues:

epics
tasks (give the issuetype the name you want)
subtasks (give the issuetype the name you want)
so the level you don't have is the task to epic level jump

obvously, you can create "fake" levels via links from issue to issue or something like that, but that's just a workaround

this is the JSON that rest/api/latest/issuetype returns for one issuetype:


   "self":"https://jiraurl/rest/api/latest/issuetype/10801",
   "id":"10801",
   "description":"",
   "iconUrl":"https://jiraurl/secure/viewavatar?size=xsmall&avatarId=10316&avatarType=issuetype",
   "name":"Subtarea Petición HR",
   "subtask":true,
   "avatarId":10316
},

Only issuetypes with "subtask":true have parent issue

So maybe you should filter issues for that "subtask":true instead of the name of the subtask itself

Janene Pappas
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
October 15, 2019

The hierarchy we have includes:

Initiative
Epic
Story or Task
Subtask

If one looks at a Story issue, there is a field "Epic Link". Is this field not exposed from within the JSON? 

fran garcia gomera
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
October 16, 2019

'epic link' is treated like a customfield, in my jira is 'customfield_10001'

you can get the value of that field with

import com.atlassian.jira.component.ComponentAccessor

def customFieldManager = ComponentAccessor.getCustomFieldManager()
def cField = customFieldManager.getCustomFieldObject(xxxxx) //being xxxxx the id of the field

// or
// def cField = customFieldManager.getCustomFieldObjectByName('custon field name')

def cfValue = cField.getValue(issue)

//or
// def cfValue = issue.getCustomFieldValue(cField)

 

if you call 

{url}/rest/api/latest/issue/{issuekey}

you get a JSON with all the fields for that issue. , you also have issuetype with the info i gave you in the previous post, the status, and all the info about fields in the issue

{
"expand":"renderedFields,names,schema,operations,editmeta,changelog,versionedRepresentations",
"id":"12992",
"self":"https://url.jira.com/rest/api/latest/issue/12992",
"key":"EMB-394",
"fields":{
"customfield_10870":null,
"resolution":{
"self":"https://url.jira.com/rest/api/2/resolution/10000",
"id":"10000",
"description":"xxxxxx xxxxxx",
"name":"Listo"
},
"customfield_10871":null,
"customfield_10872":null,

"customfield_11829":null,

.... lots of other customfields...

"issuelinks":[

],
"assignee":null,
"customfield_10850":null,

.... lots of other customfields...

"issuetype":{
"self":"https://url.jira.com/rest/api/2/issuetype/10102",
"id":"10102",
"description":"Un problema que dificulta o impide el funcionamiento del producto.",
"iconUrl":"https://url.jira.com/secure/viewavatar?size=xsmall&avatarId=10303&avatarType=issuetype",
"name":"Error",
"subtask":false,
"avatarId":10303
},
"customfield_10940":null,
"customfield_10820":null,
"customfield_10941":null,

.... lots of other customfields...


"status":{
"self":"https://url.jira.com/rest/api/2/status/6",
"description":"The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.",
"iconUrl":"https://url.jira.com/images/icons/statuses/closed.png",
"name":"Cerrada",
"id":"6",
"statusCategory":{
"self":"https://url.jira.com/rest/api/2/statuscategory/3",
"id":3,
"key":"done",
"colorName":"green",
"name":"Listo"
}
},
"customfield_14810":null,

.... lots of other customfields...

"customfield_14631":null,
"project":{
"self":"https://url.jira.com/rest/api/2/project/10605",
"id":"10605",
"key":"EMB",
"name":"TO - Message Broker",
"avatarUrls":{
"48x48":"https://url.jira.com/secure/projectavatar?avatarId=10324",
"24x24":"https://url.jira.com/secure/projectavatar?size=small&avatarId=10324",
"16x16":"https://url.jira.com/secure/projectavatar?size=xsmall&avatarId=10324",
"32x32":"https://url.jira.com/secure/projectavatar?size=medium&avatarId=10324"
},

.... lots of other customfields...

"customfield_10001":"EMB-263",
"customfield_12422":null,
"customfield_12301":null,
}
}

 
Janene Pappas
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
October 16, 2019

Thank you, Fran, this was my missing piece. I have my script working now.

fran garcia gomera
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
October 17, 2019

glad to help.

0 votes
tiago santiago December 27, 2019

@Janene Pappas would you mind sharing your script please? thank you 

Janene Pappas
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
December 30, 2019

Sure! It's set to run as the Initiating User. I've also since added some more code to update a few fields as well - that's the weekly progress status stuff

The Condition is:

((Map) issue.fields.issuetype)?.name != 'Epic' & ((Map) issue.fields.issuetype)?.name != 'Bug' & ((Map) issue.fields.issuetype)?.name != 'Spike'

and the Code is: 


def transitionID = '21'
def parentIssueName = 'customfield_10014'
def parentKey = 0

// Get the parent key, based on the issue type
if (((Map) issue.fields.issuetype)?.name == 'Sub-task') {
parentKey = issue.fields.parent.key
} else {
def fields = issue.fields as Map
parentKey = fields[parentIssueName]
}

if (parentKey != 0) {
// The rest call to transition the issue
def result = post("/rest/api/2/issue/${parentKey}/transitions")
.header("Content-Type", "application/json")
.body([transition: [id: transitionID]])
.asObject(Map)

// Check if the issue was transitioned correctly
// Log out the issues updated or which failed to update
if (result.status == 204) {
logger.info("The ${parentKey} issue was also transitioned by the post function.")

// for an Epic, also transition the weekly progress status, if needed
def parentResult = get('/rest/api/2/issue/' + parentKey)
.header('Content-Type', 'application/json')
.asObject(Map)
if (parentResult.status == 200 && ((Map) parentResult.body.fields.issuetype)?.name != 'Epic') {
logger.info("Parent is not an Epic, returning")
return
}

// Specify the name of the select list field to set
def progressStatusFieldName = 'Weekly Progress Status'

// Get the Custom field to get the option value from
def customField = get("/rest/api/2/field")
.asObject(List)
.body
.find {
(it as Map).name == progressStatusFieldName
} as Map
// Check if the custom field returns a valid field and is not null
assert customField != null : "Cannot find custom field with name of: ${progressStatusFieldName}"

def progValue = (parentResult.body.fields[customField.id] as Map)?.value

if (progValue != "Not Started") {
logger.info("Progress status is ${progValue}, returning")
return
}

def progResult = put("/rest/api/2/issue/${parentKey}")
.header('Content-Type', 'application/json')
.body([
fields: [
(customField.id):[value: "On Target"] as Map
]
])
.asString()

if (progResult.status == 204) {
logger.info( "The ${customField.name} select list field was successfully updated on the ${parentKey} issue")
} else {
logger.info( "${progResult.status}: ${progResult.body}")
}

} else {
logger.warn("The post function failed to transition the ${parentKey}issue. ${result.status}: ${result.body}")
}
}

Suggest an answer

Log in or Sign up to answer