Is there a way to ensure/enforce fix version so that sub tasks match the parent issue?

Rob Horan
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 5, 2016

Right now it is possible to have a mismatch of fix version between parent and sub task.  I want to ensure that this is not possible.  No value is fine, as long as all tickets are empty.

Script Runner or other paid plugins are not an option.

1 answer

1 accepted

0 votes
Answer accepted
Jeremy Gaudet
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 5, 2016

I have a Script Runner script listener for this exact case, though I'm also syncing a custom field called "Verified Version/s".  You probably don't need that, but I'll include it as an example.  It's implemented as a groovy class file, here is a sanitized version:

import com.atlassian.jira.event.issue.AbstractIssueEventListener;
import com.atlassian.jira.event.issue.IssueEvent;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.project.version.Version;
import com.atlassian.jira.config.SubTaskManager;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.issue.CustomFieldManager;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.event.type.EventDispatchOption;
import com.atlassian.jira.workflow.WorkflowManager;
import com.atlassian.jira.workflow.JiraWorkflow;
import java.util.ArrayList;
import java.util.Collection;
class SyncParentFixVerifiedVersionsToSubTask extends AbstractIssueEventListener 
{
    Category log = Category.getInstance(SyncParentFixVerifiedVersionsToSubTask.class);
    SubTaskManager subTaskManager = ComponentManager.getInstance().getSubTaskManager();
    WorkflowManager workflowManager = ComponentManager.getInstance().getWorkflowManager();
    IssueManager issueManager = ComponentManager.getInstance().getIssueManager();
    CustomFieldManager customFieldManager = ComponentManager.getInstance().getCustomFieldManager();
    Boolean changed = false;
    Long workflowId;
    @Override
    void workflowEvent(IssueEvent event) {
        try {
            if (subTaskManager.isSubTasksEnabled()) {
                Issue eventIssue = event.getIssue();
                JiraWorkflow workflow = workflowManager.getWorkflow(eventIssue);
                if (workflow.getName() == "Put Workflow Name Here") {
                    CustomField vvcf = customFieldManager.getCustomFieldObjectByName("Verified Version/s");
                    if ( !eventIssue.getIssueTypeObject().isSubTask() ) {
                        // Change is on a potential parent, sync to sub-tasks if there are any
                        Collection<Issue> subTasks = eventIssue.getSubTaskObjects();
                        List changeItems = event.getChangeLog().getRelated("ChildChangeItem");
                        // Sync FixVersion/s
                        if( changeItems.any {it.get('field')=='Fix Version'} ) {
                            changed = true;
                            // Collection<Version> fixVersions = new ArrayList<Version>();
                            // fixVersions = eventIssue.getFixVersions();
                            Collection<Version> fixVersions = eventIssue.getFixVersions();
                            if (!subTasks.isEmpty()) {
                                subTasks.each {
                                    it.setFixVersions(fixVersions);
                                }                     
                            }
                        }
                        // Sync Verified Version/s
                        if( changeItems.any {it.get('field')=='Verified Version/s'} ) {
                            changed = true;
                            Collection<Version> verifiedVersions = new ArrayList<Version>();
                            verifiedVersions = eventIssue.getCustomFieldValue(vvcf);
                            if (!subTasks.isEmpty()) {
                                subTasks.each {
                                    it.setCustomFieldValue(vvcf,verifiedVersions);
                                }
                            }
                        }
                        if (changed) {
                            subTasks.each {
                                issueManager.updateIssue(event.getUser(), it, EventDispatchOption.ISSUE_UPDATED, false);
                            }
                        }
                    } else {
                        // Change is on a sub-task, sync from the parent if they are out of sync
                        Issue parentIssue = eventIssue.getParentObject();
                        // Sync "Fix Version/s"
                        Collection<Version> parentFixVersions = parentIssue.getFixVersions();
                        if (parentFixVersions == null) parentFixVersions = new ArrayList<Version>();
                        Collection<Version> fixVersions = eventIssue.getFixVersions();
                        if (fixVersions == null) fixVersions = new ArrayList<Version>();
                        if(!(parentFixVersions.containsAll(fixVersions) && fixVersions.containsAll(parentFixVersions))) {
                            eventIssue.setFixVersions(parentFixVersions);
                            changed = true;
                        }
                        // Sync "Verified Version/s"
                        Collection<Version> parentVerifiedVersions = parentIssue.getCustomFieldValue(vvcf);
                        if (parentVerifiedVersions == null) parentVerifiedVersions = new ArrayList<Version>();
                        Collection<Version> verifiedVersions = eventIssue.getCustomFieldValue(vvcf);
                        if (verifiedVersions == null) verifiedVersions = new ArrayList<Version>();
                        if(!(parentVerifiedVersions.containsAll(verifiedVersions) && verifiedVersions.containsAll(parentVerifiedVersions))) {
                            eventIssue.setCustomFieldValue(vvcf,parentVerifiedVersions);
                            changed = true;
                        }
                        if (changed) {
                            issueManager.updateIssue(event.getUser(), eventIssue, EventDispatchOption.ISSUE_UPDATED, false);
                        }
                    }
                }
            }
        }
        catch (ex) {
            log.debug "Event: ${event.getEventTypeId()} fired for ${event.issue} and caught by SyncParentFixVerifiedVersionsToSubTask"
            log.debug (ex.getMessage())
        }
    }
}

I added the workflow name check so that the listener can be set for all projects, that way you don't risk adding a project and forgetting to add it.  That worked for me, but may not for you.

Jeremy Gaudet
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 5, 2016

Having said all of that, I've heard people mention that there is some built-in way to sync that field, but I don't have details.  It may be that they can only be synced on sub-task creation.  Speaking of, the checking for an update to the sub-task is to handle the case where you add a sub-task, or move an issue to a sub-task, etc.

Rob Horan
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 5, 2016

WOW!  Thanks!  I should have mentioned Script Runner isn't really an option for us since it's no longer free, and installing it will force us to remain at version 6.  We're not using Script Runner now - I was tempted, but shortly after installation it went from free to fee.  

Rob Horan
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 13, 2016

I may be wrong about getting Script Runner - I'll be giving this a try soon!  Thanks again!!

Aisha M April 26, 2018

@Jeremy Gaudet I am looking for a solution to the same question too. So, in script listener, we are supposed to place a groovy file in the listeners folder right ? So, what would be the content of that file. Is it the same script as above ? Thanks 

Suggest an answer

Log in or Sign up to answer