Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

Script to transition issue during create workflow instead of fast-track

T0pH0ur March 27, 2025

Hello,

Ive made a POC where we have an issue type and sub-tasks. The design is that when a new Event is logged we will have the subtasks auto-generated for the event manager.

Based on a select list choice, the issue transitions from Open to In-Progress and generates a specific set of subtasks.

The setup is working perfectly to create the subtasks on transition and with the POC using the ScriptRunner "Fast Track transition an issue" post function after the create event in the create transtion it worked as intended

I need to have 32 different transitions, so a bit of a pain to build with fast-track post functions and maintain, so i wrote a script.

Placing the script after the event, yields nothing, yet there are no errors in script. Im hoping Im just missing something small 

here is the simplified version, thanks for any assistance:

 

///////
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.customfields.option.Option

//field id
long fieldId = 13847L;

//map of Select list value to Transition ID
Map typeMap = [
"List Option 1": 151,
"List Option 2": 81,
"List Option 3": 61
];
def customFieldManager = ComponentAccessor.getCustomFieldManager();
CustomField field = customFieldManager.getCustomFieldObject(fieldId);
Option fieldOpt = issue.getCustomFieldValue(field) as Option;
def fieldVal = fieldOpt.getValue() as String;
def transitionID = typeMap[fieldVal];
issue.transition(transitionID);

3 answers

1 accepted

2 votes
Answer accepted
Sergei Troshin
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 27, 2025

Hi @T0pH0ur hope you're doing well!

I'm familiar with this HAPI issue, but I’m not sure why it’s not working, as I can’t see the source code. Let me share the code I use for such cases:

import groovy.transform.Field
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.util.ErrorCollection
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.workflow.TransitionOptions
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.workflow.IssueWorkflowManager
import com.atlassian.jira.workflow.WorkflowTransitionUtil
import com.atlassian.jira.issue.customfields.option.Option
import com.atlassian.jira.workflow.WorkflowTransitionUtilFactory

@Field final IssueWorkflowManager issueWorkflowManager = ComponentAccessor.getComponent(IssueWorkflowManager.class)
@Field final WorkflowTransitionUtilFactory workflowTransitionUtilFactory = ComponentAccessor.getComponent(WorkflowTransitionUtilFactory.class)
@Field final long SELECT_LIST_CF_ID = 10400
@Field final Map<String, Integer> OPTIONS_AND_TRANSITIONS_MAP = [
    "Option #1": 11,
    "Option #2": 21,
    "CustomOption #3": 31
]

MutableIssue issue = (MutableIssue) issue

CustomField optionField = ComponentAccessor.customFieldManager.getCustomFieldObject(SELECT_LIST_CF_ID)
Option option = issue.getCustomFieldValue(optionField) as Option

if (Objects.isNull(option)) {
    log.warn("Option field is empty")
    return
}

String optionValue = option.getValue()
Integer transitionId = OPTIONS_AND_TRANSITIONS_MAP.get(optionValue)

if (Objects.isNull(transitionId)) {
    log.warn("No mapping for $optionValue option")
    return
}

doTransition(issue, transitionId, Users.getByName("jirabot"), true)

boolean doTransition(MutableIssue mutableIssue, int actionId, ApplicationUser user, boolean skipRestrictions) {

    TransitionOptions.Builder builder = new TransitionOptions.Builder();
    TransitionOptions transitionOptions =
        skipRestrictions
            ? builder.skipConditions().skipPermissions().skipValidators().build()
            : builder.build()

    if (!issueWorkflowManager.isValidAction(mutableIssue, actionId, transitionOptions, user)) {
        return false
    }

    WorkflowTransitionUtil workflowTransitionUtil = workflowTransitionUtilFactory.create()
    workflowTransitionUtil.setAction(actionId)
    workflowTransitionUtil.setIssue(mutableIssue)
    workflowTransitionUtil.setUserkey(user.getKey())

    Map<String, ErrorCollection> errors = new HashMap<>();
    errors.put("validate", workflowTransitionUtil.validate());
    boolean result = !errors.get("validate").hasAnyErrors();
    errors.put("progress", workflowTransitionUtil.progress());

    if (errors.get("progress").hasAnyErrors()) {
        result = false;
    }

    return result;
}

Here is also this code in GitHub

Important! I've tested this code in my test environment, but I strongly recommend that you test it again in your own environment.

Sergei Troshin
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 27, 2025

Ooh, i forgot mention that you have to put this script at the end of post-functions:
screen1.png

T0pH0ur March 27, 2025

Hey @Sergei Troshin

 

Thanks for this. Ive added the script to the end of the post function stack as the other was before, swapping out my map values and adding in some debug to see where it might fail.

It still errors out when attempting to call the function to handle the transition. I notice on your screenshot it seems this is not in the create transition. While the normal fast track post function works there, im curious if an issue here for it?

Sergei Troshin
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 28, 2025

Hi @T0pH0ur hope you're doing well!

Oh, sorry, I misunderstood—you need to put this on the Create transition.

In this case, we first need to change OSWorkflowEntry from Created to Activated before performing the Fast-track action.


Here is complete script:

import groovy.transform.Field
import org.ofbiz.core.entity.GenericValue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.ofbiz.OfBizDelegator
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.util.ErrorCollection
import com.atlassian.jira.issue.fields.CustomField
import com.opensymphony.workflow.spi.WorkflowEntry
import com.atlassian.jira.workflow.TransitionOptions
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.workflow.IssueWorkflowManager
import com.atlassian.jira.workflow.WorkflowTransitionUtil
import com.atlassian.jira.issue.customfields.option.Option
import com.atlassian.jira.workflow.WorkflowTransitionUtilFactory

@Field final IssueWorkflowManager issueWorkflowManager = ComponentAccessor.getComponent(IssueWorkflowManager.class)
@Field final WorkflowTransitionUtilFactory workflowTransitionUtilFactory = ComponentAccessor.getComponent(WorkflowTransitionUtilFactory.class)
@Field final long SELECT_LIST_CF_ID = 10400

@Field final Map<String, Integer> OPTIONS_AND_TRANSITIONS_MAP = [
    "Option #1": 11,
    "Option #2": 21,
    "CustomOption #3": 31

]

MutableIssue issue = (MutableIssue) issue

CustomField optionField = ComponentAccessor.customFieldManager.getCustomFieldObject(SELECT_LIST_CF_ID)
Option option = issue.getCustomFieldValue(optionField) as Option

if (Objects.isNull(option)) {
    log.warn("Option field is empty")
    return
}

String optionValue = option.getValue()
Integer transitionId = OPTIONS_AND_TRANSITIONS_MAP.get(optionValue)

if (Objects.isNull(transitionId)) {
    log.warn("No mapping for $optionValue option")
    return
}

doTransition(issue, transitionId, Users.getByName("jirabot"), true)

boolean doTransition(MutableIssue mutableIssue, int actionId, ApplicationUser user, boolean skipRestrictions) {
    final OfBizDelegator ofBizDelegator = ComponentAccessor.getOfBizDelegator()
    final IssueWorkflowManager issueWorkflowManager = ComponentAccessor.getComponent(IssueWorkflowManager.class)
    final WorkflowTransitionUtilFactory workflowTransitionUtilFactory = ComponentAccessor.getComponent(WorkflowTransitionUtilFactory.class)

    GenericValue gv = ofBizDelegator.findByPrimaryKey("OSWorkflowEntry", mutableIssue.getWorkflowId());
    if (Objects.isNull(gv)) {
        log.warn("gv is null")
        return
    }

    if ((Integer) gv.get("state") == WorkflowEntry.CREATED) {
        gv.set("state", WorkflowEntry.ACTIVATED)
        gv.store()
    }

    TransitionOptions.Builder builder = new TransitionOptions.Builder();
    TransitionOptions transitionOptions =
        skipRestrictions
            ? builder.skipConditions().skipPermissions().skipValidators().build()
            : builder.build()

    if (!issueWorkflowManager.isValidAction(mutableIssue, actionId, transitionOptions, user)) {
        return false
    }

    WorkflowTransitionUtil workflowTransitionUtil = workflowTransitionUtilFactory.create()
    workflowTransitionUtil.setAction(actionId)
    workflowTransitionUtil.setIssue(mutableIssue)
    workflowTransitionUtil.setUserkey(user.getKey())

    Map<String, ErrorCollection> errors = new HashMap<>();
    errors.put("validate", workflowTransitionUtil.validate());
    boolean result = !errors.get("validate").hasAnyErrors();
    errors.put("progress", workflowTransitionUtil.progress());

    if (errors.get("progress").hasAnyErrors()) {
        result = false;
    }

    return result;
}
T0pH0ur March 28, 2025

hey again @Sergei Troshin ,

Thanks so much for the follow-up. This morning when i came in, before this was posted, I thought about how previously using fast track works from create, so my workaround was simply to add a status inline using the existing fast-track plugin on the create and then actually my script that I started the question off worked perfectly

I accepted your answer as this will hopefully provide others with two options should they run into the same situation and find this.

Cheers!

Topher

0 votes
Sergei Troshin
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 27, 2025

Here was accidently duplicated message

0 votes
Dick
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
March 27, 2025

Hi @T0pH0ur 

I'm not familiar with scriptrunner, but you should start by logging the in-between results and proof that a certain piece of script has been executed. 

This post can help you realize this.

Kind regards,

Dick

T0pH0ur March 27, 2025

hey @Dick thanks

 

So the script fails entirely at the end here:

issue.transition(transitionID);

 

My last log before shows it makes it to get the tansition ID(note this is on the full length with many more transitions and 51 is a valid transition):

"Made it to final step with transition ID as 51" 

 

Do you know if ther is an issue to transition using the ID?

Suggest an answer

Log in or Sign up to answer