path-filteringのmappingからCHANGELOGが漏れて、docsがdeployされなかった
タグ:
monorepoのdocsサイトをCircleCIでdeployしていて、npmへのpublishは成功したのにChangelogページだけが更新されない問題に遭遇しました。原因はpath-filtering orbのmappingにCHANGELOGのパスがなかったことです。orbのソースで仕様を確認しながら直した記録です。
目次
monorepoのOSSで、docsサイトをCircleCIでdeployしています。あるとき、npmへのpublishは成功しているのに、ドキュメントサイトのChangelogページだけが古いままになっていました。CircleCIはgreenで、deploy workflowは実行されず、docs/にも変更はありません。
path-filtering orbのmappingに原因があり、1行足せば直ります。ただ、AIに生成させた直しのYAMLに違和感を覚えました。
mapping: |
(\.circleci/docs-release\.yml|docs/.*|packages/[^/]+/CHANGELOG\.md) run-docs-deploy true
3つの条件を(A|B|C)で1行に押し込んだ正規表現は、単純に読みにくく感じます。mappingは複数行で書けたはずという記憶もあったので、orbのソースを確認しました。
mappingの仕様はorbのスクリプトで確認できる
path-filtering orbのv1系では、mappingをcreate-parameters.pyが解釈します。このスクリプトを読むと、判断に必要な仕様がひと通りわかります。
- mappingの文字列を
splitlines()で1行ずつに分け、各行を空白でsplit()する - 1行は3要素(パス、parameter、value)か、configファイルを加えた4要素にする。最初の行の要素数が3と4のどちらでもなければ
Invalid mapping length、行ごとに要素数がずれたらExpected N fields but found Mの例外になる - パスは
re.compile(r'^' + path + r'$')で正規表現として扱われる(^と$は自動付与) - valueは
json.loadsで解釈される - 最後は
dict(filtered_mapping)でまとめるので、同じparameter名の行は後ろの行の値で上書きされる
公式のapi-preview-docsにも「Later matches override earlier ones.」とあり、標準の例も複数行で書かれています。つまり(A|B|C)は複数行で書けるものを正規表現のorに書き直しただけでした。
なお、orbはv2.0.0でcreate-parameters.pyをやめ、bashのcreate-parameters.shに移りました。最新のv3.0.0でも、1行を空白で分割する点と、パスを^と$で囲んで正規表現にする点は同じです。
複数行に分けて、抜けていたCHANGELOGを足す
最終的なmappingは次のとおりです。
mapping: |
\.circleci/docs-release\.yml run-docs-deploy true
docs/.* run-docs-deploy true
packages/[^/]+/CHANGELOG\.md run-docs-deploy true
3行ともrun-docs-deployをtrueにするので、後勝ちのルールがあっても結果は変わりません。後勝ちが結果を変えるのは、同じparameter名にtrueとfalseを混ぜたときだけです。
docs/だけを見ていたので、deployがスキップされていた
最初のmappingから抜けていたのは、3行目のpackages/[^/]+/CHANGELOG\.mdです。Changesetsのpnpm changeset versionが更新するのはpackages/*/CHANGELOG.mdとpackages/*/package.jsonです。docs/には触れません。一方、docsサイトのChangelogページは、packages/*/CHANGELOG.mdをloaderで読んで生成しています。deployのトリガーがdocs/**だけの場合、CHANGELOGが更新されてもパイプラインは「変更なし」と判定します。その結果、deployはスキップされます。CIはgreenなのにサイトだけが古い状態は、これが原因でした。
mappingはフォルダではなく、ビルドの入力依存関係で書く
monorepoでは、docsビルドの入力ソースがdocs/の外に散らばります。packages/*/CHANGELOG.mdのほか、TypeDoc用のpackages/*/src/**やルートのREADMEなどです。「docsはこのフォルダにある」という感覚でdocs/**だけを書くと、これらの変更を取りこぼします。設計の時点で、chore: version packages相当のコミットでrun-docs-deployがtrueになるかを確かめておけば、気づけたはずです。