Search code examples
jirastack-overflowinfinite-loopjira-pluginscriptrunner-for-jira

Infinite loop - stackoverflow exception jira scriptrunner


I have an infinite loop in my code at the level of lines 125 and 133. More specifically, these are lines

   ComponentAccessor.getIssueService().transition(mycurrentUser, myresult2)

and line

IssueService.TransitionValidationResult myresult = ComponentAccessor.getIssueService().validateTransition(mycurrentUser, issue.getId(), transitionToBeDoneInt, inputParameters);

Here is my full code below. Anyone knows what is causing this infinite loop? I have looked at my code many times and I really don't understand what's wrong. I am using Jira and scriptrunner for a postfunction which is supposed to add a new comment. this code has nothing recursive in it. It is simply supposed to do a transition and that's it, NO RECURSION. The error is so weird because I am having an infinite loop even though the code is not presenting any signs of recursion.

My code is very simple, it only needs to execute 1 transition and write a comment, no recursion and no loops are required in my code.

import com.opensymphony.workflow.WorkflowContext
import com.atlassian.jira.issue.Issue;
import java.util.List;
import org.apache.log4j.Logger;
import com.atlassian.jira.issue.ModifiedValue;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.component.ComponentAccessor
import org.ofbiz.core.entity.GenericDelegator;
import com.atlassian.jira.issue.changehistory.ChangeHistoryManager;
import com.atlassian.jira.issue.history.ChangeItemBean;
import com.atlassian.jira.issue.comments.Comment
import com.atlassian.jira.workflow.JiraWorkflow
import com.atlassian.jira.workflow.WorkflowManager
import com.atlassian.jira.issue.changehistory.ChangeHistoryItem
import com.onresolve.scriptrunner.runner.util.UserMessageUtil
import com.atlassian.jira.config.SubTaskManager
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.link.LinkCollectionImpl;
import com.atlassian.jira.issue.link.IssueLink;
import com.atlassian.crowd.embedded.api.User;
import com.atlassian.jira.issue.comments.CommentManager;
import com.atlassian.jira.issue.link.IssueLinkManager;
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.jira.util.ErrorCollection;
import com.atlassian.jira.util.JiraUtils;
import com.atlassian.jira.workflow.JiraWorkflow;
import com.atlassian.jira.workflow.WorkflowManager;
import com.atlassian.jira.workflow.WorkflowTransitionUtil;
import com.atlassian.jira.workflow.WorkflowTransitionUtilImpl;
import com.atlassian.jira.workflow.function.issue.AbstractJiraFunctionProvider;
import com.opensymphony.module.propertyset.PropertySet;
import com.opensymphony.workflow.WorkflowException;
import com.opensymphony.workflow.loader.StepDescriptor;
import com.opensymphony.workflow.spi.SimpleStep;
import com.atlassian.jira.config.ConstantsManager
import com.atlassian.jira.workflow.ImmutableWorkflowDescriptor
import com.atlassian.jira.web.action.admin.workflow.ViewWorkflowStep
import com.opensymphony.workflow.loader.ActionDescriptor
import com.atlassian.jira.issue.IssueInputParametersImpl
import com.atlassian.jira.issue.IssueInputParameters
import com.atlassian.jira.bc.issue.IssueService.IssueValidationResult
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.workflow.WorkflowTransitionUtil
import com.atlassian.jira.workflow.WorkflowTransitionUtilFactory
import com.atlassian.jira.workflow.TransitionOptions
import com.atlassian.jira.bc.issue.IssueService
import com.atlassian.jira.bc.issue.IssueService.TransitionValidationResult

def log = Logger.getLogger("atlassian-jira.log")
log.warn("This is the last action ")

WorkflowManager workflowManager = ComponentAccessor.getWorkflowManager();
JiraWorkflow workflow = workflowManager.getWorkflow(issue);

def wfd = workflow.getDescriptor()
def actionName = wfd.getAction(transientVars["actionId"] as int).getName(); 

//Get worklflowname By actionId
int transitionToBeDone = transientVars["actionId"] as int;


 log.warn("CAM 1 "+ transitionToBeDone)

 
ApplicationUser mycurrentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
log.warn("CAM 2")


log.warn("CAM 3")
  int transitionToBeDoneInt = transitionToBeDone as Integer
        
List currentSteps = (ArrayList)transientVars.get("currentSteps");
log.warn("CAM 4 "+currentSteps)

SimpleStep simpleStep = currentSteps.get(0);
log.warn("CAM 5 "+simpleStep)


int beforeStepId = simpleStep.getStepId();
log.warn("CAM 6 "+beforeStepId)

ActionDescriptor ad = workflow.getDescriptor().getAction(transitionToBeDoneInt);
int afterStep = ad.getUnconditionalResult().getStep();
log.warn(" cam 7 "+afterStep)
log.warn( "resolved transition target last "+ComponentAccessor.workflowManager.getNextStatusIdForAction(issue , transientVars['actionId'] as int) )

 targetStatus=ComponentAccessor.workflowManager.getNextStatusIdForAction(issue ,transitionToBeDoneInt)
log.warn(" cam 8")

def constantsManager = ComponentAccessor.getConstantsManager()
log.warn(" cam 9")

def statusName=constantsManager.getStatus(targetStatus).getName();
log.warn(" cam 10")

log.warn("cam  transition target "+targetStatus + "status name "+statusName)
 log.warn("CAM 11")




    log.warn("cam 12")

log.warn("cam 13")

    
def mounaComment= "+++ added via workflow action "+"\""+actionName+"\"+++"
log.warn("cam 12"+mounaComment)

String content = (transientVars["comment"] +"\n"+mounaComment ) as String
log.warn("cam 13"+ content)
transientVars["comment"]= content
//inputParameters.setComment(content)
log.warn("cam 14"+ content)



log.warn("CAM 15 "+ issue.getKey())


def inputParameters = ComponentAccessor.getIssueService().newIssueInputParameters();
log.warn("CAM 16 "+ mycurrentUser+" "+issue.getId()+" "+ transitionToBeDoneInt+" "+inputParameters)

IssueService.TransitionValidationResult myresult = ComponentAccessor.getIssueService().validateTransition(mycurrentUser, issue.getId(), transitionToBeDoneInt, inputParameters);
def myresult2= myresult; 
 log.warn("CAM 16 "+ issue.getKey())

try {
    if(myresult2.isValid()) {
    log.warn("CAM 17 "+mycurrentUser+" ")

    ComponentAccessor.getIssueService().transition(mycurrentUser, myresult2)
     
}

} catch(Exception e) {
        log.warn("CAM 18 "+e)

      log.warn (result.getErrorCollection().getErrors());

}
    

Here is a snippet of what is printed in my error log enter image description here


Solution

  • I did not test it, but it looks to me that you are transitioning the issue with the same transition again, which again will execute that post function again, which will transition the issue with the same transition again, which will execute your post function again ... and so on and so on. This should also happen in the same Thread, which therefore results in a StackOverflowError, even though your Script does not have any recursion or other infinite loop.

    I am quite sure that your code to transition the issue with the transition is not needed there. Your script is a Post Function, which happens as the last step of a transition. transientVars['actionId'] should give you that exact transition id, therefore you end up transition the issue with the same transition again.

    If you just want to add the comment, then just leave the code about adding your comment and remove all the rest about transitioning the issue.