CircleCI の設定ファイル分割をモノレポ的な構成で実験

昨日(というか今朝)書いたやつの続きー!

bufferings.hatenablog.com

昨日の記事を書きながらこんなことを考えてたので、今日はモノレポっぽいものを思い浮かべながら試してみた↓

ダイナミックコンフィグの有効化

と、その前に、昨日書き忘れてたやつを最初に

CircleCI のダイナミックコンフィグはデフォルトでは無効になっているので、そのままだとこういうエラーになる

Use of setup workflows must be enabled in project settings (Project settings > Advanced -> Dynamic config using setup workflows)

なので、プロジェクトの設定から有効化してあげる必要がある。

Project Settings > Advanced の一番下にあるトグルをオンにする:

これでダイナミックコンフィグが使える

モノレポのサービスごとに設定ファイルを用意

コードはここ → GitHub - bufferings/circleci-config-separation2

昨日は .circleci/config の中に YAML ファイルを置いてそれを合成したけど

今日は、複数のサービスをひとつのリポジトリに入れて、それぞれのサービスがそれぞれの config.yml を持っていると想定して作ってみた:

せっかくだから、共通の定義を置くのも想定してみようと思って、common も作った

気をつけること

設定ファイルで、気をつけないといけないことがいっこある

最終的にはひとつの YAML ファイルにまとめてしまうので、各サービスのジョブやワークフローの名前がかぶらないようにしないといけないのだ

だから今回は「サービス名 + -」を各ジョブ名とワークフロー名のプレフィックスとしてつけておいた。例えば service1 の場合はこうしておいた:

version: 2.1

jobs:
  service1-say-hello:
    docker:
      - image: cimg/base:stable
    steps:
      - checkout
      - run:
          name: "Say hello"
          command: "echo Hello, World!1"

workflows:
  service1-say-hello-workflow:
    jobs:
      - common-say-hello
      - service1-say-hello

設定ファイルを生成

じゃ、あとは設定ファイルを生成すればいい

昨日はこうしてた↓。.circleci/configs の中の .yml を集めてきて CUE に渡して合成してる

- run:
    name: Generate config
    command: |
      cd .circleci/configs
      find . -type f -name "*.yml" | awk '{printf "\"%s\" ", $0}' \
      | xargs -0 -I {} sh -c 'cue export {} --out yaml' | tee ../generated_config.yml

今回はこれを2つのステップに分割してみた

- run:
    name: Generate config list
    command: |
      find . -type f -regex '.*/\.circleci/config\.yml' -not -regex '\./\.circleci/config\.yml' \
      | tee .circleci/config-list.txt
- run:
    name: Generate config
    command: |
      cat .circleci/config-list.txt \
      | awk '{printf "\"%s\" ", $0}' \
      | xargs -0 -I {} sh -c 'cue export {} --out yaml' \
      | tee .circleci/generated_config.yml

最初のステップで対象のファイルリストを生成してから、次のステップでそのリストのファイルを読み込んで合成するようにした

今回はファイルリストの生成部分が前回と異なるので、各サービスの config.yml を集めてくる(でも、メインの config.yml は含まない)ようにした

生成されるファイルをローカルで確認

こんな風にしたらローカルマシンで確認できる

❯ find . -type f -regex '.*/\.circleci/config\.yml' -not -regex '\./\.circleci/config\.yml' \
| awk '{printf "\"%s\" ", $0}' \
| xargs -0 -I {} sh -c 'cue export {} --out yaml'
version: 2.1
jobs:
  common-say-hello:
    docker:
      - image: cimg/base:stable
    steps:
      - checkout
      - run:
          name: Say hello
          command: echo Hello, World! common
  service3-say-hello:
    docker:
      - image: cimg/base:stable
    steps:
      - checkout
      - run:
          name: Say hello
          command: echo Hello, World!3
  service2-say-hello:
    docker:
      - image: cimg/base:stable
    steps:
      - checkout
      - run:
          name: Say hello
          command: echo Hello, World!2
  service1-say-hello:
    docker:
      - image: cimg/base:stable
    steps:
      - checkout
      - run:
          name: Say hello
          command: echo Hello, World!1
workflows:
  service3-say-hello-workflow:
    jobs:
      - common-say-hello
      - service3-say-hello
  service2-say-hello-workflow:
    jobs:
      - common-say-hello
      - service2-say-hello
  service1-say-hello-workflow:
    jobs:
      - common-say-hello
      - service1-say-hello

うん。よさそう

実行すると

こうなった。やったーヽ(=´▽`=)ノ

事前に用意しておいても

ところで、設定ファイルの生成を2つのステップに分割したのは、マージしたい config.yml のリストを事前に書いておいてもいいかもなぁって思ったから

config.yml の数ってそんなに頻繁に変わらないと思うので、リストを .circleci/config-list.txt として書いておいてコミットに含めておいてもいいのかなって

そういう気も少ししてる。また今度もう少し考えてみる

次は

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

恒例の宣伝

興味あったら今日試してみたやつのお話を雑談したりできると思うので、ぜひ遊びにきてー!

bufferings.hatenablog.com