本文转自:https://metamorphant.de/blog/posts/2021-03-20-user-related-groovy-script-snippets-for-scriptrunner-for-jira/
Using Groovy scripts in Jira Software/Core or Service Management (Server/Data Center) adds a huge amount of new possibilities in customizing workflows, enhancing the user experience and automating processes. The most powerful App in this area is ScriptRunner for Jira. Out of the box it allows you to use Groovy scripts in:
By default Jira’s data model is quite static. Also you need to be Jira Administrator to modify fields. In combination with other apps you are able to provide a completely new Jira experience. For example, using the Jira app Insight - Asset Management you can define asset objects and access them in your scripts. By that you can make Jira behave more dynamic.
In this article I will share script snippets for ScriptRunner to handle some common user related use cases I got in touch with. I don’t go into the details of the use cases. The purpose of the snippets is to get you started. Use copy & paste at your own discretion.
First of all you import all the packages you’ll need in your script context. For debugging it’s helpful to import org.apache.log4j.Logger
classes to be able to write into the Jira logs. You will soon recognize that developing in the integrated ScriptRunner script console without custom logging is quite shitty.
import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.Issue import com.atlassian.jira.issue.fields.CustomField import com.atlassian.jira.user.ApplicationUser import com.atlassian.jira.issue.util.DefaultIssueChangeHolder import com.atlassian.jira.event.type.EventDispatchOption import org.apache.log4j.Logger def log = Logger.getLogger("com.acme.workflows") log.info("Script starts...")
For providing detailed debug information I recommend to use the appropriate log4j log level log.debug(”custom debugging message”)
. Whether the log.debug statement will appear in the logs, depends on the configured log level of your Jira instance. There is even a webinterface for configuring log levels in Jira Server and Data Center.
ScriptRunner scripts can be used in different contexts (listeners, postfunctions, …). How to access the issue object depends on the context of your script. Here some common examples.
Issue issue = event.issue
In a ScriptRunner script postfunction you don’t need to fetch the issue object of the current issue. It already exists as a prepopulated variable with name issue
. You can directly access it to e.g. get the issue key by using issue.getKey()
.
Independent of the context, you can always get the issue object by the issue key.
import com.atlassian.jira.component.ComponentAccessor def issueManager = ComponentAccessor.getIssueManager() String issueKey = "TEST-1"; issue = issueManager.getIssueObject(issueKey)
Now, everything is prepared and you can start using the following script snippets. They’re all tested in Jira 8.5.x (Long Term Support release) with ScriptRunner 6.15.0 and Insight - Asset Management 8.6.15.
import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.event.type.EventDispatchOption def authContext = ComponentAccessor.getJiraAuthenticationContext() def currentUser = authContext.getLoggedInUser() // Example: populate the assignee field using a setter method issue.setAssignee(currentUser) // Example: populate the reporter field using a property accessor issue.reporter = currentUser // More complex example: populate a customfield def customFieldManager = ComponentAccessor.getCustomFieldManager() def myCustomfield = customFieldManager.getCustomFieldObject("customfield_xxxxx") issue.setCustomFieldValue(myCustomfield, currentUser) // Commit changes to issue ComponentAccessor.getIssueManager().updateIssue(currentUser, issue, EventDispatchOption.DO_NOT_DISPATCH, false)
We use several classes from the Jira Java API here:
ComponentAccessor
CustomFieldManager
JiraAuthenticationContext
Issue
In the examples you see two different styles to access a field.
import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.event.type.EventDispatchOption def customFieldManager = ComponentAccessor.getCustomFieldManager() def authContext = ComponentAccessor.getJiraAuthenticationContext() def userManager = ComponentAccessor.getUserUtil() // Store current user for later reset def currentUser = authContext.getLoggedInUser() // Switch user def otherUser = userManager.getUserByName("SomeUser") authContext.setLoggedInUser(otherUser) // Do something, e.g. manipulate issue // Commit changes ComponentAccessor.getIssueManager().updateIssue(otherUser, issue, EventDispatchOption.DO_NOT_DISPATCH, false) // Reset user authContext.setLoggedInUser(currentUser)
Make sure you’re reseting the user at the end of your script. Otherwise, the following scripts or postfunctions may use this context, too.
import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.event.type.EventDispatchOption import com.atlassian.jira.user.ApplicationUser def customFieldManager = ComponentAccessor.getCustomFieldManager() def authContext = ComponentAccessor.getJiraAuthenticationContext() def userManager = ComponentAccessor.getUserUtil() def currentUser = authContext.getLoggedInUser() // Customfield 10001 corresponds to the request participant field in our Jira instance def requestParticipantsField = customFieldManager.getCustomFieldObject("customfield_10001") def user = userManager.getUserByName("username") // We need an ArrayList because we are going to modify it ArrayList<ApplicationUser> requestParticipants = issue.getCustomFieldValue(requestParticipantsField) requestParticipants.add(user) issue.setCustomFieldValue(requestParticipantsField, requestParticipants) ComponentAccessor.getIssueManager().updateIssue(currentUser, issue, EventDispatchOption.DO_NOT_DISPATCH, false)
ArrayList is an implementation of java.util.List
, that supports the .add(...)
operation. Other list implementations will throw an UnsupportedOperationException
.
import com.atlassian.jira.component.ComponentAccessor def groupManager = ComponentAccessor.getGroupManager() def users = [] def groups = ["jira-administrators", "jira-service-desk-users"] // If a user is in both groups, they would be added twice for (group in groups) { users += groupManager.getUsersInGroup(group) } // Remove duplicate users users = users.unique()
import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.user.ApplicationUser import com.atlassian.jira.issue.util.DefaultIssueChangeHolder import com.atlassian.jira.issue.ModifiedValue def groupManager = ComponentAccessor.getGroupManager() def changeHolder = new DefaultIssueChangeHolder def userManager = ComponentAccessor.getUserManager() def customFieldManager = ComponentAccessor.getCustomFieldManager() def users = [] def groups = ["jira-administrators", "jira-service-desk-users"] // If a user is in both groups, they would be added twice for (group in groups) { users += groupManager.getUsersInGroup(group) } // Remove duplicate users users = users.unique() def approvers = [] for (user in users) { ApplicationUser approver = userManager.getUserByKey(user.getKey()) approvers.add(approver) } // Customfield 10006 corresponds to a multiple user field which we are using for the approvers if (!approvers.isEmpty()) { def approverField = customFieldManager.getCustomFieldObject("customfield_10006") // Commit changes to field approverField.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(approverField), approvers), changeHolder) }
import com.atlassian.jira.component.ComponentAccessor // Access Insight Java API Class iqlFacadeClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.IQLFacade") def iqlFacade = ComponentAccessor.getOSGiComponentInstanceOfType(iqlFacadeClass) Class objectFacadeClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade") def objectFacade = ComponentAccessor.getOSGiComponentInstanceOfType(objectFacadeClass) // Defining the Insight object information def objectKey = "ST-12345" def objectSchemaID = 1 def attributeName = "someGroupAttributeName" def groups = [] // Get the matching objects from Insight. In this case we are looking for a single object by its unique object key def insightObjects = iqlFacade.findObjectsByIQLAndSchema(objectSchemaID, "Key = \"" + objectKey + "\"") for (object in insightObjects) { def groupAttribute = objectFacade.loadObjectAttributeBean(object.getId(), attributeName) if (groupAttribute != null) { def groupAttributeValues = groupAttribute.getObjectAttributeValueBeans() if (groupAttributeValues != null) { for (group in groupAttributeValues) { groups.add(group.getValue()) } } } }
import com.atlassian.jira.component.ComponentAccessor def commentManager = ComponentAccessor.getCommentManager() def userManager = ComponentAccessor.getUserManager() def customFieldManager = ComponentAccessor.getCustomFieldManager() def user = userManager.getUserByName("username") // Set comment text e. g. with parsing a customfield value def myField = customFieldManager.getCustomFieldObject("customfield_XXXXX") def commentText = "Text pre " + issue.getCustomFieldValue(myField).toString() + " Text post" // Commit comment to issue commentManager.create(issue, user, commentText, true)
You can cover quite a distance using this approach. Just to give you some inspiration, here is a couple of other interesting ScriptRunner and Insight Groovy script use cases:
If you want more information just leave me a comment or get in touch.