CircleCI のパスフィルタリングと設定ファイル分割を組み合わせる実験

三話目の今日は、パスフィルタリングと組み合わせてみるぞー!

第一話:設定ファイル分割の紹介

bufferings.hatenablog.com

第二話:モノレポ用の実験

bufferings.hatenablog.com

前回の最後に

こんなことを言ったので、今日ぼけーっと考えてた

ブランチごとに合成方法を変えたりできるかなぁ?か、変更があったサービスのジョブだけ実行したりできないかなぁ?のどっちかを考えてみたいな。できるかどうか分かんないけど!

ブランチは別にいっか

でも、ブランチは別に考えなくていいなと思った。main だったらこの設定ファイルだけを合成に使う、feature ブランチだったらこの設定ファイル、みたいにブランチごとに合成する設定ファイルを変えるのは、あんまりユースケースが思いつかない

あるかもって思ったのは「ブランチごとの設定を別ファイルに分けてわかりやすく管理したい」かな。でも、それは特に難しいことを考えずに今の機能で足りそう。 main.yml とか feature.yml とかにそれぞれのブランチ用のワークフローを書いて、それをマージしてしまえば良さそうなので

変更があったサービスのジョブだけ実行

ということで、今日はこちらを実験してみようと思う

どういうものかというと、昨日試してみたモノレポ的なリポジトリで「変更が入ったサービスのビルドだけを実行したい!」っての

実は、これ自体は既に公式の Orb がある。path-filtering という Orb

この Orb もダイナミックコンフィグを使ってるから、組み合わせて動くかなぁ?ってのを試してみるだけになるかな

path-filtering Orb

まずは path-filtering Orb のことを簡単に紹介

僕が読んだ記事たち↓。どれも分かりやすいー!

仕組み

セットアップ用のジョブに、こんな風に書くと

version: 2.1

setup: true

orbs:
  path-filtering: circleci/path-filtering@0.1.3

workflows:
  setup-workflow:
    jobs:
      - path-filtering/filter:
          config-path: .circleci/continue-config.yml
          mapping: |
            src/.* build-code true
            doc/.* build-docs true
  1. mapping の定義に従って、正規表現に一致したファイルに変更が入った場合に、指定してあるパラメータに指定した値が設定される(正規表現 パラメータ名 パラメータ値 になってる)
  2. config-path に指定したファイルを設定ファイルとして、ダイナミックコンフィグの機能を使ってパイプラインが実行される。このときに(1)のパラメータが渡される

なので、上の例だと .circleci/continue-config.yml の中で build-codebuild-docs というパラメータが true かどうかをジョブの実行条件に加えることで「変更が入ったサービスのビルドだけを実行したい!」が実現できる

どこからの差分?

ところで「変更が入った」ってどこからの差分だろう?と思って Orb のコードを見てみたらデフォルトでは main からの差分だった。なるほど。・・・ん?

「え、じゃあ main 自体のビルドの場合はどうなるの?」って思うよね。で、見てみたら main の場合は一個前のコミットとの差分を見てた。へー

だから、気をつけておきたいのは、main でビルドに失敗して、もういっかい何か変更を加えてコミットしてプッシュしたときとかに、一個前のコミットとの差分を元に起動されて大丈夫かどうかってところかなぁ

そういうときのために、手動でトリガーできるパイプラインパラメーターを用意しておくか、まぁ、ジョブを走らせたいディレクトリのファイルをわざと触るかしたら良さそうかな

組み合わせる

で、本題の、設定ファイル分割と、この path-filtering を同時に動かせるかどうか、ってやつ

ここまでの情報をふまえると頭の中では、大丈夫そう。先に設定ファイル合成のジョブを走らせておいてから、そこで合成したファイル名を path-filtering/filter ジョブの config-path に指定してあげれば動くはず

ということで、本当に動くかどうかやってみよー!

実験

今日のコード:

github.com

こんな構成にしてみた

path-filtering は mapping にマッチしなかったケースを書いておいてあげないといけないので Tsuji さんの記事を参考に noop.yml を書いたのと

version: 2.1

jobs:
  noop:
    docker:
      - image: cimg/base:stable
    steps:
      - run:
          name: "No operation"
          command: echo "No operation"

workflows:
  noop:
    when:
      and:
        - not: << pipeline.parameters.build-service1 >>
        - not: << pipeline.parameters.build-service2 >>
    jobs:
      - noop

パラメータの定義が必要なのでそれを parameters.yml に書いておいた

version: 2.1

parameters:
  build-service1:
    type: boolean
    default: false
  build-service2:
    type: boolean
    default: false

別ファイルで既に書いてあるから、version: 2.1 はつけなくてもいいんだけど、なんとなく

それに合わせて、config.yml 以外の YAML ファイルも読み込めるように find の正規表現を昨日のやつから少し変えておいた

command: |
  find . -type f -regex '.*/\.circleci/.*\.yml' -not -regex '\./\.circleci/config\.yml' \
  | tee .circleci/config-list.txt

今日のは余裕やろー!

と思って

  • generate-config -> path-filtering/filter

なセットアップワークフローをこんな風に書いたら

workflows:
  setup-workflow:
    jobs:
      - generate-config
      - path-filtering/filter:
          config-path: .circleci/generated_config.yml
          mapping: |
            service1/.* build-service1 true
            service2/.* build-service2 true
          requires:
            - generate-config

怒られた!

jq: error: Could not open file .circleci/generated_config.yml: No such file or directory

・・・はっ!そうか。ジョブ間でファイルを渡してあげなきゃか

ワークスペースを使う

ジョブ間のファイルのやりとりにはワークスペースを使えばいいので

generate-config ジョブの最後にこうやって

      - persist_to_workspace:
          root: .
          paths:
            - .circleci/generated_config.yml

で、どうやって、このワークスペースpath-filtering/filter にアタッチしようかなぁって思って見てみたら

path-filtering/filterworkspace_path ってパラメータがあった。Orb のソースを見た感じ、これを使えばちょうどいい場所でアタッチしてくれそう

なので、こういう感じになった(workspace_path: . が足した部分)

workflows:
  setup-workflow:
    jobs:
      - generate-config
      - path-filtering/filter:
          workspace_path: .
          config-path: .circleci/generated_config.yml
          mapping: |
            service1/.* build-service1 true
            service2/.* build-service2 true
          requires:
            - generate-config

動作確認

じゃ、動作確認していこー!

service1 にも service2 にも変更が入らなかった場合 -> noop ワークフローが実行された

service1 にだけ変更が入った場合 -> service1 用のワークフローだけが実行された

service2 にだけ変更が入った場合 -> service2 用のワークフローだけが実行された

service1 にも service2 にも変更が入った場合 -> 両方のワークフローが実行された

やったー!

次は

アンカーの動作確認をしておきたい。これまで特に YAML の要素の順番を気にしてこなかったけど、YAML のアンカーって先に定義がでてきてないと怒られるんじゃないかなぁ?って思うのでその確認をしておきたい

で、それが終わったら、このファイル分割の機能を Orb 化しようかな

楽しい3連休だったー!

今日も今日とて宣伝

梅田まで来れる方はぜひお申し込みくださいませー!

bufferings.hatenablog.com