本記事のサマリ
CircleCiのブランチ毎、期間毎のbuild失敗数などを取得したかったのですが、画面からは簡単に取得ができなかったので、公開されているAPIとjsonをパースするためのコマンドラインツールであるjqを利用して、情報をサマって取得する情報をまとめました。
対象読者
- CircleCiのビルド状況を分析したいけど画面からは取得できないなぁと悩んでいる方向け
- jqって聞いたことあって、なんかjson扱うのに便利そうだと知ってるけど上手く使えなかった方の勉強にも良いかと思います。
動作確認バージョン
jq --version
-> jq-1.5
CircleCiのAPI Versionは、1.1です。
経緯
このリポジトリのmasterブランチ、最近失敗が多いようだけど、この期間のGreen率とあの期間のGreen率ってどう変化してるの??
→調査。。。「ウゲェ、webの画面にはそんな機能はなさそうやん。。。」
事前準備
CircleCiのAPIを叩く準備
まずはAPIを実行するためのトークンを生成しましょう。
CircleCiにログインした上で、以下にアクセスします。
https://circleci.com/account/api
以下のよう画面が表示されると思いますので、CreateNewTokenボタンを押しましょう。
トークンの名前を問われるので適当に目的にあったわかりやすい名前をつけましょう。ここでは、説明用なのでsample_tokenとしました。
このtokenがバレてしまうと、あなたの権限の範囲で自由にAPIを叩かれてしまうので、周りに公開したりしないでください。もしバレたら、一旦削除して再度生成しましょう。
jqのインストール
もしMACでhomebrewを使っているのであれば以下を実行するとインストールできます。
brew install jq
他の環境のインストールについては、こちらをご参照ください。
https://stedolan.github.io/jq/download/
ちなみに、jqのチュートリアルがgithubのapiを使った実例で説明があるので、そちらの方も参考になります。
こんなオンライン実行環境もあってチューニングするのに便利
https://jqplay.org/
実行できるか確認してみる。
とりあえず誰のtokenかを確認するAPIがあるので、取得の確認とjqの動作確認を兼ねて実行して見ましょう。
# XXXXXには、あなたが取得したTOKENの値を設定してください。
TOKEN=XXXXX
curl -s -u ${TOKEN}: https://circleci.com/api/v1.1/me | jq .login
-> "yukimura1227"
こんな感じで、user-nameが出てくれば取得できればオーケーです。
失敗する場合は、これまでの設定を見直して見てください。
jqを使わずにcurl〜v1.1/me部分を実行して以下のようになる場合はtokenの設定が怪しいです。
あとは、${TOKEN]: http
の部分は、コロンの後にスペースがあることに注意してください。
{
"message": "You must log in first."
}
https://circleci.com/api/v1.1/project/:vcs-type/:username/:project/tree/:branch
試しにこのAPIを実行して見ましょう(:vcs-typeはgithubかbitbucketが指定できるようです。:usernameは対象としているリポジトリのユーザー名、:projectはリポジトリ名です)
Recipes
とりあえずビルドの情報を取得してみる。
特定のリポジトリのビルド情報を取得するには以下のAPIを使います。(以降、publicなリポジトリの場合はTOKENが不要なものもありますが、全体的にTOKENをつけていますのでご了承ください。)
https://circleci.com/docs/api/v1-reference/#recent-builds-project
curl https://circleci.com/api/v1.1/project/:vcs-type/:username/:project?circle-token=:token&limit=20&offset=5&filter=completed
具体的には、以下のようになります。
curl -s -u ${TOKEN}: \
'https://circleci.com/api/v1.1/project/github/yukimura1227/codecov_sample?limit=3&offset=5&filter=completed'
# -> 情報量が多すぎるので出力は割愛
欲しい情報だけピックアップしてtsv化してみる。
これにjqを噛ませて、見やすくしましょう。
curl -s -u ${TOKEN}: \
'https://circleci.com/api/v1.1/project/github/yukimura1227/codecov_sample?limit=5&offset=0&filter=completed' | jq -r '.[] | [.build_num, .branch, .start_time, .build_time_millis, .outcome, .status] | @tsv'
20 experiment/not_suitable_path_case 2017-09-26T09:51:03.519Z 60678 success success
19 experiment/not_suitable_path_case 2017-09-26T09:46:34.319Z 66384 success fixed
18 experiment/not_suitable_path_case 2017-09-26T09:44:25.728Z 54970 failed failed
17 experiment/not_suitable_path_case 2017-09-26T09:42:06.639Z 55609 failed failed
16 experiment/not_suitable_path_case 2017-09-26T09:39:55.172Z 31531 failed failed
apiで叩いて戻ってくる一番外側が、jsonの配列になっているので、 .[]
を使います。
これは、Array/Object Value Iteratorというもので、これを使うと一番外側の配列に格納されているjsonのオブジェクトが取得できます。
それを |
(パイプ)を使って、[.build_num,...]に連携しています。
[.build_num, .branch..., .status]
では、要素を指定して抽出する対象をフィルタリングしています。
最後の @tsv
で、tsv形式で出力するようにしています。
参考:https://stedolan.github.io/jq/manual/#Basicfilters
ビルドにかかった時間の単位を整形する
ビルド時間がミリ秒だとわかりづらいので、秒単位にして見ましょう。
jqでは +
-
*
/
を使って四則演算ができますので、それを使うと以下のようにできます。
curl -s -u ${TOKEN}: \
'https://circleci.com/api/v1.1/project/github/yukimura1227/codecov_sample?limit=5&offset=0&filter=completed' | jq -r '.[] | [.build_num, .branch, .start_time, .build_time_millis/1000, .outcome, .status] | @tsv'
20 experiment/not_suitable_path_case 2017-09-26T09:51:03.519Z 60.678 success success
19 experiment/not_suitable_path_case 2017-09-26T09:46:34.319Z 66.384 success fixed
18 experiment/not_suitable_path_case 2017-09-26T09:44:25.728Z 54.97 failed failed
17 experiment/not_suitable_path_case 2017-09-26T09:42:06.639Z 55.609 failed failed
16 experiment/not_suitable_path_case 2017-09-26T09:39:55.172Z 31.531 failed failed
件数の絞り込みをjqでやってみる
CircleCIのapiはパラメータとしてlimit,offsetで絞り込めるようになっていますが、API側が提供していないケースもありますし、jqで絞り込んだ方が柔軟に対処ができるのでjqで件数を絞り込んで見ましょう。
curl -s -u ${TOKEN}: \
'https://circleci.com/api/v1.1/project/github/yukimura1227/codecov_sample?offset=0&filter=completed' | \
jq -r '.[5:10] | .[] | [.build_num, .branch, .start_time, .build_time_millis, .outcome, .status] | @tsv'
15 experiment/not_suitable_path_case 2017-09-26T09:31:13.864Z 1049764 failed failed
14 experiment/not_suitable_path_case 2017-09-26T09:28:15.344Z 46219 failed failed
13 experiment/not_suitable_path_case 2017-09-26T09:24:21.295Z 46113 failed failed
12 experiment/not_suitable_path_case 2017-09-26T09:20:16.144Z 169985 failed failed
11 experiment/not_suitable_path_case 2017-09-26T09:15:40.405Z 619652 failed failed
先ほどのapiのparameterからlimitを除外した上で、.[5:10]
という処理が追加になっています。この、.[n:m]
で部分配列を作ることができます。
配列の添字がn〜m-1のものを絞り込むことができます。
参考:https://stedolan.github.io/jq/manual/#Builtinoperatorsandfunctions
日付で絞り込んでみる
何かのデータで絞り込みたい場合は、selectを使うと便利です。and
or
not
という論理演算子も使えるので、日付の期間を指定することもできます。
例えば、start_timeの期間を指定して見ましょう。
curl -s -u ${TOKEN}: \
'https://circleci.com/api/v1.1/project/github/yukimura1227/codecov_sample?offset=0&filter=completed' | \
jq -r '.[] | select(.start_time >= "2017-09-26T09:30" and .start_time <= "2017-09-26T10:00") | [.build_num, .branch, .start_time, .build_time_millis/1000, .outcome, .status] | @tsv'
20 experiment/not_suitable_path_case 2017-09-26T09:51:03.519Z 60.678 success success
19 experiment/not_suitable_path_case 2017-09-26T09:46:34.319Z 66.384 success fixed
18 experiment/not_suitable_path_case 2017-09-26T09:44:25.728Z 54.97 failed failed
17 experiment/not_suitable_path_case 2017-09-26T09:42:06.639Z 55.609 failed failed
16 experiment/not_suitable_path_case 2017-09-26T09:39:55.172Z 31.531 failed failed
15 experiment/not_suitable_path_case 2017-09-26T09:31:13.864Z 1049.764 failed failed
.[] | select(.start_time >= "2017-09-26T09:30" and .start_time <= "2017-09-27T10:00")
これで、配列の1件1件に対して、start_timeが"2017-09-26T09:30"と"2017-09-26T10:00"の間にあるデータを絞り込んでいます。
さらにstatusごとにカウントする
jqのgroup_byとlengthを使えば、取れるのですが、結構わかりづらいので、絞りまでできたら、uniq -c
でカウントした方が簡単なのでそっちにしました。
curl -s -u ${TOKEN}: \
'https://circleci.com/api/v1.1/project/github/yukimura1227/codecov_sample?offset=0&filter=completed' | \
jq -r '.[] | select(.start_time >= "2017-09-26T09:30" and .start_time <= "2017-09-26T10:00") | [.status] | @tsv' | sort | uniq -c
1 success
1 fixed
4 failed