Groovy : Set Remaining time on subtask to 0

Thibauld Leprince February 11, 2014

Hi,
i am recently using the script runner plugin to autoclose suktasks when the parent issue is closed.

Can you tell me the lines to add to force the "Remaning Time" on subtasks to 0 at the same time ?

Thank you.

6 answers

1 accepted

2 votes
Answer accepted
Henning Tietgens
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.
March 3, 2014

You can try this.

import com.atlassian.jira.bc.issue.IssueService
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.config.SubTaskManager
import com.atlassian.jira.issue.IssueInputParameters
import com.atlassian.jira.issue.MutableIssue
import org.apache.log4j.Category
import static org.apache.log4j.Level.DEBUG

log = Category.getInstance("com.onresolve.jira.groovy.AutoCloseChildIssues")
log.setLevel(DEBUG)
log.debug "debug statements"

IssueService issueService = ComponentAccessor.getIssueService()
SubTaskManager subTaskManager = ComponentAccessor.getSubTaskManager();

if (subTaskManager.subTasksEnabled) {

    MutableIssue issue = issue  // this is only for the IDE
    log.debug ("issue.statusObject.name: " + issue.statusObject.name)
    def currentUser = ComponentAccessor.getUserUtil().getUser("muleuser")

    issue.getSubTaskObjects().each { subtask ->
        IssueInputParameters issueInputParameters = issueService.newIssueInputParameters();
        issueInputParameters.setRemainingEstimate(0L);
        issueInputParameters.setComment("*Réouverte*, car la demande mère a été réouverte.")

        IssueService.TransitionValidationResult transitionValidationResult = issueService.validateTransition(currentUser, subtask.id, 3, issueInputParameters);
        if (transitionValidationResult.isValid()){
            IssueService.IssueResult transitionResult = issueService.transition(currentUser, transitionValidationResult);
            if (!transitionResult.isValid()) {
                transitionResult.errorCollection.errorMessages.each {log.error "Error Message: $it"}
                transitionResult.errorCollection.errors.each {log.error "Error: $it"}
                transitionResult.errorCollection.reasons.each {log.error "Reason: $it"}
            }
        } else {
            transitionValidationResult.errorCollection.errorMessages.each {log.error "Error Message: $it"}
            transitionValidationResult.errorCollection.errors.each {log.error "Error: $it"}
            transitionValidationResult.errorCollection.reasons.each {log.error "Reason: $it"}
        }

    }
}

There is a nice documentation on how to use the issueService. If it doesn't work there could be a problem with the transition screen. Take a look here, especially setSkipScreenCheck().

Thibauld Leprince March 3, 2014

You are really Good, it works fine.

Another question : if I want set the estimate to 2h for example ?

I wrote setRemainingEstimate(2h) but i doesnt work

Thibauld Leprince March 3, 2014

it doesnt work

Henning Tietgens
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.
March 3, 2014

Try setRemainingEstimate('2h')

Henning Tietgens
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.
March 4, 2014

You have to make sure you're using a String as parameter, than it should work like documented here. Could you enter 2h manually while entering an estimate?

If it doesn't work you could calculate a long of 2h in your timetracking default units ( APKeys.JIRA_TIMETRACKING_DEFAULT_UNIT) and use this as parameter.

Thibauld Leprince March 4, 2014

Yes, i can write 2h in the field "remaining estimate".

I also try issueInputParameters.setRemainingEstimate(1100L);

but no result

Henning Tietgens
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.
March 4, 2014

Mmh. Setting to 0 works but not to any other value? What did you get if you call issueInputParameters.getRemainingEstimate() after setting the remaining estimate (before the transition)?

log.error "getRemainingEstimate(): ${issueInputParameters.getRemainingEstimate()}"

Are there any other errors in the log?

Thibauld Leprince March 4, 2014

i found this error :

2014-03-05 13:42:34,087 ajp-bio-8009-exec-31 ERROR leprince.t 821x55358x1 1v714k4 10.253.114.5 /secure/WorkflowUIDispatcher.jspa [atlassian.event.internal.AsynchronousAbleEventDispatcher] There was an exception thrown trying to dispatch event 'com.atlassian.jira.event.issue.IssueEvent@122580a1[issue=PROJWMS-16227,comment=<null>,worklog=<null>,changelog=[GenericEntity:ChangeGroup][id,3359167][author,leprince.t][created,2014-03-05 13:42:24.05][issue,420304],eventTypeId=5,sendMail=true,params={eventsource=workflow, baseurl=https://jira-app-rec-03.stef.com/jira},subtasksUpdated=false]' from the invoker 'SingleParameterMethodListenerInvoker{method=public void com.stef.jira.plugin.listener.JiraIssueListener.onIssueEvent(com.atlassian.jira.event.issue.IssueEvent), listener=com.stef.jira.plugin.listener.JiraIssueListener@2eedaaf4}'.
java.lang.RuntimeException: java.lang.StackOverflowError

Henning Tietgens
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.
March 4, 2014

Do you have any recursion in your code? Could you post the complete stack trace?

Thibauld Leprince March 4, 2014

(sample catalina.out.txt) contains all lines after the error line i sent before

Henning Tietgens
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.
March 5, 2014

There is a recursion in this code part:

at com.stef.jira.plugin.business.IssueEventFactory.buildCollectionIssueImpl(IssueEventFactory.java:276)
	at com.stef.jira.plugin.business.IssueEventFactory.buildIssueImpl(IssueEventFactory.java:79)
	at com.stef.jira.plugin.business.IssueEventFactory.buildIssueImpl(IssueEventFactory.java:78)
	at com.stef.jira.plugin.business.IssueEventFactory.buildCollectionIssueImpl(IssueEventFactory.java:276)

The numbers at the end are the line numbers in the source file. Maybe you should add some debug output to these lines to see why your code is calling itself over and over again. This leads to the stack overflow.

Thibauld Leprince March 5, 2014

Ok thanks i will check that. we keep in touch

Thibauld Leprince March 12, 2014

I tried on another jira instance, but it still doesnt work

Henning Tietgens
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.
March 12, 2014

Any errors in the log?

Stefano Rosario Aruta February 6, 2019

hi dude, i need your help, i want to changes status on every sub-task in a main issue. I make this code but it doen't work. Can you help me?? 

import com.atlassian.jira.bc.issue.IssueService
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.config.SubTaskManager
import com.atlassian.jira.issue.IssueInputParameters
import com.atlassian.jira.issue.MutableIssue

import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.config.SubTaskManager;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.AttachmentManager
import com.atlassian.jira.issue.attachment.Attachment;
import com.atlassian.jira.issue.IssueFactory;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.issue.MutableIssue;

Issue parentIssue = issue
IssueService issueService = ComponentAccessor.getIssueService()
def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser();

if (issue.getIssueType().getName() != "Sub-task") {
if (parentIssue.getSubTaskObjects().size()>0) {
for(int o = 0; parentIssue.getSubTaskObjects().size() > o; o++) {
if(!parentIssue.getSubTaskObjects()[o].getStatus().equals("DONE")) {
//TransitionOptions traOpt = issue;

IssueInputParameters issueInputParameters = issueService.newIssueInputParameters();
issueInputParameters.setRemainingEstimate(0L);
issueInputParameters.setComment("*Réouverte*, car la demande mère a été réouverte.")
// validateTransition(ApplicationUser user, Long issueId, int actionId, IssueInputParameters issueInputParameters, TransitionOptions transitionOptions)
IssueService.TransitionValidationResult transitionValidationResult = issueService.validateTransition(currentUser, parentIssue.getSubTaskObjects()[o].getId(), 3 as Integer, issueInputParameters);
//IssueService.TransitionValidationResult transitionValidationResult = issueService.validateTransition(currentUser, parentIssue.getSubTaskObjects()[o].getId(), 3,"10001", 5 as Integer, issueInputParameters, );
}
}
}
}
Henning Tietgens
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.
February 6, 2019

Hi Stefano,

you're only validating the transition, you have to do it if the validation result is valid.

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

Issue parentIssue = issue
def issueService = ComponentAccessor.getIssueService()
def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()

if (!parentIssue.isSubTask()) {
parentIssue.subTaskObjects.each{ subtask ->
if (subtask.status.name != "DONE") {
def issueInputParameters = issueService.newIssueInputParameters()
issueInputParameters.setRemainingEstimate(0L)
issueInputParameters.setComment("*Réouverte*, car la demande mère a été réouverte.")
def transitionValidationResult = issueService.validateTransition(currentUser, subtask.id, 3 as Integer, issueInputParameters)
if (transitionValidationResult?.isValid()) {
issueService.transition(currentUser, transitionValidationResult)
} else {
def text = "Transition failed. "
transitionValidationResult?.errorCollection?.errorMessages?.each { text += "Error Message: $it\r\n" }
transitionValidationResult?.errorCollection?.errors?.each { text += "Error: $it\r\n" }
transitionValidationResult?.errorCollection?.reasons?.each { text += "Reason: $it\r\n" }
log?.error(text)
}
}
}
}

Best regards,
Henning

Stefano Rosario Aruta February 6, 2019

i copy and paste this scritp on my post function but it dosen't work

Henning Tietgens
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.
February 6, 2019

Is the status name correct? Maybe it's "Done"?

Stefano Rosario Aruta February 6, 2019

the condition is if the sub-task is not DONE  run this code to set sub-task done

Annotazione 2019-02-06 140200.png

Henning Tietgens
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.
February 6, 2019

Yes, that‘s correct. But it‘s a difference if the status name is DONE or Done. Case matters.

Henning Tietgens
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.
February 6, 2019

Take a look into the status list in administration to see the correct case. 

Stefano Rosario Aruta February 6, 2019

Annotazione 2019-02-06 140200.png

Stefano Rosario Aruta February 6, 2019

The problem is that script doesn't run

Annotazione 2019-02-06 140200.pngi don't know it doesn't run

Henning Tietgens
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.
February 6, 2019

Did you changed 

if (subtask.status.name != "DONE") {

to

if (subtask.status.name != "Done") {

 ?

But this doesn't explain why the postfunction has not run yet. Did you publish the workflow?

Stefano Rosario Aruta February 6, 2019

ure dude look the code:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.onresolve.scriptrunner.runner.util.UserMessageUtil

UserMessageUtil.success("script is run");
Issue parentIssue = issue
def issueService = ComponentAccessor.getIssueService()
def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()

if (!parentIssue.isSubTask()) {
parentIssue.subTaskObjects.each{ subtask ->
UserMessageUtil.success("we are in the cicle");
if (subtask.status.name != "Done") {
UserMessageUtil.success("we are on the condition - if (subtask.status.name != Done)");
def issueInputParameters = issueService.newIssueInputParameters()
issueInputParameters.setRemainingEstimate(0L)
issueInputParameters.setComment("TESTETSTESTTESTET.")
def transitionValidationResult = issueService.validateTransition(currentUser, subtask.id, 3 as Integer, issueInputParameters)
if (transitionValidationResult?.isValid()) {
UserMessageUtil.success("insane - if (transitionValidationResult?.isValid())");
issueService.transition(currentUser, transitionValidationResult)
} else {
def text = "Transition failed. "
transitionValidationResult?.errorCollection?.errorMessages?.each { text += "Error Message: $it\r\n" }
transitionValidationResult?.errorCollection?.errors?.each { text += "Error: $it\r\n" }
transitionValidationResult?.errorCollection?.reasons?.each { text += "Reason: $it\r\n" }
log?.error(text)
}
}
}
}
Henning Tietgens
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.
February 6, 2019

And, do you see any of the messages?

Stefano Rosario Aruta February 6, 2019

ok i fix that, now the script run, but it worked also if the sub-task is on some status where is connected with a transaction DONE, i need that status change always

Henning Tietgens
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.
February 6, 2019

You have to take care that from every possible status of the subtask workflow (every status not "Done") there is the transition with ID 3 to status Done. If this is not the case add a global transition to Done and use the ID of this transition in your post function script.

0 votes
Thibauld Leprince March 3, 2014

Hi,

i dont know how to use issueService and issueInputParameters.setRemainingEstimate()

0 votes
Thibauld Leprince February 26, 2014

Hi Henning and Julian,

Many thanks for your asnwer.

Henning, here is my script, can you help me to apply what you said ?

import com.atlassian.jira.ComponentManager
import com.atlassian.jira.issue.IssueService
import com.atlassian.jira.issue.comments.CommentManager
import com.opensymphony.workflow.WorkflowContext
import org.apache.log4j.Category
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 org.apache.log4j.Category
 
def Category log = Category.getInstance("com.onresolve.jira.groovy.PostFunction")
log.setLevel(org.apache.log4j.Level.DEBUG)
log.debug "debug statements"
 
log = Category.getInstance("com.onresolve.jira.groovy.AutoCloseChildIssues")
 
String currentUser = ComponentManager.getInstance().getUserUtil().getUser("muleuser").getName()

WorkflowTransitionUtil workflowTransitionUtil = ( WorkflowTransitionUtil ) JiraUtils.loadComponent( WorkflowTransitionUtilImpl.class );
 
SubTaskManager subTaskManager = ComponentManager.getInstance().getSubTaskManager();
Collection subTasks = issue.getSubTaskObjects()
if (subTaskManager.subTasksEnabled && !subTasks.empty) {
    subTasks.each {
        log.debug ("issue.statusObject.name: " + issue.statusObject.name)
        workflowTransitionUtil.setIssue(it);
        workflowTransitionUtil.setUsername(currentUser);
        workflowTransitionUtil.setAction (3)    // 3 == REOPEN ISSUE
	 issueInputParameters.setRemainingEstimate(3)
 
        // Add a comment so people have a clue why the child has been closed
        CommentManager commentManager = (CommentManager) ComponentManager.getComponentInstanceOfType(CommentManager.class);
        String comment = "*Réouverte*, car la demande mère a été réouverte.";
        commentManager.create(it, currentUser, comment, true);
 
        // validate and transition issue
        workflowTransitionUtil.validate();
        workflowTransitionUtil.progress();
    }
}

0 votes
JulianA
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.
February 24, 2014

I had created a simliar script for this a few months ago. Maybe this can help you.

Usage: Create a JQL-Query that matchs the subtasks, you want to edit. Copy that query

Replace ("INSERT HERE YOUR JQL QUERY") with the created Query.

Run the script

import com.atlassian.jira.issue.Issue;

import com.atlassian.jira.issue.IssueManager;

import com.atlassian.jira.issue.MutableIssue;

import com.atlassian.jira.component.ComponentAccessor;

import com.atlassian.jira.issue.fields.CustomField;

import com.atlassian.jira.bc.JiraServiceContextImpl;

import com.atlassian.jira.bc.filter.SearchRequestService;

import com.atlassian.jira.bc.issue.search.SearchService;

import com.atlassian.jira.component.ComponentAccessor;

import com.atlassian.jira.issue.search.SearchRequest;

import com.atlassian.jira.issue.search.SearchResults;

import com.atlassian.jira.user.ApplicationUser;

import com.atlassian.jira.web.bean.PagerFilter;

import com.atlassian.query.Query;

 


SearchResults getissuesByJQL(String jql) throws Exception

    {

        SearchService serchService = ComponentAccessor.getComponentOfType(SearchService.class);

        SearchService.ParseResult parseResult = serchService.parseQuery(ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser(), jql);

        

        if (!parseResult.isValid())

        {

            throw new Exception("jql is not valid. jql was "+jql);

        }

        

        Query query = parseResult.getQuery();

           SearchResults sr = serchService.search(ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser(), query, PagerFilter.getUnlimitedFilter());

            return sr;

 

 

    }

    

    

void setEstimateToNull(String key) {
IssueManager im = ComponentAccessor.getIssueManager();
        MutableIssue issue = im.getIssueObject(key);
        issue.setEstimate(0L);
        issue.store();
}

 

 

for (Issue issue : getissuesByJQL("INSERT HERE YOUR JQL QUERY").getIssues())

{

    setEstimateToNull(issue.getKey());

}

0 votes
Thibauld Leprince February 24, 2014

any idea ?

0 votes
Henning Tietgens
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.
February 24, 2014

Use issueService and issueInputParameters.setRemainingEstimate()

Suggest an answer

Log in or Sign up to answer