CircleCiのAPIとjqでビルド情報を特定期間に絞ってサマる

本記事のサマリ

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ボタンを押しましょう。
Kobito.siqL2Z.pn

トークンの名前を問われるので適当に目的にあったわかりやすい名前をつけましょう。ここでは、説明用なのでsample_tokenとしました。

Kobito.VukJYb.png

こんな感じになりました。
Kobito.u3cOO8.png

この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
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.