Script Examples
We have provided a few example scripts below. These examples serve as a good starting point for writing and editing your own code. Once you have completed your code changes, you can test it by clicking the Run button.
Run Code As User
Code that is run from the Script Console can make requests back to Jira using either the ScriptRunner Add-on user or the Current User. See the Run As User section of Workflow Extensions for more information.
Example Scripts
Get Jira Version
Starting with a very simple script to read the Jira version and display it in the console. API Reference.
groovyget('/rest/api/2/serverInfo') .queryString('doHealthCheck', 'true') .asObject(Map) .body .version
Line 1: This is a get request to the serverInfo resource
Line 2: Just as an example we see how to add a query string parameter of doHeathCheck
and set it to true
Line 3: asObject(Map)
makes the request and converts the response into a Map
Line 4: Calling .body
on the result of asObject(Map)
returns a Map
representation of the JSON response
Line 5: We now read the version property of the resulting Map
Show Issue Counts for Projects Based on JQL
Now let’s perform a JQL search to find all stories and group them into projects to determine which projects have the most stories.
groovyMap<String, Object> searchResult = get('/rest/api/2/search') .queryString('jql', 'issuetype = Story') .queryString('fields', 'project') .asObject(Map) .body def issues = (List<Map<String, Object>>) searchResult.issues issues.groupBy { issue -> ((Map<String, Map>) issue.fields).project.key }.collectEntries { pKey, issueList -> [(pKey): issueList.size()] }.toString()
Line 1-5: Perform the JQL search, specifying we are interested in the project field from the issue
Line 7: Grab all the issues from the search
Line 10: Take each issue and group them by project key
Line 12: The resulting list can be transformed into pairs of project key and the number of issues with that project key
Line 13: Turn the result into a string for display
As it is not possible to render returned html in Cloud (not permitted by Atlassian), you cannot display this data output as a html table . The script returns html that can be saved somewhere else to display the table.
groovyimport groovy.xml.MarkupBuilder Map<String, Object> searchResult = get('/rest/api/2/search') .queryString('jql', 'issuetype = Story') .queryString('fields', 'project') .asObject(Map) .body def issues = (List<Map<String, Object>>) searchResult.issues def mapping = issues.groupBy { issue -> ((Map<String, Map>) issue.fields).project.key }.collectEntries { pKey, issueList -> [(pKey): issueList.size()] } import static io.github.openunirest.http.Unirest.get def writer = new StringWriter() def builder = new MarkupBuilder(writer) builder.table(class: "aui") { thead { tr { th("Project Key") th("Count") } } tbody { mapping.each { projectKey, count -> tr { td { b(projectKey) } td(count) } } } } return writer.toString()
Line 10: Up until this point everything is the same, except we assign the result to mapping
Line 19: A new MarkupBuild is created, note the import. The markup builder takes advantage of Groovy’s meta-programming so the static type checking will cause errors, this is nothing to be worried about.
Update an Issue
Another common task is to update a field of an issue. In this case we set the summary to be a new summary.
groovydef issueKey = 'TP-1' def newSummary = 'Updated by a script' def result = put("/rest/api/2/issue/${issueKey}") //.queryString("overrideScreenSecurity", Boolean.TRUE) .header('Content-Type', 'application/json') .body([ fields: [ summary: newSummary ] ]) .asString() if (result.status == 204) { return 'Success' } else { return "${result.status}: ${result.body}" }
Line 1: Issue key and new summary to set
Line 4: Create the rest PUT request - see documentation
Line 5: You must pass overrideScreenSecurity=true if you are trying to amend fields that are not visible on the screen - Note you must use the Add-on user when setting overrideScreenSecurity=true
Line 6: Important to set the content type of the PUT, and then the body content as a Groovy Map
Line 12: Calling .asString()
executes the put and parses the result as a string
Line 14: The REST request responds with a 204 (no content) so there is no point reading the body
Update a Resolution on an Issue
This example shows how you can update the resolution on an issue and could be used to set the resolution on an issue which was closed with no resolution specified.
groovy// The issue to be updated def issueKey = '<IssueKeyHere>' // The Name of the resolution to be set def resolutionName = '<ResolutionNameHere>' def result = put('/rest/api/2/issue/' + issueKey) .queryString("overrideScreenSecurity", Boolean.TRUE) .header('Content-Type', 'application/json') .body([ fields:[ resolution:[name:resolutionName] ] ]) .asString() if (result.status == 204) { return 'Success' } else { return "${result.status}: ${result.body}" }
Line 2: The issue key for the issue to be updated.
Line 7: Create the rest PUT request - see documentation
Line 8: Here we must pass the overrideScreenSecurity=true query string as we are updating a field that is not on a screen - Note: - you must use the Add-on user when setting overrideScreenSecurity=true.
Line 9: Important to set the content type of the PUT, and then the body content as a Groovy Map
Line 12: Pass in an array which contains the name of the resolution to be set.
Line 15: Calling .asString()
executes the put and parses the result as a string
Line 17: The REST request responds with a 204 (no content) so there is no point reading the body
Bulk Update Multiple Issue Resolutions
This example extends the previous example and shows how you can update the resolution on multiple issues and could be used to set the resolution on issues which have been closed with no resolution specified.
groovy// Define a JQL query to search for the issues on which you want to update the resolution def query = '<JQLQueryHere>' // The Name of the resolution to be set def resolutionName = '<ResolutionNameHere>' // Search for the issues we want to update def searchReq = get("/rest/api/2/search") .queryString("jql", query) .queryString("fields", "resolution") .asObject(Map) // Verify the search completed successfully assert searchReq.status == 200 // Save the search results as a Map Map searchResult = searchReq.body // Iterate through the search results and update the resolution for each issue returned searchResult.issues.each { Map issue -> // Log out what the value from the resolution field was for the original issue. logger.info("The original resolution was ${issue.fields.resolution ?: 'null'} for the ${issue.key} issue.") def result = put("/rest/api/2/issue/${issue.key}") .queryString("overrideScreenSecurity", Boolean.TRUE) .header('Content-Type', 'application/json') .body([ fields:[ resolution:[name:resolutionName] ] ]) .asString() // Log out the issues updated or which failed to update if (result.status == 204) { logger.info("Resolution set to ${resolutionName} for the ${issue.key} issue") } else { logger.warn("Failed to set the resolution to ${resolutionName} on the ${issue.key} issue. ${result.status}: ${result.body}") } } // end of loop return "Script Completed - Check the Logs tab for information on which issues were updated."
Line 2: The rest call to execute the JQL search and return the issue keys
Line 8: The rest call to execute the JQL search and return the issue keys
Line 17: Save the results returned from the JQL search to a map
Line 20: Loop over each of each issue key returned in the search results.
Line 24: Create the rest PUT request - see documentation
Line 25: Here we must pass the overrideScreenSecurity=true query string as we are updating a field that is not on a screen - Note: - you must use the Add-on user when setting overrideScreenSecurity=true.
Line 26: Important to set the content type of the PUT, and then the body content as a Groovy Map
Line 29: Pass in an array which contains the name of the resolution to be set.
Line 32: Calling .asString()
executes the put and parses the result as a string
Line 35: The REST request responds with a 204 (no content) so there is no point reading the body
Add a User or Group to a Project Role
Say we would like to add a user to a group. This can be quickly achieved using the following assuming that the user, group, project and role all exist
groovydef accountId = '123456:12345a67-bbb1-12c3-dd45-678ee99f99g0' def groupName = 'jira-core-users' def projectKey = 'TP' def roleName = 'Developers' def roles = get("/rest/api/2/project/${projectKey}/role") .asObject(Map).body String developersUrl = roles[roleName] assert developersUrl != null def result = post(developersUrl) .header('Content-Type', 'application/json') .body([ user: [accountId], group: [groupName] ]) .asString() assert result.status == 200 result.statusText
Line 7: First all the roles for the project are fetched
Line 13: Then the url for the specified role is found to use to post to
Line 16: In this case we have a group and a user to add, user
and group
must be arrays
Extract the Value From a Select List Custom Field
This example shows how you can extract the value that has been specified inside a select list field on an issue.
groovy// The issue key def issueKey = '<IssueKeyHere>' // Fetch the issue object from the key def issue = get("/rest/api/2/issue/${issueKey}") .header('Content-Type', 'application/json') .asObject(Map) .body // Get all the fields from the issue as a Map def fields = issue.fields as Map // Get the Custom field to get the option value from def customField = get("/rest/api/2/field") .asObject(List) .body .find { (it as Map).name == '<CustomFieldNameHere>' } as Map assert customField : "Failed to find custom field with given name" // Extract and store the option from the custom field def value = (fields[customField.id] as Map)?.value // Return the option value return "The value of the select list from the ${customField.name} custom field is: ${value}"
Extract the Values From a Multi Select List Custom Field
This example shows how you can extract the values that have been specified inside a multi select list field on an issue.
groovy// The issue key def issueKey = '<IssueKeyHere>' // Fetch the issue object from the key def issue = get("/rest/api/2/issue/${issueKey}") .header('Content-Type', 'application/json') .asObject(Map) .body // Get all the fields from the issue as a Map def fields = issue.fields as Map // Get the Custom field to get the option value from def customField = get("/rest/api/2/field") .asObject(List) .body .find { (it as Map).name == '<CustomFieldNameHere>' } as Map // Extract and store the option from the custom field def values = fields[customField.id] as List<Map> // Get each of the values from the multi select list field and store them def fieldValues = values.collect { it.value } // Return the option values return "The values of the multi select list from the ${customField.name} custom field are: ${fieldValues}"
Extract the Value From a Radio Button Custom Field
This example shows how you can extract the value that has been specified inside a radio button field on an issue.
groovy// The issue key def issueKey = '<IssueKeyHere>' // Fetch the issue object from the key def issue = get("/rest/api/2/issue/${issueKey}") .header('Content-Type', 'application/json') .asObject(Map) .body // Get all the fields from the issue as a Map def fields = issue.fields as Map // Get the Custom field to get the option value from def customField = get("/rest/api/2/field") .asObject(List) .body .find { (it as Map).name == '<CustomFieldNameHere>' } as Map // Extract and store the option from the radio buttons custom field def radioButtonValue = (fields[customField.id] as Map).value // Return the option value return "The value of the radio buttons from the ${customField.name} custom field is: ${radioButtonValue}"
Extract the Values From a Checkbox Custom Field
This example shows how you can extract the values that have been specified inside a checkbox field on an issue.
groovy// The issue key def issueKey = '<IssueKeyHere>' // Fetch the issue object from the key def issue = get("/rest/api/2/issue/${issueKey}") .header('Content-Type', 'application/json') .asObject(Map) .body // Get all the fields from the issue as a Map def fields = issue.fields as Map // Get the Custom field to get the option value from def customField = get("/rest/api/2/field") .asObject(List) .body .find { (it as Map).name == '<CustomFieldNameHere>' } as Map // Extract and store the option from the custom field def checkboxValues = fields[customField.id] as List<Map> // Get each of the values from the checkbox field and store them def checkboxFieldValues = checkboxValues.collect { it.value } // Return the option values return "The values of the checkboxes from the ${customField.name} custom field are: ${checkboxFieldValues}"
Create a Link to an External URL on an Issue
This example shows how you can create a link to an external URL on an issue.
groovy// The url for the link def linkURL = '<LinkURLHere>' // the title for the link def linkTitle = '<LinkTitleHere>' // The issue key def issueKey = '<IssueKeyHere>' // Create the link on the specified issue def result = post("/rest/api/2/issue/${issueKey}/remotelink") .header('Content-Type', 'application/json') .body([ object: [ title:linkTitle, url:linkURL ] ]) .asObject(String) // Check if the link created succesfully if (result.status == 201) { return "Remote link with name of ${linkTitle} which links to ${linkURL} created successfully" } else { return "${result.status}: ${result.body}" }
Flag an Issue as an Impediment
This example shows how you can flag an issue as an impediment.
groovy// Specify Issue Key here def issueKey = '<IssueKeyHere>' // Look up the custom field ID for the flagged field def flaggedCustomField = get("/rest/api/2/field") .asObject(List) .body .find { (it as Map).name == 'Flagged' } as Map // Update the issue setting the flagged field def result = put("/rest/api/2/issue/${issueKey}") .header('Content-Type', 'application/json') .body([ fields:[ // The format below specifies the Array format for the flagged field // More information on flagging an issue can be found in the documentation at: // https://confluence.atlassian.com/jirasoftwarecloud/flagging-an-issue-777002748.html (flaggedCustomField.id): [ // Initialise the Array [ // set the component value value: "Impediment", ], ] ] ]) .asString() // Check if the issue was updated correctly if (result.status == 204) { return 'Success - Issue was updated by a script and issue flagged.' } else { return "${result.status}: ${result.body}" }
Bulk Set Flag on Multiple Issues
This example extends the previous example and shows how you can set the Impediment flag on multiple issues.
groovy// Define a JQL query to search for the issues on which you want to set the impediment flag def query = '<JQLQueryHere>' // Look up the custom field ID for the flagged field def flaggedCustomField = get("/rest/api/2/field") .asObject(List) .body .find { (it as Map).name == 'Flagged' } as Map // Search for the issues we want to update def searchReq = get("/rest/api/2/search") .queryString("jql", query) .queryString("fields", "Flagged") .asObject(Map) // Verify the search completed successfully assert searchReq.status == 200 // Save the search results as a Map Map searchResult = searchReq.body // Iterate through the search results and set the Impediment flag for each issue returned searchResult.issues.each { Map issue -> def result = put("/rest/api/2/issue/${issue.key}") .queryString("overrideScreenSecurity", Boolean.TRUE) .header('Content-Type', 'application/json') .body([ fields:[ // The format below specifies the Array format for the flagged field // More information on flagging an issue can be found in the documentation at: // https://confluence.atlassian.com/jirasoftwarecloud/flagging-an-issue-777002748.html // Initialise the Array (flaggedCustomField.id): [ [ // set the component value value: "Impediment", ], ] ] ]) .asString() // Log out the issues updated or which failed to update if (result.status == 204) { logger.info("The ${issue.key} issue was flagged as an Impediment. ") } else { logger.warn("Failed to set the Impediment flag on the ${issue.key} issue. ${result.status}: ${result.body}") } } // end of loop return "Script Completed - Check the Logs tab for information on which issues were updated."
Line 2: The JQL search that will be used to return the list of issue keys.
Line 5: The rest call to look up the ID of the 'Flagged' custom field
Line 13: The rest call to execute the JQL search and return the issue keys
Line 22: Save the results returned from the JQL search to a map
Line 25: Loop over each of each issue key returned in the search results.
Line 27: Create the rest PUT request - see documentation
Line 28: Here we must pass the overrideScreenSecurity=true query string as we are updating a field that is not on a screen - Note: - you must use the Add-on user when setting overrideScreenSecurity=true.
Line 29: Important to set the content type of the PUT, and then the body content as a Groovy Map
Line 36: Pass in an array which contains the Impediment value to be set on the 'Flagged' field.
Line 44: Calling .asString()
executes the put and parses the result as a string
Line 47: The REST request responds with a 204 (no content) so there is no point reading the body
Create a SubTask
This example shows how you can create a subtask below for a specified parent issue.
This example only works with Company Managed projects.
groovy// Specify the key of the parent issue here def parentKey = '<ParentIssueKeyHere>' // Get the parent issue type def issueResp = get("/rest/api/2/issue/${parentKey}") .asObject(Map) assert issueResp.status == 200 // get the body of the parent issue type def issue = issueResp.body as Map // Get the issue types for the instance def typeResp = get('/rest/api/2/issuetype') .asObject(List) assert typeResp.status == 200 def issueTypes = typeResp.body as List<Map> // Here we set the basic subtask issue details def summary = "Subtask summary" // The summary to use for def issueType = "Sub-task" // The Sub Task Issue Type to Use // Get the sub task issue type to use def issueTypeId = issueTypes.find { it.subtask && it.name == issueType & !it.scope }?.id assert issueTypeId : "No subtasks issue type found called '${issueType}'" // Get the project to create the subtask in def project = (issue.fields as Map).project // Create the subtask def resp = post("/rest/api/2/issue") .header("Content-Type", "application/json") .body( fields: [ project: project, issuetype: [ id: issueTypeId ], parent: [ id: issue.id ], summary: summary ]) .asObject(Map) // Get and validate the newly created subtask def subtask = resp.body assert resp.status >= 200 && resp.status < 300 && subtask && subtask.key != null // If the sub task created successfully return a success message along with its key if (resp.status == 201) { return 'Success - Sub Task Created with the key of ' + resp.body.key.toString() } else { return "${resp.status}: ${resp.body}" }
Line 5: Get the issue object for the specified parent issue
Line 13: Get a list of all of the issue types for the instance
Line 24: Lookup the ID for the specified sub task issue type
Line 31: Create the sub task below the parent issue specified
Line 51: Validate that the sub task created successfully and display a message if it did.
Set Due Date Field Value
This example shows how you can set the due date field on an issue.
groovy// Specify the issue key to update def issueKey = '<IssueKeyHere>' // Get today's date to set as the due date def today = new Date() // Update the issue def result = put("/rest/api/2/issue/${issueKey}") .header('Content-Type', 'application/json') .body([ fields:[ // Set the due date to today's date duedate: today.format('yyyy-MM-dd') as String ] ]) .asString() // Validate the issue updated correctly if (result.status == 204) { return "Success - The issue with the key of ${issueKey} has been updated with a new due date" } else { return "${result.status}: ${result.body}" }
Set Custom Date Field Value
This example shows how you can set a custom date picker field on an issue.
groovy// Specify the issue key to update def issueKey = '<IssueKeyHere>' // Get today's date to set as the due date def today = new Date() // Specify the name of the date picker field to set def datePickerFieldName = '<DatePickerFieldNameHere>' // Get the Custom field to get the option value from def customField = get("/rest/api/2/field") .asObject(List) .body .find { (it as Map).name == datePickerFieldName } as Map // Check if the custom field returns a valid field and is not null assert customField != null : "Cannot find custom field with name of: ${datePickerFieldName}" // Update the issue def result = put("/rest/api/2/issue/${issueKey}") .header('Content-Type', 'application/json') .body([ fields:[ // Set the custom date picker field date to today's date (customField.id): today.format('yyyy-MM-dd') as String ] ]) .asString() // Validate the issue updated correctly if (result.status == 204) { return "Success - The issue with the key of ${issueKey} has been updated with a new date in the ${datePickerFieldName} field." } else { return "${result.status}: ${result.body}" }
Set Select List Field Value
This example shows how you can set the value of a single select list field on a issue.
groovy// Specify the issue key to update def issueKey = '<IssueKeyHere>' // Specify the name of the select list field to set def selectListFieldName = '<SelectListFieldNameHere>' // Get the Custom field to get the option value from def customField = get("/rest/api/2/field") .asObject(List) .body .find { (it as Map).name == selectListFieldName } as Map // Check if the custom field returns a valid field and is not null assert customField != null : "Cannot find custom field with name of: ${selectListFieldName}" def result = put("/rest/api/2/issue/${issueKey}") // Uncomment the line below if you want to set a field which is not pressent on the screen. Note - If using this you must run the script as the ScriptRunner Add-On User. //.queryString("overrideScreenSecurity", Boolean.TRUE) .header('Content-Type', 'application/json') .body([ fields: [ (customField.id):[value: "<OptionValueHere>"] as Map ] ]) .asString() if (result.status == 204) { return "The ${customField.name} select list field was successfully updated on the ${issueKey} issue" } else { return "${result.status}: ${result.body}" }
Create a Confluence Page With a Label
This example shows how you can create a page inside of a Confluence instance and add a label to the newly created page.
This example requires that you have both ScriptRunner for Jira Cloud and ScriptRunner for Confluence Cloud installed. If you do not have ScriptRunner for Confluence Cloud installed then you will need to update this example to specify user credentials to access the Confluence instance.
groovy// Specify the id of the parent page that the new page will be created under def parentPageId = "<PageIDHere>" //Specify a title for the new page def pageTitle = "<PageTitleHere>" // Specify the space key of the spcae that the new page will be created in def spaceKey = "<SpaceKeyHere>" // Specify the body of the page in storage format - below is some example storage format. def storageFormat = """<h1>A page created by ScriptRunner</h1> <p>The first line of my page.</p> <p>The second line of my page</p>""" // Specify the body of the rest request def body = [ type: "page", title: pageTitle, space: [ key: spaceKey ], ancestors: [[ id: parentPageId ]], body:[ storage:[ value: storageFormat, representation: "storage" ] ] ] //create confluence (cloud) page def createPageResult = post("/wiki/rest/api/content") .header("Content-Type", "application/json") .header("Accept", "application/json") .body(body) .asObject(Map) // Assert that the new page created successfully assert createPageResult.status == 200 : "Failed to create the page" // Add some labels to the newly created Confluence page def addLabels = post("/wiki/rest/api/content/${createPageResult.body.id}/label") .header("Content-Type", "application/json") .header("Accept", "application/json") .body( [ // Note you can specify a comma seperated lists of strings here if you wish to add multiple labels to a page. // An example of adding more than 1 label is "name" : "ALabel,label2" "name" : "<LabelNameHere>", "prefix": "global" ]) .asString() // Assert that the label was added to the page correctly assert addLabels.status == 200 : "Failed to add labels to the page" // Return the result of the created page return "Confluence page created with the name of: ${pageTitle} \n" + createPageResult
Line 14: Here we specify the content to be added to the page using the 'Storage Format' for Confluence.
Line 17: Here we specify the body that is passed into the rest call to create the Confluence page.
Line 35: The rest API call to create the Confluence page..
Line 45: The rest API call to add a label to the newly created page.
Copy Versions to a New Project
This example shows how you can copy a set of versions from one project to another project.
This example will only copy versions where a version with the same name does not exist in the target project.
groovy// Specify the master project to get the versions form def masterProjectKey = "<ProjectKeyHere>" // Specify the key of the project to copy the version to def projectToCopyVersionTo = "<ProjectKeyHere>" // get the project versions def versions = get("/rest/api/2/project/${masterProjectKey}/versions") .header('Content-Type', 'application/json') .asObject(List).body // Loop over each version returned and create a version in the new project versions.each { boolean archivedValue = it.archived boolean releasedValue = it.released // Get todays date as a string for any date properties which dont have a value set def today = new Date().format('yyyy-MM-dd').toString() // Declare some variables to store the start and release date values def startDateValue; def releaseDateValue // Get the start date and if it is null set it to todays date as a start date is required when creating a version in a new project if (it.startDate != null) { startDateValue = it.startDate.toString() } else { startDateValue = today } // Get the release date and if it is null set it to todays date as a release date is required when creating a version in a new project if (it.releasedDate != null) { releaseDateValue = it.startDate.toString() } else { releaseDateValue = today } // Make the rest call to create the version logger.info("Copying the version with the name of: ${it.name.toString().replaceAll("\\[", "").replaceAll("\\]", "")}") def createVersion = post("/rest/api/2/version") .header("Content-Type", "application/json") .body([ "description": it.description.toString()?: "", // Get the desceription and pass an emtpy string if it is null "name": it.name.toString()?: "", // Get the name and pass an emtpy string if it is null "archived": archivedValue, // Get the archived value and pass an emtpy string if it is null "released": releasedValue, // Get the released value and pass an emtpy string if it is null "startDate": startDateValue, "releaseDate": releaseDateValue, "project": projectToCopyVersionTo ]).asString() } return "Versions Copied. Check the 'Logs' tab for more details"
Line 10: Here we make a rest API call to get the versions to be copied as a List object.
Line 13: Here we loop over each version and ensure that we have the values in the correct format to pass to the rest call to create the version.
Line 42: Here we make a rest API call to create the current version.
Post to Slack
This example posts a message to Slack in the format specified, along with issue details.
groovy// Specify the issue key. def issueKey = '<IssueKeyHere>' //Get the issue def issueResp = get("/rest/api/2/issue/${issueKey}") .header("Content-Type", "application/json") .asObject(Map) assert issueResp.status == 200 def issue = issueResp.body // Get the issue summary. def summary = issue.fields.summary // Get the issue description. def description = issue.fields.description // Specify the name of the Slack room you want to post to. def channelName = '<ChannelName>' // Specify the name of the user who will make the post. def username = '<SlackUsername>' // Specify the message metadata. Map msg_meta = [ channel: channelName, username: username ,icon_emoji: ':rocket:'] // Specify the message body which is a simple string. Map msg_dets = [text: "A new issue was created with the details below: \n Issue key = ${issueKey} \n Issue Sumamry = ${summary} \n Issue Description = ${description}"] // Post the constructed message to Slack. def postToSlack = post('https://slack.com/api/chat.postMessage') .header('Content-Type', 'application/json') .header('Authorization', "Bearer ${SLACK_API_TOKEN}") // Store the API token as a script variable named SLACK_API_TOKEN. .body(msg_meta + msg_dets) .asObject(Map) .body assert postToSlack : "Failed to create Slack message check the logs tab for more details" return "Slack message created successfully"
Set URL Field Value
This example shows how you can set the value of a custom URL field on an issue.
groovy// Specify the issue key to update def issueKey = '<IssueKeyHere>' // Specify the name of the select list field to set def URLFieldName = '<URLFieldNameHere>' // Get the Custom field to get the option value from def customField = get("/rest/api/2/field") .asObject(List) .body .find { (it as Map).name == URLFieldName } as Map // Check if the custom field returns a valid field and is not null assert customField != null : "Cannot find custom field with name of: ${URLFieldName}" def updateURL = put("/rest/api/2/issue/${issueKey}") // Uncomment the line below if you want to set a field which is not pressent on the screen. Note - If using this you must run the script as the ScriptRunner Add-On User. //.queryString("overrideScreenSecurity", Boolean.TRUE) .header('Content-Type', 'application/json') .body([ fields:[ (customField.id):"https://www.adaptavist.com" ] ]).asString() if (updateURL.status == 204) { return "The ${customField.name} select list field was successfully updated on the ${issueKey} issue" } else { return "${updateURL.status}: $updateURL.body}" }
Connect to databases
You can make database connection calls via groovy within ScriptRunner for Jira Cloud, meaning that you can read or write to a database as part of a script.
As this feature is provided from within the groovy scripts, in order to use it, you need to import SQL modules in groovy that allow you to run SQL against an external database, as outlined in the examples below.
Connecting to postgres database:
groovyimport groovy.sql.Sql import java.sql.Driver def db = [url:'jdbc:postgresql://my.example.com:1234/', user:'username', password:'password', driver:'org.postgresql.Driver'] def sql = Sql.newInstance(db.url, db.user, db.password, db.driver) sql.rows ''' SELECT * FROM "example" LIMIT 100 '''
Connecting to mySQL database:
groovyimport groovy.sql.Sql import java.sql.Driver def db = [url:'jdbc:mysql://my.example.com', user:'username', password:'password', driver:'com.mysql.cj.jdbc.Driver'] def sql = Sql.newInstance(db.url, db.user, db.password, db.driver) sql.rows ''' SELECT * FROM "example" LIMIT 100 '''
Connecting to MSSQL database:
groovyimport groovy.sql.Sql import java.sql.Driver def db = [url:'jdbc:sqlserver://my.example.com', user:'username', password:'password', driver:'com.microsoft.sqlserver.jdbc.SQLServerDriver'] def sql = Sql.newInstance(db.url, db.user, db.password, db.driver) sql.rows ''' SELECT * FROM "example" LIMIT 100 '''
Transition an Issue and Add a Comment
This example shows how you can transition an issue to a different status and add a comment to the issue whilst it is transitioned.
Note that you cannot skip or ignore conditions and validators when transitioning an issue, so if they are not met, then you need to allow the transition to pass.
groovy// The ID of the workflow transition to execute. // Note - The transition ID must represent a valid transition for the workflow that the issue uses. def transitionID = '<TransitionIDHere>' // Specify here the issue key for the issue to transition def issueKey = '<IssueKeyHere>' // The rest call to transition the issue def transitionIssue = post("/rest/api/2/issue/${issueKey}/transitions") .header("Content-Type", "application/json") .body([ "update" : [ "comment": [ [ "add": [ "body": "A sample comment added during a transition" ] ] ] ], transition: [id: transitionID] ]) .asObject(Map) // Check if the issue was transitioned correctly if (transitionIssue.status == 204) { return "The ${issueKey} issue was transitioned to the status with the id of ${transitionID}" } else { return "The escalation service failed to transition the ${issueKey}issue. ${transitionIssue.status}: ${transitionIssue.body}" }
Copy Project
The copy project ScriptRunner for Jira Server/DC built-in script can achieve the same functionality in Jira Cloud by using the Script Console and a script. There are limitations to what can be copied to the new project due to the request body parameters for the create project API call.
java// Set the source project key def sourceProjectKey = 'SUP' // Get the source project def sourceProject = get("/rest/api/3/project/${sourceProjectKey}") .header('Content-Type','application/json') .asObject(Map) if(sourceProject.status == 200){ // Assign project variables and build body def copyKey = 'TEST' def copyName = 'Test Project' def projectTypeKey = sourceProject.body.projectTypeKey def projectTemplateKey = 'com.pyxis.greenhopper.jira:gh-simplified-scrum-classic' def description = sourceProject.body.description def leadAccountId = sourceProject.body.lead.accountId def assigneeType = sourceProject.body.assigneeType def notifyScheme = get("/rest/api/3/project/${sourceProjectKey}/notificationscheme") .header('Content-Type', 'application/json') .asObject(Map) .body as Map def notifySchemeId = notifyScheme.id def permissionScheme = get("/rest/api/3/project/${sourceProjectKey}/permissionscheme") .header('Content-Type', 'application/json') .asObject(Map) .body as Map def permissionSchemeId = permissionScheme.id def body = [ "key": copyKey, "name": copyName, "projectTypeKey": projectTypeKey, "projectTemplateKey": projectTemplateKey, "description": description, "leadAccountId": leadAccountId, "assigneeType": assigneeType, "notificationScheme": notifySchemeId, "permissionScheme": permissionSchemeId ] // Create new project def newProject = post("/rest/api/3/project") .header('Content-Type','application/json') .body(body) .asString() if(newProject.status == 201){ return "Project ${sourceProjectKey} copied to create new project ${copyKey}" }else{ return "Failed to create new project - ${newProject.status}" } }else{ return "Failed to find project ${sourceProjectKey}" }
Add Comment Using Atlassian Document Format (ADF)
This example shows how you can add a comment on an issue using Atlassian Document Format to add rich text markup in the comment.
def issueKey = 'AddIssueKeyHere'
def commentBody = '''{
"body": {
"content": [
{
"content": [
{
"text": "A demo comment added using Atlassian document format",
"type": "text"
}
],
"type": "paragraph"
}
],
"type": "doc",
"version": 1
}
}
''';
def addComment = post("/rest/api/3/issue/${issueKey}/comment")
.header('Content-Type', 'application/json')
.body(commentBody)
.asObject(Map)
if (addComment.status >= 200 && addComment.status <= 300) {
return "Succesfully added comment to the ${issueKey} issue"
} else {
return "${addComment.status}: ${addComment.body}"
}