Bambooのビルド結果をSkypeに通知する

これは[Atlassian User Group Tokyo Advent Calendar 2016](http://qiita.com/advent-calendar/2016/augtokyo)の10日目の記事です。

最近ようやくBambooを触る機会があり、JenkinsでやっていたようにChatへビルド実行結果を共有したい！という思いが強く、調べてみました。

* HipChatの場合：アトラシアン製品ですので、標準で連携してます。
* Slackの場合：世界的に使われている製品ですので、Add-on探せばいっぱいありました。
* Chatworkの場合：日本の製品ですので、見当たらず
* Skypeの場合：世界的なはずなのに出てこないｗｗ　＃BotFrameworkが新しいからですかねorz

本記事ではSkypeを対象にしてますが、Chatworkでも同じような考え方だと思いますので参考にしていただければと思います

## 1. × Jobの一番最後にShellScriptで組み込む

まずやってみたのがこれです。Jenkins使ってた時代もこんな感じでやっていたなぁという記憶をもとにトライしました。
ただし、BambooのビルドJobの中から環境変数などで簡単にビルドの状態は取得できないことが判明( ﾉД`)（参考：[Bamboo variables](https://confluence.atlassian.com/bamboo/bamboo-variables-289277087.html)）

そこで以下を参考にスクリプトの中でBambooのRestAPIを叩いてビルド結果を取得するという構成にしました。
https://gist.github.com/remmelt/9640659

ちゃんとコメントまで読めばよかったのですが、Jobの中に組み込んだスクリプトからlatest.jsonを読み取っても**前回のビルド結果が取得される**だけで思ったものはできていないです。とはいえ、参考までにコードは載せておきます。

### コード

使ったサーバにjqが入っていなかったという理由で、シェル芸がいくつか出てきてますｗ
社内サーバだとそういう人もいるかなと思い最後までがんばりましたが、途中何度か心折れそうになりました。
jqがある環境の人はぜひjq使いましょう！

```bash
#!/bin/sh
set -ex

curl -X GET -sS\
 -u "${bamboo.rest.api.id}:${bamboo.rest.api.password}" \
 -H "Content-Type: application/json" \
 https://YOUR_BAMBOO_SERVER/bamboo/rest/api/latest/result/${bamboo_buildKey}/latest.json?buildstate > build.json

buildStatus=$(cat build.json | awk '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' |  grep -o '\"buildState\":\".*\"' | sed s/\"//g | cut -d ':' -f2)
testResult=$(cat build.json | awk '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' |  grep -o '\"buildTestSummary\":\".*\"' | sed s/\"//g | cut -c18- | sed -e 's/<[^>]*>//g')
reason=$(cat build.json | awk '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' |  grep -o '\"reasonSummary\":\".*\"' | sed s/\"//g |  cut -c15- | sed -e 's/<[^>]*>//g')

message="------------------------------\n Build is ${buildStatus}!!\n------------------------------\n${reason}\n${planName} : ${testResult}\n"

# 失敗例なので、Skype投稿部分は省略

rm -f build.json
```

### 環境設定

```${bamboo.XXX}``` となっている箇所はBambooのVariablesで設定を行う箇所です。
bamboo部分は自動的に補完されますので、XXX部分を定義する形となります。passwordとついているものはマスクされ、ログにも出ないので安心して使えます。


## 2. × 別Stageに通知用Jobを組み込む

これもダメ。一瞬うまくいったと思いましたが、**前のStageがこけた場合に通知用Jobが実行されない**という致命的な問題がありましたorz

## 3. ○ 同一Stageに通知用Jobを組み込み、ビルドJobが完了するまでポーリングする

同一StageだとJobは並列に実行されます。通知用Jobはすぐに実行開始されますが、ビルドJobが実行中だと一定間隔後にリトライを行うことでビルド結果が確認できるまで待つような構成になっています。現在はこれで動かしています。

### 通知用JOBのコード

1の処理にビルド中ならリトライするという処理を組み込んだだけです。無限ループはあまりよくないかと思い、10分でタイムアウトするようにしています。ビルドJOBは「JOB1」というキーになっている前提のコード例です。

Skype投稿用のID/PWなどは私の過去の投稿を参考にしてください
　→ [MicrosoftBotFrameworkのRestAPIを使ったTimerBot](http://qiita.com/nyasba/items/268524b2349cfe54600d)の「Botアカウントの作成」部分

```bash
set -ex

buildjson="build_${bamboo_planKey}_${bamboo_buildNumber}.json"
authjson="auth_${bamboo_planKey}_${bamboo_buildNumber}.json"

RETRY_COUNT=30
SLEEP_TIME=20s

for i in `seq 1 $RETRY_COUNT`
do
  curl -X GET -sS\
   -u "${bamboo.rest.api.id}:${bamboo.rest.api.password}" \
   -H "Content-Type: application/json" \
   https://YOUR_BAMBOO_SERVER/bamboo/rest/api/latest/result/${bamboo_planKey}-JOB1/${bamboo_buildNumber}.json?buildstate > "${buildjson}"

  buildStatus=$(cat "${buildjson}" | awk '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' |  grep -o '\"buildState\":\".*\"' | sed s/\"//g | cut -d ':' -f2)
  testResult=$(cat "${buildjson}" | awk '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' |  grep -o '\"buildTestSummary\":\".*\"' | sed s/\"//g | cut -c18- | sed -e 's/<[^>]*>//g')
  reason=$(cat "${buildjson}" | awk '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' |  grep -o '\"reasonSummary\":\".*\"' | sed s/\"//g |  cut -c15- | sed -e 's/<[^>]*>//g')

  if [ "$buildStatus" != "Unknown" ]; then
	break
  else
    echo "retry #$i .."
    sleep "${SLEEP_TIME}"
  fi
done

cat "${buildjson}" | awk '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'

message="------------------------------\n build is ${buildStatus}!!\n------------------------------\n${reason}\n${bamboo_planRepository_branch} #${bamboo_buildNumber} : ${testResult}\n"

curl  -X POST -sS\
 -H "Content-Type: application/x-www-form-urlencoded" \
 -d grant_type=client_credentials \
 -d client_id=${bamboo.skype.bot.id} \
 -d client_secret=${bamboo.skype.bot.password} \
 -d scope=https%3A%2F%2Fgraph.microsoft.com%2F.default \
 https://login.microsoftonline.com/common/oauth2/v2.0/token > "${authjson}"
 
token=$(cat "${authjson}" | grep -o '\"access_token\":\".*\"' | sed s/\"//g | cut -d ':' -f2)

curl -X POST -sS\
 -H "Accept: application/json" \
 -H "Content-Type: application/json" \
 -H "Authorization: Bearer ${token}" \
 -d "{ 'type' : 'message/text', 'text' : '${message}' }" \
 https://api.skype.net/v3/conversations/${bamboo.skype.chatroom}/activities/ 


rm -f "${buildjson}"
rm -f "${authjson}"
```

### 注意点：ビルド実行エージェント

Bambooのビルドはエージェントに対して1つずつ実行されるようです。このようなJob構成にするには2つのエージェントが必要で、なおかつ同一サーバのキューに入ることがないことを保証しなければいけません。
そのため、Job設定の画面で「Requirements」を指定し、実行するサーバを排他にしておくとよいと思います。

### 結果

成功するとこんな通知が届くことになるかと思います

```
------------------------------
  build is Successful!!
------------------------------
Code changes detected
develop #10 : 100 passed
```

## 4. RSSを監視して通知する

Bambooの外の話になってしまいましたが、実はこれが一番簡単です。ただ、3でできてしまったので見送っています。

## 5. Add-onを開発し、NotificationにSkypeを追加する

これが本来の形ですね。長期的にはやりたいですが、まだ手を出してません。


明日は@yutwatanさんです！