環境
- CircleCI version 2.1
- circleci/path-filtering@1.0.0
やりたいことの前提
- Monorepo
- 具体的には、以下のようなディレクトリがレポジトリ配下に存在し、ファイルの変更されたPATHに応じて、必要なworkflowのみを実行する。
frontend
backend
- 具体的には、以下のようなディレクトリがレポジトリ配下に存在し、ファイルの変更されたPATHに応じて、必要なworkflowのみを実行する。
- 管理のため、それぞれのcircle configも分ける。
CircleCI の設定の前提
ここにある通り、Enable dynamic config using setup workflows
が on
になっていること。
上記の設定をしても、今まで通り単一の config.yml
で書くことは可能。
config.yml
のトップレベルで setup: true
と定義することにより、上記で有効にした dynamic config using setup workflows
が有効になる。
CircleCI Config ファイル構成
※分かりやすいように、前述の backend
, frontend
というディレクトリも記載している。
├── .circleci
│ ├── config.yml
│ ├── _base.yml # ファイル名は任意
│ ├── packages # PATH、及びその配下のファイル名は任意
│ ├── backend_config.yml
│ ├── frontend_config.yml
│
├── backend
├── frontend
各 yml ファイル
.circleci/_base.yml(ファイル名は任意)
.circleci/_base.yml
version: 2.1
orbs:
parameters:
executors:
commands:
jobs:
workflows:
.circleci/config.yml
setup: true
の定義により、dynamic configuration が有効になる。
.circleci/config.yml
version: 2.1
# this allows you to use CircleCI's dynamic configuration feature
setup: true
orbs:
path-filtering: circleci/path-filtering@1.0.0
jobs:
merge-config:
docker:
- image: cimg/base:stable
steps:
- checkout
- run:
name: "Generate yaml"
# https://mikefarah.gitbook.io/yq/operators/reduce#merge-all-yaml-files-together
command: |
mkdir -p /tmp/workspace
yq eval-all '. as $item ireduce ({}; . * $item )' .circleci/_base.yml .circleci/packages/*.yml > /tmp/workspace/merged.yml
cat /tmp/workspace/merged.yml
- persist_to_workspace:
root: /tmp/workspace
paths:
- merged.yml
workflows:
generate-config:
jobs:
- merge-config
- path-filtering/filter:
requires:
- merge-config
pre-steps:
- attach_workspace:
at: /tmp/workspace
base-revision: develop
config-path: /tmp/workspace/merged.yml
mapping: |
backend/.* run_backend_jobs true
frontend/.* run_frontend_jobs true
.circleci/packages/backend_config.yml
.circleci/packages/backend_config.yml
version: 2.1
parameters:
run_backend_jobs:
type: boolean
default: false
executors:
backend_default:
working_directory: ~/repo # default: ~/project
docker:
- image: cimg/ruby:3.2.2
environment:
BUNDLER_VERSION: 2.4.15
BUNDLE_APP_CONFIG: ~/repo/backend/.bundle
RAILS_ENV: test
commands:
restore_bundle_dependencies:
steps:
- restore_cache:
name: Restore bundle dependencies cache
keys:
- v1-bundle-dependencies-{{ checksum "backend/Gemfile.lock" }}
- v1-bundle-dependencies-
install_bundler:
steps:
- run:
name: Install bundler
working_directory: backend
command: gem install bundler -v $BUNDLER_VERSION
set_bundle_config:
steps:
- run:
name: Set bundle config
working_directory: backend
command: bundle config --local path 'vendor/bundle'
install_bundle_dependencies:
steps:
- run:
name: Install bundle dependencies
working_directory: backend
command: |
bundle install --jobs=4 --retry=3
save_bundle_dependencies:
steps:
- save_cache:
key: v1-bundle-dependencies-{{ checksum "backend/Gemfile.lock" }}
paths:
- backend/vendor/bundle
run_rubocop:
steps:
- run:
name: Run rubocop
working_directory: backend
command: bundle exec rubocop
jobs:
backend_setup:
executor: backend_default
steps:
- checkout
- restore_bundle_dependencies
- install_bundler
- set_bundle_config
- install_bundle_dependencies
- save_bundle_dependencies
- persist_to_workspace:
root: ~/repo
paths:
- backend
backend_lint_rubocop:
executor: backend_default
steps:
- attach_workspace:
at: ~/repo
- restore_bundle_dependencies
- install_bundler
- run_rubocop
workflows:
backend:
when: << pipeline.parameters.run_backend_jobs >>
jobs:
- backend_setup
- backend_lint_rubocop:
requires:
- backend_setup
.circleci/packages/frontend_config.yml
.circleci/packages/frontend_config
version: 2.1
parameters:
run_frontend_jobs:
type: boolean
default: false
executors:
frontend_default:
working_directory: ~/repo # default: ~/project
docker:
- image: cypress/base:18.16.1
environment:
YARN_CACHE_FOLDER: ~/repo/frontend/yarn_packages
TZ: Asia/Tokyo
jobs:
frontend_setup:
executor: frontend_default
steps:
- checkout
- restore_cache:
keys:
- v1-yarn-packages-{{ checksum "frontend/yarn.lock" }}
- v1-yarn-packages
- restore_cache:
keys:
- v1-node-modules-{{ checksum "frontend/package.json" }}
- v1-node-modules
- run:
name: Install yarn packages
working_directory: frontend
command: yarn install
- save_cache:
key: v1-yarn-packages-{{ checksum "frontend/yarn.lock" }}
paths:
- frontend/yarn_packages
- .cache
- save_cache:
key: v1-node-modules-{{ checksum "frontend/package.json" }}
paths:
- frontend/node_modules
- .cache
- persist_to_workspace:
root: ~/repo
paths:
- frontend
- .cache
frontend_lint_eslint:
executor: frontend_default
steps:
- attach_workspace:
at: ~/repo
- run:
name: Run eslint
working_directory: frontend
command: yarn run lint
workflows:
frontend:
when: << pipeline.parameters.run_frontend_jobs >>
jobs:
- frontend_setup
- frontend_lint_eslint:
requires:
- frontend_setup
参考
-
Dynamic Configuration
- CircleCI の config を Pipeline values やファイルPATH に応じて、動的に生成する場合の説明(monorepo 時に有用)。
- Using dynamic configuration
- circleci/path-filtering@1.0.0
- 6 optimization tips for your CI configuration
- https://qiita.com/algas/items/d0e4d460b938d924ae8f