For our backlog prioritization meetings I want to color-highlight issues in our scrum board which have not yet been manually ranked. My idea is to create a custom field (single choice, yes or no) indicating whether or not the Rank has been changed since the issue was created.
The custom field would default to 'No' on issue creation. I want to use a ScriptRunner listener on all issue updates to set the custom field to 'Yes' if and only if the Rank was changed in the update.
I cannot find any ScriptRunner examples to (1) check whether the Rank was changed in the issue update and (2) update my custom field.
Thank you,
Nathan
p.s. I would be receptive to other suggestions if you think I'm going about this the wrong way.
Hi Nathan
During a listener event you can determine which field has changed like
import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.Issue import com.atlassian.jira.issue.ModifiedValue import com.atlassian.jira.issue.util.DefaultIssueChangeHolder Issue issue = event.issue def customFieldManager = ComponentAccessor.getCustomFieldManager() def change = event?.getChangeLog()?.getRelated("ChildChangeItem").find {it.field == "Name of field"} if (change) { def tgtField = customFieldManager.getCustomFieldObjects(issue).find {it.name == "My custom field"} def changeHolder = new DefaultIssueChangeHolder() tgtField.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(tgtField, "new value"), changeHolder) } else return
Try the above and let me know if this works for you.
Thank you. Do you recommend doing this as a "Custom listener" or a "Fires an event when condition is true", or other?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
The above is for a custom listener, I just added like this in order to see how you can retrieve the changed values. But yes in your case you can use the fires an event when condition is true. There are examples and in particular see the priority has changed. And then set the custom field value.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
For the above script if you associate an Issue Updated event, then every time someone updates the rank the custom field will be updated as well. The custom field will not get updated during the issue create event, this means that unless someone edits the rank, after the creation, the custom field will hold always the initial value. Hope I was clear enough.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Additionally, if "Rank" is available on a transition screen, and that transition emits a different type of event, you'll have to include those as well.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Yes that's true, thanks for mentioning that Jeremy.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thank you, I got it working. Here is my final code:
import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.Issue import com.atlassian.jira.issue.ModifiedValue import com.atlassian.jira.issue.util.DefaultIssueChangeHolder import org.ofbiz.core.entity.GenericValue; import org.ofbiz.core.entity.GenericEntityException; import com.atlassian.jira.issue.fields.config.FieldConfig import com.atlassian.jira.issue.customfields.option.Options log.setLevel(org.apache.log4j.Level.INFO) log.info("start"); Issue issue = event.issue // Log changes List<GenericValue> changeItems = null; try { GenericValue changeLog = event.getChangeLog(); changeItems = changeLog.getRelated("ChildChangeItem"); // changeLog.internalDelegator.findByAnd("ChangeItem", EasyMap.build("group",changeLog.get("id"))); } catch (GenericEntityException e){ log.error(e.getMessage()); } log.info("number of changes: " + changeItems.size()); for (Iterator<GenericValue> iterator = changeItems.iterator(); iterator.hasNext();){ GenericValue changetemp = (GenericValue) iterator.next(); String field = changetemp.getString("field"); String oldstring = changetemp.getString("oldstring"); String newstring = changetemp.getString("newstring"); StringBuilder fullstring = new StringBuilder(); fullstring.append("Issue "); fullstring.append(issue.getKey()); fullstring.append(" field "); fullstring.append(field); fullstring.append(" has been updated from "); fullstring.append(oldstring); fullstring.append(" to "); fullstring.append(newstring); log.info("changes " + fullstring.toString()); } // Check if Rank changed and update custom field def customFieldManager = ComponentAccessor.getCustomFieldManager() def change = event?.getChangeLog()?.getRelated("ChildChangeItem").find {it.field == "Rank"} if (change) { log.info ("Rank changed") def tgtField = customFieldManager.getCustomFieldObjects(issue).find {it.name == "Rank Set"} log.info ("tgtField: " + tgtField); def changeHolder = new DefaultIssueChangeHolder() FieldConfig fieldConfig = tgtField.getRelevantConfig(issue); def optionsManager = ComponentAccessor.getOptionsManager(); final Options options = optionsManager.getOptions(fieldConfig); com.atlassian.jira.issue.customfields.option.Option yesOption = options.getOptionForValue("Yes", null); log.info ("Previous value of 'Rank Set': " + issue.getCustomFieldValue(tgtField)) tgtField.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(tgtField), yesOption), changeHolder) log.info ("New value of 'Rank Set': " + issue.getCustomFieldValue(tgtField)) } else { log.info ("Rank did not change") }
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
The approach is sound; the alternative is to remove "rank" from the update screen, and use self-targeting transitions in the workflow to "Rank" the issue. There's a certain elegance to that approach; if you do it that way, you can set the custom field in a post-function, and it makes "Rank" a first-class operation. Whether or not it complicates the workflow will depend on how many states require the option.
This link (http://stackoverflow.com/questions/18428756/update-jira-subtask-fix-version-when-parent-issue-fix-version-updated) shows an example of how to check if a field is changed, and how to do an update; it doesn't include a custom field, but I have that example below. The code is a little stale, some of the object types needed updating. I can provide a more modern example if you need it, I've been meaning to make my version generic so I can share it more readily anyways.
import com.atlassian.jira.ComponentManager; import com.atlassian.jira.issue.CustomFieldManager; import com.atlassian.jira.issue.fields.CustomField; CustomFieldManager customFieldManager = ComponentManager.getInstance().getCustomFieldManager(); CustomField manRankCF = customFieldManager.getCustomFieldObjectByName("Manually Ranked"); Boolean ranked = true; issue.setCustomFieldValue(manRankCF,ranked);
Note that I'm not certain a Boolean is the correct type here, I'd need to do more research.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thank you for the answer. I used the other code from Thanos, only because I tried it first and it worked.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.