困っていること
Backlogで過去の課題を複製する機能は便利なのですが、過去のチケットのデータを引き継いて欲しくないケースもあります。(複製時は消せと何度も言っているのに!)作成者が消すのを忘れてしまうことがあります。
こういうのは人間に任せるからミスをするので、人間に任せない仕組みにしてしまいたいと思います
今回使ったもの
- Backlog WebHook(新規登録)
- Microsoft Flow (HTTP受信とHTTP発信)
- Backlog API(課題情報の更新)
今回は簡単に実現するために、Microsoft Flowを使いました。
やってみよう
1. BacklogAPIのKeyを発行
Backlog右上の人アイコンから、個人設定、APIからBacklogAPIのキーを発行し、APIをブラウザで叩いて自分の情報が取れるか確認しておきます。
https://kanaxx.backlog.com/api/v2/users/myself?apiKey=YOUR KEY
2. BacklogのWebHook設定
Backlogのダッシュボードからプロジェクト設定を開き、WebHookを設定をします。
まだMicrosoft Flow側の受信の設定をしていないので、WebHook URLは一時的にhttp://localhost
を設定しています。
今回は課題の新規作成のみWebHookが飛ぶように設定をしました。
画面の一番下にある「テスト実行」を押してサンプルのデータを出力してみます(実際にはlocalhostで受信はできません。)
テスト実行を押したあとに、WebHookの一覧から送信履歴から送信データを確認します。
「全て表示」を押すと、WebHookで送信されるデータの形式が確認できます。
データはこんな感じです。(ユーザ情報は置き換え済みです)
{
"created": "2019-03-26T11:52:03Z",
"project": {
"archived": false,
"projectKey": "TEST",
"name": "TestProject",
"chartEnabled": false,
"id": 100,
"subtaskingEnabled": false
},
"id": 10,
"type": 1,
"content": {
"summary": "test issue",
"key_id": 100,
"customFields": [
],
"dueDate": "",
"description": "test description",
"priority": {
"name": "",
"id": null
},
"resolution": {
"name": "",
"id": null
},
"actualHours": null,
"issueType": {
"color": "null",
"name": "Bug",
"displayOrder": null,
"id": 400,
"projectId": null
},
"milestone": [
{
"archived": "false",
"releaseDueDate": "null",
"name": "prototype release",
"displayOrder": null,
"description": "",
"id": null,
"projectId": null,
"startDate": "null"
},
{
"archived": "false",
"releaseDueDate": "null",
"name": "alpha release",
"displayOrder": null,
"description": "",
"id": null,
"projectId": null,
"startDate": "null"
},
{
"archived": "false",
"releaseDueDate": "null",
"name": "beta release",
"displayOrder": null,
"description": "",
"id": null,
"projectId": null,
"startDate": "null"
},
{
"archived": "false",
"releaseDueDate": "null",
"name": "product release",
"displayOrder": null,
"description": "",
"id": null,
"projectId": null,
"startDate": "null"
}
],
"versions": [
{
"archived": "false",
"releaseDueDate": "null",
"name": "Version0.1",
"displayOrder": null,
"description": "",
"id": null,
"projectId": null,
"startDate": "null"
},
{
"archived": "false",
"releaseDueDate": "null",
"name": "Version0.2",
"displayOrder": null,
"description": "",
"id": null,
"projectId": null,
"startDate": "null"
},
{
"archived": "false",
"releaseDueDate": "null",
"name": "Version1.0",
"displayOrder": null,
"description": "",
"id": null,
"projectId": null,
"startDate": "null"
}
],
"parentIssueId": null,
"estimatedHours": null,
"id": 100,
"assignee": null,
"category": [
{
"name": "Category1",
"displayOrder": null,
"id": null
},
{
"name": "Category2",
"displayOrder": null,
"id": null
}
],
"startDate": "",
"status": {
"name": "In Progress",
"id": 2
}
},
"notifications": [
],
"createdUser": {
"nulabAccount": {
"nulabId": "xxx",
"name": "xxx",
"uniqueId": "xxx"
},
"name": "kanaxx",
"mailAddress": null,
"id": 0,
"roleType": 1,
"lang": "ja",
"userId": null
}
}
WebHookデータの中にissueKeyがありません。これが今後のドハマりポイントになります。
3.Microsoft Flowの受信の詳細設定
Microsoft Flowでjsonデータを受信するときは、BacklogのWebHookデータのそのものか、json schemaが必要です。今回は上で作ったサンプルデータをもとにデータのペイロードをして形を作ります。
トリガーにHTTP要求の受信時
を設定し、サンプルのペイロードを利用してスキーマを生成するをクリック。これは実データをMicrosoft Flowに解析してもらい、データの項目を確定させる方法です。
上で作ったBacklogのWebHookサンプルデータを投入し、OKを押すとjson schemaが作成される。
メソッドをPOST
に設定しておく。受信用のURLはまだ作成できません。次の工程までお待ちください
4.Microsoft FlowにHTTP(発信)を追加
アクションにHTTP
を追加して、Microsoft FlowからBacklogのAPIを実行する仕掛けを作ります。
入力が簡単なところは以下の3つ。
方法はPatch
ヘッダ Content-Type
= application/x-www-form-urlencoded
クエリー apiKey
= YOUR API KEY
さくっといれてしまいましょう。
URLの設定
URLはちょっと複雑です。
FlowのURLには、Backlogの課題更新のAPIのURLを設定します。このAPIは、URLの最後に課題のIDを設定する必要があります。つまりチケットごとにURLが変わるわけです。このため、課題IDは変数からIDを持ってきます。
URLにカーソルを置くと、右側の変数サポートで何も出てきません。「もっと見る」を押すと出てきます。
課題のIDは9番目のIDなので、9番目のIDがURLの最後尾に付くように設定します。
必ずidの9番目が課題IDなのか自信がないので、コードのプレビュー機能を使って確認できます。
{triggerBody()?['content']?['id']}",
になっていれば正解です。ならない場合には総当たりで11回試してください。たぶん、下から試すのが早いです。
本文
本文はBacklog APIの課題更新のパラメータを設定します。name=valueを&で繋ぐ形式です。
versionId=[]&milestoneId[]=&dueDate=
今回はバージョン、マイルストーン、締切日を空にするように設定しています。カスタムフィールドも対応可能ですが、フリープランだと使えないのでできる範囲でやっています。パラメータの詳細はBacklog APIのドキュメントを見てください。
URLの発行
フローを保存すると、HTTP要求受信用のURLが発行されます。
次で使うのでコピーしておきます。
5. Backlog WebHookのURLを修正
手順2で、Backlog側のWebHookのURLを一時的にhttp://localhost
で作ってあります。WebHookの設定画面を開き、Microsoft Flowで発行されたURLに修正します。
これで準備完了。
いざ実行
バージョン、マイルストン、締切日を設定済み
うっかり、マイルストーンとバージョンと期限日を消すのを忘れてしまい、新規登録を完了させる
確認
WebHookの発信確認
増えてるので何か送っているっぽい。一番新しい送信履歴を見てみる
今追加したチケットの情報が送られているのを確認。(issueKeyはやっぱり無い)
チケットの確認
WebHook -> Microsoft Flow -> Backlog APIが実行されたあと。右上の期限日も消えてる
Flowのプランにもよると思いますが、自分の環境だと新規登録の1秒後には消えていました。
登録日:2019/03/26 23:05:22
更新日:2019/03/26 23:05:23
まとめ
Microsoft Flowは便利です。プログラム作らずにできちゃいます。たぶんZapierでもできると思います。
今回はやらなかったですが、Flowの分岐機能を使えば、特定のチケット種別のときだけ初期化するとか、子チケットのときだけ初期化するとか、期限日を強制的に3日後に更新してしまうとか、応用はいろいろできると思います。
FlowからのHTTPコネクタがFlow for Office365のライセンスでは使えないかもしれません。自分のところは使えているので、使えない場合にはライセンスを確認してください。
https://blog.iotaker.jp/?p=294
おまけ
実は手順3時点で、工夫したjson schemaを入れると、もうちょっと簡単に課題IDを設定できるようになります。参考までに自分が作ったものを置いておきます。細かいところは正確じゃないかもしれません。Backlog WebHookの仕様が変わってもこのQiitaは更新しないと思うので、変わっていたらごめんなさい。(json schemaはAPI提供側から提供されるのがよいですよね。)
変更点1:
ペイロードしたjson schemaドキュメントの"type"="object"
の内側に、"title"="project"や"title"="content"と設定を追加する。
変更点2:
11個あるIDに名前が付くようになるので、backlog_issue content id
を選べばOK
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"title": "backlog_issue",
"properties": {
"created": {
"type": "string"
},
"project": {
"type": "object",
"title": "project",
"properties": {
"archived": {
"type": "boolean"
},
"projectKey": {
"type": "string"
},
"name": {
"type": "string"
},
"chartEnabled": {
"type": "boolean"
},
"id": {
"type": "integer"
},
"subtaskingEnabled": {
"type": "boolean"
}
},
"required": [
"archived",
"projectKey",
"name",
"chartEnabled",
"id",
"subtaskingEnabled"
]
},
"id": {
"type": "integer"
},
"type": {
"type": "integer"
},
"content": {
"type": "object",
"title": "content",
"properties": {
"summary": {
"type": "string"
},
"key_id": {
"type": "integer"
},
"customFields": {
"type": "array",
"items": {}
},
"dueDate": {
"type": "string"
},
"description": {
"type": "string"
},
"priority": {
"type": "object",
"title": "priority",
"properties": {
"name": {
"type": "string"
},
"id": {
"type": "integer"
}
},
"required": [
"name",
"id"
]
},
"resolution": {
"type": "object",
"title": "resolution",
"properties": {
"name": {
"type": "string"
},
"id": {
"type": "null"
}
},
"required": [
"name",
"id"
]
},
"actualHours": {
"type": "null"
},
"issueType": {
"type": "object",
"title": "issue_type",
"properties": {
"color": {
"type": "string"
},
"name": {
"type": "string"
},
"displayOrder": {
"type": "integer"
},
"id": {
"type": "integer"
},
"projectId": {
"type": "integer"
}
},
"required": [
"color",
"name",
"displayOrder",
"id",
"projectId"
]
},
"milestone": {
"type": "array",
"items": {}
},
"versions": {
"type": "array",
"items": {}
},
"parentIssueId": {
"type": "integer"
},
"estimatedHours": {
"type": "null"
},
"id": {
"type": "integer"
},
"assignee": {
"type": "null"
},
"category": {
"type": "array",
"items": {}
},
"startDate": {
"type": "string"
},
"status": {
"type": "object",
"title": "status",
"properties": {
"name": {
"type": "string"
},
"id": {
"type": "integer"
}
},
"required": [
"name",
"id"
]
}
},
"required": [
"summary",
"key_id",
"customFields",
"dueDate",
"description",
"priority",
"resolution",
"actualHours",
"issueType",
"milestone",
"versions",
"parentIssueId",
"estimatedHours",
"id",
"assignee",
"category",
"startDate",
"status"
]
},
"notifications": {
"type": "array",
"items": {}
},
"createdUser": {
"type": "object",
"title": "created_user",
"properties": {
"nulabAccount": {
"type": "null"
},
"name": {
"type": "string"
},
"mailAddress": {
"type": "null"
},
"id": {
"type": "integer"
},
"roleType": {
"type": "integer"
},
"userId": {
"type": "null"
}
},
"required": [
"nulabAccount",
"name",
"mailAddress",
"id",
"roleType",
"userId"
]
}
},
"required": [
"created",
"project",
"id",
"type",
"content",
"notifications",
"createdUser"
]
}