Status rollback after transition

Mário dos Santos _TOTVS_ April 24, 2017

I've an intermittent trouble when doing a transition in an issue parent.
There is a post function that solves the subtasks and this action is occurring normally.
However, sometimes the parent issue is transitioned but your status back to the previous.
In the history and transitions tab panels I can see that issue is in the final status which it should is.
There is no information in history or log that indicates what is happen.
I assume that is a possible rollback, but nothing is thrown in the log file.

To clarify, the issue below is in 'PRONTO PARA EXPEDIÇÃO' status.

 

Sem título.png

 

 

But seeing the moviments, it should to be in 'EXPEDIDO' status.

There isn't in the workflow a transition that leaves status back on this way.

 

Someone have any ideia how to fix this?

 

Thanks.

2 answers

0 votes
JohnsonHoward
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 27, 2017

Ok and do you get an error on the times that it fails?

Mário dos Santos _TOTVS_ April 27, 2017

No, nothing falls on atlassian-jira.log file around the transition time.

Mário dos Santos _TOTVS_ April 27, 2017

I think can be a bug in JIRA or Scriptrunner maybe.

I'm able to reproduce this exact behavior making a simple script post function like this:

def subTasks = issue.subTaskObjects
subTasks.each { subTask -> 

// Here, make a transition

}

// Here, updating the issue and making external update


When I leave the transitions on subtask by last, like below, the bug go away.

 

// Here, updating the issue and making external update

def subTasks = issue.subTaskObjects
subTasks.each { subTask -> 

// Here, make a transition

}

 

 

But, it isn't the case of my Script, else it would fail every time.

 

Could you test the above condition to rule out a possible problem in my environment, please?

JohnsonHoward
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 27, 2017

The transition code seems to work fine for me. You say the error where the parent task is left in it's previous status only happens once ever 200 times on average? This might suggest that it is something on the issue that is causing it to fail. Have you looked for trends accross the issues that it is failing for?

JohnsonHoward
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 27, 2017

Also, which version of JIRA and ScriptRunner are you using?

JohnsonHoward
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 27, 2017

It seems like this might be a known issue with the IssueService, it might be best to user IssueManager and do issue.setStatus() on the issue then do issue.updateIssue(). This should correctly set the status if the transition fails.

Mário dos Santos _TOTVS_ April 28, 2017

I'm using JIRA 7.1.2 and ScriptRunner 4.3.16

About the trends on fail issues I didn't find apparent similarity.
I was suspecting the number of subtasks (in some cases with 400 or more). But there were parent failure with 30 subtasks, for example.

For the suggestion to use IssueManager instead IssueService, would you think the problem is in update the subtasks?

Because in that scenario, all subtasks are updated correctly. The even problem is in the parent issue. In this way, the update of the status is being doing by standard workflow post functions (only with the mentioned listener like last in list).

Therefore, the listener runs transitioning all subtasks and finishes. The JIRA makes the transition (or, in that case, it doesn't get to do it completely until the end).

The curious thing is that everything seems to happen correctly because it records the history, transitions, comments and after that the problem occurs.

0 votes
JohnsonHoward
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 27, 2017

Hi Mário dos Santos,

 

Do you have the code for the post-function that I can look at please?

 

Thanks,

Johnnson

Mário dos Santos _TOTVS_ April 27, 2017

Currently, I'm using it into a listener to reuse in others workflows.

But even though using it in the listener, the blinking continues.

The rate of this failure is more or less one for every 200 issues processed.

 

import groovy.json.JsonOutput
import com.atlassian.jira.issue.*
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.attachment.Attachment
import javax.ws.rs.core.MultivaluedMap
import com.atlassian.jira.util.io.InputStreamConsumer
import org.apache.commons.io.IOUtils
import java.net.HttpURLConnection;
import com.atlassian.jira.issue.fields.*
import java.net.URL;
import groovyx.net.http.HTTPBuilder
import org.apache.commons.codec.binary.Base64
import java.io.OutputStream
import java.io.BufferedInputStream
import groovy.json.JsonSlurper
import groovy.json.JsonOutput 
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.bc.issue.IssueService
import com.atlassian.jira.user.ApplicationUser

class Global {
    static String baseUrl = ComponentAccessor.getApplicationProperties().getString("jira.baseurl")
    static String urlAddTags = baseUrl+'/rest/scriptrunner/latest/custom/addTagsToZendesk?'
    static String urlGetAttachmentToken = baseUrl+'/rest/scriptrunner/latest/custom/getTokenForLastAttachment?'
    static String urlSendAttachment = baseUrl+'/rest/scriptrunner/latest/custom/sendAttachment?'
    static String urlAddComment = baseUrl+'/rest/scriptrunner/latest/custom/addComment?'
    static String cfTicket = "customfield_11086"
    static String cfNomeCliente = "customfield_11071"
    static String cfEndCentralDownloads = "customfield_11054"
    static String tipoContrato = "customfield_11037"
}

def issue = event.getIssue()

def commentManager = ComponentAccessor.getCommentManager()
def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()

CustomField cfTicket = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(Global.cfTicket)
CustomField cfNomeCliente = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(Global.cfNomeCliente)
CustomField cfEndCentralDownloads = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(Global.cfEndCentralDownloads)
CustomField tipoContrato = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(Global.tipoContrato)

def ticket = issue.getCustomFieldValue(cfTicket) as String
ArrayList contratos = issue.getCustomFieldValue(tipoContrato) as ArrayList
def nomeCliente = issue.getCustomFieldValue(cfNomeCliente) as String
def endCentralDownloads = issue.getCustomFieldValue(cfEndCentralDownloads) as String
def issueKey = issue.getKey()

if (ticket != null && nomeCliente != null) {
    
    ticket = ticket.replace("]","")
    ticket = ticket.replace("[","")
    
    String commentValue
    commentValue = "Olá " + nomeCliente + ",\n\n" +
    "A Release Oficial foi expedida e publicada na Central de Downloads.\n" +
    "O pacote pode ser acessado no endereço: " + endCentralDownloads
    
    //Adiciona comentário no JIRA
    commentManager.create(issue, user, commentValue, false)
    //Adiciona comentário no Zendesk
    addComment(issueKey, ticket, commentValue)
    def outputTAG
    if (contratos != null) {
        for (int i = 0; i <= contratos.size(); i++) {
            if (contratos[i].toString() == "CLOUD") {
                outputTAG = "tags=exp_cloud&tags=exp_def&tags=jira_issue_resolvida"
                break
            }
        }
        if (outputTAG==null) {
            outputTAG = "tags=exp_def&tags=jira_issue_resolvida"
        }
        addTag(issueKey, ticket, outputTAG)
    }
}

def issueService = ComponentAccessor.getIssueService()
def userManager = ComponentAccessor.getUserManager()
ApplicationUser userAdmin = userManager.getUserByKey("integrador.jira")

if (!issue.isSubTask()) {
    def subTasks = issue.getSubTaskObjects()
    subTasks.each {
        if (it.getStatus().name == "Associado") {
            def issueInputParameters = issueService.newIssueInputParameters()
            def actionID = 131
            def validationResult = issueService.validateTransition(userAdmin, it.id, actionID,issueInputParameters)
            if (validationResult.isValid()) {
               def issueResult = issueService.transition(user, validationResult)
               if (! issueResult.isValid()) {
                   log.warn("Failed to transition subtask " + it.key + " errors: " + issueResult.errorCollection)
               }
            }
            else {
                log.warn("Could not transition subtask " + it.key + " errors: " + validationResult.errorCollection)
            }
        }  
    }
}

Object addTag(String issueKey, String ticket , String tags) {
    URL url = new URL(Global.urlAddTags + 'issueKey=' + issueKey + '&ticket=' + ticket + '&' + tags)
    HttpURLConnection conn = (HttpURLConnection) url.openConnection()
    conn.setRequestMethod("GET")
    conn.setDoOutput(true)
    def sb = new StringBuffer()
    def is = new BufferedInputStream(conn.getInputStream())
    def br = new BufferedReader(new InputStreamReader(is))
    def inputLine = ""
    while ((inputLine = br.readLine()) != null) {
        sb.append(inputLine)
    }
    return new JsonSlurper().parseText(sb.toString())
}

Object addComment(String issueKey, String ticket, String commentValue) {
    def urlString = Global.urlAddComment + 'issueKey=' + issueKey + '&ticket=' + ticket + '&commentValue=' + URLEncoder.encode(commentValue, "UTF-8")
    URL url = new URL(urlString)
    HttpURLConnection conn = (HttpURLConnection) url.openConnection()
    conn.setRequestMethod("GET")
    conn.setDoOutput(true)
    def sb = new StringBuffer()
    def is = new BufferedInputStream(conn.getInputStream())
    def br = new BufferedReader(new InputStreamReader(is))
    def inputLine = ""
    while ((inputLine = br.readLine()) != null) {
        sb.append(inputLine);
    }
    return new JsonSlurper().parseText(sb.toString())
}

Suggest an answer

Log in or Sign up to answer
TAGS
AUG Leaders

Atlassian Community Events