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) } } }