Azure API Management(APIM)のAPIOpsでrun-extractor.ymlを動かしているのに、生成されるはずのtags/productsフォルダーがプルリクエスト(PR)の差分に出てこない――そんな現象は「生成に失敗した」のではなく、PRが比較しているターゲットブランチ側にすでに同じ内容が入っていることが原因のケースが多いです。仕組みの整理から、確実にPRへ含める手順、再発防止のチェックリストまでまとめます。
想定する環境と前提
ここで扱うのは、Azure API Management(APIM)をGit管理し、APIOps(API Operations)で構成をエクスポートしてAzure DevOpsのリポジトリに反映する運用です。特に、APIOps toolkitのエクストラクター(run-extractor.yml)をパイプラインで実行し、生成物をテンプレート用ブランチへコミットしてPRを作る流れを想定します。
| 項目 | 例 | 補足 |
|---|---|---|
| 対象サービス | Azure API Management(APIM) | API定義・ポリシー・Named Value等を構成管理する |
| 自動化 | Azure DevOps Pipelineでrun-extractor.ymlを実行 | 抽出→コミット→push→PR作成までを自動化するケースが多い |
| 問題の対象 | tags / products フォルダー | アーティファクトやテンプレートブランチには生成されるが、PR差分に表示されない |
症状:アーティファクトにはあるのにPRの差分に出てこない
現象を整理すると次のとおりです。
- パイプライン(run-extractor.yml)の実行自体は成功し、生成物がアーティファクトとして確認できる
- テンプレート用ブランチ(生成物を置くブランチ)にも、tags / products フォルダーが存在する
- しかし、テンプレート用ブランチからmain/masterなどへPRを作っても、tags / products が「変更」として差分に表示されない
この状態だと「PRに含めたいのに表示されない=何か設定が足りないのでは?」と疑いがちですが、実はAzure DevOpsのPR差分の仕組みを理解するとスッと腑に落ちます。
まず理解しておくべき:Azure DevOpsのPR差分は「ターゲットブランチとの差分」だけ
Azure DevOpsのPR画面が表示するのは、基本的に「ソースブランチ(PR元)」と「ターゲットブランチ(PR先)」の差分です。言い換えると、ターゲットブランチ側にすでに同じ内容のファイルが存在する場合、そのファイルは差分に現れません。
特に混乱が起きやすいポイントを、Gitの性質とあわせて表にまとめます。
| 状況 | Gitの扱い | PR差分に出るか | 見え方の例 |
|---|---|---|---|
| ターゲットと同一内容 | 変更なし(差分ゼロ) | 出ない | 「生成されているのにPRに出ない」ように見える |
| ファイル内容が一部でも違う | 変更あり | 出る | tags/products配下のJSONやYAMLが変更として表示される |
| フォルダーが空 | Gitは空ディレクトリを追跡しない | 出ない | フォルダーだけ作ってもPRには現れない(中にファイルが必要) |
| .gitignore等で除外 | そもそもコミットされない | 出ない | アーティファクトにはあるが、リポジトリには入っていない |
今回のケースは、アーティファクトにもテンプレートブランチにも存在していることから、空フォルダーや.gitignoreの可能性は低く、「ターゲットブランチ側にすでに同じ内容がある」が最有力になります。
根本原因:初回のPRで既に取り込まれており、以後の実行で差分が発生しなかった
結論から言うと、原因は次の2点がセットで起きていました。
- エクストラクター(APIOps)初回実行時のPRをすでにマージしており、その時点で生成されたtags/products(を含む生成物)がターゲットブランチ(main/master等)へ反映済みだった
- その後のパイプライン実行では、ターゲットブランチ側のファイル内容と、エクストラクターが出力するファイル内容に差分がなかった
これを時系列で見ると理解しやすいです。
| タイミング | ターゲットブランチ(例:main) | テンプレートブランチ(例:apiops-template) | PR差分 |
|---|---|---|---|
| 初回抽出前 | 生成物がない / 少ない | 未作成 or 空 | — |
| 初回のrun-extractor実行 | まだ生成物なし | tags/products含む生成物をコミット | 大量に出る(新規追加) |
| 初回PRをマージ | tags/products含む生成物が取り込まれる | 同じ内容 | — |
| 2回目以降のrun-extractor実行 | すでに同じ内容が存在 | 同じ内容が再生成される | 差分ゼロ(出ない) |
Azure DevOpsのPR差分は「ターゲットブランチとの差分だけ」を表示します。したがって、内容に変更がないtags/productsは「変更なし」と判断され、PRの差分に表示されません。これは不具合ではなく、GitとPRの正しい挙動です。
解決策:生成物が未反映のターゲットブランチを用意し、そこを比較対象にして再抽出する
今回の解決策は、「生成物がまだ取り込まれていないターゲットブランチ」を用意し直すことです。ターゲット側に生成物が存在しなければ、抽出結果は「新規追加」として必ず差分に現れます。
手順:ターゲットブランチを作り直し、パイプラインのPR先を切り替える
- 生成物が未反映のターゲットブランチを作成する
ここが一番重要です。すでにmain/masterへ生成物をマージ済みの場合、ただmainからブランチを切るだけでは生成物も一緒にコピーされるため、差分は出ません。次のいずれかの方法で「生成物が入っていない状態」を作ります。- 方法A:初回PRをマージする前のコミットを基点にブランチを作る
初回PRのマージコミットの直前のコミットを特定し、そのコミットから新しいブランチを作成します。Azure DevOpsのUIでも、特定コミットを選んでブランチを作成できます。 - 方法B:オーファンブランチ(履歴を引き継がない空のブランチ)を作る
生成物専用のベースラインが欲しい場合に有効です。手元で作成してpushする運用にすると、ターゲットを完全にクリーンな状態にできます。 - 方法C:新ブランチ上で生成物をいったん削除してコミットする
履歴上は残りますが、比較対象ブランチから生成物を外せるため「再追加」として差分を出したいときに使えます。運用上の意図が明確な場合のみ選びます。
- 方法A:初回PRをマージする前のコミットを基点にブランチを作る
- エクストラクター(run-extractor.yml)がPRを作る先(ターゲットブランチ)を変更する
パイプラインの変数、YAML内のブランチ指定、スクリプトのpush先など、あなたの実装に応じて変更点は異なります。ポイントは「PR先が新規ブランチになっていること」です。 - run-extractor.ymlを再実行する
新しいターゲットブランチ側には生成物がないため、tags/productsを含む全生成物が「新規追加」としてコミットされます。 - PRを作成して差分にtags/productsが出ることを確認する
差分に現れれば、やりたいこと(PRに含める)は達成です。あとは通常どおりレビューしてマージできます。
確認ポイント:本当に「差分ができた」かを手元のコマンドで見る
PR画面だけに頼ると混乱しやすいので、パイプライン内やローカルで差分を確認できると安心です。代表的な確認方法を載せます。
(例)ターゲットブランチとの差分ファイル一覧を確認
git fetch origin
git diff --name-only origin/main-apiops-reset...HEAD -- tags products
(例)tags/products配下にコミット対象が存在するかを確認
git status --porcelain
git ls-tree -r --name-only HEAD tags
git ls-tree -r --name-only HEAD products
ここでファイル一覧が出ているのにPR差分に出ない場合は、PRのターゲットブランチ指定やブランチの取り違えを疑うのが近道です。
なぜ「ターゲットブランチを作り直す」と解決するのか
今回の現象は、要するに比較の基準(ターゲットブランチ)がすでに完成形だったことが原因です。APIOpsの抽出結果が正しくても、PRが比較する相手(ターゲット)に同一内容があれば差分は出ません。
逆に言えば、「差分が出ない=生成できていない」ではありません。この誤解がいちばんの落とし穴です。生成物の有無は、アーティファクト、テンプレートブランチの実体、コミット内容で判断し、PR差分は「比較結果の見え方」と割り切ると整理しやすくなります。
再発防止の運用ヒント:APIOpsは「差分がない状態」も正常になり得る
APIOpsは、環境(APIM)の現状を抽出してGitに反映する仕組みです。APIM側に変更がなければ、抽出結果が前回と同一になるのはむしろ正常です。つまり、パイプラインが毎回何かしら差分を出すとは限らないという前提で運用設計しておくと、今回のような混乱を避けられます。
差分ゼロを「正常終了」として扱う設計にする
おすすめは、パイプライン内で差分の有無を明示し、ログに残すことです。例えば以下のように、差分がない場合はコミット・push・PR作成をスキップし、代わりに「差分なし」と出力します。
# 例:差分があるときだけコミットする(概念例)
git status --porcelain
# 出力が空なら差分なし → commitしない
これにより「PRに出ない」ではなく「そもそも差分がなかった」という事実が運用者に伝わります。
同様の事象を見たときのチェックリスト
今回のケースは「差分がなかったこと」が主因でしたが、APIOps+Azure DevOpsの構成では他にも似た症状になり得るポイントがあります。発生頻度が高い順に確認項目を整理します。
Git操作まわり(コミット・push・ブランチ名)
| チェック項目 | なぜ重要か | よくある症状 | 確認方法 |
|---|---|---|---|
| checkoutでpersistCredentialsを有効化 | パイプラインがpushするための認証が必要 | コミットは作れてもpushで失敗 / そもそもブランチが更新されない | パイプラインログでgit pushの結果を見る |
| push先ブランチ名が想定どおり | 違うブランチへpushするとPR差分が噛み合わない | テンプレートブランチを見ているつもりが更新されていない | git branch -vv / Azure DevOps上のブランチ最新コミットを確認 |
| コミット対象にtags/productsが含まれている | 生成物があってもaddされていなければ差分に出ない | アーティファクトにはあるがリポジトリに反映されない | git status と git ls-tree で確認 |
| .gitignoreで除外されていない | 無意識の除外で「存在するのに追跡されない」状態になる | 作業ディレクトリにはあるが、コミットに入らない | git check-ignore -v <file> |
権限・ブランチポリシー
Azure DevOpsでは、パイプライン実行ユーザー(Build Serviceやサービス接続)が権限不足だと、pushやPR作成が途中で止まります。止まっていないように見えても、PR作成タスクだけ失敗していることもあります。
- パイプラインが使うアカウントに「Contribute(書き込み)」権限があるか
- ブランチポリシーで特定ユーザーのpush/PR作成が制限されていないか
- スクリプトで
System.AccessTokenを使う場合、「Allow scripts to access the OAuth token」が有効か
APIOpsの設定(includeTags / includeProducts / フィルター)
今回の現象は「生成されているのに差分に出ない」でしたが、そもそもtags/productsが生成されない場合は設定側を疑います。特に次のような設定が入っていると、意図せず除外されます。
apiops.config.json等の設定で"includeTags": true/"includeProducts": trueになっているか- tags/productsを除外するフィルター(例:特定パス除外、命名規則フィルター)が入っていないか
- 「管理対象のAPIMインスタンス」が想定と一致しているか(別環境を抽出していると差分が読めない)
「差分が出ない」を最短で切り分ける診断フロー
最後に、同じ現象が起きたときに迷わないための、実務向けの診断手順をまとめます。ポイントはPR画面を見る前に、Git上の実体を確認することです。
- アーティファクトにtags/productsがあるか
なければ抽出や設定(includeTags/includeProducts)側の問題です。 - テンプレートブランチの最新コミットにtags/productsがあるか
Azure DevOpsのファイルブラウザで確認するか、次のようにコミット内容を見ます。git fetch origin git checkout apiops-template git ls-tree -r --name-only HEAD tags git ls-tree -r --name-only HEAD products - ターゲットブランチ(main/master)との差分が本当にあるか
差分が空なら、今回のケースと同じで「すでに取り込まれている」可能性が高いです。git fetch origin git diff --name-only origin/main...origin/apiops-template -- tags products - 差分があるのにPRに出ない場合は、PRの比較設定ミスを疑う
PRのソース/ターゲットブランチが意図した組み合わせになっているか、間違って別リポジトリや別ブランチを見ていないかを確認してください。
まとめ
- tags/productsがアーティファクトやテンプレートブランチに存在するのにPR差分に出ない場合、まず「ターゲットブランチ側に同じ内容がある=差分ゼロ」を疑う
- 初回PRをすでにマージしていると、以後の抽出では同一内容になりやすく、PR差分に出ないのは正常な挙動
- 確実にPRへ含めたい(新規追加として見せたい)なら、生成物未反映のターゲットブランチを用意し、そこへ向けてrun-extractorを再実行する
- あわせて、Git操作(commit/push/ブランチ名)、権限、APIOps設定(includeTags/includeProducts/フィルター)をチェックすると切り分けが早い

コメント