Some exciting news from the Jira changes (maybe).

We’re done!  We’ve even achieved the stretch goals.

Does anyone have any further suggestions from the new workflow, after having 
tried it out for a bit?  Speak up while we have the easy capability to make 
changes!

- Somebody has proposed making Change Category a multi-select list, which would 
require recreating this.  Does anybody have an opinion on this? 
- Would anybody prefer that one of the new fields be recreated as a 
project-specific select-list, like Platform and Impacts (see below), so we can 
manage the options?

Gavin McDonald kindly set us up with two plugins.  With the ScriptRunner 
plugin, I’ve setup scripted listeners to maintain the Authors field (based on 
Assignee) and Priority field (based on updates to Severity), as well as 
initialising both of these for all issues.  Try it out - it works surprisingly 
well, but please let me know ASAP if there are any bugs.  

The Authors management may be slightly unintuitive, in that if assignee is 
updated we always overwrite Authors to the value of the assignee.  We could 
maybe do something more sophisticated by checking what the prior value of 
Assignee was, but this looked very fiddly.  I think in the vast majority of 
circumstances this will work as we expect; if there are multiple authors 
actively working I expect the assignee not to change; if the assignee is 
cleared we probably want to clear the Authors field; and if it is set to a new 
value it’s probably the new author.  If somebody has suggestions for a better 
approach, please chime in.

The other plugin provided us with project-specific select lists - which we’ve 
used for Platform and Impacts.  These can be modified by any project admin, so 
we can maintain them ourselves.  Impacts and Platform have a default value of 
None and All respectively, to avoid UX ugliness with this multi-select list; 
don’t ask me why this makes them prettier, but it does.  I had originally 
proposed using these values so that we could force the user to specify a value, 
but opted to not make the UX ugly, while supporting project ownership of the 
options.  Opinions on this decision welcome.

For posterity, here are the ScriptRunner scripts I used and setup:


===== LISTENER TO SET PRIORITY WHEN SEVERITY UPDATED ====

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.util.ImportUtils
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.util.IssueChangeHolder
import com.atlassian.jira.issue.priority.Priority
import com.atlassian.jira.issue.context.IssueContext
import com.atlassian.jira.issue.customfields.option.Option
import com.atlassian.jira.issue.customfields.option.Options
import com.atlassian.jira.issue.customfields.manager.OptionsManager

def issue = event.issue as MutableIssue
def severityChange = null != 
event?.getChangeLog()?.getRelated("ChildChangeItem")?.find {it.field == 
"Severity"}
if (issue.issueType.name == "Bug" && severityChange) {
    def issueManager = ComponentAccessor.getIssueManager()
    def customFieldManager = ComponentAccessor.getCustomFieldManager()
    def cf = customFieldManager.getCustomFieldObject("customfield_12313820" );

    def constantsManager = ComponentAccessor.getConstantsManager()
    Priority pUrgent = constantsManager.getPriorities().find {it.name == 
"Urgent"}
    Priority pHigh = constantsManager.getPriorities().find {it.name == "High"}
    Priority pNormal = constantsManager.getPriorities().find {it.name == 
"Normal"}
    Priority pLow = constantsManager.getPriorities().find {it.name == "Low"}

    def optManager = ComponentAccessor.getOptionsManager(); 
    Options severities = 
optManager.getOptions(cf.getRelevantConfig(IssueContext.GLOBAL))   
    Option sCritical = severities.getOptionForValue("Critical", null)
    Option sNormal = severities.getOptionForValue("Normal", null)
    Option sLow = severities.getOptionForValue("Low", null)

    def sdUser = ComponentAccessor.getUserManager().getUserByKey('robot')
    def priority = issue.getPriority()
    def severity = issue.getCustomFieldValue(cf)

    if (severity != null) {
        def newPriority = priority;
        if (severity == sCritical) {
            newPriority = pUrgent
        } else if (severity == sNormal) {
            newPriority = pNormal
        } else if (severity == sLow) {
            newPriority = pLow
        }
        if (newPriority != priority) {
            issue.setPriority(newPriority)
            issueManager.updateIssue(sdUser, issue, 
EventDispatchOption.DO_NOT_DISPATCH, false)
        }
    }
}


===== LISTENER TO SET AUTHORS WHEN ASSIGNEE UPDATED ====

import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.index.IssueIndexingService

def sdUser = ComponentAccessor.getUserManager().getUserByKey('robot')
def issueManager = ComponentAccessor.getIssueManager()
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def cf = customFieldManager.getCustomFieldObjectByName( "Authors" );

def issue = event.issue as MutableIssue
def assignee = issue.getAssignee()
if (assignee != null) {
    def authors = (List<ApplicationUser>)issue.getCustomFieldValue(cf)
    if (authors == null || !authors.contains(assignee)) {
        authors = new ArrayList<ApplicationUser>()
        authors.add(assignee)
        issue.setCustomFieldValue(cf, authors)
        issueManager.updateIssue(sdUser, issue, 
EventDispatchOption.DO_NOT_DISPATCH, false)
    }
} else {
    def authors = (List<ApplicationUser>)issue.getCustomFieldValue(cf)
    if (authors != null) {
        issue.setCustomFieldValue(cf, new ArrayList<ApplicationUser>())
        issueManager.updateIssue(sdUser, issue, 
EventDispatchOption.DO_NOT_DISPATCH, false)
    }
}


===== SCRIPT RO COPY ASSIGNEE TO AUTHORS ====

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.search.SearchProvider
import com.atlassian.jira.jql.parser.JqlQueryParser
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.index.IssueIndexingService
import com.atlassian.jira.util.ImportUtils
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.util.IssueChangeHolder

def issueManager = ComponentAccessor.getIssueManager()
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def cf = customFieldManager.getCustomFieldObjectByName( "Authors" );

def sdUser = ComponentAccessor.getUserManager().getUserByKey('robot')
def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser)
def searchProvider = ComponentAccessor.getComponent(SearchProvider)
def query1 = jqlQueryParser.parseQuery("project = CASSANDRA")
def results1 = searchProvider.search(query1, sdUser, 
PagerFilter.getUnlimitedFilter())
log.warn("All issues=" + results1.total)
results1.getIssues().each() {
    documentIssue ->
        def issue = issueManager.getIssueObject(documentIssue.id)
        def assignee = issue.getAssignee()
        if (assignee != null) {
            def authors = (List<ApplicationUser>)issue.getCustomFieldValue(cf)
            if (authors == null) {
                authors = new ArrayList<ApplicationUser>()
            } else {
                authors = new ArrayList<ApplicationUser>(authors)
            }
            if (!authors.contains(assignee)) {
                authors.add(assignee)
                issue.setCustomFieldValue(cf, authors)
                issueManager.updateIssue(sdUser, issue, 
EventDispatchOption.DO_NOT_DISPATCH, false)
                log.warn(documentIssue.id)
            }
        }
}


===== SCRIPT TO COPY PRIORITY TO SEVERITY ====

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.search.SearchProvider
import com.atlassian.jira.jql.parser.JqlQueryParser
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.index.IssueIndexingService
import com.atlassian.jira.util.ImportUtils
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.util.IssueChangeHolder
import com.atlassian.jira.issue.priority.Priority
import com.atlassian.jira.issue.context.IssueContext
import com.atlassian.jira.issue.customfields.option.Option
import com.atlassian.jira.issue.customfields.option.Options
import com.atlassian.jira.issue.customfields.manager.OptionsManager

def issueManager = ComponentAccessor.getIssueManager()
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def cf = customFieldManager.getCustomFieldObject("customfield_12313820" );

def constantsManager = ComponentAccessor.getConstantsManager()
Priority pUrgent = constantsManager.getPriorities().find {it.name == "Urgent"}
Priority pHigh = constantsManager.getPriorities().find {it.name == "High"}
Priority pNormal = constantsManager.getPriorities().find {it.name == "Normal"}
Priority pLow = constantsManager.getPriorities().find {it.name == "Low"}

def optManager = ComponentAccessor.getOptionsManager(); 
Options severities = 
optManager.getOptions(cf.getRelevantConfig(IssueContext.GLOBAL))   
Option sCritical = severities.getOptionForValue("Critical", null)
Option sNormal = severities.getOptionForValue("Normal", null)
Option sLow = severities.getOptionForValue("Low", null)

def sdUser = ComponentAccessor.getUserManager().getUserByKey('robot')
def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser)
def searchProvider = ComponentAccessor.getComponent(SearchProvider)
def query1 = jqlQueryParser.parseQuery("project = CASSANDRA and priority = 
High")
def results1 = searchProvider.search(query1, sdUser, 
PagerFilter.getUnlimitedFilter())
log.warn("All issues=" + results1.total)
results1.getIssues().each() {
    documentIssue ->
        def issue = issueManager.getIssueObject(documentIssue.id)
        def priority = issue.getPriority()
        if (priority != null) {
            def severity = issue.getCustomFieldValue(cf)
            def newSeverity = severity;
            if (priority == pUrgent) {
                newSeverity = sCritical
            } else if (priority == pHigh) {
                newSeverity = sNormal
            } else if (priority == pNormal) {
                newSeverity = sNormal
            } else if (priority == pLow) {
                newSeverity = sLow
            } else {
                log.warn(priority)
            }
            if (newSeverity != severity) {
                issue.setCustomFieldValue(cf, newSeverity)
                issueManager.updateIssue(sdUser, issue, 
EventDispatchOption.DO_NOT_DISPATCH, false)
            }
        }
}

Reply via email to