Referencing the round robin assignment script from adaptavist library:https://library.adaptavist.com/entity/round-robin-assign-issue-to-users-in-a-certain-project-role, I want to get the last issue created in a project, but i also want to focus in on a certain issue type.
Here's what I changed in the script:
def lastIssueIdWithAssignee = issueManager.getIssueIdsForProject(issue.projectObject.id)
.sort()
.reverse()
.find {issue.getAsString("issuetype") == "Certification" }
So with this, I thought I'd be able to find the last Certification issue created in that project, but this doesn't seem to be the case...because the assignee keeps defaulting to the first user listed in the user key array.
Is there anything wrong with the change I made to the script?
Hi @Ian Balas ,
please try to change it like this:
def lastIssueIdWithAssignee = issueManager.getIssueIdsForProject(issue.projectObject.id)
.sort()
.reverse()
.find {
def foundIssue = issueManager.getIssueObject(it)
return foundIssue.assignee && foundIssue.issueType.name == "Certification"
}
@Hana Kučerová Works like a charm! Thank you so much :)
For learning purposes, how did you know to re-declare the issue id and set the return types for issue assignee and issue type? Does that part of the code serve as the condition of the find function? (Like return the first issue that has an assignee and as of Certification type?)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Ian Balas yes, find method finds the first value in a collection that matches some criterion.
1) find issue ids for project (getIssueIdsForProject returns Collection<Long>)
def ids = issueManager.getIssueIdsForProject(issue.projectObject.id)
2) ids are sorted, reversed
ids
.sort()
.reverse()
3) search through the ids and find the first issue with some specific data
.find { issueManager.getIssueObject(it).assignee }
We need to get the issue object based on provided id (variable it) to be able to find out if it has an assignee and specific issue type name
I used foundIssue variable, because I didn't want to search for the issue object twice
This part
def foundIssue = issueManager.getIssueObject(it)
return foundIssue.assignee && foundIssue.issueType.name == "Certification"
Is basically the same as
issueManager.getIssueObject(it).assignee && issueManager.getIssueObject(it).issueType.name == "Certification"
So I only added the second condition, which also needs to be true (if issue has assignee and it's issue type is "Ceritifcation", it matches the criterion and it's id is returned)
lastIssueIdWithAssignee could be null, if there is no such issue, or it is the issue id of found issue (because we are iterating through the ids)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Hana Kučerová I guess I must have been pointing to the issue I was creating in the post function rather that getting the issue object based on id. In other words, I wasn't searching for the issue based on the provided id, but was rather pointing to the issue I was creating in the post function (Feel free to correct me if I'm wrong).
But I do understand your solution, and now know a little more about the find method thanks to you.
Again, many thanks!
-Ian
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Hana Kučerová One more thing...I hope this isn't too much to ask, but is there a way to add a condition to see if the assignee was set via automation (the script is run as user "automation")? A problem came up where an issue, which was originally assigned through this round robin script, was manually re-assigned...and then the assignee for the next Certification issue created afterwards was automatically set to the first assignee in the round robin user list.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Ian Balas Hi, to be honest, I don't fully understand your problem. Do I get it right you want to exclude all the issues, where the last assign action was made by automation user?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Hana Kučerová Yeah that's what I'm looking for, but still focus just on Certification issues.
Here's some user feedback from my end regarding what they want:
"we want the tickets to be auto-assigned in that order (Ben M, Kristen B, Minyoung K, Mari L), regardless of re-assignment.
So, for example, a ticket is auto-assigned to Ben. However, let's say Ben is on vacation this week. Therefore, we manually reassign the ticket to Minyoung. If the round robin assignment order is Ben, Kristen, Minyoung, Mari, we still want the next ticket to be auto-assigned to Kristen given this is the auto-assignment order."
So with this feedback, I assume the way to make this possible were if I could make sure the previous Certification issue was auto-assigned by the user "automation" (since the script in the post function is ran as user "automation") and not manually reassigned.
Let me know if this makes sense!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Ian Balas Thank for the clarification, now I get it... It could be done, but I don't like the idea of looping through each issue's history and search for the author of the last assignee change... what about to store author of the last assignee change to some custom field and use this custom field in the condition instead of searching in the history? Or use some other custom field to mark the issues, which should be excluded from the automation?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Hana Kučerová I like the idea of storing the author of the last assignee change in a custom field and using that in the condition. So in this case, the issue object to be found would be one that is of certification type, and the author of the last assignee change would have to come up as automation.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @Hana Kučerová ,
Thanks again for the tip regarding the round robin solution I was looking for.
As for the solution you offered regarding the scripted field, which would store the author of the last assignee change, I tried creating a field called Assignee Last Changed By:, and added this script so far (in reference to https://community.atlassian.com/t5/Jira-questions/How-to-get-previous-changed-custom-field-data/qaq-p/829463):
import com.atlassian.jira.component.ComponentAccessor
def changeHistoryManager = com.atlassian.jira.component.ComponentAccessor.getChangeHistoryManager()
def old = changeHistoryManager.getChangeItemsForField(issue, 'Assignee')
return old.fromString
This doesn't seem to return anything unfortunately :( just a result of "Anonymous" along with an empty log record each time, even when testing on issues where users manually changed the assignee field.
Would you happen to know how I could improve this scripted field?
(FYI I created another post specific to this additional ask https://community.atlassian.com/t5/Jira-questions/Get-user-author-who-last-changed-Assignee-field/qaq-p/1552568#M457256)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @Ian Balas
I would recommend you to use "User Picker (single user)" field instead of scripted one and store the event actor to it everytime the field Assignee is changed.
Customer listener defined for you project and event "Issue updated" will hopefully do the trick (xxxxx needs to be replaced by your custom field id)
The listener script basically checks, whether field Assignee has been changed during update. If so, it stores the user, who changed the issue, to the custom field.
Please try.
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.event.issue.IssueEvent
import static com.atlassian.jira.issue.IssueFieldConstants.ASSIGNEE
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.user.ApplicationUser
import org.ofbiz.core.entity.GenericValue
String userCustomFieldName = "customfield_xxxxx"
MutableIssue issue = event.getIssue()
IssueManager issueManager = ComponentAccessor.getIssueManager()
CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager()
CustomField userCustomField = customFieldManager.getCustomFieldObject(userCustomFieldName)
GenericValue change = event?.getChangeLog()?.getRelated("ChildChangeItem")?.find {it.field == ASSIGNEE}
if (!change) {
return
}
ApplicationUser newUser = event.getUser()
ApplicationUser oldUser = userCustomField.getValue(issue) as ApplicationUser
if (newUser != oldUser) {
issue.setCustomFieldValue(userCustomField, newUser)
issueManager.updateIssue(newUser, issue, EventDispatchOption.DO_NOT_DISPATCH, false)
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You're a genius @Hana Kučerová ! I really appreciate you going above and beyond with this.
After applying this listener script and the user picker, I can report that this is definitely a great addition to have along with the original round robin script. It's an improvement because now if a Certification issue is manually re-assigned, the next issue will auto-assign to the user in the round robin queue that was originally auto-assigned to the previous issue, as opposed to starting over and assigning the issue to the first user in the round robin queue.
To further explain in accordance to our round robin order (Ben M, Kristen B, Minyoung K, Mari L), Here's an example of how this works now from our use case:
"Minyoung K was auto-assigned to a cert issue, issueA via round robin. Afterwards, another cert issue ,issueB, is created and auto-assigns Mari L as expected. issueB is then manually assigned to another user. If you create another cert issue, issueC, right after that, it'll be auto-assigned to Mari L again"
So this works almost 100% the way we want it. Ideally, issueC should have auto-assigned to Ben M, regardless of the manual re-assignment.
We'll make do with what we have if this is the best it can be...but is there a way for the script to auto-assign to the next user in queue no matter what? If not, it's okay :)
Again, I really appreciate all the help you've provided up to this point!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @Ian Balas ,
thank you :-). I'm really happy to help. Let's try to make it 100% :-).
It seems to me, that another user custom field could help here - to store the information, who was originally assigned to the issue by round robin script. Then the round robin will use this user instead of assignee to get the next user in the row. Does this make sense to you? If so, I can improve the listener script to handle this new custom field. We will also need to change the round robin script itself. I'm not sure about the current status of the script, so maybe it will be the best, if you paste it here first. Thank you.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Hana Kučerová I like that idea.
Here's the round robin script. I have it set as a scripted operation on issue post-function upon issue creation:
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.security.roles.ProjectRoleManager
// The role you want assignees to set from
final roleName = 'Workers'
// If it is true, the assigned issues will be reassigned
final reassignedIssues = true
def issueManager = ComponentAccessor.issueManager
def projectRoleManager = ComponentAccessor.getComponent(ProjectRoleManager)
// Get all of the users associated with the specified project role
def projectRole = projectRoleManager.getProjectRole(roleName)
// Sort the users of the project role using the user key
def users = projectRoleManager.getProjectRoleActors(projectRole, issue.projectObject)
.applicationUsers
.toSorted { it.key }
// There are no users in the specific project role
if (!users) {
log.info ("No users for project role $roleName")
return
}
if (!reassignedIssues && issue.assignee) {
log.info ('The issue is already assigned')
return
}
// Find the latest created issue id that has an assignee
def lastIssueIdWithAssignee = issueManager.getIssueIdsForProject(issue.projectObject.id)
.sort()
.reverse()
.find {
def foundIssue = issueManager.getIssueObject(it)
return foundIssue.assignee && foundIssue.issueType.name == "Certification" && !foundIssue.get("customfield_20500")
}
if (!lastIssueIdWithAssignee) {
issue.setAssignee(users.first())
return
}
def lastAssignee = issueManager.getIssueObject(lastIssueIdWithAssignee).assignee
def lastAssigneeIndex = users.indexOf(lastAssignee)
def nextAssignee = users[(lastAssigneeIndex + 1) % users.size()]
issue.setAssignee(nextAssignee)
Notice the changes you made to the lastIssueIdWithAssignee variable. Here, I added the condition, " && !foundIssue.get("customfield_20500")". This custom field translates to a user picker called Assignee Change Author, which I created along with the listener as per your other suggestion. If a user manually re-assigns an issue, their name will populate to that field...otherwise, the field will remain empty.
So now this script looks for the latest Certification issue, with an assignee, where the Assignee Change Author field is empty.
Thanks again for all the help!!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @Ian Balas ,
in the end I just updated your round Robin script. Everytime this script assigns some issue, it should also store the original assignee to the user custom field, which you will need to create for such purpose.
What is great - it seems to me, that the script listener and the customfield_20500 is not needed anymore. Because I think what you need is to find last assigned issue (and it doesn't matter, whether the assignee was later manually changed or not) and get original assignee from here (who is now stored in the new user custom field).
Does it make sense to you?
Please try the updated round robin script (xxxxx needs to be replaced with the id of the new user custom field):
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.security.roles.ProjectRoleManager
// The role you want assignees to set from
final roleName = 'Workers'
final originalAssigneeCustomFieldName = "customfield_xxxxx"
// If it is true, the assigned issues will be reassigned
final reassignedIssues = true
def issueManager = ComponentAccessor.issueManager
def projectRoleManager = ComponentAccessor.getComponent(ProjectRoleManager)
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def originalAssigneeCustomField = customFieldManager.getCustomFieldObject(originalAssigneeCustomFieldName)
// Get all of the users associated with the specified project role
def projectRole = projectRoleManager.getProjectRole(roleName)
// Sort the users of the project role using the user key
def users = projectRoleManager.getProjectRoleActors(projectRole, issue.projectObject)
.applicationUsers
.toSorted { it.key }
// There are no users in the specific project role
if (!users) {
log.info ("No users for project role $roleName")
return
}
if (!reassignedIssues && issue.assignee) {
log.info ('The issue is already assigned')
return
}
// Find the latest created issue id that has an assignee
def lastIssueIdWithAssignee = issueManager.getIssueIdsForProject(issue.projectObject.id)
.sort()
.reverse()
.find {
def foundIssue = issueManager.getIssueObject(it)
return foundIssue.assignee && foundIssue.issueType.name == "Certification"
}
if (!lastIssueIdWithAssignee) {
issue.setAssignee(users.first())
return
}
def issue = issueManager.getIssueObject(lastIssueIdWithAssignee)
def lastAssignee = issue.getCustomFieldValue(originalAssigneeCustomField) ?: issue.assignee
def lastAssigneeIndex = users.indexOf(lastAssignee)
def nextAssignee = users[(lastAssigneeIndex + 1) % users.size()]
issue.setAssignee(nextAssignee)
issue.setCustomFieldValue(originalAssigneeCustomField, nextAssignee)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @Hana Kučerová ,
This doesn't seem to work as intended unfortunately :(
So I went ahead and replaced the round robin script I had with your version instead. I created a field called Original Assignee, and form my understanding that field is supposed to pre-fill with the first assignee of that issue...presumptively after the round robin script auto-assigns. Instead, when I create the next certification issue no matter who the assignee is in the previous issue, the assignee field is left unassigned and nothing prefills in the Original Assignee field.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @Ian Balas ,
sorry, please try to add your custom field Original Assignee to the issue create screen.
Please also try to check the log, if there's some error - probably there is one, because both the fields are not working.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @Hana Kučerová ,
Okay I added the field to the create screen but that didn't seem to help.
I ran a server log audit right when I created the issue and these following errors were logged:
2020-12-21 21:26:29,691+0000 http-nio-8080-exec-402 INFO ibalas 1286x180169x1 174kpd7 184.165.15.13,52.13.84.207,10.1.0.7 /secure/QuickCreateIssue.jspa [c.a.j.authenticator.okta.OktaJiraAuthenticator30] Authentication result=USER_ALREADY_LOGGED_IN 2020-12-21 21:26:29,867+0000 http-nio-8080-exec-402 ERROR ibalas 1286x180169x1 174kpd7 184.165.15.13,52.13.84.207,10.1.0.7 /secure/QuickCreateIssue.jspa [c.o.scriptrunner.customfield.GroovyCustomField] ************************************************************************************* 2020-12-21 21:26:29,867+0000 http-nio-8080-exec-402 ERROR ibalas 1286x180169x1 174kpd7 184.165.15.13,52.13.84.207,10.1.0.7 /secure/QuickCreateIssue.jspa [c.o.scriptrunner.customfield.GroovyCustomField] Script field failed on issue: CERT-3325, field: Assignee Last Changed By java.util.NoSuchElementException: Cannot access last() element from an empty List at Script7.run(Script7.groovy:4) 2020-12-21 21:26:29,936+0000 http-nio-8080-exec-402 ERROR ibalas 1286x180169x1 174kpd7 184.165.15.13,52.13.84.207,10.1.0.7 /secure/QuickCreateIssue.jspa [c.o.scriptrunner.customfield.GroovyCustomField] ************************************************************************************* 2020-12-21 21:26:29,936+0000 http-nio-8080-exec-402 ERROR ibalas 1286x180169x1 174kpd7 184.165.15.13,52.13.84.207,10.1.0.7 /secure/QuickCreateIssue.jspa [c.o.scriptrunner.customfield.GroovyCustomField] Script field failed on issue: CERT-3325, field: Assignee Last Changed By java.util.NoSuchElementException: Cannot access last() element from an empty List at Script7.run(Script7.groovy:4) 2020-12-21 21:26:30,009+0000 http-nio-8080-exec-402 ERROR ibalas 1286x180169x1 174kpd7 184.165.15.13,52.13.84.207,10.1.0.7 /secure/QuickCreateIssue.jspa [c.o.scriptrunner.customfield.GroovyCustomField] ************************************************************************************* 2020-12-21 21:26:30,009+0000 http-nio-8080-exec-402 ERROR ibalas 1286x180169x1 174kpd7 184.165.15.13,52.13.84.207,10.1.0.7 /secure/QuickCreateIssue.jspa [c.o.scriptrunner.customfield.GroovyCustomField] Script field failed on issue: CERT-3325, field: Assignee Last Changed By java.util.NoSuchElementException: Cannot access last() element from an empty List at Script7.run(Script7.groovy:4) 2020-12-21 21:26:30,431+0000 http-nio-8080-exec-402 ERROR ibalas 1286x180169x1 174kpd7 184.165.15.13,52.13.84.207,10.1.0.7 /secure/QuickCreateIssue.jspa [c.o.scriptrunner.customfield.GroovyCustomField] ************************************************************************************* 2020-12-21 21:26:30,431+0000 http-nio-8080-exec-402 ERROR ibalas 1286x180169x1 174kpd7 184.165.15.13,52.13.84.207,10.1.0.7 /secure/QuickCreateIssue.jspa [c.o.scriptrunner.customfield.GroovyCustomField] Script field failed on issue: CERT-3325, field: Assignee Last Changed By java.util.NoSuchElementException: Cannot access last() element from an empty List at Script7.run(Script7.groovy:4) 2020-12-21 21:26:30,644+0000 httpclient-callbacks:thread-266 WARN anonymous [c.a.webhooks.plugin.PublishTaskFactoryImpl$PublishTaskImpl] Client error - 404 when posting to web hook at 'https://hooks.slack.com/services/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' 2020-12-21 21:26:30,692+0000 http-nio-8080-exec-402 ERROR ibalas 1286x180169x1 174kpd7 184.165.15.13,52.13.84.207,10.1.0.7 /secure/QuickCreateIssue.jspa [c.o.scriptrunner.customfield.GroovyCustomField] ************************************************************************************* 2020-12-21 21:26:30,692+0000 http-nio-8080-exec-402 ERROR ibalas 1286x180169x1 174kpd7 184.165.15.13,52.13.84.207,10.1.0.7 /secure/QuickCreateIssue.jspa [c.o.scriptrunner.customfield.GroovyCustomField] Script field failed on issue: CERT-3325, field: Assignee Last Changed By java.util.NoSuchElementException: Cannot access last() element from an empty List at Script7.run(Script7.groovy:4)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Actually, please disregard these logs. These are auditing the Assignee Last Changed By scripted field I created earlier, which I forgot to remove.
Running the audit after removing this, however, doesn't seem to point out any errors in creating the issue:
2020-12-21 21:52:30,653+0000 http-nio-8080-exec-376 INFO ibalas 1312x181230x1 174kpd7 184.165.15.13,52.13.84.207,10.1.0.7 /secure/QuickCreateIssue.jspa [c.a.j.p.webhooks.matcher.JqlEventMatcher_SLOW] JQL query '{project = "WFS"} AND {issuetype in ("Support Request", "Defect")} AND {key in ("CERT-3331")}' produced lucene query and took '96' ms to run.
This was all that came up in the audit log
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @Ian Balas ,
I apologize, it couldn't work. The main problem is with usage of setCustomFieldValue, I just assumed it behaves the same as setAssignee.
What needs to be set:
Here is the updated script (xxxxx needs to be replaced by your id) - I tested it and it works for me now.
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.security.roles.ProjectRoleManager
// The role you want assignees to set from
final roleName = 'Workers'
final originalAssigneeCustomFieldName = "customfield_xxxxx"
// If it is true, the assigned issues will be reassigned
final reassignedIssues = true
def issueManager = ComponentAccessor.issueManager
def projectRoleManager = ComponentAccessor.getComponent(ProjectRoleManager)
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def originalAssigneeCustomField = customFieldManager.getCustomFieldObject(originalAssigneeCustomFieldName)
// Get all of the users associated with the specified project role
def projectRole = projectRoleManager.getProjectRole(roleName)
// Sort the users of the project role using the user key
def users = projectRoleManager.getProjectRoleActors(projectRole, issue.projectObject)
.applicationUsers
.toSorted { it.key }
// There are no users in the specific project role
if (!users) {
log.info ("No users for project role $roleName")
return
}
if (!reassignedIssues && issue.assignee) {
log.info ('The issue is already assigned')
return
}
// Find the latest created issue id that has an assignee
def lastIssueIdWithAssignee = issueManager.getIssueIdsForProject(issue.projectObject.id)
.sort()
.reverse()
.find {
def foundIssue = issueManager.getIssueObject(it)
return foundIssue.assignee && foundIssue.issueType.name == "Certification"
}
if (!lastIssueIdWithAssignee) {
issue.setAssignee(users.first())
def changeHolder = new DefaultIssueChangeHolder()
originalAssigneeCustomField.updateValue(null, issue, new ModifiedValue(null, users.first()), changeHolder)
return
}
def lastIssue = issueManager.getIssueObject(lastIssueIdWithAssignee)
def lastAssignee = lastIssue.getCustomFieldValue(originalAssigneeCustomField) ?: lastIssue.assignee
def lastAssigneeIndex = users.indexOf(lastAssignee)
def nextAssignee = users[(lastAssigneeIndex + 1) % users.size()]
issue.setAssignee(nextAssignee)
def changeHolder = new DefaultIssueChangeHolder()
originalAssigneeCustomField.updateValue(null, issue, new ModifiedValue(null, nextAssignee), changeHolder)
How it works:
Let's assume we have 4 users - Ben, Kristen, Miny, Mari
Hopefully I get it right now, please try.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Hana Kučerová I think we're finally all set! It works 100% the way we want it! I even hid the original assignee field from user's view (but still have it on create screen) and the script still works as expected! Thank you very much Hana, I'm beyond thankful you stuck this out with me all the way to the end :D.
Now just one last final question regarding the solution...I read through the script and I think I almost understand how it works. But as for the condition you set for lastIssueIdWithAssignee:
if (!lastIssueIdWithAssignee) {
issue.setAssignee(users.first())
def changeHolder = new DefaultIssueChangeHolder()
originalAssigneeCustomField.updateValue(null, issue, new ModifiedValue(null, users.first()), changeHolder)
return
}
and the part where the assignee and original assignee fields are set for the new issue:
issue.setAssignee(nextAssignee)
def changeHolder = new DefaultIssueChangeHolder()
originalAssigneeCustomField.updateValue(null, issue, new ModifiedValue(null, nextAssignee), changeHolder)
What exactly did you do in both blocks? How did you use the defaultIssueChangeHolder and ModifiedValue classes to make this work? Just out of curiosity.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @Ian Balas ,
I'm really happy it works now!
These two blocks do the same thing - set the Original Assignee and Assignee fields...
I used setCustomFieldValue originally, but it didn't work as I expected.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Ah, I see now how updateValue works instead of setCustomFieldValue. The value needs to get updated in data store, and not just specifically on the issue object.
Okay, this all makes sense to me.
Well thank you very much for all the time you've put into this ticket! My team and I really appreciate your effort into this as you did't have to go all out like you did. We won't forget it!
Have a Happy New Year!
-Ian Balas
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.
Hi @Hana Kučerová ,
Hope all is well with you! I wanted to reach out to you again regarding a few slight changes that I want to make for the final version of the round robin auto-assignment script that you helped me with.
I wanted to make a copy of this post function script, set it for the 'Defect' issue type, and scan through the users with the 'Operations' and 'Utility' roles (rather than 'Workers'), still assigning in round-robin rotation, but now making it time-dependent. Basically I want 'Defect' issues to assign to 'Utility' users in round robin fashion from 4AM-4PM, and assign to 'Operations' users from 4PM-4AM. Is this at all possible by tweaking the script above in any way?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I was able to get this to work in another post.
See below:
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.security.roles.ProjectRoleManager
import java.time.ZoneOffset
def issueManager = ComponentAccessor.issueManager
if (!!issue.assignee){
return
} else {
def utcHour = new Date().toInstant().atOffset( ZoneOffset.ofTotalSeconds(0)).hour
if (utcHour >= 16 || utcHour < 4) {
// The role you want assignees to set from
final roleName = 'Utility'
final originalAssigneeCustomFieldName = "customfield_20321"
// If it is true, the assigned issues will be reassigned
final reassignedIssues = true
def projectRoleManager = ComponentAccessor.getComponent(ProjectRoleManager)
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def originalAssigneeCustomField = customFieldManager.getCustomFieldObject(originalAssigneeCustomFieldName)
// Get all of the users associated with the specified project role
def projectRole = projectRoleManager.getProjectRole(roleName)
// Sort the users of the project role using the user key
def users = projectRoleManager.getProjectRoleActors(projectRole, issue.projectObject)
.applicationUsers
.toSorted { it.key }
// There are no users in the specific project role
if (!users) {
log.info ("No users for project role $roleName")
return
}
if (!reassignedIssues && issue.assignee) {
log.info ('The issue is already assigned')
return
}
// Find the latest created issue id that has an assignee
def lastIssueIdWithAssignee = issueManager.getIssueIdsForProject(issue.projectObject.id)
.sort()
.reverse()
.find {
def foundIssue = issueManager.getIssueObject(it)
return foundIssue.assignee && foundIssue.issueType.name == "Defect"
}
// If no issue fulfilling above criteria is found, new cert issue is assigned to the first user in rr queue
if (!lastIssueIdWithAssignee) {
issue.setAssignee(users.first())
def changeHolder = new DefaultIssueChangeHolder()
originalAssigneeCustomField.updateValue(null, issue, new ModifiedValue(null, users.first()), changeHolder)
return
}
// If issue is found, then assignee is based on the Original Assignee and Assignee fields:
// * assuming Original Assignee field is not empty, user in said field is taken, and issue assigns to
//the next user in queue
def lastIssue = issueManager.getIssueObject(lastIssueIdWithAssignee)
def lastAssignee = lastIssue.getCustomFieldValue(originalAssigneeCustomField) ?: lastIssue.assignee
def lastAssigneeIndex = users.indexOf(lastAssignee)
def nextAssignee = users[(lastAssigneeIndex + 1) % users.size()]
issue.setAssignee(nextAssignee)
def changeHolder = new DefaultIssueChangeHolder()
originalAssigneeCustomField.updateValue(null, issue, new ModifiedValue(null, nextAssignee), changeHolder)
}
}
There's something else I was looking to add, though.
I want to enable the user to be able to manually set the assignee during issue creation, foregoing the round robin auto-assignment. But for the next issue created, if assignee is left blank, then pick right back up on the auto-assignment: set assignee as the next user after the user who the previous ticket was originally intended for before manual assignment.
For example, working again with the original 4 users (Ben M, Kristen B, Minyoung K, Mari L):
Is this at all possible?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Online forums and learning are now in one easy-to-use experience.
By continuing, you accept the updated Community Terms of Use and acknowledge the Privacy Policy. Your public name, photo, and achievements may be publicly visible and available in search engines.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.