can we create a listener to update a field in one project when field in another project is updated

jui kulkarni May 21, 2024

We have a project R which holds the requirements and a project T which holds the test cases.
We now want to change the status of the test case and update a custom field when a certain field of requirement object is changed.
How can we do this using scriptrunner listener?

1 answer

1 accepted

0 votes
Answer accepted
Matt Parks
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.
May 22, 2024

You could create an Automation rule that publishes an event when the custom field is changed on the requirement.

Then create a script listener that listens for that event which executes a transition on the test case.

If you're wondering how to actually execute the transition on the test case, below is an example of a script that I use to do that, although you'll have to have some association between the requirement and the test case in order for this to work.

In the example below, the script triggers when a version is released. It first grabs all of the issues associated with that release and iterates through them to execute the 'Done' transition and adds a comment if it was successful. If it turns out that the issue wasn't already in the Done status but still couldn't execute the transition, it removes the issue from that Release.

There is some extra stuff in the script that you don't have to include (the writeLog functions), but, as long as you can figure out what test cases you're trying to transition, this should get you there.

As a note, I'm running 9.12.4 and I had to update the part of the script where it tries to execute the transition, as the code I was using in 8.20.26 no longer worked after the upgrade.

 

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.project.version.VersionManager
import com.atlassian.jira.project.version.Version
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.security.JiraAuthenticationContext;
import com.atlassian.jira.event.type.EventDispatchOption;
import com.atlassian.jira.bc.issue.search.SearchService;
import com.atlassian.jira.bc.issue.IssueService;
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.jira.issue.MutableIssue;
import com.atlassian.jira.user.util.UserUtil;
import com.atlassian.jira.util.ImportUtils;
import groovy.transform.Field;
import com.atlassian.jira.issue.index.IssueIndexingService;
import com.opensymphony.workflow.loader.ActionDescriptor;
import com.atlassian.jira.workflow.WorkflowManager;  
import com.atlassian.jira.util.ErrorCollection;
import com.atlassian.jira.workflow.IssueWorkflowManager
import com.atlassian.jira.event.project.VersionReleaseEvent
import com.atlassian.jira.bc.issue.IssueService
import com.atlassian.jira.workflow.TransitionOptions

@field boolean writeDebugLogs = false;
@field ApplicationUser user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser();
@field SearchService searchService = ComponentAccessor.getComponent(SearchService.class);
@field IssueManager issueManager = ComponentAccessor.getIssueManager();
@field UserUtil userUtil = ComponentAccessor.getUserUtil();
@field IssueIndexingService issueIndexingService = ComponentAccessor.getComponent(IssueIndexingService);
@field WorkflowManager workflowManager = ComponentAccessor.getComponent(WorkflowManager);

def releaseEvent = event as VersionReleaseEvent
def versManager = ComponentAccessor.getVersionManager()
def fixVersion = releaseEvent.getVersion()

def issuesInVersion = versManager.getIssuesWithFixVersion(fixVersion)
MutableIssue mutIssue

issuesInVersion.each
{
    def item = issueManager.getIssueObject(it.getKey());
    mutIssue = (MutableIssue) item
    tryTransitionIssue(mutIssue, "Done")
}

int getTransitionIdByName(MutableIssue issue, String transitionName)
{
    writeLog("Trying to get transition ID for " + transitionName)
    def issueWorkflow = ComponentAccessor.getComponentOfType(IssueWorkflowManager.class);
    Collection<ActionDescriptor> actions = issueWorkflow.getAvailableActions(issue, user);
   
    for (action in actions)
    {
       
        def stepName = action.getName();
        if (stepName != transitionName)
        {
            writeLog(stepName + " did not match " + transitionName)
            continue;
        }
        writeLog("Found " + stepName)
        return action.getId();
    }
   
    writeLog("didn't find any step name match")
    if (issue.status.name != "Done")
    {
        issue.setFixVersions(null)
        ComponentAccessor.getIssueManager().updateIssue(user, issue, EventDispatchOption.DO_NOT_DISPATCH, false)
        reindexIssue(issue)
    }
   
    return -1;
}

void tryTransitionIssue(MutableIssue issue, String transitionName)
{  
    writeLog("Trying to transition issue")
    def actionId = getTransitionIdByName(issue, transitionName);

    if (actionId <= 0)
    {
        return;
    }
   
    IssueService issueService = ComponentAccessor.getIssueService()
    ApplicationUser currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
    TransitionOptions transitionOptions = new TransitionOptions.Builder()
            .skipConditions()
            .skipPermissions()
            .skipValidators()
            .build()

    IssueService.TransitionValidationResult result = issueService.validateTransition(currentUser,
            issue.getId(),
            actionId,
            issueService.newIssueInputParameters(),
            transitionOptions)

    if (result.isValid()) {
        issueService.transition(currentUser, result)
    } else {
        log.warn result.getErrorCollection().getErrors()
    }
   
    def commentManager = ComponentAccessor.getCommentManager()
    def commentBody = "Issue has been transitioned to ${transitionName} because the version has been released"
    commentManager.create(issue, user, commentBody, false)
   
    reindexIssue(issue);
}


void reindexIssue(Issue issue)
{
    boolean wasIndexing = ImportUtils.isIndexIssues();
    ImportUtils.setIndexIssues(true);
    issueIndexingService.reIndex(issueManager.getIssueObject(issue.id));
    ImportUtils.setIndexIssues(wasIndexing);
}

 
boolean hasErrors(ErrorCollection errs)
{
    if (errs == null)
    {
        return false;
    }

    int errCount = 0;
    def errMaps = errs.getErrors();
    def errMsgs = errs.getErrorMessages();
    if (errMsgs != null)
    {
        errCount = errCount + errMsgs.size();
    }
 
    if (errMaps != null)
    {
        errCount = errCount + errMaps.size();
    }

    if (errCount == 0)
    {
        return false;
    }

    for(errMsg in errMsgs)
    {
        log.error(errMsg);
    }

    for(errMap in errMaps)
    {
        log.error("Field ${errMap.key} Error: ${errMap.value}");
    }

    return true;
}

void writeLog(String note)
{
    writeLog(note, writeDebugLogs);
}

void writeLog(String note, boolean write)
{
    if (!write)
    {
        return;
    }
    log.error(note);
}
jui kulkarni May 23, 2024

Thank you very much @Matt Parks .
We might need to make some changes as per our requirement. But we now have some starting point.

Suggest an answer

Log in or Sign up to answer