Groovy use of the Jira REST API to update a custom field

We use Jira for managing a specific type of project at work. For some time, we’ve used the description field of certain issues to hold a particular piece of information. We recently decided to make a custom field for this instead, so that we could use the description field for its intended purpose, and include our new custom field in issue lists.

The challenge was to update the new custom field with the data from the description field for all historical issues. I couldn’t see a way to do it through Jira directly, so I thought I’d take the opportunity to exercise my groovy skills, and explore the Jira REST API.

I decided to use the HTTPBuilder library. Here is the grab and the imports:

@Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.5.2' )

import groovy.json.*

import groovyx.net.http.RESTClient
import groovy.util.slurpersupport.GPathResult
import groovyx.net.http.ContentType;

Good practice next, I don’t want to hard code my username and password in a script, so lets prompt for them:

String username = System.console().readLine("%s ", ["Jira Username:"] as String) 
String password = String.valueOf(System.console().readPassword("%s ", ["Jira Password:"] as String[]))

Next we make a client for all our rest requests:

def jiraClient = new RESTClient("https://my.jira.url");

Now I’m going to set up the authorisation header, and some settings that I’ll reuse each time I make a REST request. I spent a while working out how to do the authorisation. You can post to the /auth/1/session resource and then store a cookie, but sending an Authorisation Header seems nice and simple

def authString = "${username}:${password}".getBytes().encodeBase64().toString()
def requestSettings = [contentType: ContentType.JSON, requestContentType: ContentType.JSON, headers:['Authorization':"Basic ${authString}"]]

Here’s the first REST request, to the search resource. The clever groovy bit is adding two maps together, using the plus operator. I spent a while looking for a special function to do that. Sometimes groovy makes things too easy! The plus operator adds two maps and returns a new one. In contrast using the left shift operator would alter the map on the left.

def jqlQuery = "type = \"My Issue Type\" and cf[11720] is EMPTY and project = MYPROJ"
def issueRequest = jiraClient.post(settings + [path: "/rest/api/latest/search", body:  [jql: jqlQuery, maxResults: 10000]])

Next we run a REST PUT request for each issue returned. The groovy JsonBuilder makes is really easy to construct a correctly formatted JSON String to send. The syntax is a bit complicated – as well as the REST API documentation I found this example helpful: https://developer.atlassian.com/display/JIRADEV/JIRA+REST+API+Example+-+Edit+issues.

issueRequest.data.issues.each() { issue ->
  def json = new groovy.json.JsonBuilder()
  def root =  json.update {  
		customfield_11720 ( [{
			set "${issue.fields.description}"
		}] )
  }
  
  try {
      def result = jiraClient.put(settings + [path: "/rest/api/latest/issue/${issue.key}", body:  json.toString()] )
      println "${issue.key} | ${issue.fields.summary} | ${issue.fields.description} |  ${result.status}"
  } catch (Exception ex) {
      println "${issue.key} | ${issue.fields.summary} | ${issue.fields.description} |  FAIL"
  }
  
}

Unfortunately some of the put requests failed, because we’ve made more fields mandatory since we started and some of the older issues were missing data for mandatory fields, but it still saved a lot of time!

Leave a Reply

Your email address will not be published. Required fields are marked *