IT業務効率化

PythonでBacklogの〆切課題を毎日Slackに通知する

課題管理の課題

Backlogとは

Backlogはタスク管理ツールです。課題やプロジェクト毎にチケットを切り、進捗管理、チームの連携を行います。コードやファイルのやり取りをするにも使いやすく、みやすくする工夫がされています。

Backlogの課題を見逃してしまうことがある

Backlogは素晴らしい機能を豊富に備えており、課題が追加更新された時にメールも送信できます。Slack連携機能で課題追加時に通知する機能はデフォルトで備わっています。でもせっかく期限日のチケットを通知する機能は、私のみた限り見当たりませんでした。

ですので今回は、締め切りの近い課題のSlack通知をPythonで実現しようと思います。

〆切りが近くなった課題を通知する方法

Backlog API KEYとSlackのincoming webhook urlを取得する

BacklogのAPI KEYの取得方法はメイン画面の右上の「個人設定」に進むと、APIという項目があるので、そこで取得してください。公式ドキュメントもご参考にしていただけると良いかと思います。

Slackは今回incoming webhook urlを利用します。公式ドキュメントを参考にできますが、ここにも手順を書いておきます。まずはアプリ管理画面に移動します。下のリンクをあなたのSlackのワークスペース名に置き換えることでアクセスできます。

https://<Slackのワークスペース名>/apps

ワークスペース名はトップ画面の左上をクリックすると確認できるかと思います。

slack.comまで入力してください。アプリ管理画面にたどり着いたら、アプリの検索でincomingと入力すると出てくると思います。

ここでincoming Webhookを選択してください。「設定を追加」という項目があるので、クリックしてください。次に送信先の「チャンネルを選択」という画面に移ります。ここでは好きなチャンネルを適当に選択してください。これはデフォルトの送信先なので、後からコード上で好きに上書きできます。

これでincoming webhook urlを取得できたと思います。

https://hooks.slack.com/services/xxxxxxxxxxxx

という形式で表示されていると思うので、取得しておきます。

Backlog APIを使ってみる

まずはBacklogにリクエストを投げるところまでいきたいと思います。

APIのキーは、Backlogの個人設定から取得できます。一覧にない場合はユーザに権限が与えられていないのかもしれません。

Backlog APIのリクエストパラメータ

BacklogのAPIに関する情報はこのページが公式だと思います。この中の課題一覧の取得を参考にします。

まず、リクエスト先のURLは

あなたのbacklog_url + /api/v2/issues

となります。

そして下記が、リクエスト時のパラメータです。(https://developer.nulab.com/ja/docs/backlog/api/2/get-issue-list/ )から持ってきました。

パラメーター名 内容
projectId[] 数値 プロジェクトのID
issueTypeId[] 数値 種別のID
categoryId[] 数値 カテゴリーのID
versionId[] 数値 発生バージョンのID
milestoneId[] 数値 マイルストーンのID
statusId[] 数値 状態のID

1: 未対応
2: 処理中
3: 処理済み
4: 完了

ステータスとコードについてより詳しく

priorityId[] 数値 優先度のID
assigneeId[] 数値 担当者のID
createdUserId[] 数値 登録者のID
resolutionId[] 数値 完了理由のID
parentChild 数値 親子課題の条件
0: すべて
1: 子課題以外
2: 子課題
3: 親課題でも子課題でもない課題
4: 親課題
attachment 真偽値 添付ファイルを含む場合はtrue
sharedFile 真偽値 共有ファイルを含む場合はtrue
sort 文字列 課題一覧のソートに使用する属性名
“issueType”
“category”
“version”
“milestone”
“summary”
“status”
“priority”
“attachment”
“sharedFile”
“created”
“createdUser”
“updated”
“updatedUser”
“assignee”
“startDate”
“dueDate”
“estimatedHours”
“actualHours”
“childIssue”
“customField_${id}”
order 文字列 “asc”または”desc” 指定が無い場合は”desc”
offset 数値
count 数値 取得上限(1-100) 指定が無い場合は20
createdSince 文字列 登録日 (yyyy-MM-dd)
createdUntil 文字列 登録日 (yyyy-MM-dd)
updatedSince 文字列 更新日 (yyyy-MM-dd)
updatedUntil 文字列 更新日 (yyyy-MM-dd)
startDateSince 文字列 開始日 (yyyy-MM-dd)
startDateUntil 文字列 開始日 (yyyy-MM-dd)
dueDateSince 文字列 期限日 (yyyy-MM-dd)
dueDateUntil 文字列 期限日 (yyyy-MM-dd)
id[] 数値 課題のID
parentIssueId[] 数値 親課題のID
keyword 文字列 検索キーワード

Project IDを取得する

projectIdを指定する必要があります。このIDはBacklogでそのプロジェクトを開いてプロジェクト設定ページに行くと、URLに埋め込まれています。

Pythonで通知する

リクエストを投げる

conf.pyというファイルを作成し、下記の変数を定義します。

incoming_webhook = ""
backlog_url = ""
backlog_api_key = ""

まずはBacklogにAPIリクエストをして、json形式で値を取得します。上のドキュメントにあるように、GET形式でリクエストをします。

import requests
import json
from datetime import datetime, timezone, timedelta, date
from conf import incoming_webhook, backlog_url, backlog_api_key

# backlogのAPI課題取得用URL
request_url_for_issues = backlog_url + "/api/v2/issues"
# 取得する情報を絞る、下記URLはパラメータ一覧
# https://developer.nulab.com/ja/docs/backlog/api/2/get-issue-list/
params = {
    "apiKey": backlog_api_key,  # 必須
    'projectId[]': 57237,
    'statusId[]': 1,  # 1:未対応 2;処理中 3:処理済み 4:完了
    "dueDateSince": date.today().strftime("%Y-%m-%d"),  # 期限日=当日
    "dueDateUntil": date.today().strftime("%Y-%m-%d"),  # 期限日=当日
    "count": 20  # デフォルトが20上限は100
}
# json形式で帰ってくるので、テキストとして取得
issues_res = requests.get(request_url_for_issues, params)
# jsonとして整形
issues_responses = json.loads(issues_res.text)

request_url_for_issuesという名前で、リクエスト先のURLを指定します。httpsから始めてください。

PythonでGETリクエストパラメータを指定する時は、まず辞書型(連想配列)に値を入れていきます。今回はparamsという変数に値を込めました。あとは

requests.get(request_url_for_issues, params)

でリクエストを投げて値を取得します。するとjson形式で値が返ってくるため、辞書型として扱いやすいように

issues_responses = json.loads(issues_res.text)

というかたりで、型変換します。

Slackに通知する

前準備として、Slackに綺麗に表示するためにfieldsという変数を用意しておきます。

またこの記事を書いている2019年6月17日時点では、取得した時間はUTCとなっているため、日本時間を足す処理を加えます。

fields = []
JST = timedelta(hours=9)

今回は課題番号、課題のタイトル、登録日、担当者を通知しようと思うので、jsonからその値を取得できるように書きます。

for issue in issues_responses:
    issueKey = issue["issueKey"]  # 課題番号
    short_summary = issue["summary"][:19]  # 課題のタイトル
    status = issue["status"]["name"]  # ステータス
    origin_time = issue['created']  # 登録時刻
    created = datetime.strptime(origin_time, "%Y-%m-%dT%H:%M:%SZ") + JST
    created_str = datetime.strftime(created, "%Y/%m/%d")
    assignee_dict = issue['assignee'] # 担当者
    if assignee_dict is None:
        assignee = "未設定"
    else:
        assignee = assignee_dict["name"]
    field = {
            "title": short_summary,
            "value": "担当:" + assignee + "\r\n登録日:" + created_str + "\r\nlink:"
            + "<あなたのBacklogのURL/view/{0}|{0}>".format(issueKey),
            "short": True
        }
    fields.append(field)

issues_responsesは課題ごとのjsonをリストにしたものなので、for文で回してやれば、課題ごとに処理ができます。以下のような状態です。

[{課題1の情報}, {課題2の情報}, {}, ….]

fieldの書き方はBacklogの話ではなく、Slackの話です。titile、value、shortを指定して、最後通知の時に整形されます。詳しくはこちらの記事を参考にしてください。

<あなたのBacklogのURL/view/{0}|{0}>という書き方をすると、URLの埋め込みができます。<URL|文字>という規則で、今のところbotやincoming_webhookからの通知でのみしか使えない記法のようです。

最後Slackにメッセージを送る時は、以下のコードで送ることができます。

from slackweb import Slack
attachment = {
    'color': 'danger',
    "fields": fields
    }
slack = Slack(url=incoming_webhook)
slack.notify(icon_emoji=":shimekiri:", username="締め切りチケット通知", attachments=[attachment])

 

最後に例ですが、アウトプットのイメージを載せておきます。

おわりに

私のチームではこの通知botを導入してから、作業の締め切り忘れが減りました。

githubにあげるには恥ずかしいコードなのであげていませんが、上の情報が少しでもご参考になれば幸いです。

読んでいただきありがとうございました。
ABOUT ME
hirayuki
今年で社会人3年目になります。 日々体当たりで仕事を覚えています。 テーマはIT・教育です。 少しでも技術に親しんでもらえるよう、noteで4コマ漫画も書いています。 https://note.mu/hirayuki