Come for the products,
stay for the community

The Atlassian Community can help you and your team get more value out of Atlassian products and practices.

Atlassian Community about banner
4,293,293
Community Members
 
Community Events
165
Community Groups

Set Linked Issue dependencies via post-function with JMWE or Scriptrunner

Hi all,

I'm wondering if there is a way to automatically set issue links through Scriptrunner or JMWE post-function.

So far, I have four 'create/clone issue(s)' post-functions set for the Epic workflow in a project to automatically create and nest four different types of issues under the triggering epic:

Screen Shot 2021-09-14 at 5.14.35 PM.png

 

Each of the Issues in epic (Define Requirements, Solutions Analysis, Implementation, and Rollout) have their own set of sub-tasks which are also auto-generated via post-functions set in workflows unique to each issue type. For example, Rollout:

 

Screen Shot 2021-09-14 at 5.15.48 PM.png

Almost all the issues created have linked issue dependencies:

Screen Shot 2021-09-14 at 5.49.09 PM.png

This is where I'm stuck. I'm not exactly sure how to set the 'Linked Issues' field to direct to issues that aren't directly involved in the automation. For instance, I have a 'Create / Clone Issue(s) Post-function' set in the create transition for the Rollout workflow that's responsible for creating the Update Documentation Sub-task nested under Rollout:

Screen Shot 2021-09-14 at 6.32.50 PM.png

In Groovy, what expression would work to set a "blocks" link to the parent issue's epic, as well as a "is blocked by" link to a separate sub-task nested in the parent issue called Plan Communications?

2 answers

import com.innovalog.workflow.utils.IssueLinkWithDirection

issue.getIssueLinks().findAll{
  it.direction == com.atlassian.jira.issue.link.Direction.IN &&
  it.sourceObject.issueType.name == "Bug" &&
  it.issueLinkType.id == 10201
}.collect{
  IssueLinkWithDirection link = new IssueLinkWithDirection(issue, it)
  link.changeLinkTypeId(10700)
  return link
}

 For a simpler use case, others may refer to above

  • condition based on link's property
  • update the link type for the new link
0 votes
Fabian Lim Community Leader Sep 14, 2021

Hi @Ian Balas

Since you are using jmwe already, I would just script everything from with the groovy script post function.

Here is an example on how to link tickets: https://library.adaptavist.com/entity/add-or-update-the-issue-link-for-an-issue-in-jira

Thanks

Thanks for the reply @Fabian Lim

So I tried using that snippet for my use case to link the Update Documentation sub-task that's being created here to the most recently created Plan Communications sub-task (both of which are nested under the same Rollout parent issue) indicating that the Update Documentation sub-task "is blocked by" the Plan Communications sub-task. I added this as a post-creation script in the 'Create / Clone Issue(s)' post-function that creates the Update Documentation sub-task:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.link.IssueLinkTypeManager

def issueManager = ComponentAccessor.issueManager

// the issue key to create the link from
final String sourceIssueKey = newIssue.getAsString("issuekey")

// the issue key to create the link to
final String destinationIssueKey =
issueManager.getIssueIdsForProject(issue.projectObject.id)
.sort()
.reverse()
.find { issue.getAsString("issuetype") == "Plan Communications" }

// the name of the issue link
final String issueLinkName = "Is Blocked By"

// the sequence of the link
final Long sequence = 1L

def loggedInUser = ComponentAccessor.jiraAuthenticationContext.loggedInUser
def issueLinkTypeManager = ComponentAccessor.getComponent(IssueLinkTypeManager)

def sourceIssue = issueManager.getIssueByCurrentKey(sourceIssueKey)
def destinationIssue = issueManager.getIssueByCurrentKey(destinationIssueKey)
assert sourceIssue && destinationIssue: "Source and/or Destination Issue(s) does not exist"

def availableIssueLinkTypes = issueLinkTypeManager.issueLinkTypes
def linkType = availableIssueLinkTypes.findByName(issueLinkName)
assert linkType : "Could not find link type with name $issueLinkName. Available issue link types are ${availableIssueLinkTypes*.name.join(", ")}"

ComponentAccessor.issueLinkManager.createIssueLink(sourceIssue.id, destinationIssue.id, linkType.id, sequence, loggedInUser)

 

I seem to get an error trying to pull the issue key for the new issue created by the post-function as a whole:

Message:
groovy.lang.MissingPropertyException: No such property: newIssue for class: script_ed72a80b03323e9341f643bdd9c8b891
Stack:
org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:65)
org.codehaus.groovy.runtime.callsite.PogoGetPropertySite.getProperty(PogoGetPropertySite.java:51)
org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:309)
script_ed72a80b03323e9341f643bdd9c8b891.run(script_ed72a80b03323e9341f643bdd9c8b891.groovy:7)

This I'm not sure why I'm getting this error since this issue variable should be valid to call after the issue is created. 

Fabian Lim Community Leader Sep 15, 2021

Hi @Ian Balas

I would recommend you use the groovy postfuntion where you would create the all the tickets and linkages.  You will then have all the keys of the issues created in one place. Using separate postfunctions to create/clone and then link issues may not be the right approach.  

Regards 

Fabian Lim Community Leader Sep 23, 2021

@Ian Balas

Were you able to figure this one out? If not I can paste some sample code that I use.

Make sure you mentioned me so I get notified.

@Fabian Lim 

No I can't seem to figure this part out. That would be helpful if you have.

Basically, I want the source issue to be the subtask that's created from the post-function itself, and the destination issue(s) have to be the Plan Communications sub-task that's part of the same Rollout parent issue (with an outward issue link of "is blocked by"), as well as the epic of the parent Rollout issue (with an outward link of "Blocks").

@Fabian Lim 

I've actually made some progress on this since my last comment.

Here's my updated post-creation script:

 

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.config.SubTaskManager
import com.atlassian.jira.issue.CustomFieldManager;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.issue.link.IssueLinkManager;
import com.atlassian.jira.security.JiraAuthenticationContext

def issueManager = ComponentAccessor.issueManager

// the issue key to create the link from
final String sourceIssueKey = transientVars.newIssue.getAsString("issuekey")

// the epic key to create the link to
final epicLinkFieldName = "customfield_10001"
CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager();
def epicLinkField = customFieldManager.getCustomFieldObject(epicLinkFieldName)
final String epicIssueKey = issueManager.getIssueObject((String)issue.getCustomFieldValue(epicLinkField))

// the "Plan Communications" sub-task from parent issue to link to
SubTaskManager subTaskManager = ComponentAccessor.getSubTaskManager();
Collection subTasks = issue.getSubTaskObjects()
final String destinationIssueKey =
subTasks.each {
find { issue.getAsString("issuetype") == "Plan Communications" }
}.key

// the sequence of the link
final Long sequence = 1L

def loggedInUser = ComponentAccessor.jiraAuthenticationContext.loggedInUser
JiraAuthenticationContext authContext = ComponentAccessor.getJiraAuthenticationContext();
IssueLinkManager issueLinkManager = ComponentAccessor.getIssueLinkManager()

def sourceIssue = issueManager.getIssueByCurrentKey(sourceIssueKey)
def epicIssue = issueManager.getIssueByCurrentKey(epicIssueKey)
def destinationIssue = issueManager.getIssueByCurrentKey(destinationIssueKey)

assert sourceIssue && epicIssue: "Source and/or Destination Issue(s) does not exist"

// issue-link id of "Blocks" is 10000
ComponentAccessor.issueLinkManager.createIssueLink(sourceIssue.id, epicIssue.id, Long.parseLong("10000"), sequence, loggedInUser)
ComponentAccessor.issueLinkManager.createIssueLink(destinationIssue.id, sourceIssue.id, Long.parseLong("10000"), sequence, loggedInUser)

With this, I was able to set an outward link of "Blocks" from the  Update Documentation  subtask to the parent issue's epic with my update above.

Now the only thing that I have to figure out is how to get the issue key of the Plan Communications subtask which is nested under the same parent (created in a postfunction before this one). For this, I'm met with an error:

Caused by: com.atlassian.jira.workflow.WorkflowException: An error occurred while executing a Create / Clone Issue(s) post-function: Cannot get property 'id' on null object : root cause: Cannot get property 'id' on null object

How could this be? I figured it would pick up on a subtask from the parent issue, of issue type "Plan Communications".

Suggest an answer

Log in or Sign up to answer
TAGS
Community showcase
Published in Jira Software

Upcoming changes to epic fields in company-managed projects

👋 Hi there Jira Community! A few months ago we shared with you plans around renaming epics in your company-managed projects. As part of these changes, we highlighted upcoming changes to epics on...

14,097 views 34 44
Read article

Community Events

Connect with like-minded Atlassian users at free events near you!

Find an event

Connect with like-minded Atlassian users at free events near you!

Unfortunately there are no Community Events near you at the moment.

Host an event

You're one step closer to meeting fellow Atlassian users at your local event. Learn more about Community Events

Events near you