テスト用GitHubレポジトリを作成
CircleCI 2.0の公式ドキュメントからもリンクされている
CircleCI Demos: Workflows: https://github.com/CircleCI-Public/circleci-demo-workflows
をforkしてCircleCI 2.0の機能を体験してみる。
今回のfork先は以下
https://github.com/mumoshu/circleci-demo-workflows
git clone git@github.com:mumoshu/circleci-demo-workflows.git
cd circleci-demo-workflows
masterブランチはREADMEしか置いてなくて、他のブランチにそれぞれ異なるテーマのサンプルが入っている模様。
ワークフローの仕組みをざっくりおさらい
2.0 Project Tutorial - CircleCI
- Gitレポジトリ内の
.circleci/config.yml
にワークフローの定義を書く - ワークフロー=Jobの集合
以下、その前提で読み進めます。
「Blogワークフロー」サンプルをビルドしてみる
git push origin remotes/origin/blog-workflows-1:master -f
rake_testタスクを覗いてみる。まず、rake db:create db:schema:load
を実行しているが、この対象のPostgresqlはどうやって起動するんだろう?と疑問に思った。
答えは、.circleci/config.yml
の以下の部分
rake_test:
docker:
- image: circleci/ruby:2.4-node
- image: circleci/postgres:9.4.12-alpine
steps:
- checkout
- restore_cache:
keys:
- v1-bundle-{{ checksum "Gemfile.lock" }}
- v1-bundle-
- run: bundle --path vendor/bundle
- run: bundle exec rake db:create db:schema:load
- run:
name: Run tests
command: bundle exec rake
依存先サービスはどうやって定義する・どう実装されている?
CircleCI 2.0の公式ドキュメントを読むと、
Note that the PostgreSQL database is available at localhost.
2.0 Project Tutorial - CircleCI
- rake_test.docker.images[]に依存先サービスのコンテナの定義(使用するコンテナイメージなど)を書く
- PostgreSQLコンテナのPostgreSQLサーバはlocalhostで待ち受けしている
らしいので、おそらくK8SのPodのように、ビルド環境のコンテナ、依存先サービスのコンテナがnetnsを共有している?のかなと想像。詳しい方情報求む!
また、rake_test.steps[]
にビルド環境のコンテナ内で実行するビルドステップ(任意のコマンド)を書く。
感想: Pipelineが第一級市民なCIとしてConcourseCIを長らく使っていましたが、その難点の
ビルドキャッシュはどうやって使う?どう実装されている?
save_cache
というステップを使うと、任意のキャッシュキーで任意のファイルパス(複数指定可)をキャッシュに保存できて、restore_cache
というステップでキャッシュキーを指定するとキャッシュを保存されたファイルパス以下に復元できる。
キャッシュはワークフロー内に閉じていて、ジョブ間で共有される。結果的に、save_cache
とrestore_cache
が異なるジョブにあってもOK。
実際、blog-workflowサンプルだとbundle_dependenciesという最初のジョブでsave_cacheしたもの(key: v1-bundle-{{ checksum "Gemfile.lock" }}
でsave_cache)
bundle_dependencies:
docker:
- image: circleci/ruby:2.4-node
- image: circleci/postgres:9.4.12-alpine
steps:
- checkout
- restore_cache:
keys:
- v1-bundle-{{ checksum "Gemfile.lock" }}
- v1-bundle-
- run: bundle install --path vendor/bundle
- save_cache:
key: v1-bundle-{{ checksum "Gemfile.lock" }}
paths:
- ~/circleci-demo-workflows/vendor/bundle
を後続のrake_testジョブでrestore_cacheしている(key: v1-bundle-{{ checksum "Gemfile.lock" }}
でrestore_cache)
rake_test:
docker:
- image: circleci/ruby:2.4-node
- image: circleci/postgres:9.4.12-alpine
steps:
- checkout
- restore_cache:
keys:
- v1-bundle-{{ checksum "Gemfile.lock" }}
- v1-bundle-
Workspace Forwardingサンプルをビルドしてみる
workspace-forwardingブランチのビルドをトリガーするために、コミットを追加してpushする。
git checkout -b workspace-forwarding remotes/origin/workspace-forwardin
emacs README.md
git add
git commit -m 'First change'
git push origin workspace-forwarding
手動でデプロイメントを実行する
例えば、テストジョブが通った後にデプロイジョブが実行されるようになっているWorkflowで、デプロイジョブの実行を人が承認するまで待機させるという機能はある。
Web UIからボタンぽちでデプロイジョブを実行する、というような機能はない。
Manually triggered deployment stages - Feature Requests - CircleCI Community Discussion
例えば、workspace-forwardingサンプルの.circleci/config.ymlでworkflow定義を以下のように変更する。
BEFORE
workflows:
version: 2
build-and-deploy:
jobs:
- bundle_dependencies
- rake_test:
requires:
- bundle_dependencies
- precompile_assets:
requires:
- bundle_dependencies
- deploy:
requires:
- rake_test
- precompile_assets
AFTER
workflows:
version: 2
build-and-deploy:
jobs:
- bundle_dependencies
- rake_test:
requires:
- bundle_dependencies
- precompile_assets:
requires:
- bundle_dependencies
- hold:
type: approval
requires:
- rake_test
- precompile_assets
- deploy:
requires:
- hold
こうすると、deployジョブは、rake_testとprecompile_assetsのビルドが成功したあとで、さらに承認があって初めて実行されるようになる。
実際にこの.circleci/config.ymlの変更をするコミットをpushしてみる。
すると、holdの要求するrake_testとprecompile_assetsまで自動的にビルドが走った状態で停止する。
Workflowsをみると、workspace-forwardingブランチのワークフローが表示されているのでそれを見てみる。
ON HOLDと表示されているワークフロー実行をクリックすると・・・
パイプライン中でholdジョブの色が変わっている。そこをクリックするとダイアログがでる。
Approveをクリックすると、Workflowが再開する。
その他
Slack通知
Project > Chat Notificationsの設定でSlackのWebhook URLを設定すればOK
Test Hookをすると、以下のようにcircleci botがテストメッセージを送る
2.0 WorkflowsはデフォルトではFork PRsのビルドをしない
Travis等だとFork先からFork元にPRを投げた時にビルドを走らせてくれますが、2.0 Workflowsはデフォルトではそれをしません。
同レポジトリ内のブランチからPRを投げた場合
CircleCIによるビルドが動いて、結果がPRのステータスに反映されます。
CircleCI側ではBuilds > 以下に該当ブランチのビルド結果ページができています。
別レポジトリからPRを投げた場合
CircleCIによるビルドは動かず、PRのステータスにも登場しません。
Forked PRもビルドしたい場合
ドキュメントには未対応と書いてあった気がするのですが、Advanced Settings > Build forked pull requestsにチェックを入れるとできました。
この状態からPRを投げると、以下のようにCircleCIのビルドがトリガーされます。
Forked PRの注意点(?)
Forked PR元で.circleci/config.ymlを変更すると、変更後のワークフローとジョブがPR先のCircleCIプロジェクトで走ってしまいます。
以下はmumoshuがPR先、mumoshubotがPR元で、mumoshubot側のブランチで`.circleci/config.yamlにfooというjobしかないような状態に書き換えたPRを投げたときの様子です。
CircleCIが、mumoshubotが仕込んだfooというジョブをmumoshuプロジェクトで実行してしまっています。
これでクレデンシャルなどを抜けたりするとまずいので、もしそうならパブリックなCircleCIプロジェクトではForked PRのビルドは有効にしないほうがいいんでしょうか・・。
APIで任意のジョブを実行する
まずUser > User SErttings > Peronal API Tokensで適当なAPIトークンを作成する。
Running Jobs With the API - CircleCIを参考に以下のようなコマンドでジョブを実行する。
curl -u ${CIRCLE_API_TOKEN}: \
-d build_parameters[CIRCLE_JOB]=deploy_production \
https://circleci.com/api/v1.1/project/<vcs-type>/<org>/<repo>/tree/master
-
<vcs-type>
はGitHubを使っている場合github
-
<org>
はGitHubユーザまたはOrganizationアカウント名 -
<repo>
はレポジトリ名 -
build_parameters[CIRCLE_JOB]=
の右辺、上記の例でいうとdeploy_production
の部分が、.circleci/config.ymlのjobs直下に書いたjob名
例えば、blog-workflows-1サンプルのrake_testジョブを実行する場合は、以下のようなコマンドになる。
curl -u ${CIRCLE_API_TOKEN}: \
-d build_parameters[CIRCLE_JOB]=rake_test \
https://circleci.com/api/v1.1/project/github/mumoshu/circleci-demo-workflows/tree/master
実行すると、以下のようにWorkflowとは独立して、該当jobだけが実行される。
条件付きで後続ジョブを実行する
ワークフロー中などでdeployがビルドされるとして、deployのビルド後に特定の条件に合致したときだけ後続のdeploy_dockerをビルドする例。
前述のAPIを使って任意のジョブを実行する方法を応用して、同じプロジェクトのワークフロー内の他のジョブをAPIを使って呼ぶという荒技(?)。
- deploy:
name: conditionally run a deploy job
command: |
# replace this with your build/deploy check (i.e. current branch is "release")
if [[ true ]]; then
curl --user ${CIRCLE_API_TOKEN}: \
--data build_parameters[CIRCLE_JOB]=deploy_docker \
--data revision=$CIRCLE_SHA1 \
https://circleci.com/api/v1.1/project/github/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/tree/$CIRCLE_BRANCH
fi
deploy_docker:
docker:
- image: ruby:2.4.0
working_directory: /
steps:
- ...
参考: Conditionally Running Jobs With the API
手動で特定のジョブを実行する
できないみたい?