Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

Scriptrunner Update Epic Link Status based on current status of Epic and Linked Issue

Christina Hiller
Contributor
June 25, 2019

Objective: Update Epic Link Status based on current status of Epic Link and current status of the Issue being transitioned

Problem:
Consider a simple workflow: To Do > In Progress > Done
If a story is in Done status, then is transitioned to To Do or In Progress AND the Epic Link is in Done Status, then update the Epic status to In Progress

Scenarios:

Scenario 1

  • Epic 1 current status = Done
  • Story A current status = Done
  • Story B current status = Done
  • Story B status is changing to In Progress
  • Expect Story B Status updated to In Progress and Epic 1 updated to In Progress

Scenario 2

  • Epic 1 current status = In Progress
  • Story A current status = Done
  • Story B current status = Done
  • Story B status is changing to In Progress
  • Expect Story B Status updated to In Progress and Epic 1 status remains unchanged

Attempted Solution used as a Workflow Post Function:

See Screenshot below w/ error I'm receiving.  Any advice?


import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.workflow.TransitionOptions

def ACTION_ID = 21 // Repoace with the ID of the Epic action to be taken
def EPIC_STORY_LINK = "Epic-Story Link"
def STATUS_NAME = "In Progress" //Target Epic Status

def issue = issue as MutableIssue
def workflow = ComponentAccessor.workflowManager.getWorkflow(issue)
def action = workflow.allActions.find { it.id == ACTION_ID }

//getting current workflow description
def wfd = workflow.getDescriptor()
def actionName = wfd.getAction(transientVars["actionId"] as int).getName()
log.debug("Current action name: $actionName")
//

if (!action) {
log.debug "No action with id $ACTION_ID found, for workflow $workflow.name"
return
}

def user = ComponentAccessor.jiraAuthenticationContext.loggedInUser
def issueLinkManager = ComponentAccessor.issueLinkManager

def epicIssue = issueLinkManager.getInwardLinks(issue.id).find {
it.issueLinkType.name == EPIC_STORY_LINK
}?.sourceObject
if (!epicIssue) {
return
}

//If the Story Current Status is Done and Epic Link Status is Done, then update Epic Status to In Progress
if (myIssue.statusObject.name =="Done" && epicIssue.statusObject.name == "Done")
{

transitIssue(epicIssue, ACTION_ID, user)
{

MutableIssue transitIssue (Issue issue, int actionId, ApplicationUser cwdUser) {
def issueService = ComponentAccessor.issueService
def issueInputParameters = issueService.newIssueInputParameters()
issueInputParameters.setComment("This Epic automatically moved to In Progress since a previously completed story was reopened.")
issueInputParameters.setSkipScreenCheck(true)

def transitionOptions = new TransitionOptions.Builder()
.skipConditions()
.skipPermissions()
.skipValidators()
.build()

def transitionValidationResult =
issueService.validateTransition(cwdUser, issue.id, actionId, issueInputParameters, transitionOptions)

if (!transitionValidationResult.isValid()) {
log.error transitionValidationResult.errorCollection
return null
}

issueService.transition(cwdUser, transitionValidationResult).issue
}
}
}

 

workflow_prev status.png

 

 

 

1 answer

0 votes
PD Sheehan
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.
June 25, 2019

Without actually testing it, the following removes your compilation errors:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.workflow.TransitionOptions

def ACTION_ID = 21 // Replace with the ID of the Epic action to be taken
def EPIC_STORY_LINK = "Epic-Story Link"
def STATUS_NAME = "In Progress" //Target Epic Status

def issue = issue as MutableIssue
def workflow = ComponentAccessor.workflowManager.getWorkflow(issue)
def action = workflow.allActions.find { it.id == ACTION_ID }

//getting current workflow description
def wfd = workflow.getDescriptor()
def actionName = wfd.getAction(transientVars["actionId"] as int).getName()
log.debug("Current action name: $actionName")
//

if (!action) {
log.debug "No action with id $ACTION_ID found, for workflow $workflow.name"
return
}

def user = ComponentAccessor.jiraAuthenticationContext.loggedInUser
def issueLinkManager = ComponentAccessor.issueLinkManager

def epicIssue = issueLinkManager.getInwardLinks(issue.id).find {
it.issueLinkType.name == EPIC_STORY_LINK
}?.sourceObject
if (!epicIssue) {
return
}

//If the Story Current Status is Done and Epic Link Status is Done, then update Epic Status to In Progress
if (issue.status.name =="Done" && epicIssue.status.name == "Done"){
def issueService = ComponentAccessor.issueService
def issueInputParameters = issueService.newIssueInputParameters()
issueInputParameters.setComment("This Epic automatically moved to In Progress since a previously completed story was reopened.")
issueInputParameters.setSkipScreenCheck(true)

def transitionOptions = new TransitionOptions.Builder()
.skipConditions()
.skipPermissions()
.skipValidators()
.build()

def transitionValidationResult = issueService.validateTransition(user, issue.id, ACTION_ID, issueInputParameters, transitionOptions)

if (!transitionValidationResult.isValid()) {
log.error transitionValidationResult.errorCollection
return null
}

def transitionResult = issueService.transition(user, transitionValidationResult)
if(!transitionResult.isValid()){
log.error transitionResult.errorCollection
return null
}

}

I don't see any need to encapsulate the transition into a "transitIssue" method (that's what it looks like you were trying to do).

If you were insistent in doing that, the call to the method can't include the method.

Try this instead:

if (myIssue.statusObject.name =="Done" && epicIssue.statusObject.name == "Done") 
{
transitIssue(epicIssue, ACTION_ID, user)
}


MutableIssue transitIssue (Issue issue, int actionId, ApplicationUser cwdUser) {
/* ... */
}
Christina Hiller
Contributor
June 30, 2019

Thanks! I'll try it out and let you know how it goes.

Suggest an answer

Log in or Sign up to answer
TAGS
atlassian, ace, atlassian community event, donation, girls who code, women in tech, malala fund, plan international, kudos, community badge, badge, atlassian badge, International Women’s month, International Women’s Day, women's month, women's day

10 for Change at Atlassian Community Events

Show up and give back by attending an Atlassian Community Event: we’ll donate $10 for every event attendee in March!

Join an Atlassian Community Event!
AUG Leaders

Upcoming Jira Events