Blog Cover Image

Inspire you to have New thinking, Walk out your unique Road.

有的時候,你無意間遇到的一些故事,會激發你的靈感,改變你的想法,接下來你會用與之前全然不同的觀念去創造屬於你獨特的故事。

Sign @MinaYu.

[後端] 如何使用Python Requests通過Jira APIs 達成基本的自動化功能 (創建Ticket、留Comment及上傳Attachment)

Posted on

Jira 應該是許多軟體開發團隊會使用的一個專案管理進度控管工具。

目錄

  • 前言
  • 實作
    • Case 1: 創建一張新的Jira Ticket
    • Case 2: 偵測指定的Jira Ticket 狀態
    • Case 3: 在指定的Jira Ticket上留下Comment (留言)
    • Case 4: 在指定的Jira Ticket上上傳Attachment (上傳附件與檔案)

前言

隨著Scrum及Kanban等敏捷開發模式崛起,許多團隊開發可運用於敏捷專案管理的軟體服務。像我第一家工作的公司是使用Trello,而第二家公司使用Redmine,目前正在工作的公司使用Jira。

最近工作上有一個需求,是產品經理們希望能將軟體Release新版本的流程給自動化。由於公司的系統龐大且複雜,所以在控管每次開發好需要發行於Production的功能,都會需要一連串嚴密且複雜的流程。

此流程也是使用Jira控管每一次的新部署,然後關聯到這些新的功能會需要工程師們提供相對應的安全掃描報告,產品經理們希望能夠將原本需要手動掃描報告的流程以及偵測部署相關的Jira Ticket狀態改變流程都自動化。

所以在做這項研究時,經過幾番測試後,我成功的用Python的Requests 套件,通過Jira APIs達成我希望的目標。


實作

那就直接上Code吧

通用設定

# 變數
# 當使用Requests 傳送請求於Jira APIs時,我們需要在Header加上Authorization,判定這個請求是由你本人的帳號傳送。
# 可以去Jira的帳號與設定找到產生Token的地方,如果沒有就產生一個新的Token。
Auth = "Bearer <your-token>"

# 通常在創建一張新的Jira Ticket時,會連帶產生一個代表該Ticket的Key代表編號,各家公司設定不同,這邊我們取個測試用的Key Name。 
issue_key = "PX-1996"

Case 1: 創建一張新的Jira Ticket

def create_ticket(issue_key, title, description):
    try:
        # API請求網址,創建的API是 /rest/api/2/issue/
        # 而hostname 要看團隊使用的Jira 網址是什麼,替代以下的<jira.hostname>
        url = "https://<jira.hostname>/rest/api/2/issue/"

        headers = {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
            'Authorization': Auth
        }

        data = {
            'fields': {
                'project': {
                    # 填上代表這張Ticket的Key Name
                    'key': issue_key
                },
                # 填上Ticket的標題
                'summary': title,
                # Ticket的描述
                'description': description,
                # Issue Type,這邊範例是Story,你可以填其他Type,像是Task
                'issuetype': {
                    'name': 'Story'
                },
                # 這邊這個欄位是當建立這張Ticket後,會直接Assign給哪個團隊,如果不需要可以刪掉。
                # 每個Jira對於Team所使用的欄位代號不同,這邊是customfield_23231。
                # 若要確認你們的Jira所使用的欄位代號,可以前往其他張Ticket,對Team或其他欄位點取右鍵>偵查>開啟開發者工具去確認該欄位的代號是什麼。
                'customfield_23231': {"value": "<Team Name>"}
            }
        }

        # 發送POST請求於Jira API
        response = requests.post(url, headers=headers, json=data)
        print(response.status_code)
        print(response.text)

        # HTTP code 201代表Ticket創建成成功
        if response.status_code == 201:
            issue_key = response.json().get('key')
            print(f'Jira issue created with key: {issue_key}')
        else:
            print('Failed to create Jira issue..')

    # Error 處理
    except Exception as ex:
        print(f'Exception in creating Jira issue: {ex}')

    finally:
        print('process finish.')

Case 2: 偵測指定的Jira Ticket 狀態

def detect_ticket_status(issue_key):
    # API請求網址,欲知道指定的Ticket內容的API是 /rest/api/2/issue/<issue-key>
    # 而hostname 要看團隊使用的Jira 網址是什麼,替代以下的<jira.hostname>
    # 將你想獲取指定Ticket內容的Ticket Key加到/issue/後,傳送請求便可獲得資訊
    url = f"https://<jira.hostname>/rest/api/2/issue/{issue_key}"

    headers = {
        # 加上 Token作身份驗證
        "Authorization": Auth
    }

    # 取得資訊,我們用Get 請求
    response = requests.get(url, headers=headers)

    # 成功後會取得HTTP Code 200
    if response.status_code == 200:
        data = response.json()
        # 而Ticket狀態可以從 data內的架構中取得
        # 可以選擇print data,先了解會取得哪些資訊,再依照您的需求取出資料。
        workflow_status = data['fields']['status']['name']
        print(f"{issue_key} workflow status:{workflow_status}")

    else:
        print(f"Error status code: {response.status_code}")

Case 3: 在指定的Jira Ticket上留下Comment (留言)

def add_jira_comment(issue_key, comment):
    try:
        # API請求網址,若要在指定的Ticket中新增留言則需要使用此API /rest/api/2/issue/<issue_key>/comment
        # 而hostname 要看團隊使用的Jira 網址是什麼,替代以下的<jira.hostname>
        url = f"https://<jira.hostname>/rest/api/2/issue/{issue_key}/comment"

        headers = {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
            'Authorization': Auth
        }

        data = {
            'body': comment
        }

        # 新增留言,使用Post請求
        response = requests.post(url, headers=headers, json=data)
        print(response.status_code)
        print(response.text)

        # 留言新增成功,則會回傳HTTP Code 201
        if response.status_code == 201:
            print(response.json())
            print(f'Jira cooment upload successful.')
        else:
            print('Failed to uplad jira comment..')

    except Exception as ex:
        print(f'Exception in uploading Jira comment: {ex}')

    finally:
        print('process finish.....!!!!')

Case 4: 在指定的Jira Ticket上上傳Attachment (上傳附件與檔案)


# 上傳檔案,允許多個,此為範例
files = [
    ('file', ('test_photo1.png', open('./screenshot_1.png', 'rb'), 'image/png')),
    ('file', ('test_photo2.png', open('./screenshot_2.png', 'rb'), 'image/png'))
]

def add_jira_attachment(issue_key, files):
    # API請求網址,若要在指定的Ticket中上傳檔案,則需要使用此API /rest/api/2/issue/<issue_key>/attachments
    # 而hostname 要看團隊使用的Jira 網址是什麼,替代以下的<jira.hostname>
    url = f"https://<jira.hostname>/rest/api/2/issue/{issue_key}/attachments"

    # 上傳檔案使用的驗證方式與先前不同,這邊我們使用requests內的HTTPBasicAuth為我們創建此驗證物件
    # 驗證的參數是你的Jira User Name(還是Id)跟你登入Jira的密碼,不是信箱喔。
    credentials = requests.auth.HTTPBasicAuth("Jira Username", "Jira Password")

    # 上傳檔案需要在Header加上這個參數
    headers = {'X-Atlassian-Token': 'no-check'}

    # 傳送Post請求,並挾帶剛剛創建的HTTPAuth驗證物件與欲上傳的的檔案
    response = requests.post(url, auth=credentials, files=files, headers=headers)

    # 上傳成功,印出response
    print(response.status_code)
    print(response.text)

以上就是這次我對於公司新的需求的研究啦。

更多運用麻煩參考官方文件囉: REST APIs - Jira Server