概要
CircleCIのDynamic Configでconfig.ymlを分割管理する - Carpe Diem
↑ではファイルを分割管理する方法を説明しました。
今回はpath filteringを使って差分ビルド(変更のあるディレクトリのみビルド)する方法を説明します。
環境
- CircleCI 2.1
- circleci/path-filtering 0.1.2
以下のようなモノリポ環境だったとします。
$ tree . ├── LICENSE ├── README.md ├── go │ ├── pkg │ │ └── uuid │ │ └── uuid.go │ └── services │ ├── service1 │ │ └── cmd │ │ └── main.go │ └── service2 │ └── cmd │ └── main.go ├── go.mod └── go.sum
差分ビルド要件
今回は
service1
に変更があればservice1
のみビルドservice2
に変更があればservice2
のみビルドservice1
,service2
が依存するpkg
に変更があれば両方ビルド
という差分ビルドを実現したいとします。
導入手順
Setup workflowの用意
version: 2.1 setup: true orbs: path-filtering: circleci/[email protected] workflows: always-run: jobs: - path-filtering/filter: name: check-updated-files # <regex path-to-test> <parameter-to-set> <value-of-pipeline-parameter> mapping: | go/services/service1/.* run-build-service1-job true go/services/service2/.* run-build-service2-job true go/pkg/.* run-build-pkg-job true base-revision: main config-path: .circleci/continue_config.yml
ポイント
ポイントは以下です。
mapping
で「pathの正規表現」「次のconfigに渡すパラメータ名」「セットするパラメータの値」を書くbase-revision
に比較するベースとなるブランチを指定するconfig-path
に次に実行するconfigファイル
continue_config.yml
pipeline parameters
「次のconfigに渡すパラメータ名」は予め以下のように定義しておく必要があります。
parameters: run-build-service1-job: type: boolean default: false run-build-service2-job: type: boolean default: false run-build-pkg-job: type: boolean default: false
workflows
そしてworkflowsではwhen
で上記のパイプラインパラメータを使用します。
workflows: version: 2 noop: when: and: - not: << pipeline.parameters.run-build-service1-job >> - not: << pipeline.parameters.run-build-service2-job >> - not: << pipeline.parameters.run-build-pkg-job >> jobs: - noop service1: when: or: - << pipeline.parameters.run-build-service1-job >> - << pipeline.parameters.run-build-pkg-job >> jobs: - build: target: service1 service2: when: or: - << pipeline.parameters.run-build-service2-job >> - << pipeline.parameters.run-build-pkg-job >> jobs: - build: target: service2
ポイント
when
でパイプラインパラメータを使って発火させる- or条件、and条件をうまく組み合わせる
- 1つのjobも発火しないとエラーになるので何もしないjobを用意しておく
jobs
jobs: noop: executor: default steps: - run: name: "No operation" command: echo "No operation" build: executor: default parameters: target: type: string steps: - checkout - setup_remote_docker: version: 20.10.11 docker_layer_caching: true - run: name: Build command: | cd go/services/<< parameters.target >> go build cmd/main.go
jobsの方はこんな感じです。job内のparametersを使ってうまく共通化すると良いです。
動作確認
それでは動作確認してみます。
service1だけ変更した場合
以下のようにservice1だけビルドされます。
https://app.circleci.com/pipelines/github/jun06t/circleci-dynamic-config?branch=test-diff&filter=all
共通なpkgが変更された場合
service1、service2の両方がビルドされます。
サンプルコード
今回のサンプルコードはこちら
まとめ
CircleCIで手軽に差分ビルドを実現することができました。
Bazelのようなツールを使わないモノリポ環境ではぜひ導入したいですね。