Automatic subtask status change depending on previous subtask status

Germain Vincent July 13, 2017

Hi everybody,

 

context: JIRA 7.2.0 and ScriptRunner. Not allowed to install more plugin. 2 worflows, one for the parent and one workflow dedicated to subtasks.

 

I'm new to JIRA and my company ask me to create post script functions that could be able to automatically change the status of subtasks or parents on specific conditions.

More specifically:

While the parent ticket is on "Open" status, user can create as many qualification subtasks as he wants/needs.

When all qualification subtasks are created, user can use the "start qualification" transition. This will change the parent status from "OPEN" to "Qualification in progress" and the status of the first subtask of the list from "Waiting" to "To do".

My first question is: Which script would you use to do that?

Then, I must add a post script function on the transition "Close subtask" that set the subtask status from "In progress" to "Closed" which will automatically change the status of the next subtask from "Waiting" to "To do".

Have you any idea on how I could manage that?

 

Thanks in advance.

 

Regards,

 

 

2 answers

1 accepted

1 vote
Answer accepted
Tarun Sapra
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
July 13, 2017

Hi Germain,

 

When user "clicks" on the "start qualification" to transition the parent from "open" to "qualification in progress" then to transition the first sub-task, you can see complete code sample here - https://community.atlassian.com/t5/Atlassian-Marketplace-questions/Groovy-Script-for-auto-transition-of-Subtask-which-can-be/qaq-p/152675 

You can write a similar script to transition to transition the "next subtask" from "waiting" to "to do"

Germain Vincent July 13, 2017

Thanks a lot Tarun, I will have a look on that!

Germain Vincent July 13, 2017

Tarun,

The link is not working. But I found the topic by searching through Atlassian. Thank you.

If I copy/paste th code in my JIRA I got a lot of unknown method error as you can see in the screenshot jira.PNG

I also copy/paste all the needed imports.

Do you have any idea why not working in my context?

Sorry, I'm a real beginner...

Tarun Sapra
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
July 17, 2017

Hello Germain, 

Can you please post the code on gist.github.com and share here, it seems you are missing some import statements.

Germain Vincent August 2, 2017

Hi Tarun,

 

Sorry for being so long answering you, I was on vacation.

I still have the same issues, when I copy paste the code you linked to me I got a lot of unexpected error.

Here is a link to gist:

https://gist.github.com/anonymous/60c80f93577b7d2b3e50fea932c6b68a

Thanks in advance if you can have a look.

 

Have a nice day!

Germain Vincent August 2, 2017

The problem is that with gist you don't see the errors I got while pasting in JIRA.

Nevertheless you can see that I copy the same code.

When paste into JIRA I got a lot of  "Cannot find matching method"

Tarun Sapra
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
August 2, 2017

You can't use the exact same code, as the code is a reference which is using the "transition" id of close for sub-tasks but in your case you have to move the sub-task  from waiting to "To do" thus you have to use the transition ID of your workflow and change the code as per your requirement.

Tarun Sapra
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
August 2, 2017

I have updated the code in the gist link and it should remove some of the compile errors, but for the rest you have to go through the code and update as per your workflow and transition ID.

Germain Vincent August 2, 2017

Fantastic!

I'll work on that.

Thanks a lot Tarun.

Tarun Sapra
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
August 2, 2017

Sure, could you please accept/upvote the answer if it works for you.

Germain Vincent August 2, 2017

Sure, I will!

Germain Vincent August 2, 2017

Just got a few "deprecation" errors left and I would be able to adapt the code to my needs.

Thanks a lot Tarun, your answers were really helpfull!

 

Regards,

Germain Vincent August 3, 2017

Hi,

 

Now I would like to automaticaly change the status of the next subtask when the current subtask is in status "CLOSED".

 

Regarding the subtask worflow, when I execute the transition "CLOSE"  on a subtask I would like the next subtask in the list to go from "WAITING" to "TO DO".

 

My problem is that I have no idea on how to select or aim the next subtask. It's quit easy to select the first or last element of my subtasks collection but no clue on how to get the next one in the list that is not closed.

I tried with an "each" or "for" method but I didn't find how to make it works due to my lack of experience in JIRA, groovy, Java etc...

 

If anybody as an idea that would be great.

 

Thanks in advance.

 

PS: Must I open a new topic for my new question?

Tarun Sapra
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
August 3, 2017

Try with "find" operator, wherein the mement you find the sub-task in "waiting" state you make it go to "TO DO" and then return true.

As with .each in groovy you can't break the execution.

See sample here

https://stackoverflow.com/questions/3049790/can-you-break-from-a-groovy-each-closure

Germain Vincent August 3, 2017

Thanks a lot Tarun for your quick and efficent answer!

I understand why .each is not adapted in my context and yes .find seems to be a solution.

Can you help me completing my code please?

 

Collection subTasks = issue.getParentObject().getSubTaskObjects();

if (!subTasks.empty)
{
    MutableIssue nextSubTask = subTasks.find(??????????)
    workflowTransitionUtil.setIssue(nextSubTask);
    workflowTransitionUtil.setAction(711)
    workflowTransitionUtil.validate();
    workflowTransitionUtil.progress();
}

 

It's certainly basic syntax and something quite easy to find by himself but trust me I'm a real beginner and I feel a bit lost.

 

Thanks in advance!

Tarun Sapra
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
August 3, 2017
subTasks.find { it -> it.status.name == "WAITING" }

This should fetch the next sub-task who has the status = "WAITING" (make sure it's caps if it's caps in your workflow otherwise match the case) 

Germain Vincent August 3, 2017

Thanks Tarun!
Will try this solution ASAP.

PS: As I didn't opened a new topic I can't upvote your answer while you deserve it.

Germain Vincent August 3, 2017

Tarun,

Sorry for being so bad but I got a null pointer exception. I tried some alternative but didn't find any solution.

Maybe if I show you the code you will quickly understand why it doesn't work.

Here is a gist link:

https://gist.github.com/GermainVincent/989d5aea0369343e6911c53c4dbd1cfb

 

Thanks again!

 

PS: You sure you don't want I open a new topic?

Tarun Sapra August 3, 2017

IN the gist can you also paste the Null pointer exception?

Germain Vincent August 3, 2017

Done!

Tarun Sapra August 3, 2017

Also, aren't you already in the post-funciton of the parent issue?

Thus 

instead of 

Collection subTasks = issue.getParentObject().getSubTaskObjects();

you can only do

Collection subTasks = issue..getSubTaskObjects();

 

Because If I understand correct, when you transition the parent issue only then you want to move the first sub-task from "waiting" to "todo"

So let's first execute this scenario. Then we can also look at the second senario wherein when you close the sub-task then the other sub-task should move from waiting to "todo", in that scenario you would need the code

Collection subTasks = issue.getParentObject().getSubTaskObjects();

 

But first atleast run the first scenario wherein the first sub-tasks moved to "todo" when parent does a transition to ""qualification in progress" 

Germain Vincent August 3, 2017

I guess that you understood correctly my context. To be sure cause english is not my first language:

First I want to transition the first subtask of the list from "WAITING" to "TO DO" when I transition the parent issue from "WAITING" to "QUALIFICATION IN PROGRESS".

That's something that is achieved by a post script function on the "START QUALIFICATION" transition of the main worflow.

Thanks to your advices this transition is working efficiently.

Effectively, I used in this scenario the syntax:

Collection subTasks = issue..getSubTaskObjects();

 

Now I'm working on the "CLOSE" transition in the dedicated subtasks workflow.

I want this transition to move the next subtask of the list from "WAITING" to "TO DO".

So, on the "CLOSE" transition post script function I selected the syntax:

Collection subTasks = issue.getParentObject().getSubTaskObjects();

In order to collect the subtasks from the parent issue. I believe that asking for the subtask of the current subtask will not work at all.

 

So, yes it seems that you perfectly understood my context.

 

The first scenario is working perfectly and my problem now concerns the "CLOSE" transition of the subtasks workflow.

The code I posted on gist recently concerns this transition.

 

EDIT: I saw your answers on gist. Will try that tomorrow morning. Thanks a lot Tarun, your help is very welcome!

Germain Vincent August 3, 2017

I add some comment on gist.

Have a look when you can.

I need to go.

See you tomorrow.

 

Thanks again Tarun, have  nice evening.

Germain Vincent August 4, 2017

My code now looks like:

Collection subTasks = issue.getParentObject().getSubTaskObjects();

MutableIssue nextSubTask = (MutableIssue)subTasks.find { it -> it.status.name == "EN ATTENTE" };

log.debug(issue);

 

 

Then I obtain this message in the log:
2017-08-04 09:49:57,996 ERROR [workflow.ScriptWorkflowFunction]: *************************************************************************************
2017-08-04 09:49:57,996 ERROR [workflow.ScriptWorkflowFunction]: Script function failed on issue: TRYSCRIPTS-1449, actionId: 2, file:
groovy.lang.MissingMethodException: No signature of method: static com.atlassian.jira.issue.MutableIssue.getParentObject() is applicable for argument types: () values: []
at Script2557.run(Script2557.groovy:17)

 

 

Do you understand what this log means?

Tarun Sapra
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
August 4, 2017

Can you put

log.debug("issue is ----->" + issue);

before issue.getParentObject() and is this post-funciton after the built-in "create postfunction"

And from the above log output see what's getting printed in the log file.

Also split the code like

MutableIssue parentIssue = (MutableIssue)issue.getParentObject();

Collection<Issue> subTasks = parentIssue.getSubTaskObjects();
Germain Vincent August 8, 2017

Hi tarun,

 

Even if I split the code like you told me I again get the Null pointer exception.

I tried log.debug("issue is ----->" + issue); at different point in the script but it doesn't log anything more.

The post function is after the built-in "create postfunction" so I don't understand what is not working.

Any idea?

Tarun Sapra
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
August 8, 2017

Hello Germain,

 

can you post the whole code on github gist and also the screenshot of your workflow postfunction order from JIRA

Germain Vincent August 8, 2017

Hey Tarun,

 

I posted the code and screenshots on gist:

https://gist.github.com/anonymous/60c80f93577b7d2b3e50fea932c6b68a

 

Thanks!

Tarun Sapra
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
August 8, 2017

Hello @Germain Vincent

Earlier you were getting - groovy.lang.MissingMethodException: and now it's NullPointerException, can you please also post the exact stack-trace and add checks as I have shred on the gist

Germain Vincent August 8, 2017

I added some comments on gist.

thanks Tarun.

Tarun Sapra August 8, 2017
Germain Vincent August 8, 2017

Was talking about previous comments before you answered.

 

As you adviced me, I modified the code.

I got no more errors and can execute the code but unfortunately I still have the Null pointer exception and so the automatic subtask status change doesn't occurs.

Tarun Sapra August 8, 2017

At which line of the script is the NPE coming?

Germain Vincent August 9, 2017

I'm sorry Tarun but I don't have this information.

I didn't succeed on adding logs to my code and in the default log I can see I have no information regarding the line.

Do you have any idea?

Germain Vincent August 10, 2017

Hi Tarun,

 

I asked the system administrator if he can get the logs on the JIRA server for me.

Good news, he was able to get the logs and sent them to me.

Bad news, in the server logs I don't have the line information either...

For each try, here is the message:

2017-08-10 15:03:41,228 http-nio-8080-exec-15 ERROR GVincent 903x133747x1 loxcoq 192.168.138.106 /secure/CommentAssignIssue.jspa [c.o.s.jira.workflow.ScriptWorkflowFunction] Script function failed on issue: TRYSCRIPTS-1626, actionId: 2, file: <inline script>
java.lang.NullPointerException

 

Nothing more.

I guess it's not really helpfull?

Tarun Sapra
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
August 11, 2017
Germain Vincent August 17, 2017

I had a look on this topic and tried som solutions but I still have the same "Null pointer exception".

The good news is think that I found the line where the NPE occurs.

Here is my whole actual code (I also post it on the gisthub):

 

import com.atlassian.jira.ComponentManager
import com.opensymphony.workflow.WorkflowContext
import com.atlassian.jira.config.SubTaskManager
import com.atlassian.jira.workflow.WorkflowTransitionUtil;
import com.atlassian.jira.workflow.WorkflowTransitionUtilImpl;
import com.atlassian.jira.util.JiraUtils;
import com.atlassian.jira.issue.resolution.Resolution
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.IssueInputParameters
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.Issue;


WorkflowTransitionUtil workflowTransitionUtil = ( WorkflowTransitionUtil ) JiraUtils.loadComponent( WorkflowTransitionUtilImpl.class );

SubTaskManager subTaskManager = ComponentAccessor.getSubTaskManager();

MutableIssue parentIssue = issue.getParentObject() as MutableIssue;

Collection subTasks = parentIssue.getSubTaskObjects();

if (!subTasks.empty)
{
    MutableIssue nextSubTask = (MutableIssue)subTasks.find {issue.getStatus()?.name == 'EN ATTENTE'}
    workflowTransitionUtil.setIssue(nextSubTask);
    workflowTransitionUtil.setAction(711)
    workflowTransitionUtil.validate();
    workflowTransitionUtil.progress();
}

 

I'm quite sure it's the " MutableIssue nextSubTask = (MutableIssue)subTasks.find {issue.getStatus()?.name == 'EN ATTENTE'} " line that send back an NPE.

 

Do you have any idea why?

 

Thanks.

Germain Vincent August 17, 2017

Hi Tarun,

 

Thanks for the link.

I tried some solutions but still have the Null pointer exception.

Hopefully I'm pretty sure that I found the line which generates this NPE:

MutableIssue nextSubTask = (MutableIssue)subTasks.find {issue.getStatus()?.name == 'EN ATTENTE'}

I posted the whole code on Gisthub.

 

Do you have any idea why this line returns an NPE?

 

Thanks.

Tarun Sapra
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
August 18, 2017

Hello Germain,

 

At this point, I am not sure what's going wrong. I would suggest you to do some debugging in the script console.

Germain Vincent August 18, 2017

Hi Tarun,

 

After some modifications I found a solution that is not creating any Null pointer exception but that has no incidence on the workflow. Next subTask status is not evolving.

 

here is the code:

 

import com.atlassian.jira.ComponentManager
import com.atlassian.jira.component.ComponentAccessor
import com.opensymphony.workflow.WorkflowContext
import com.atlassian.jira.config.SubTaskManager
import com.atlassian.jira.workflow.WorkflowTransitionUtil;
import com.atlassian.jira.workflow.WorkflowTransitionUtilImpl;
import com.atlassian.jira.util.JiraUtils;
import com.atlassian.jira.issue.resolution.Resolution
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.IssueInputParameters
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.Issue;

 

WorkflowTransitionUtil workflowTransitionUtil = ( WorkflowTransitionUtil ) JiraUtils.loadComponent( WorkflowTransitionUtilImpl.class );

MutableIssue parentIssue = issue.getParentObject() as MutableIssue;

Collection <Issue> subTasks = parentIssue.getSubTaskObjects();

Issue nextSubTask = (Issue)subTasks.find { it -> it.status.name == "EN ATTENTE" };
    
if (!subTasks.empty)
{
    workflowTransitionUtil.setIssue((MutableIssue)nextSubTask);
    workflowTransitionUtil.setAction(711)
    workflowTransitionUtil.validate();
    workflowTransitionUtil.progress();
}

 

Do you understand why I have no result?

 

I'm working on the way to get logs and debug.

 

Thanks!

0 votes
Germain Vincent August 18, 2017

Hi Tarun,

 

Someone in my company helped me finding a different solution.

Comments are in French.

I also added a function that allow to change subtasks's status only if they share a "Lot" number.

 

Thanks for all your helps!

 

//Imports nécessaires
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.IssueInputParametersImpl
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.config.SubTaskManager
import com.atlassian.jira.workflow.WorkflowTransitionUtil
import com.atlassian.jira.workflow.WorkflowTransitionUtilImpl
import com.atlassian.jira.util.JiraUtils
import com.opensymphony.workflow.WorkflowContext
import com.atlassian.jira.issue.customfields.manager.OptionsManager


//Création des variables et des différentes classes
def constantManager = ComponentAccessor.getConstantsManager()
def issueService = ComponentAccessor.getIssueService()
def cwdUser = ComponentAccessor.jiraAuthenticationContext.getLoggedInUser()
def issueManager = ComponentAccessor.getIssueManager()
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def componentManager = ComponentManager.instance
def optionsManager = ComponentManager.getComponentInstanceOfType(OptionsManager.class)
def subTaskManager = ComponentAccessor.getSubTaskManager()
//Variable permettant de rentrer et de sortir de la boucle "each"
def eachExit=0


//Récupération de la valeur du champ "Lot" de la sous-tâche affectée par la transition "CLOSE"
def Lot = customFieldManager.getCustomFieldObject("customfield_12604")
String LotValue = issue.getCustomFieldValue(Lot)


//Création de la collection de sous-tâches
MutableIssue parentIssue = issue.getParentObject() as MutableIssue
Collection subTasks = parentIssue.getSubTaskObjects()


//Si sous-tâches existantes
if (subTaskManager.subTasksEnabled && !subTasks.empty)
{
    //On parcourt la collection de sous-tâches
    subTasks.each
    {
        Issue it ->
        //Récupération de la valeur du champ "Lot" de chaque sous-tâches de la collection
        def Lot2 = customFieldManager.getCustomFieldObject("customfield_12604")
        String LotValue2 = it.getCustomFieldValue(Lot2)
        //Lorsque l'on rencontre une sous-tâche de la collection ayant un statut "En attente" et portant le même numéro de lot que la sous-tâche affectée par la transition "CLOSE"
        if(it.getStatus()?.name == 'En attente' && eachExit==0 && LotValue == LotValue2)
        {
            def issueInputParameters = new IssueInputParametersImpl()
            def transitionValidationResult = issueService.validateTransition(cwdUser, it.id, 711, issueInputParameters)
            //Afin de ne modifier l'état que de la première sous-tâche en statut "En attente" on arrête de balayer la collection en implémentant la variable
            eachExit=1
            //On fait évoluer le statut de la sous-tâche en "To do"
            if (transitionValidationResult.isValid())
            {
                issueService.transition(cwdUser, transitionValidationResult)
            }    
        }       
    }
}

Tarun Sapra August 18, 2017

But what exactly was the issue?

Germain Vincent August 18, 2017

Even my colleague was not able to find the issue.

So he gave me a code he wrotes a few times ago that was doing nearly the same I was expecting.

I just adapted the code to my context.

Sorry, I can't tell you what was not working with your solution in my context.

 

Anyway, thanks a lot, your help was really helpfull and even it was not perfectly working at the end (my fault) I learned a lot from you!

 

See you.

 

Germain

Suggest an answer

Log in or Sign up to answer