Missed Team ’24? Catch up on announcements here.

×
Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

Proper way to change issue status in code?

Alexey Paveliev
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.
December 17, 2012

There are at least three ways to change issue status I know (I am two weeks in Jira API):

1. set status to value and shoot store() on it - Does not appear to do things right as UI still shows transitions per previous state. Can reidex help?

2. do issueManager.updateIssue(...) -have not tried this one yet

3. Do proper workflow transition with WorkflowManager - appears overkill at first glance assuming there are no specific conditions or validations I cannot do in code prior to status change

What is the Kosher way of doing it? Samples?


5 answers

1 accepted

Comments for this post are closed

Community moderators have prevented the ability to post new answers.

Post a new question

3 votes
Answer accepted
Nic Brough -Adaptavist-
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
December 17, 2012

1. No.

Those issues are very broken - you need to set them back to the previous status, then run the integrity checker. You might need to reindex as well, but you could trigger that by making any other change to the issue, rather than redoing the whole system.

2. Don't bother - it's much the same as point 1 - you're changing too little of the data you need to hit and you'll simply break the issues

3. This is the right way to do it. Yes, there are conditions/validators/post-functions you can run here, but it will also handle all the other things that just changing the status will break. There's an assumption here - that Status is a field like the other issue attributes, but that's incorrect - status is a consequence of a position in a workflow. Ideally, it should be removed from the issue completely, which would save a lot of confusion...

I have this scribbled down for some stuff I vaguely need to do in the future (although I've not tried it in anger yet):

TransitionValidationResult validationResult = issueService.validateTransition(user, theIssue.id, actionId as Integer, issueInputParameters)
issueService.transition(user, validationResult)

3 votes
Mizan
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.
December 17, 2012

You want to change the status of the issue , this means you want to transition the issue from one status to another , Have a look at the below code snippet , you will get an idea how to transition an issue programmatically .

MutableIssue issue1=getIssueObject();
final String remoteuser=ComponentManager.getInstance().getJiraAuthenticationContext().getUser().getName();
WorkflowTransitionUtil workflowTransitionUtil = ( WorkflowTransitionUtil ) JiraUtils.loadComponent( WorkflowTransitionUtilImpl.class );
workflowTransitionUtil.setIssue(issue1);
workflowTransitionUtil.setUsername(remoteuser);
workflowTransitionUtil.setAction(5);//Id of the status you want to transition to
workflowTransitionUtil.progress();


Hope it helps :)

JamieA
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.
December 17, 2012

This works but using IssueService is preferred going forward. If it's available in your jira version, use it...

Alexey Paveliev
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.
December 17, 2012

Jamie, got code snippet? It's just so confusing to have so much choice :)

JamieA
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.
December 17, 2012
IssueService issueService = ComponentManager.getComponentInstanceOfType(IssueService.class)
IssueInputParameters issueInputParameters = new IssueInputParametersImpl([:])

issueInputParameters.setComment("Test script transitioned this to resolved...")
issueInputParameters.setResolutionId("2")
IssueService.TransitionValidationResult validationResult = issueService.validateTransition(adminUser, issue.id, 5 as Integer, issueInputParameters)
def errorCollection = validationResult.errorCollection
log.debug(errorCollection)
if (! errorCollection.hasAnyErrors()) {
    issueService.transition(adminUser, validationResult)
}
else {
    // log errors etc
}

IshanL
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.
April 28, 2015

@Jamie Echlin [Adaptavist] , Thanks for the code.

Sachin Dhamale June 14, 2015

Mizan; It update only in history but not on view issue page what is a problem?

1 vote
Sergio Samaan May 16, 2013

I m facing this problem... but I don t have a transition from 'oldstatus' to 'newstatus'. Can I change the status without using a transition? Can I execute a 'Integrity Checker' in one issue?

0 votes
Timothy Harris May 29, 2015

I call my transitionIssue function from here and then call an update function which does reIndex.

@Override
void issueClosed(IssueEvent event) {
    log.warn("----------------------------")
    log.warn("Issue Closed Event: " + event.getEventTypeId() + " fired for issue: " + event.getIssue().toString() + " and caught by Incomplete Story Listener")

    //Transition the issue to reopened so we can edit it.
    transitionIssue(event.getIssue(), getActionId(event.getIssue(),ISSUE_ACTION_REOPEN),ISSUE_STATUS_REOPENED);
    // Reload the issue and Re-index it
    updateIncomplete(event.getIssue());
}

This is the transition function

boolean transitionIssue(Issue issue, int actionID, String targetStatus) {
    log.warn("Trying to transition issue " + issue.getKey() + " with action ID " + actionID + "\n");
    IssueService.TransitionValidationResult validationResult;
    def res = false;
    if (actionID) {
        def issueInputParameters = issueService.newIssueInputParameters();
        issueInputParameters.setStatusId(targetStatus);
        issueInputParameters.setSkipScreenCheck(true);
        issueInputParameters.setResolutionId(null);
        validationResult = this.issueService.validateTransition(this.authContext.getUser().getDirectoryUser(), issue.getId(), actionID, issueInputParameters);
        if (validationResult.isValid()) {
            log.warn("Transition validated. Let's do it.");
            def IssueService.IssueResult transitionResult = this.issueService.transition(this.authContext.getUser().getDirectoryUser(), validationResult);
            if(transitionResult.isValid()){
                log.warn("Succesfully transitioned: " + transitionResult.getIssue().toString());
            } else {
                showIssueErrors(transitionResult);
            }
            // Here I print out the status of the transition result. It is Reopened!!!!
            log.warn("Transition result status is: " + transitionResult.getIssue().getStatusObject().getName());
        } else {
            showTransitionErrors(validationResult);
        }
        res = validationResult.isValid();
    } else {
        log.warn("NO valid ActionID!!!!")
    }
    return res;
}

This is the Update Function

Issue updateIncomplete(Issue issue) {
    log.warn("updating issue: " + issue.toString() + " which is in state: " + issue.getStatusObject().getName())
    def issueInputParameters = issueService.newIssueInputParameters();
    issueInputParameters.setStatusId(ISSUE_STATUS_REOPENED);
    issueInputParameters.setResolutionId(null);
    IssueService.UpdateValidationResult validationRes = issueService.validateUpdate(authContext.getUser().getDirectoryUser(), issue.getId(), issueInputParameters);
    if(validationRes.isValid()) {
        IssueService.IssueResult updateResult = issueService.update(authContext.getUser().getDirectoryUser(),validationRes);
    } else {
        Collection<String> errors = validationRes.getErrorCollection().getErrorMessages();
        for(String errMsg in errors) {
            log.warn("[ERROR] - Error message:" + errmsg);
        }
    }
    def idxMgr = ComponentAccessor.getIssueIndexManager();
    idxMgr.reIndex(issue);
    log.warn("What is the status of the updated issue?? " + issue.getStatusObject().getName());
}

 

So the issue is in Closed. I transition it. The transition result says status is Reopened. I then do an update to set status to Reopened followed by a reIndex. Status never moves from closed sad

 

Harsh Dubey-Admin June 10, 2019

Same here, did you find any solution for it?

Nic Brough -Adaptavist-
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
June 10, 2019

This is a 4 year old block of code with no Jira version referenced, so there's no way of knowing whether it might have been mildly tweaked to fix it, or completely rewritten.

You will need to check that your code is valid for your version of Jira and then share the detail of what you're doing if you want more help with it.

Harsh Dubey-Admin June 10, 2019

That's correct. I have made necessary code changes at my end. After applying the reindex of issue it doesn't change the status in the UI. I don't know what I'm missing here. The problem is same as above.

Nic Brough -Adaptavist-
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
June 13, 2019

Then your code has not been changed correctly, as it's not changing the status.  I'm afraid we can't tell you what might be wrong without seeing it (and knowing what version of Jira you are aon)

Harsh Dubey-Admin June 13, 2019

Hello Nic,

thanks for your response.

here is the code snippet.

else if( EventType.ISSUE_GENERICEVENT_ID.equals(eventTypeId) && IssueEventSource.WORKFLOW.equals(eventSource)){
//Custom workflow event.

JiraWorkflow workFlow = ComponentAccessor.getWorkflowManager().getWorkflow(issue);
Status status = issue.getStatus();
if(null!= status && status.getName().equalsIgnoreCase("Done")) {
MutableIssue mutableIssue = ComponentAccessor.getIssueManager().getIssueObject(issue.getId());
int actionId = 0;
ChangeHistoryManager changeHistoryManager = ComponentAccessor.getChangeHistoryManager();
String oldStatusId = changeHistoryManager.getChangeItemsForField(issue, "status").get(changeHistoryManager.getChangeItemsForField(issue, "status").size() - 1).getFrom();
Status oldStatus = ComponentAccessor.getConstantsManager().getStatusObject(oldStatusId);
Collection<ActionDescriptor> actions = workFlow.getAllActions();

if(null != oldStatus) {
for (ActionDescriptor actionDescriptor : actions) {
if (actionDescriptor.getName().equals(oldStatus.getName())) {
actionId = actionDescriptor.getId();
}
}

IssueService issueService = ComponentAccessor.getIssueService();
issueService.newIssueInputParameters().setStatusId(oldStatusId).setResolutionId(null).setSkipScreenCheck(true);
IssueService.TransitionValidationResult transitionValidationResult = issueService
.validateTransition(authContext.getLoggedInUser(),
issue.getId(), actionId, issueService.newIssueInputParameters());
if (transitionValidationResult.isValid()) {
transitionValidationResult.getIssue().setStatus(oldStatus);
IssueService.IssueResult transitionResult = issueService.transition(
authContext.getLoggedInUser(), transitionValidationResult);
if (transitionResult.isValid()) {
// Do something
log.info("Valid transition :::: "+ transitionResult.isValid());
IssueIndexingService issueIndexingService = ComponentAccessor.getComponent(IssueIndexingService.class);
IssueIndexingParams params = IssueIndexingParams.INDEX_ALL;
try {
List<Issue> issues = new ArrayList<>();
issues.add(issue);
long durationMillis = issueIndexingService.reIndexIssueObjects(issues, params);
log.info("Re indexed {} issues in {} milliseconds.", issues.size(), durationMillis);
} catch (IndexException e) {
log.warn("Failed to reindex issues.", e);
}
}
}
}


}
}

Harsh Dubey-Admin June 13, 2019

I'm using Jira 7.10, please help.

0 votes
Timothy Harris May 28, 2015

Well, I am using issueService to do the transitions and to me it looks as if it is broken. I have a listener on issue event "Closed". If a condition is met, I am moving the issue back to "Reopened". There is more to the use case but that is not important right now and I don't think it maters what event you are listening to or the status you want to transition the issue to.

Basically the status and resolution are NOT set but the issue HAS BEEN transitioned in the workflow. I think it is because the previous transition and update is somehow NOT complete. Even though the I have recieved the "IssueClosed" event. 

From an agile board I drag an issue to "Closed" status.

  • My listener detects "IssueClosed" event. 
  • Checks some conditions and transitions the event to "Reopen status". 

On the board the issues status and resolution are still "Closed" and "Fixed". If I open the issue, the workflow shows the issue is in the "Reopened" status, i.e, I can transition it to "In Progress". So the issue status and resolutiona are out of sync. I have tried updating Status and resolution on the issue AFTER the transition but have had no luck.

If my assumption that the issue is still being processed by the UI action when I try to transition it to a new state is correct. And this is the cause of the failed updates then I think the API could be called broken. I think it should ensure ordered actions on issues. Either by queueing them or by not sending the event until the issue updates are actually finished.

 

Nic Brough -Adaptavist-
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
May 28, 2015

Those symptoms are yelling "the indexing is not being done". As a general rule, JIRA works off the index, so most searches and displays like the issue navigator and gadgets are showing you index data. Issue updates and, most importantly, issue *view* read the database. So when you change an issue and it looks fine in view but wrong in the navigator/gadget/board, it's the index. Does your code try to index the changed issue at all?

Timothy Harris May 28, 2015

This is the function I am calling from the IssueClosed event. boolean transitionIssue(Issue issue, int actionID, String targetStatus) { log.warn("Trying to transition issue " + issue.getKey() + " with action ID " + actionID + "\n"); IssueService.TransitionValidationResult validationResult; def res = false; if (actionID) { def idxMgr = ComponentAccessor.getIssueIndexManager(); def issueInputParameters = issueService.newIssueInputParameters(); issueInputParameters.setStatusId(targetStatus); issueInputParameters.setResolutionId(null); validationResult = this.issueService.validateTransition(this.authContext.getUser().getDirectoryUser(), issue.getId(), actionID, issueInputParameters); if (validationResult.isValid()) { log.warn("Transition validated. Let's do it."); def IssueService.IssueResult transitionResult = this.issueService.transition(this.authContext.getUser().getDirectoryUser(), validationResult); if(transitionResult.isValid()){ log.warn("Succesfully transitioned: " + transitionResult.getIssue().toString()); } else { Collection<String> errors = transitionResult.getErrorCollection().getErrorMessages(); for (errmsg in errors){ log.warn("[ERROR] - Error message:" + errmsg); } } idxMgr.reIndex(validationResult.getIssue()); } else { Collection<String> errors = validationResult.getErrorCollection().getErrorMessages(); for (errmsg in errors) { log.warn("[ERROR] - Error message:" + errmsg); } } res = validationResult.isValid(); } else { log.warn("NO valid ActionID!!!!") } return res; } I have also tired a full reindex but that changes nothing.

Timothy Harris May 28, 2015

Sorry it's a bit messy. But I do call reIndex with the ValidationResult. Quite possible I am doing something wrong. So any help would be appreciated!

Timothy Harris May 28, 2015

Also why would issue service not simple call the reIndex itself?

Comments for this post are closed

Community moderators have prevented the ability to post new answers.

Post a new question

TAGS
AUG Leaders

Atlassian Community Events