これは CircleCI Advent Calendar 2018 の20日目です。
sue445/ruby-orbs を作って1ヶ月くらい経ちましたが、Orbをメンテしやすくするためのテクニックがいくつか分かってきたので紹介したいと思います
リリースごとに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をリリースできるようにするのがスマートだと思ったので実装しました。
実装方法
ソースはここにあります
- https://github.com/sue445/circleci-ruby-orbs/blob/1.3.10/.circleci/config.yml
- https://github.com/sue445/circleci-ruby-orbs/blob/1.3.10/.circleci/push_latest_version_tag.rb
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: /.*/
解説
orb-tools/increment
でOrbのパッチバージョンを上げて、Orbリリース後にpush_latest_version_tag.rbを実行- ローカルからtagをpushした時にもincrementが走ると嫌なので、念の為
tags:ignore: /.*/
で明示的に除外しています。(なくてよかったかも)
- ローカルからtagをpushした時にもincrementが走ると嫌なので、念の為
push_latest_version_tag.rb
は https://github.com/sue445/circleci-ruby-orbs/blob/1.3.10/.circleci/push_latest_version_tag.rb を参照
ローカルから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 配下のリポジトリにまとまっているのですが、僕は普段下記のリポジトリを参考にしています。
- https://github.com/CircleCI-Public/orb-tools-orb
- https://github.com/CircleCI-Public/circleci-orbs
- https://github.com/CircleCI-Public/slack-orb
*1:自分が見つけきれていない説もある