Azure PipelinesのPath Filterの挙動

このエントリーをはてなブックマークに追加

GitHub - MeilCli/AzurePipelineSample: multi project/module Azure Pipelines sample

multi project/module Azure Pipelines sample. Contribute to MeilCli/AzurePipelineSample development by creating an account on GitHub.

github.com

GitHub - MeilCli/AzurePipelineSample: multi project/module Azure Pipelines sample
Go to GitHub - MeilCli/AzurePipelineSample: multi project/module Azure Pipelines sample

↑のリポジトリーを作ってるときにいろいろとわかったことがあるので共有

Azure Pipelines でのトリガー - Azure Pipelines

Azure Pipelines で CI トリガー、スケジュールされたトリガー、ゲート トリガー、およびその他のトリガーを指定する方法について説明します

docs.microsoft.com

Azure Pipelines でのトリガー - Azure Pipelines
Go to Azure Pipelines でのトリガー - Azure Pipelines

Path Filterとはなんぞやってとこは公式ドキュメントを見てください。簡単に説明するとtrigger:によるブランチ・タグトリガーとpr:によるPullRequestトリガーにおいて、paths:の中でinclude:, exclude:することで発火する条件に変更のあったファイルパスを含めることができます

Classicタブの説明では以下のような仕様のようです

Tips:

  • If you don’t set path filters, then the root folder of the repo is implicitly included by default.
  • When you add an explicit path filter, the implicit include of the root folder is removed. So make sure to explicitly include all folders that your build needs.
  • If you exclude a path, you cannot also include it unless you qualify it to a deeper folder. For example if you exclude /tools then you could include /tools/trigger-runs-on-these
  • The order of path filters doesn’t matter.

ガバガバ日本語訳するとだいたいこんな感じかなと

  • Path filterを設定しないときはRepositoryのrootフォルダーが暗黙的にinclude:として設定されます
  • 明示的にPath filterを追加すると暗黙的にinclude:設定されたrootフォルダーは削除されます。そのためビルドに必要なフォルダーすべてを明示的にinclude:するようにしてください
  • exclude:でパスを指定すると、より深いフォルダーをinclude:しないといけません。たとえばexclude: /toolsとするとinclude: /tools/trigger-runs-on-theseと指定することができます
  • Path filterの順序は関係ありません

また、Path Filterを指定するときはbranches:またはtags:を指定しておく必要があります。

ここで、マルチプロジェクト/モジュールの場合に変更があった場所orそれに関係する場所をビルドするPipelineを組みたくなった時、まず以下のyamlが思いつくでしょう

# Pipeline: A
pr:
  branches:
    include:
      - master
  paths:
    include:
      - A/*
    exclude:
      - B/*
# Pipeline: B
pr:
  branches:
    include:
      - master
  paths:
    include:
      - B/*

Bというプロジェクト/モジュールがAというプロジェクト/モジュールに依存していて、Bの変更があった場合Aのビルドをしたくないという感じの2つのPipelineを考えてみます

このPipelineは以下の場合は期待値通りに動作します

  • Aのみの変更: Pipeline Aが作動
  • Bのみの変更: Pipeline Bが作動

しかし、AとB両方が変更された時は期待値通りに動かずPipeline AとPipeline Bが作動してしまいます。原因はおそらくexclude:よりinclude:のほうが優先度が高いということだと思われます

いろいろ試してみましたがPath Filterではこの動作は防ぎようがない感じでした。なので、Jobを最大限活用するという感じにこの動作を許しておくか、Path Filter以外で期待値通りの動作を実現するしかありません。Path Filter以外での方法は最初に挙げたリポジトリーで実装しているのでそれを参考にしてください。

ちなみに、Pipeline Bでinclude: A/*, B/*とすると、And条件ではなくOr条件になってしまい、A/*が変更されたときまたはB/*が変更されたときまたはその両方のときに発火してしまいます