これは CircleCI Advent Calendar 2018 の20日目です。
qiita.com
sue445/ruby-orbs を作って1ヶ月くらい経ちましたが、Orbをメンテしやすくするためのテクニックがいくつか分かってきたので紹介したいと思います
sue445.hatenablog.com
sue445.hatenablog.com
リリースごとにgitのtagを打つ
- パッチバージョンのアップデート(+0.0.1)はmasterブランチへのコミットの度にリリース&tag pushする
- メジャーバージョンのアップデート(+1.0.0)やマイナーバージョンのアップデート(+0.1.0)はローカルでgitのtagを作ってpushし、そこからCircleCI上でOrbをリリースする
この運用が自分の中で一番しっくりきています。
理由
- バージョンごとにリポジトリにtagが打たれていると、GitHub上でのバージョン間の差分が見やすいため
- パッチバージョンのアップデートは基本全自動で問題なさそうだが、メジャーバージョンやマイナーバージョンのアップデートは人間の意思が介在するのでローカルで作業をしたい(要出典)
後者に関してはローカルから circleci increment major
や circleci increment minor
を叩いても実現はできます。
ただし自分の場合作業環境を複数台持っている(PCではなくサーバに入って作業することも多い)ので、各環境にcircleci cliのトークンを置くよりはgitでtag pushしたら自動でそのバージョンのOrbをリリースできるようにするのがスマートだと思ったので実装しました。
実装方法
ソースはここにあります
masterブランチへのコミットの度に自動でOrbをリリース&tag pushする
関連するソースは下記です
version: 2.1
orbs:
orb-tools: circleci/orb-tools@2.0.2
jobs:
push_latest_version_tag:
docker:
- image: circleci/ruby:2.5
working_directory: ~/app
steps:
- checkout
- add_ssh_keys:
fingerprints:
- "43:39:3a:d1:90:49:a4:85:db:17:41:ce:88:55:44:92"
- run: curl -fLSs https://circle.ci/cli | sudo bash
- run:
name: Setup git
command: |
git config push.default current
git config user.email "$EMAIL"
git config user.name "CircleCI"
- run: ruby .circleci/push_latest_version_tag.rb sue445/ruby-orbs
workflows:
version: 2
btd:
jobs:
(略)
- orb-tools/increment:
orb-path: packed/orb.yml
orb-ref: "sue445/ruby-orbs"
segment: "patch"
publish-token-variable: "$CIRCLECI_API_TOKEN"
attach-workspace: true
checkout: false
requires: [orb-tools/test-in-builds]
filters:
branches:
only: master
- push_latest_version_tag:
requires: [orb-tools/increment]
filters:
branches:
only: master
tags:
ignore: /.*/
解説
ローカルからtagをpushしたら自動でOrbをリリースする
関連するソースは下記です
workflows:
version: 2
release:
jobs:
- orb-tools/pack:
source-dir: src/
destination-orb-path: packed/orb.yml
workspace-path: packed/orb.yml
artifact-path: packed/orb.yml
filters:
tags:
only: /^[0-9.]+\.0$/
branches:
ignore: /.*/
- orb-tools/publish:
orb-path: packed/orb.yml
orb-ref: "sue445/ruby-orbs@${CIRCLE_TAG}"
publish-token-variable: "$CIRCLECI_API_TOKEN"
attach-workspace: true
checkout: false
requires: [orb-tools/pack]
filters:
tags:
only: /^[0-9.]+\.0$/
branches:
ignore: /.*/
解説
tag pushに反応して $CIRCLE_TAG
に対応したバージョンでOrbをリリースしています。
filters:branches:ignore: /.*/
で全てのbranchを明示的に除外しておかないと、ブランチpush時にもreleaseワークフローが実行され $CIRCLE_TAG
が取れないのでエラーになります
fiters:tags:only: /^[0-9.]+\.0$/
のような正規表現にすることで、1.2.3
-> 1.2.4
のようなCircleCIからのパッチバージョンリリースでは実行されずに、1.2.3
-> 1.3.0
のようなローカルからのtag pushのみで実行されるようになります
この設定をしておかないと
- masterブランチをpush
- CircleCIでマイナーバージョンアップデート
- push_latest_version_tagでOrbの最新バージョンを取得してtag push
- 同じtagが作成済みなのでエラーになる
- Orbのバージョンもtagもちゃんと作られているのに、コミットのビルドステータスが赤になるので気持ち悪い
ということになるので必要です。
CircleCIのOrbは基本的に1つのyamlファイルです。
機能が少ないうちはいいのですが、機能が増えてくるとyamlファイルが巨大になって見通しが悪くなってしまいます。
- orb-tools/pack:
source-dir: src/
destination-orb-path: packed/orb.yml
workspace-path: packed/orb.yml
artifact-path: packed/orb.yml
のように書くことで、src/にある階層化されたyamlファイルをいい感じに1つのyamlファイルにマージしてくれます。
説明すると長くなるので詳しくは下記PRを見てください。
https://github.com/sue445/circleci-ruby-orbs/pull/30/files
examplesを書く
Orbsのソースコードから実際の使い方を読み解くのは最初のうちは難しいです。GitHubみたいにREADMEがあればサンプルコードを書く余地があるのですが、Registryには(今のところ)そういう機能がありません。
しかし、examples
を書くことでRegistryのUsage Examplesに表示させることができます。
Orbのexampleの記載
examples:
bundle-install:
description: |
Run `bundle install` using cache.
usage:
jobs:
rspec:
docker:
- image: circleci/ruby
steps:
- checkout
- ruby-orbs/bundle-install:
bundle_clean: true
bundle_extra_args: ""
bundle_gemfile: Gemfile
bundle_jobs: 4
bundle_path: vendor/bundle
bundle_retry: 3
cache_key_prefix: v1-bundle
restore_bundled_with: true
- run: bundle exec rspec
orbs:
ruby-orbs: sue445/ruby-orbs@1.3.0
version: 2.1
Registryでの表示
https://circleci.com/orbs/registry/orb/sue445/ruby-orbs#usage-bundle-install
Orbsの書き方の学習方法
公式ドキュメントはこちらになります
https://circleci.com/docs/2.0/creating-orbs/
しかしドキュメント化されてない機能もある*1ため、公式のOrbsのソースを読むのが一番です。
公式Orbsのソースは https://github.com/CircleCI-Public 配下のリポジトリにまとまっているのですが、僕は普段下記のリポジトリを参考にしています。