phpでJIRAのWebhookを受けて更新通知をChatworkに投げる

# 概要
JIRAの更新通知がChatworkに届くと引用とかできるし便利という意見があったので、
元々JIRAの機能として存在するWebhookを利用してJIRAの更新通知をChatworkに投げる仕組みを作った。

# 必要なもの
- apache(もしくは適当なWebサーバー)を入れた適当なLinuxマシン。
    - インターネットから80番でアクセスできること。
    - IPアドレスで適宜アクセス制御ができること。
    - httpで外部APIを叩けること。
- JIRAの管理者アカウント。
    - 今回はクラウド版のJIRAを利用。
- Chatworkのアカウント
    - APIでPOSTできるチャットならなんでもOK。
    - むしろ今回Chatworkで投げる部分は割愛する。

# 処理の流れ
1. JIRAチケット更新
2. JIRAがWebhookで設定したURLへPOSTアクセス
3. Key情報をパラメータにしてJIRAのAPIを叩いてチケット詳細を取得
4. 取得内容をチャットワークに投げる

本当は2→4と行きたいが、一部情報がhookで受け取れるパラメータに含まれていない(ような気がする)ので、
Key(チケットのID)でチケットの詳細情報を取得しなおす。

というわけで、やることは以下となる。

- JIRA管理者アカウントでWebhookの設定をする。
- IPアドレス制限を外す。
- Webhook先のphpを実装する。

# JIRA管理者アカウントでWebhookの設定をする
#### 1. 管理者アカウントでログインして、以下ページへアクセス。
https://XXXX.atlassian.net/plugins/servlet/webhooks#
※XXXX部分は(たぶん)ライセンス毎に変わる。

#### 2. 画面右上のWebhookの作成をクリック
帯がピンクになってるのは気にしないでほしい。
![9c776e27c6ed3ecbac6ff7366f9d1732.png](https://qiita-image-store.s3.amazonaws.com/0/115539/bc0c89c3-663f-e6fa-8f01-6268c5cef6bf.png)

#### 3.適宜項目を埋める
色々設定項目はあるが、とりあえず以下の内容で設定する。

- webhook先サーバのjiraWebHook.phpにチケットのKey(Project名-XXXみたいなやつ)を付与してhookする
- 対象プロジェクトをJQL(JIRA用SQL的なやつ)で絞る
- 課題が作成された時と更新された時だけhookする

![e2bd1d3a3ab3982e5e1e59a1be988309.png](https://qiita-image-store.s3.amazonaws.com/0/115539/4520dbfd-571e-88fd-4c28-b3ff671315fe.png)

webhookの設定自体はこれで終わり。

# IPアドレス制限を外す
https://confluence.atlassian.com/cloud/database-and-ip-information-744721662.html
クラウド版の場合は上記のページに書いてある通り、以下のIPアドレスからの80番アクセスを許可する。

|IPアドレス|
|:--------|
|131.103.26.0/23|
|131.103.29.0/24|
|165.254.226.0/23|
|131.103.28.0/24|
|104.192.140.0/23|
|104.192.136.0/23|

自前のサーバーで稼働させている場合はそのサーバーのIPを許可すれば良いと思われる。
クラウド版の場合はCloudfrontからのアクセスになるらしいので、
会社のポリシー次第ではそもそもWebhookが使えないかも。
その場合は定期的にフィルターでチケットをクロールするぐらいしか思いつかない。

# Webhook先のphpを実装する
今回はAWS EC2でDebian wheezyのインスタンスを立ち上げてapacheとphpをインストールし、
DefaultのDocmentRoot /var/wwwにjiraWebHook.phpというファイルを作成した。
JIRAアカウントについては適当に権限を付けたアカウントを用意しておく。
PHPは滅多に書かないので変なことやってても見逃してほしい。

```
jiraWebHook.php
<?php
 
$base_url='https://XXXX.atlassian.net';
$end_point=$base_url . '/rest/api/2/issue/' . $_GET["key"];
 
// Webhook用に作成したJIRAアカウント情報を入れる
$user_name="";
$password="";
 
// hookで受け取ったKeyに対応するチケットの詳細を
// JIRAのAPIを使って取得する。
$curl = curl_init();
 
// IDとパスを生で設定してるのはご愛嬌
$option = [
    CURLOPT_URL => $end_point,
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_SSL_VERIFYPEER => false,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_USERPWD => $user_name . ":" . $password,
];
 
curl_setopt_array($curl,$option);
 
$response = curl_exec($curl);
$result = json_decode($response, true);
 
curl_close($curl);
  
// チケットのステータスに応じてChatworkの絵文字を付ける
switch ($result['fields']['status']['id']) {
    // 解決済み
    case 5:
        $mark = '(F)';
        break;
    // クローズ
    case 6:
        $mark = '(coffee)';
        break;
    // オープン
    default:
        $mark = '(*)';
        break;
}
 
// プロジェクトIDによってチャットワークの通知先を決定
switch($result['fields']['project']['id']) {
    case 10100:
        $room_id = "room_id1";
        break;
    case 10400:
        $room_id = "room_id2";
        break;
    default:
        $room_id = "";
        break;
}
 
// 本文を適当に結合。[info]とかはchatwork用のタグ。
$mes_body = "[info][title](" . $mark . $result['fields']['status']['name'] . ")" . $result['key'] . "\:\ " . $result['fields']['summary'] . "(Reporter\:\ " . $result['fields']['reporter']['displayName'] . ")[/title]URL\:\ " . $base_url . "/browse/" . $result['key'] . "[/info]";
 
// 何故か()があると上手くChatworkへ通知が飛ばなかったためエスケープ。
// きっともっといいやり方がある。
$mes_body=str_replace("(", "\(", $mes_body);
$mes_body=str_replace("（", "\（", $mes_body);
$mes_body=str_replace(")", "\)", $mes_body);
$mes_body=str_replace("）", "\）", $mes_body);
 
// チャットワークへ投げる処理。
// チャットワークに限らず、適当なチャットサービスのAPIにメッセージボディとか指定して投げればOK。
// とりあえずダミーの関数を書いておいた。
send_chat_service($room_id, $mes_body);
```