It's not the same without you

Join the community to find out what other Atlassian users are discussing, debating and creating.

Atlassian Community Hero Image Collage

Script Runner: Subtask creates other subtask on same parent (postfunction)

Javier Salvay Jul 11, 2017

Hi,

Probably somebody can help me out with this. I'm wondering if there is possible to create (via post-function) on a subtask, to create other one.

In that way, if Subtask A was transitioned, a post-function creates Subtask B.

 

Is there anybody that can help me out?

Thanks!

jay

6 answers

0 votes

Hello Javier.

Yes this is very possible. 

This has been discussed before, Thanos added an answer to this a while ago. I would suggest you do a thorough search in google before posting, since you can come up with a lot of information that is already out there. 

But since I'm here, I'll tell you how to do this.

You got two options:

The hard way

Basically you need to create a custom scriptfunction that triggers on your transition. 

The customScript should check that the issueType is a subtask, and if it isn't, it shouldn't do anything, but if it is, it should trigger creation of a subtask.

The easy way

However you will find this easier:

Go to postfunctions and add "create subtask" on your transition,

The screen should look like this:

Screen Shot 2017-07-12 at 11.01.23.pngIn the condition field, you should check for the original Issuetype, and if it isn't subtask, you should return false, and if it is, you should return true.

Does this help?

Cheers!

DYelamos

 

Javier Salvay Jul 13, 2017

Hi Daniel, Thanks for your reply. So, I have tried the easy way and it is working perfectly on the parent issue (postfuncion that creates a sub-task). However, it is not working when the post-function is on the subtask (that is on the same parent), it does nothing.

I updated to the latest version, but it does not work anyway. So, can you please help me out to understand what is going on?

Since I'm getting some presure here at work, I have done this:

1) set a post-function in the sub-task A,

2) that sub-task A ask to the parent issue to execute another post-function in order to create a sub-task B. 

 

Thanks again!

Eduardo Seixas Jul 17, 2017

Hello @Daniel Yelamos [Adaptavist],

How can I write the script to do this? (The hard way)

I need a script to put inside of one transition in the subtask workflow, to generate other one subtask in your same parent.
They subtasks will be sisters.

 

 

E.g.:

- Parent A
-- Subtask A1 in parent A
--- The transition nº 100 in the workflow of Subtask A1 have the script to generate a new subtask

When execute the transition nº 100 in the Subtask A1, will be created the Subtask A2 like a sister of the Subtask A1 in parent A

 

Being thus:

- Parent A
-- Subtask A1
-- Subtask A2 (generated by Subtask A1)

Thanos Batagiannis [Adaptavist] Community Leader Jul 17, 2017

Hi Eduardo,

Try a custom script post funtion in the subtask's workflow. You script should be similar to 

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.MutableIssue

def issue = issue as MutableIssue

// if the issue in transition is not subtask then do nothing
if (! issue.isSubTask())
return

// get the parent issue
def parentIssue = issue.parentObject

def issueFactory = ComponentAccessor.getIssueFactory()
def subTaskManager = ComponentAccessor.getSubTaskManager()
def constantManager = ComponentAccessor.getConstantsManager()
def issueManager = ComponentAccessor.getIssueManager()

def asUser = ComponentAccessor.userManager.getUserByKey("bot")
def newSubTask = issueFactory.getIssue()

newSubTask.setSummary("A new subtask")
newSubTask.setParentObject(parentIssue)
newSubTask.setPriorityObject(issue.priority) // copy the priority from the subtask in transition
newSubTask.setProjectObject(parentIssue.getProjectObject())
newSubTask.setIssueTypeId(constantManager.getAllIssueTypeObjects().find { it.getName() == "Sub-task" }.id)

// Add any other fields you want for the newly created sub task ...

Map<String,Object> newIssueParams = ["issue" : newSubTask] as Map<String,Object>
issueManager.createIssueObject(asUser, newIssueParams)
subTaskManager.createSubTaskIssueLink(parentIssue, newSubTask, asUser)
log.info "Issue with summary ${newSubTask.summary} created"

Please let me know if this does the trick

kind regards, Thanos 

Eduardo Seixas Jul 17, 2017

Hi Thanos,

 

I recieved this error:

 

2017-07-17 13:56:47,679 ERROR [workflow.ScriptWorkflowFunction]: *************************************************************************************
2017-07-17 13:56:47,681 ERROR [workflow.ScriptWorkflowFunction]: Script function failed on issue: CMC-1030, actionId: 761, file: <inline script>
com.atlassian.jira.exception.CreateException: An unknown exception occured executing Validator com.atlassian.jira.workflow.SkippableValidator@bc1eaa1: root cause: java.lang.NullPointerException
 at com.atlassian.jira.issue.managers.DefaultIssueManager.createIssue(DefaultIssueManager.java:588)
 at com.atlassian.jira.issue.managers.DefaultIssueManager.createIssue(DefaultIssueManager.java:494)
 at com.atlassian.jira.issue.managers.DefaultIssueManager.createIssueObject(DefaultIssueManager.java:599)
 at com.atlassian.jira.issue.managers.RequestCachingIssueManager.createIssueObject(RequestCachingIssueManager.java:198)
 at com.atlassian.jira.issue.IssueManager$createIssueObject$1.call(Unknown Source)
 at Script6854.run(Script6854.groovy:30)
Caused by: com.atlassian.jira.workflow.WorkflowException: An unknown exception occured executing Validator com.atlassian.jira.workflow.SkippableValidator@bc1eaa1: root cause: java.lang.NullPointerException
 at com.atlassian.jira.workflow.OSWorkflowManager.createIssue(OSWorkflowManager.java:760)
 at com.atlassian.jira.issue.managers.DefaultIssueManager.createIssue(DefaultIssueManager.java:580)
 ... 5 more
Caused by: com.opensymphony.workflow.WorkflowException: An unknown exception occured executing Validator com.atlassian.jira.workflow.SkippableValidator@bc1eaa1: root cause: java.lang.NullPointerException
 at com.opensymphony.workflow.AbstractWorkflow.verifyInputs(AbstractWorkflow.java:1523)
 at com.opensymphony.workflow.AbstractWorkflow.transitionWorkflow(AbstractWorkflow.java:1203)
 at com.opensymphony.workflow.AbstractWorkflow.initialize(AbstractWorkflow.java:615)
 at com.atlassian.jira.workflow.OSWorkflowManager.createIssue(OSWorkflowManager.java:741)
 ... 6 more
Caused by: java.lang.NullPointerException
 at com.atlassian.jira.workflow.validator.AbstractPermissionValidator.hasUserPermission(AbstractPermissionValidator.java:38)
 at com.atlassian.jira.workflow.validator.PermissionValidator.validate(PermissionValidator.java:37)
 at com.atlassian.jira.workflow.SkippableValidator.validate(SkippableValidator.java:45)
 at com.opensymphony.workflow.AbstractWorkflow.verifyInputs(AbstractWorkflow.java:1512)
 ... 9 more

 

 

 

Thanks. 

Thanos Batagiannis [Adaptavist] Community Leader Jul 17, 2017

Hi Eduardo, 

Did you change the 

def asUser = ComponentAccessor.userManager.getUserByKey('bot')

to point to a userkey that has permissions to create issues ? 

0 votes
Eduardo Seixas Jul 17, 2017

Sorry Thanos, I forgot this detail. 

 

Can you tell me how I can add in this script to link the two subtasks?

Thanos Batagiannis [Adaptavist] Community Leader Jul 17, 2017

Add the following lines in the end of your script 

def sourceIssueId = issue.id
def destinationIssueId = newSubTask.id

def linkTypeId = ComponentAccessor.getComponent(IssueLinkTypeManager).issueLinkTypes.find {it.name == "Cloners"}?.id
if (linkTypeId) {
ComponentAccessor.issueLinkManager.createIssueLink(sourceIssueId, destinationIssueId, linkTypeId, 0L, asUser)
}
else {
log.warn "Could not find link type with name Cloners"
}

 Now this will create a clone issue between the subtask in transition and the new subtask. Change the name of the issue type you want to set. 

hope that helps, 

Thanos

Eduardo Seixas Jul 17, 2017 • edited

Thanos,

 

If I use this lastesd lines, I receive the error:

2017-07-17 15:02:21,243 ERROR [workflow.ScriptWorkflowFunction]: *************************************************************************************
2017-07-17 15:02:21,243 ERROR [workflow.ScriptWorkflowFunction]: Script function failed on issue: CMC-1030, actionId: 761, file: <inline script>
java.lang.NullPointerException
 at com.atlassian.jira.issue.link.DefaultIssueLinkManager.getIssueLink(DefaultIssueLinkManager.java:373)
 at com.atlassian.jira.issue.link.DefaultIssueLinkManager.createIssueLink(DefaultIssueLinkManager.java:83)
 at com.atlassian.jira.issue.link.IssueLinkManager$createIssueLink$1.call(Unknown Source)
 at Script6897.run(Script6897.groovy:33)


But If I use the "Inward Description" of the link (e.g. "is cloned by"), I'm not receive the error, create other subtask, but don't links the subtasks.

 

Eduardo Seixas Jul 17, 2017 • edited

The script now:

 

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

def issue = issue as MutableIssue

// if the issue in transition is not subtask then do nothing
if (! issue.isSubTask())
return

// get the parent issue
def parentIssue = issue.parentObject

def issueFactory = ComponentAccessor.getIssueFactory()
def subTaskManager = ComponentAccessor.getSubTaskManager()
def constantManager = ComponentAccessor.getConstantsManager()
def issueManager = ComponentAccessor.getIssueManager()

def asUser = ComponentAccessor.userManager.getUserByKey("user")
def newSubTask = issueFactory.getIssue()

newSubTask.setSummary("A new subtask test")
newSubTask.setParentObject(parentIssue)
newSubTask.setPriorityObject(issue.priority) // copy the priority from the subtask in transition
newSubTask.setProjectObject(parentIssue.getProjectObject())
newSubTask.setIssueTypeId(constantManager.getAllIssueTypeObjects().find { it.getName() == "Licensing (new)" }.id)

def sourceIssueId = issue.id
def destinationIssueId = newSubTask.id

def linkTypeId = ComponentAccessor.getComponent(IssueLinkTypeManager).issueLinkTypes.find {it.name == "is cloned by"}?.id
if (linkTypeId) {
ComponentAccessor.issueLinkManager.createIssueLink(sourceIssueId, destinationIssueId, linkTypeId, 0L, asUser)
}
else {
log.warn "Could not find link type with name is cloned by"
}

// Add any other fields you want for the newly created sub task ...

Map<String,Object> newIssueParams = ["issue" : newSubTask] as Map<String,Object>
issueManager.createIssueObject(asUser, newIssueParams)
subTaskManager.createSubTaskIssueLink(parentIssue, newSubTask, asUser)
log.info "Issue with summary ${newSubTask.summary} created"

Thanos Batagiannis [Adaptavist] Community Leader Jul 17, 2017

Hey eduardo, 

As I mentioned you have to add those lines (that create the issue link) in the end of your script.

Because in order to create the link you will need to first have the source and destination issues created.

regards, Thanos

 

Eduardo Seixas Jul 17, 2017 • edited Jul 18, 2017

Sorry for my mistake! Again...

 

But don't work yet.

 

The script now:

 

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

def issue = issue as MutableIssue

// if the issue in transition is not subtask then do nothing
if (! issue.isSubTask())
return

// get the parent issue
def parentIssue = issue.parentObject

def issueFactory = ComponentAccessor.getIssueFactory()
def subTaskManager = ComponentAccessor.getSubTaskManager()
def constantManager = ComponentAccessor.getConstantsManager()
def issueManager = ComponentAccessor.getIssueManager()

def asUser = ComponentAccessor.userManager.getUserByKey("user")
def newSubTask = issueFactory.getIssue()

newSubTask.setSummary("A new subtask test")
newSubTask.setParentObject(parentIssue)
newSubTask.setPriorityObject(issue.priority) // copy the priority from the subtask in transition
newSubTask.setProjectObject(parentIssue.getProjectObject())
newSubTask.setIssueTypeId(constantManager.getAllIssueTypeObjects().find { it.getName() == "Licensing (new)" }.id)

// Add any other fields you want for the newly created sub task ...

Map<String,Object> newIssueParams = ["issue" : newSubTask] as Map<String,Object>
issueManager.createIssueObject(asUser, newIssueParams)
subTaskManager.createSubTaskIssueLink(parentIssue, newSubTask, asUser)
log.info "Issue with summary ${newSubTask.summary} created"

def sourceIssueId = issue.id
def destinationIssueId = newSubTask.id

def linkTypeId = ComponentAccessor.getComponent(IssueLinkTypeManager).issueLinkTypes.find {it.name == "Depends of Licensing"}?.id
if (linkTypeId) {
ComponentAccessor.issueLinkManager.createIssueLink(sourceIssueId, destinationIssueId, linkTypeId, 0L, asUser)
}
else {
log.warn "Could not find link type with name Depends of Licensing"
}  

 

Thanos Batagiannis [Adaptavist] Community Leader Jul 17, 2017

Do you get any errors in your logs ?

Eduardo Seixas Jul 17, 2017

Thanos,

 

The Log error:

image.png

 

 

See the image attached of my link Issues configuration.image.png

Thanos Batagiannis [Adaptavist] Community Leader Jul 17, 2017

Eduardo, 

Try to use Licensing Dependency in the name of the issue link type instead of Depends on Licensing.

 

Eduardo Seixas Jul 17, 2017

Error...

java.lang.NullPointerException
at com.atlassian.jira.issue.link.DefaultIssueLinkManager.getIssueLink(DefaultIssueLinkManager.java:373)
at com.atlassian.jira.issue.link.DefaultIssueLinkManager.createIssueLink(DefaultIssueLinkManager.java:83)
at com.atlassian.jira.issue.link.IssueLinkManager$createIssueLink$6.call(Unknown Source)
at Script6945.run(Script6945.groovy:40)
Eduardo Seixas Jul 18, 2017

Hi Thanos,

 

I think the problem was because of the outdated version of Script Runner.

 

Now works with the script in the lastest version (5.0.11):

 

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

def issue = issue as MutableIssue

// if the issue in transition is not subtask then do nothing
if (! issue.isSubTask())
return

// get the parent issue
def parentIssue = issue.parentObject

def issueFactory = ComponentAccessor.getIssueFactory()
def subTaskManager = ComponentAccessor.getSubTaskManager()
def constantManager = ComponentAccessor.getConstantsManager()
def issueManager = ComponentAccessor.getIssueManager()

def asUser = ComponentAccessor.userManager.getUserByKey("user")
def newSubTask = issueFactory.getIssue()

newSubTask.setSummary("CMC Licensing - " + issue.parentObject.summary)
newSubTask.setParentObject(parentIssue)
newSubTask.setDescription(issue.parentObject.description)
newSubTask.setPriorityObject(issue.priority) // copy the priority from the subtask in transition
newSubTask.setProjectObject(parentIssue.getProjectObject())
newSubTask.setIssueTypeId(constantManager.getAllIssueTypeObjects().find { it.getName() == "Licensing (new)" }.id)

// Add any other fields you want for the newly created sub task ...

Map<String,Object> newIssueParams = ["issue" : newSubTask] as Map<String,Object>
issueManager.createIssueObject(asUser, newIssueParams)
subTaskManager.createSubTaskIssueLink(parentIssue, newSubTask, asUser)
log.info "Issue with summary ${newSubTask.summary} created"

def sourceIssueId = issue.id
def destinationIssueId = newSubTask.id

def linkTypeId = ComponentAccessor.getComponent(IssueLinkTypeManager).issueLinkTypes.find {it.name == "Licensing Dependency"}?.id
if (linkTypeId) {
ComponentAccessor.issueLinkManager.createIssueLink(sourceIssueId, destinationIssueId, linkTypeId, 0L, asUser)
}
else {
log.warn "Could not find link type with name Depends of Licensing Dependency"
}

 

But Is linking with the inverse sort of "Inward / Outward" link that I need.
I need set to link "Inward Description" (Depends of Licensing) 

 

e.g.:

With this script, where is setted "Licensing Dependency" name of link, when the subtask A generate the subtask B, the subtask A received the link "Licensing to" and subtask B "Depends of licensing". I need the reverse of this, as subtask A receive "Depends of Licensing" and subtask B receive "Licensing to".

 

Can you tel me how I do this?

Thanks.

Thanos Batagiannis [Adaptavist] Community Leader Jul 18, 2017

Hi Eduardo,

Cool. So in order to reverse the link direction just cahneg the lines below like 

def sourceIssueId = newSubTask.id

def destinationIssueId = issue.id

May I ask in which ScriptRunner version you were before the update ?

kind regards 

Thanos

Eduardo Seixas Jul 18, 2017

GREAT!!!

WORKS NOW!!! 

 

I revise and checked that it works also in the old version. (my older version is 5.0.1)

 

Thank you so much Thanos.

Eduardo Seixas Jul 18, 2017

@Thanos Batagiannis [Adaptavist]

One more little help, please...

 

How I add a condition to verify one custom field before follow the script?

If the custom field (select list) "customfield_15223" == 'Yes', generate the subtask...

 

Thanks.

Eduardo Seixas Jul 19, 2017

???

0 votes
Eduardo Seixas Jul 17, 2017 • edited Jul 18, 2017

 

 

0 votes
Eduardo Seixas Jul 17, 2017 • edited

 

 

 

0 votes
Eduardo Seixas Jul 18, 2017 • edited

Latest script that working, for anyone that need...

 

 

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

def issue = issue as MutableIssue

// if the issue in transition is not subtask then do nothing
if (! issue.isSubTask())
return

// get the parent issue
def parentIssue = issue.parentObject

def issueFactory = ComponentAccessor.getIssueFactory()
def subTaskManager = ComponentAccessor.getSubTaskManager()
def constantManager = ComponentAccessor.getConstantsManager()
def issueManager = ComponentAccessor.getIssueManager()

def asUser = ComponentAccessor.userManager.getUserByKey("user")
def newSubTask = issueFactory.getIssue()

newSubTask.setSummary("[CMC] Licensing - " + issue.parentObject.summary) // copy the summary from the parent adding a text
newSubTask.setParentObject(parentIssue)
newSubTask.setDescription(issue.parentObject.description)// copy the description from the parent
newSubTask.setPriorityObject(issue.parentObject.priority) // copy the priority from the parent
newSubTask.setProjectObject(parentIssue.getProjectObject())
newSubTask.setIssueTypeId(constantManager.getAllIssueTypeObjects().find { it.getName() == "Licensing (new)" }.id)

// Add any other fields you want for the newly created sub task ...

Map<String,Object> newIssueParams = ["issue" : newSubTask] as Map<String,Object>
issueManager.createIssueObject(asUser, newIssueParams)
subTaskManager.createSubTaskIssueLink(parentIssue, newSubTask, asUser)
log.info "Issue with summary ${newSubTask.summary} created"

def sourceIssueId = newSubTask.id
def destinationIssueId = issue.id

def linkTypeId = ComponentAccessor.getComponent(IssueLinkTypeManager).issueLinkTypes.find {it.name == "Licensing Dependency"}?.id
if (linkTypeId) {
ComponentAccessor.issueLinkManager.createIssueLink(sourceIssueId, destinationIssueId, linkTypeId, 0L, asUser)
}
else {
log.warn "Could not find link type with name Depends of Licensing Dependency"
}

 

 

0 votes
Eduardo Seixas Jul 19, 2017 • edited

Latest script to verifying first a custom field value for create the sister subtask depending on the this custom field value:

 

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

def issue = issue as MutableIssue

def customFieldManager = ComponentAccessor.getCustomFieldManager()
def cf = customFieldManager.getCustomFieldObject("customfield_15223");
def cfvalue = issue.getCustomFieldValue(cf)


if (! issue.isSubTask() || issue.getCustomFieldValue(cf).toString().contains('Yes')){


// get the parent issue
def parentIssue = issue.parentObject

def issueFactory = ComponentAccessor.getIssueFactory()
def subTaskManager = ComponentAccessor.getSubTaskManager()
def constantManager = ComponentAccessor.getConstantsManager()
def issueManager = ComponentAccessor.getIssueManager()


def asUser = ComponentAccessor.userManager.getUserByKey("user")
def newSubTask = issueFactory.getIssue()

newSubTask.setSummary("[CMC] Licensing - " + issue.parentObject.summary) // copy the summary from the parent adding a text
newSubTask.setParentObject(parentIssue)
newSubTask.setDescription(issue.parentObject.description)// copy the description from the parent
newSubTask.setPriorityObject(issue.parentObject.priority) // copy the priority from the parent
newSubTask.setProjectObject(parentIssue.getProjectObject())
newSubTask.setIssueTypeId(constantManager.getAllIssueTypeObjects().find { it.getName() == "Licensing (new)" }.id)

// Add any other fields you want for the newly created sub task ...

Map<String,Object> newIssueParams = ["issue" : newSubTask] as Map<String,Object>
issueManager.createIssueObject(asUser, newIssueParams)
subTaskManager.createSubTaskIssueLink(parentIssue, newSubTask, asUser)
log.info "Issue with summary ${newSubTask.summary} created"

def sourceIssueId = newSubTask.id
def destinationIssueId = issue.id

def linkTypeId = ComponentAccessor.getComponent(IssueLinkTypeManager).issueLinkTypes.find {it.name == "Licensing Dependency"}?.id
if (linkTypeId) {
ComponentAccessor.issueLinkManager.createIssueLink(sourceIssueId, destinationIssueId, linkTypeId, 0L, asUser)
}
else {
log.warn "Could not find link type with name Depends of Licensing Dependency"
}
}

 

Suggest an answer

Log in or Sign up to answer
This widget could not be displayed.
This widget could not be displayed.
Community showcase
Published in Marketplace Apps & Integrations

Webinar alert! An IT Admin's Guide to Securing Collaboration at Scale

Hello, Atlassian Community! My name is Dave Meyer and I'm a Principal Product Manager at Atlassian. I wanted to give this community a heads up about an upcoming Webinar that might be of interest...

185 views 2 7
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