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

Javier Salvay July 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
EduardoS July 19, 2017

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"
}
}

 

0 votes
EduardoS July 18, 2017

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
EduardoS July 17, 2017

 

 

 

0 votes
EduardoS July 17, 2017

 

 

0 votes
EduardoS July 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_
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.
July 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

EduardoS July 17, 2017

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.

 

EduardoS July 17, 2017

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_
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.
July 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

 

EduardoS July 17, 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_
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.
July 17, 2017

Do you get any errors in your logs ?

EduardoS July 17, 2017

Thanos,

 

The Log error:

image.png

 

 

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

Thanos Batagiannis _Adaptavist_
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.
July 17, 2017

Eduardo, 

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

 

EduardoS July 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)
EduardoS July 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_
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.
July 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

EduardoS July 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.

EduardoS July 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.

EduardoS July 19, 2017

???

0 votes
Daniel Yelamos [Adaptavist]
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.
July 12, 2017

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 July 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!

EduardoS July 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_
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.
July 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 

EduardoS July 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_
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.
July 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 ? 

Suggest an answer

Log in or Sign up to answer
TAGS
AUG Leaders

Atlassian Community Events