#背景
プロジェクトやタスク管理、業務管理ツールとして「Jira」に日々触れるなかで、Slackなどのメッセージツールから直接チケットを発行(=課題を作成)できると便利です。Jiraの画面上で課題を作成したり、課題更新時の通知についてはWebhook、課題画面内にタブを追加できるアドオンがありますが、SlackからJiraの課題を作る機能がありません。そこで作ってしまいましょう。
#やりたいこと
- Slackに、プロジェクトキーと課題の要約を投稿すると、プロジェクトキーをもとに課題を作成し、課題のURLをレスポンスとしてSlackに返す。
- 課題タイプは、タスクに固定。
- 課題の説明は、デフォルトで「Slackから作成」に固定。
数秒待つと、Jiraから作成された課題のURLが返ってくる。
#仕様
- 外部から接続可能なサーバー上に、Node-REDを導入。手順例:Amazon Linuexの場合
- 外部から接続可能なサーバー上に、Jira(Jira Software)を導入。手順例:IBM Cloud IaaSの場合
- Node-REDは、ユーザー名とパスワードによる基本の認証を適用
- Node-REDのパレット管理にて、node-red-contrib-slackノードを追加
#実際の動作
- Slack Bot in で、Slackからのメッセージを受信。Slack Bot Inで指定したチャンネルにて、メッセージの文法は、プロジェクトキー:課題の要約。プロジェクトキーと課題の要約をコロンでつなげる。
- Slackからのメッセージをプロジェクトキーと課題の要約に分割し、別々の変数に変換。splitやswitchノードで処理。
- JSON形式で、curl でJIRA REST API にPOSTするためのテキストファイル「apidata.txt」を作成する。
- execノードを使い、Jira REST APIの仕様にもとづき、crulコマンドを実行し、プロジェクトキーに紐づく課題を作成。
- 「4」のレスポンスをJSON形式に変換し、Slack向けのメッセージを生成。Slackに返信。
#Node-REDフローのソース
お使いのJiraのURLやJiraのユーザー名、パスワードなどを置き換える必要がありますが、実際に動くフローのソースは下記になります。
[{"id":"c640a629.5ff6d8","type":"tab","label":"Jira Create Issue","disabled":false,"info":""},{"id":"58aafc60.c78114","type":"split","z":"c640a629.5ff6d8","name":"","splt":":","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":130,"y":160,"wires":[["edf7ab1a.c6d678"]]},{"id":"edf7ab1a.c6d678","type":"switch","z":"c640a629.5ff6d8","name":"","property":"payload","propertyType":"msg","rules":[{"t":"regex","v":"^[A-Z0-9]+$","vt":"str","case":false},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":130,"y":220,"wires":[["e2d141b6.a1175"],["9e5f869e.9fc248"]]},{"id":"e2d141b6.a1175","type":"function","z":"c640a629.5ff6d8","name":"variable:Project Key","func":"var message = msg.payload;\nvar msg = {\n projkey: message\n };\n flow.set('project',msg);\nreturn msg;","outputs":1,"noerr":0,"x":340,"y":200,"wires":[[]]},{"id":"9e5f869e.9fc248","type":"function","z":"c640a629.5ff6d8","name":"variable:Issue Summary","func":"var message = msg.payload;\nvar msg = {\n summary: message\n };\n flow.set('issue',msg);\nreturn msg;","outputs":1,"noerr":0,"x":190,"y":300,"wires":[["85b34b69.bbaa98"]]},{"id":"85b34b69.bbaa98","type":"function","z":"c640a629.5ff6d8","name":"POST - Create Issue","func":"var project = flow.get('project');\nvar issue = flow.get('issue');\nvar projkey = project.projkey;\nvar summary = issue.summary;\nmsg.payload = {\n \"fields\": {\n \"project\":{\"key\":projkey},\n \"summary\":summary,\n \"description\":\"Slackから作成\",\n \"issuetype\":{\"id\": \"10002\"}\n }\n }\nreturn msg;","outputs":1,"noerr":0,"x":180,"y":400,"wires":[["6ab60ef8.86d27","8c8219fd.2598e8"]]},{"id":"6ab60ef8.86d27","type":"file","z":"c640a629.5ff6d8","name":"","filename":"apidata.txt","appendNewline":false,"createDir":false,"overwriteFile":"true","x":410,"y":400,"wires":[]},{"id":"f700ac62.94151","type":"exec","z":"c640a629.5ff6d8","command":"curl -u admin:password -X POST --data @apidata.txt -H \"Content-Type: application/json\" https://your-jira-url/rest/api/latest/issue","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":540,"y":600,"wires":[["200e603f.7aa1f"],[],[]]},{"id":"8c8219fd.2598e8","type":"delay","z":"c640a629.5ff6d8","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":140,"y":500,"wires":[["f700ac62.94151"]]},{"id":"200e603f.7aa1f","type":"json","z":"c640a629.5ff6d8","name":"","property":"payload","action":"","pretty":false,"x":1090,"y":580,"wires":[["bb119331.35a4b"]]},{"id":"bb119331.35a4b","type":"function","z":"c640a629.5ff6d8","name":"post message","func":"var project = flow.get('project');\nvar projkey = project.projkey\nvar home = \"https://your-jira-url/projects/\"\nvar link = msg.payload.key;\nmsg.payload = \"issues-url:\"+home+projkey+\"/issues/\"+link;\nreturn msg;","outputs":1,"noerr":0,"x":960,"y":720,"wires":[["3914bc0c.1a1d44","68f10547.2916cc"]]},{"id":"37222cc3.a51ee4","type":"Slack Bot In","z":"c640a629.5ff6d8","name":"Slack Bot in","apiToken":"xxxxxx","channel":"slack-channel","x":110,"y":60,"wires":[["7b0c1264.e59bcc"]]},{"id":"68f10547.2916cc","type":"Slack Bot Out","z":"c640a629.5ff6d8","name":"Slack Bot out","apiToken":"xxxxx","channel":"#slack-channel","x":1190,"y":680,"wires":[]},{"id":"3914bc0c.1a1d44","type":"debug","z":"c640a629.5ff6d8","name":"debug:exec","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":1190,"y":720,"wires":[]},{"id":"7b0c1264.e59bcc","type":"function","z":"c640a629.5ff6d8","name":"slack message","func":"msg.payload = msg.payload;\nreturn msg;","outputs":1,"noerr":0,"x":300,"y":60,"wires":[["58aafc60.c78114"]]}]
実際に動かすには、次の処理が必要です。
- 外部公開済みのサーバー(仮想マシンでも可)に、Node-REDを導入し、上のソースを読み込みます。
- Jira上でプロジェクトを登録します。
- 「1」の「Slack Bot Inノード」にて、API Tokenとチャンネルを書き換えます。
- 「4」の「execノード」にて、Jiraのユーザー名とパスワード、JiraのURLを書き換えます。
- 「5」の「post messageノード」にてJiraのURLを書き換えます。
- 「Slack Bot outノード」にて、API Tokenとチャンネルを書き換えます。
- デプロイボタンを実行し、実際にSlackから投稿して動作確認しましょう。
#参考資料
Jira Software:https://www.ricksoft.jp/atlassian/jira/
Jira REST APIs:https://developer.atlassian.com/server/jira/platform/rest-apis/
REST API で Jira Software を操作してみる:https://www.ricksoft.jp/blog/archives/7021/