Blog - Isos Technology

How to Use the Jira/Google Drive API

Written by Vivian Escalante | Feb 9, 2021

The Use Case: A Quick Overview

You'd be surprised by the many ways Jira is able to integrate with other applications, such as Google Drive. I recently came across an interesting use case, one that involved storing a copy of a document in Google Drive when a Jira ticket went through an approval workflow. I'll walk you through how I handled it so you can set it up yourself.

The reason why this was important for this team was for legal reasons. The reporter would submit a link to the Google Drive document on the Jira ticket, so the legal team could track exactly what they had approved in their very own Google Drive folder. In order to save data space, this team decided to continue to allow the reporter to submit only the Google Doc link. It was time to use the Google Drive API!

The Solution

Here's how it works:

  1. Create an automated middleman. With all automation, you need a "user" whose sole purpose is to perform the automation. This is critical because if there are any issues with the implementation you can pin down who performed the action—in this case, an automation user, rather than an actual user. Another reason we don't want to use a real user is if this user leaves the company and their user is deactivated, it will affect the implementation. An IAM account will only act as player to impersonate a Jira service account. This account can't own a drive of its own, but allows you to download a JSON file with credentials to impersonate a service account. Lets call this account jira-middleman-google. 

  2. Authenticate with OAuth 2.0. There are different scopes the middleman can have access to that limit the user to act on only the necessary data. An important thing I stumbled upon was the fact that the scope below didn't allow me to impersonate my service account to copy, create, or update a file. The only way this scope will work is if you have a login screen and the service account is able to authenticate, which wasn't the case in this situation. This implementation was to be all automated.

     

    https://www.googleapis.com/auth/drive.file

    So we needed the scope below:

    https://www.googleapis.com/auth/drive
  3. Provide the data to Google Drive API. I used a post-function Groovy script that was triggered once the team approved the Jira ticket. The groovy script grabs the Google Doc link and parses only the file ID that needs copying. 

     

    Post-Function Groovy Script
    import com.atlassian.jira.component.ComponentAccessor
    import java.util.regex.Matcher
     
    //Jira link field
    def customfieldManager = ComponentAccessor.getCustomFieldManager()
    String google_file_link = issue.getCustomFieldValue(customfieldManager.getCustomFieldObject("customfield_id"))
    if (google_file_link){
        Matcher matchGroup = fileLink =~ /.*(\/d)\/(.*)\/.*/
        if(matchGroup.matches()) {
            String fileID = matchGroup.group(2)
            def comm = "python {python_file} {middleman_json_file} {middleman_account} service-account@domain.com ${fileID} ${fileName}"
            def execComm = comm.execute()
            execComm.waitFor()
            def result = execComm.in.text
        }
        else {log.warn("File URL doesn't match gdrive URL format.")}
    }
    else{ log.warn("There's no file URL provided.")}

    Once it has the parsed file ID, it runs the Python file that uses the jira-middleman to impersonate the service account and make a copy of the file with the provided file ID. 

     

    Python File
    from oauth2client.service_account import ServiceAccountCredentials
    from httplib2 import Http, ServerNotFoundError
    from apiclient.discovery import build
    import json, sys, os, time
     
    def main():
        # get the args
        secret_file = sys.argv[1]
        service_account_email = sys.argv[2].lower()
        impersonate = sys.argv[3].lower()
        file_id = sys.argv[4]
        file_name = sys.argv[5]
     
        # use the credentials to call the Google Drive API
        service = get_service(service_account_email, secret_file, impersonate)
        body={"title": file_name}
        result = copy_file(service, file_id , body)
     
    def get_service(service_account_email, secret_file, impersonate, retry=0):
        try:
            credentials = ServiceAccountCredentials.from_json_keyfile_name(secret_file, scopes=['https://www.googleapis.com/auth/drive'])
            delegated_credentials = credentials.create_delegated(impersonate)
            http_auth = delegated_credentials.authorize(Http())
            return build('drive', 'v3', http=http_auth) # gets access to the drive API
        except ServerNotFoundError as e:
            if retry >= 10:
                print(e)
                exit()
            else:
                retry += 1
                time.sleep(5)
                return get_service(secret_file, impersonate, retry)
     
    def copy_file(service, source_file_id, body):
        """Copy an existing file.
        Args:
        service: Drive API service instance.
        source_file_id: ID of the source file to copy.
     
        Returns:
        The copied file if successful, None otherwise.
        """
        
        try:
            return service.files().copy(fileId=source_file_id, body=body).execute()
        except errors.HttpError, error:
            print 'ERROR: %s' % error
        return None
     
    if __name__ == '__main__':
       main()

 

Now They're Talkin'

This is just one of the many powerful and customizable integrations we can perform with Jira. Stay tuned for more! And as always, reach out to Isos Technology if you'd like to speak with somebody about what Jira can do for your organization.