はじめに
CIツールのスタンダードとなりつつある CircleCIは、Github等のpushをトリガーに設定したCIジョブを実行してくれる便利なツールです。
CircleCIはAPIを公開しています。このAPIによってリポジトリにpushしたりtagの発行がなくてもCIを実行することができます。例えば、複数リポジトリ間のCIトリガーを一括で制御したい!といった場合や、リポジトリ内のコードに変更はないけど、内部でダウンロードしてくるファイルやDockerイメージの中身に変更が生じたためpushせずにテストを回したい!というときに非常に有用です。
しかし、API経由ではCircleCI 2.0で実装されたworkflows
機能が働かないということがわかりました。
というより、workflows
ブロックがconfig.yml
に入ったCIをAPI経由で実行すると必ずCIが失敗します。
公式でもそんなことが書いてあります。
Note: It is not yet possible to run Workflows with the API.
https://circleci.com/docs/2.0/api-job-trigger/
この記事ではworkflows
が設定されたCIをAPI経由で実行する方法を共有します。
解決策
CircleCIのAPIではCIの設定単位ではなく、ymlの中で設定されたjob単位でも実行することができます。
この方法だと上記のworkflows問題を回避することができます。
やり方は以下の通り
- 設定単位
curl https://circleci.com/api/v1.1/project/:vcs-type/:username/:project/tree/:branch?circle-token=${CIRCLE_TOKEN}
- job単位
curl -d build_parameters[CIRCLE_JOB]=${JOB_NAME} https://circleci.com/api/v1.1/project/:vcs-type/:username/:project/tree/:branch?circle-token=${CIRCLE_TOKEN}
実行例
例として以下のようなconfig.ymlを用意します。
このCIでは必ずjob1が実行され、その後developブランチであればjob2、masterブランチであればjob3が実行されます。
version: 2
jobs:
job1:
docker:
- image: circleci/python:3.6.1
steps:
- run:
name: echo1
command: echo fuwafuwa
job2:
docker:
- image: circleci/python:3.6.1
steps:
- run:
name: echo2
command: echo mochimochi
job3:
docker:
- image: circleci/python:3.6.1
steps:
- run:
name: echo3
command: echo pikapika
workflows:
version: 2
test-jobs:
jobs:
- job1
- job2:
requires:
- job1
filters:
branches:
only: develop
- job3:
requires:
- job1
filters:
branches:
only: master
それではまず、gitのpushをトリガーとしてCIを走らせてみましょう。
masterブランチにpushした結果が以下の通り。
共通jobのjob1と、masterブランチ限定のjob3が走っていることがわかります。job2はdevelopブランチにpushされたときだけ実行されるので、今回は実行されていません。
API経由で全く同じCIを叩いてみましょう。
curl https://circleci.com/api/v1.1/project/github/smn-ailab/hiranuma_qiita/tree/master?circle-token=${CIRCLE_TOKEN}
ymlのsyntaxエラーのような記述ですね。なにはともあれ、API経由ではworkflows
が設定されたCIは実行できないことが確認できました。
それでは今回のテーマである、job単位での実行をやってみましょう。
curl -d build_parameters[CIRCLE_JOB]=job1 https://circleci.com/api/v1.1/project/github/smn-ailab/hiranuma_qiita/tree/master?circle-token=${CIRCLE_TOKEN}
動作できています!
これでworkflows
を無視してAPIからjobを実行できました!
おまけ: APIでworkflowsの挙動を再現してみた
workflows
の機能が使えないため、jobの依存関係を呼び出し側で制御する必要があります。
buildのstatusを参照するAPIを使って依存関係を書いてみます。
BUILD_NUM=`curl \
-d build_parameters[CIRCLE_JOB]=job1 \
https://circleci.com/api/v1.1/project/github/smn-ailab/hiranuma_qiita/tree/master?circle-token=${CIRCLE_TOKEN} | jq -r '.build_num'`
while true
do
STATUS=`curl -s -S https://circleci.com/api/v1.1/project/github/smn-ailab/minerva-analysis/${BUILD_NUM}?circle-token=${API_TOKEN} | jq -r '.status'`
if [ ${STATUS} = "success" ]; then
echo ${STATUS}
break
elif [ ${STATUS} = "failed" ]; then
echo ${STATUS}
exit 1
else
echo ${STATUS}
sleep 60
fi
done
curl \
-d build_parameters[CIRCLE_JOB]=job3 \
https://circleci.com/api/v1.1/project/github/smn-ailab/hiranuma_qiita/tree/master?circle-token=${CIRCLE_TOKEN}
CIを実行するAPIでは、返り値としてBuildの情報がjson形式で返ってきます。
ここではCIを実行すると同時にBuild番号を受け取り、番号を元にAPIを叩いて該当BuildのStatusを確認しています。$STATUSが"success"であれば、次のBuildを走らせるcurlコマンドの部分へ移行し、failedであればその時点でシェルは終了します。それ以外の場合は1分待ってから再度STATUS確認に移ります。このようにすればjobの依存関係を再現できます。
おわりに
今回ご紹介した方法ではworkflows
の設定を一切無視するので、branches: only master
としているjobをdevelopブランチで実行することも出来てしまいます。
使用する際はご注意下さい。