CI/CD using Jira & GitHub-Actions, Python, REST API.

Author: aashutosh

Updated: 17 Feb 2023 8:49 p.m.

Tags: #Python #Scripting #REST #API #Automation #Jira

Summary : Integrate Jira and GitHub-Actions using Python script & REST API.

This is quick hack to automate advanced functionalities in Jira using custom Python script and utilizing GitHub-Actions or any other tools like AWS Lambda, GCP & Azure Functions, Jenkins, or any custom webserver.

 

Jira Service Management has very good Automation feature, but to automate highly advanced features, we can use a custom python script which does the business logic processing and update Jira via REST API.

 

We can write a workflow, whenever any event happens in Jira, we will trigger our script to execute, hosted on GitHub in this case.

 

Use Case Example:

Global Finance Application

 

Step 1 : Create automation rule in Jira.

Project -> Project Settings -> Automation -> Create Rule
New Trigger -> Select Event when you want to trigger rule.
Example: When Issue Created.

               Then Send Web Request
               Send Web Request to GitHub Repository dispatch with custom data (issue key & jira api token)

 

 

Step 2: Set up GitHub

Create a GitHub Repo and below workflow.yml file in .github/workflows/ directory

name: my build name 

# trigger when this repository is dispatch (called from Jira Web request)
on: repository_dispatch  
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-python@v4
      with:
        python-version: '3.10' 
    - name: Install Dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
    - name: Name of run task
      run: |
        python automation_script.py ${{ github.event.client_payload.key }} ${{ github.event.client_payload.jira-token }}

Upload Python Script & dependent files to GitHub Reposiory

Approvers Matrix

 

Python Script
 

import re 
import sys
import json
import requests 
import datetime
import pandas as pd
from requests.auth import HTTPBasicAuth

# get jira issue key and api token passed via Jira web request as arguments to script as defined in GitHub-Actions Workflow
issueKey=sys.argv[1]
jiraAPIToken=sys.argv[2]

jiraAPIToken = '***********8'
email = 'aashutosh'
auth = HTTPBasicAuth(email,jiraAPIToken)
headers = {
    "Accept": "application/json",
    "Content-Type": "application/json"
}

# generate REST API URL with issue-key
url='https://mysite.atlassian.net/rest/api/3/issue/'+issueKey

# fetch data using requests from Jira REST API
response = requests.request(
   "GET",
   url,
   headers=headers,
   auth=auth
)

# print json data in pretty format
# print(json.dumps(json.loads(response.text), sort_keys=True, indent=4, separators=(",", ": ")))
data=json.loads(response.text)

'''
Perform Business Logic
Jira Custom Fields ID
customfield_10001 = Country & City Custom Field id in Jira
customfield_10002 = Amount
customfield_10003 = Currency
customfield_10004 = Level 1 Approver
customfield_10005 = Level 2 Approver
customfield_10006 = Level 3 Approver
customfield_10007 = Amount in Euro
'''

country  = data['fields']['customfield_10001']['value']
city     = data['fields']['customfield_10001']['value']
amount   = float(data['fields']['customfield_10002'])
currency = data['fields']['customfield_10003']

#Store Approver & Approvers Matrix in an excel sheet mapped to each Country & City
#Read approvers excel sheet using pandas dataframe
df = pd.read_excel('approver.xlsx')

# Read Approvers Excel file
df = pd.read_excel('approvers.xlsx')

# Read Approvers Name & Jira Account IDs. convert pairs into dictionary
accountIDs_df = pd.read_excel('approvers.xlsx', sheet_name=1)

# Make Dictionary of Approvers Account Names & AccountIDs
approvers_accountIDs = dict(zip(accountIDs_df.Name, accountIDs_df.AccountID))

#Filter Approvers Row for each Country & City
approver_row = df[ (country == df['Country']) & (city == df['City']) ]

def get_approversID(column_name, approver_row):
    '''
    Get Approvers Account ID from Excel sheet, 
    join account ids for multiple users in single cell, 
    split, strip & join.
    '''
    # split multiple users in once cell
    approvers = approver_row[column_name].values[0].split(',')
    # strip whitespaces in users name
    approvers = [ user.strip() for user in approvers ]
    # join users with comma, return their Account ID
    approvers = ','.join([approvers_accountIDs[user] for user in approvers])
    return approvers


level1Approvers = get_approversID('Level_1_Approver',approver_row)
level2Approvers = get_approversID('Level_2_Approver',approver_row)
level3Approvers = get_approversID('Level_3_Approver',approver_row)


def currRate(curr):
    # Function to convert currency into EURO, ruturn currency exchange rate w.r.t EURO
    return  {
        'AED - UAE Dirham'                  :   4.55,
        'ARS - Argentine Peso'              :   90.4693,
        'AUD - Australian Dollar'           :   1.62,
        'BRL - Brazilian Real'              :   6.6308,
        'CAD - Canadian Dollar'             :   1.52,
        'CNY - Yuan Reminbi'                :   7.972,
        'EUR - Euro'                        :   1,
        'GBP - Pound Sterling'              :   0.89,
        'HKD - Hong Kong Dollar'            :   8.915,
        'INR - Indian Rupee'                :   84,
        'JPY - Yen'                         :   121,
        'MXN - Mexican Peso'                :   24,
        'RUB - Ruble'                       :   91.7763,
        'SEK - Swedish Kronor'              :   10.5713,
        'SGD - Singapore Dollar'            :   1.58,
        'THB - Baht'                        :   37.079,
        'USD - US Dollar'                   :   1.15,
    }.get(curr)

    
# get amount in Eurom by multiplying amount with currency rate
amount_Euro = float(amount * currRate(currency)


payload = json.dumps( {
    "fields": {
        "customfield_10004": [{"accountId": level1Approvers}],
        "customfield_10004": [{"accountId": level1Approvers}],
        "customfield_10005": [{"accountId": level2Approvers}],
        "customfield_10006": [{"accountId": level3Approvers}],
        "customfield_10007": amount_Euro,
        }
})   

#Update Jira
response = requests.request(
   "PUT",
   url,
   data=payload,
   headers=headers,
   auth=auth
)
print(f'Response = {response.status_code, response.text}')