mcpField
D
deploy-pipeline

deploy-pipeline

github.com/microsoftクラウド・DevOps1.1k164 回インストール今日更新
リポジトリ

deploy-pipeline について

deploy-pipelineは、構成済みのPower Platform Pipelineを実行するPower Pages向けスキルです。対象ステージを選び、ソリューションパッケージを検証して対象環境へデプロイし、記録を残します。

主な機能

  1. 01デプロイ対象ステージの選択
  2. 02ソリューションパッケージの検証
  3. 03Power Platform Pipelinesによるデプロイ
  4. 04環境と認証の前提条件確認
  5. 05デプロイ情報の記録

活用シーン

  1. 01Power Pagesソリューションを別ステージへ昇格
  2. 02検証済みパッケージを対象環境へデプロイ
  3. 03デプロイ前に利用可能なステージを確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/microsoft/power-platform-skills --skill deploy-pipeline

インストール後、Claude Code で/deploy-pipelineを入力して読み込まれたか確認します。

同梱ファイルassets/deploy-history-template.htmlscripts/validate-deploy-pipeline.js

詳細

プラグインの確認:node "${PLUGIN_ROOT}/scripts/check-version.js" を実行してください。メッセージが出力された場合は、続行する前にユーザーに表示してください。

deploy-pipeline

Power Platform Pipeline のデプロイ実行を開始します。docs/alm/last-pipeline.json から既存のパイプライン構成を読み込み、対象ステージを選択し、ソリューションパッケージを検証して、対象環境にデプロイします。

前提条件:まず /power-pages:setup-pipeline を実行して、パイプライン構成を作成してください。

このスキルで使用する HAR で確認済みの API パターンについては、${PLUGIN_ROOT}/references/cicd-pipeline-patterns.md を参照してください。

前提条件

重要:ソース(開発)環境には、Power Platform Pipelines のホスト環境を構成する必要があります。これは Power Platform 管理センター(環境 → 環境を選択 → パイプライン)またはテナントレベルの DefaultCustomPipelinesHostEnvForTenant 設定で行います。この構成がない場合、pac pipeline deploy は失敗します。setup-pipeline スキルはホスト環境にパイプライン定義を作成します。この管理者による手順で、開発環境をそのホストに接続します。

  • docs/alm/last-pipeline.json が存在する(setup-pipeline によって作成されます)
  • .solution-manifest.json が存在する
  • Azure CLI にログインしている(az account show が成功する)
  • PAC CLI にログインしている(pac env who が成功する)

フェーズ

フェーズ 0 — ALM 計画のゲート

plan-alm が最初の窓口です。 ユーザーが ALM に関する意図(昇格する/出荷する/デプロイする/ステージングに移行する/本番環境にプッシュする/このバージョンをリリースする)を示した場合、オーケストレーター(/power-pages:plan-alm)を最初に実行してください。deploy-pipeline を直接呼び出すと、オーケストレーターによる事前計画の完全性チェック、ステージごとの環境変数の解決、アクティベーション手順、検証実行を回避します。このゲートにより、その回避が明示されます。

スキップ規則。 このスキルが 実行中の plan-alm オーケストレーションの一部として 呼び出された場合は、フェーズ 0 全体をスキップし、フェーズ 1 に進みます。ゲートヘルパーはこれを inExecution ブロックで示します。次の場合は何も表示せずフェーズ 1 に進んでください。

inExecution.status === "active"

ヘルパーは docs/.alm-plan-data.json の PLAN_STATUS === "In Execution" かつ LAST_INVOCATION_AT が過去 60 分以内であることから、この状態を算出します。check-alm-plan.js は、計画が実行中であることを確認するたびに LAST_INVOCATION_AT を自動更新します。そのため、チェーン内の各スキルが次のスキルのためにチェーンを維持します。デプロイに数時間かかる場合でも(deploy-pipeline 単体ではステージごとに最大 60 分かかることがあります)、チェーンが誤って実行状態ではないと判定されることなく、この時間枠内に収まります。停止したチェーン(60 分を超えてハートビートがない場合)は stale-heartbeat として再分類され、フェーズ 0 のゲートが通常どおり実行されます。これにより、放棄された計画がユーザー確認を黙って回避することを防ぎます。

inExecution.status が "active" 以外("not-running"、"stale-heartbeat"、"no-plan")の場合は、以下のフェーズ 0 のゲートフローを実行します。残りのヘルパーフィールドに応じて分岐してください。

手順 1 — ゲートヘルパーを実行します。

node "${PLUGIN_ROOT}/scripts/lib/check-alm-plan.js" \
  --projectRoot "." \
  --envUrl "{devEnvUrl}" \
  --token "{token}" \
  --solutionId "{solutionId from .solution-manifest.json, if available}"

ヘルパーは { exists, stale, staleness: { reason, detail }, generatedAt, planStatus, ... } を含む JSON を返します。最新性の確認には環境の認証情報と solutionId が必要です。これらがない場合、ヘルパーは存在確認のみを行います。

手順 2 — 結果に応じて分岐します。

結果動作
deferred: trueユーザーはこのプロジェクトでの ALM を明示的に保留しています(.alm-deferred マーカーが存在します)。何も表示せずフェーズ 1 に進み、しつこく促さないでください。
exists: falseユーザーはまだ plan-alm を実行していません。手順 3 を参照してください。
exists: true, stale: false計画は最新です。何も表示せずフェーズ 1 に進みます。
exists: true, stale: true(理由:solution-modified)計画の生成後にソリューションが変更されています。手順 4 を参照してください。

手順 3 — 計画がありません。 ユーザーに次のように伝えます。

"このプロジェクトには ALM 計画がありません。/power-pages:plan-alm はプロジェクトの状態を検出し、昇格戦略について確認したうえで、setup-solution / setup-pipeline / activate-site / test-site とともに、このスキルを適切な順序でオーケストレーションします。今すぐ plan-alm を実行しますか?" 🚦 ゲート(intent · deploy-pipeline:0.no-plan): check-alm-plan.js が exists:false を返した場合に動作するフェイルクローズ方式の開始ゲートです。ヘルパースクリプトに基づきます。

AskUserQuestion:

質問ヘッダー選択肢
先に /power-pages:plan-alm を実行しますか?ALM プランゲートはい — 今すぐ /power-pages:plan-alm を実行(推奨)、プランなしで続行(上級者向け — すぐにデプロイしたい場合)、キャンセル
  • はい(推奨) → /power-pages:plan-alm を実行します。プランを作成して戻ります。plan-alm はプランナーであり、デプロイは実行しません。その後、このスキルは Phase 0 のチェックを再実行し(この時点で exists:true)、Phase 1 に進みます。
  • プランなしで続行 → BYPASSED_PLAN_GATE = true を設定し、Phase 1 に進みます。デプロイ自体は実行されますが、環境変数のステージごとの値、アクティベーション、デプロイ後の検証はオーケストレーションされません。
  • キャンセル → 正常に終了します。

ステップ 4 — 古いプラン。 ユーザーに次のように伝えます。

"ALM プランは {generatedAt} に作成されていますが、その後 {solution.modifiedon} にソースソリューションが変更されています。プランのコンポーネント数、サイズ分析、分割の判断が古くなっている可能性があります。plan-alm を再実行すると分析が更新されます。"

🚦 ゲート(intent · deploy-pipeline:0.stale-plan): check-alm-plan.js が stale:true を返した場合に動作するフェイルクローズ方式の開始ゲートです。ヘルパースクリプトに基づきます。

AskUserQuestion:

質問ヘッダー選択肢
先にプランを更新しますか?ALM プランの鮮度更新 — /power-pages:plan-alm を再実行(推奨)、既存のプランで続行、キャンセル
  • 更新(推奨) → /power-pages:plan-alm を実行します。完了後、鮮度を確認するために Phase 0 のヘルパーをもう一度実行します。まだ古い場合は詳細を提示し、そのまま Phase 1 に進みます(無限ループにはしません)。
  • 続行 → STALE_PLAN_ACK = true を設定し、Phase 1 に進みます。
  • キャンセル → 正常に終了します。

Phase 3.5(デプロイ前の完全性チェック)との関係。 Phase 3.5(このスキルの後半)は、デプロイ直前にソリューションの不足を検出します。Phase 0 が検出するのは、より重大な見落としです。つまり、オーケストレーターを一度も実行せず、不完全なデプロイをそのままプッシュしようとしているケースです。この2つは相互に補完します。

Phase 1 — 前提条件の確認

この Phase の開始時に、すべてのタスクを作成します。

作成するタスク:

  1. 「前提条件を確認」
  2. 「対象ステージを選択」
  3. 「パイプライン情報を解決」
  4. 「パッケージを検証」 — MULTI_RUN_MODE では、スキップされていない N 個すべてのソリューションを対象とする単一の並列バッチ(Phase 3.6)になります。単一ソリューション/レガシー v2 モードでは、Phase 4 の各イテレーション内で実行されます。
  5. 「デプロイ設定を構成」
  6. 「デプロイと監視」
  7. 「デプロイ記録を作成」

手順:

  1. まずプロジェクトに設定されている環境 URL を解決し、次に PAC が実際にその環境に接続されていることを確認します。 verify-alm-prerequisites.js は PAC の 現在の組織コンテキスト(pac env who)から環境を解決しますが、これはプロジェクトと一致するとは限りません。PAC が別の環境に切り替わっている場合(有効な pac auth プロファイルの重複、または外部プロセスによるアクティブ環境の切り替え)、このスキルは気付かないまま、検出処理を実行し、後続の pac pipeline deploy も誤った環境(本番環境の可能性もあります)に対して実行します。不一致の場合は --envUrl を固定するのではなく、アサーションで確認して即時停止してください。URL を固定しても Dataverse API の呼び出しだけが修正され、後続の PAC CLI 操作は切り替わったコンテキストに従ったままです。そのため、PAC 自体が正しい環境を参照していることを確認するのが、より安全なゲートです。

    プロジェクトに記録された環境 URL を読み取ります(最初に見つかったものを使用):.solution-manifest.json → トップレベルの environmentUrl、なければ powerpages.config.json → environmentUrl。CONFIGURED_ENV_URL として保存します。(どちらのフィールドもトップレベルの environmentUrl 文字列です。SPA/EDM 以外のサイトには powerpages.config.json がないため、その場合はマニフェストを参照します。)

    CONFIGURED_ENV_URL が実際に URL に解決された場合にのみ、--expectedEnvUrl を渡します。 記録された環境 URL がある場合は最初の形式を、どちらのファイルにも記録されていない場合は2番目の形式を使用します。空または未解決の --expectedEnvUrl "{CONFIGURED_ENV_URL}" は渡さないでください。

    # CONFIGURED_ENV_URL resolved (recorded in manifest/config) — assert PAC is on it:
    node "${PLUGIN_ROOT}/scripts/lib/verify-alm-prerequisites.js" --require-manifest --expectedEnvUrl "{CONFIGURED_ENV_URL}"
    
    # Neither file records an env URL — omit the flag, fall back to the pac-context default:
    node "${PLUGIN_ROOT}/scripts/lib/verify-alm-prerequisites.js" --require-manifest
    

    --expectedEnvUrl を指定すると、ヘルパーは PAC が解決した環境(オリジンのみ)と CONFIGURED_ENV_URL を比較し、不一致の場合は 「Environment mismatch: PAC CLI is connected to {X} but this project targets {Y} — run pac env select …」 というエラーを表示して、ゼロ以外の終了コードで終了します。(安全策として、値が解析可能な環境 URL でない場合、ヘルパーは検証をスキップします。空の文字列や未置換のプレースホルダーでは処理が停止しません。ただし、記録済みの URL がない場合は、フラグ自体を省略することを推奨します。)出力を JSON として取得し、.envUrl(devEnvUrl として保存)と .token(DEV_TOKEN として保存)を抽出します。スクリプトがゼロ以外で終了した場合は、停止してエラーを提示してください。環境の不一致、または az login/pac auth/WhoAmI の失敗を示しています。

  2. detect-project-context.js を実行して、プロジェクト設定とソリューションマニフェストを読み取ります。

    node "${PLUGIN_ROOT}/scripts/lib/detect-project-context.js"
    

    出力を JSON として取得し、.solutionManifest(solutionManifest として保存)、.siteName(siteName として保存)、.websiteRecordId を抽出します。solutionManifest が null の場合は続行します。この段階ではマニフェストは必須ではありません(ソリューション情報は docs/alm/last-pipeline.json から取得します)。

  3. docs/alm/last-pipeline.json を探します。見つからない場合は停止し、最初に /power-pages:setup-pipeline を実行するよう案内します。

    マニフェストのバージョン確認:

    • schemaVersion === 3 の場合は、MULTI_RUN_MODE = true を設定し、deploymentOrder[] を DEPLOYMENT_ORDER として保存します。ステージのセットが 1 つのパイプラインに対し、order の各ソリューションについて同じステージを対象とした複数のステージ実行を行います。これが現在推奨されている構成です。
    • schemaVersion === 2(レガシー)の場合は、MULTI_PIPELINE_MODE = true を設定し、pipelines[] を PIPELINES_LIST として保存します。このスキルは、複数の deploymentpipelines レコードを順に処理する以前の動作にフォールバックします。ユーザーに setup-pipeline を再実行して v3 に移行するよう案内します。
    • それ以外の場合は、pipelineId、pipelineName、hostEnvUrl、sourceDeploymentEnvironmentId、solutionName、stages[] を読み取ります(単一ソリューションモード。既存の動作)。

    MULTI_RUN_MODE の場合: DEPLOYMENT_ORDER の各反復で、solutionName と solutionId を解決します。status === "SkippedEmpty" のエントリ(通常は {Prefix}_Future バッファ)はスキップします。ステージ実行は作成されません。単一の pipelineId/hostEnvUrl/sourceDeploymentEnvironmentId が、すべての実行に適用されます。

    MULTI_PIPELINE_MODE(レガシー v2)の場合: ループ内でパイプラインごとに solutionName を解決します(全体では解決しません)。すべてのパイプラインで同じ hostEnvUrl と sourceDeploymentEnvironmentId を使用します。

  4. ホスト環境のトークンを取得します。

    az account get-access-token --resource "{hostEnvOrigin}" --query accessToken -o tsv 2>/dev/null
    

    hostEnvOrigin は hostEnvUrl のスキームとホストです。HOST_TOKEN として保存します。取得に失敗した場合は停止し、Azure CLI の認証を確認するよう案内します。

  5. solutionManifest が利用可能な場合は、検出されたコンテキストから solutionManifest.solution.solutionId と solutionManifest.solution.uniqueName を読み取ります。それ以外の場合は、docs/alm/last-pipeline.json の solutionName を使用します。

  6. 次の内容を報告します。「パイプライン:{pipelineName}。ソリューション:{solutionName}。利用可能なステージ:{stage names}。」

フェーズ 1.5 — 現行の Pipelines デプロイメントドキュメントに基づく確認

参照:${PLUGIN_ROOT}/references/alm-docs-grounding.md

このステップは約30秒以内に完了してください。MCP の検索/取得でエラーが発生した場合は、1行のメモを記録して続行してください。このスキルはオフラインでも実行可能である必要があります。

  1. クエリ Power Platform Pipelines stage run validation ValidatePackageAsync DeployPackageAsync approval を指定して microsoft_docs_search を実行します。
  2. https://learn.microsoft.com/en-us/power-platform/alm/pipelines(およびステージ実行、検証、承認ゲートに関する関連ページを最大1ページ)を、microsoft_docs_fetch で並列に取得します。
  3. ステージ実行のライフサイクル、検証結果、承認ゲートのワークフロー、deploymentsettingsjson のオーバーライドについて、Microsoft Learn の最新の説明を1段落にまとめて抽出します。${PLUGIN_ROOT}/references/cicd-pipeline-patterns.md と比較し、相違点(新しいステータスコード、変更された stagerunstatus の終端値、新しい承認ゲート API)にフラグを立てます。
  4. この要約をフェーズ 2 以降の判断に反映します。スキルの動作を黙って変更しないでください。相違点があれば、フェーズ 4(ステージ実行の作成とパッケージの検証)の前に、ユーザーに警告として伝えてください。
フェーズ 2 — 対象ステージの選択

ユーザーが引数としてステージ名または環境ラベル(例:staging)を指定した場合は、docs/alm/last-pipeline.json のステージと照合し、この質問をスキップします。

🚦 ゲート(計画 · deploy-pipeline:2.stage): 対象ステージを選択 — Staging/Production など。ここで対象ステージを誤って選択することが、このスキルで最も大きな単一の失敗要因です。

それ以外の場合は、AskUserQuestion を使って質問します。

「どの環境にデプロイしますか? docs/alm/last-pipeline.json にあるステージの番号付きリスト。例:

  1. Staging にデプロイ → {stagingEnvUrl}
  2. Production にデプロイ → {prodEnvUrl}」

選択したステージを SELECTED_STAGE として保存します(stageId、name、targetDeploymentEnvironmentId、targetEnvironmentUrl を含む)。

設計上の理由 — デプロイループは意図的に逐次実行します。 DEPLOYMENT_ORDER に N 個のエントリ(例:2 ソリューションに分割し、将来用のバッファーを設ける場合の Core → WebAssets → Future)があるとき、ループは order の昇順で、一度に 1 つのソリューションを処理し、最初の失敗時に停止します。これは意図的な設計です。次の 4 つの制約が重なっているため、並列の DeployPackageAsync 呼び出しはメリットがないだけでなく、実害をもたらします。

  1. ターゲット環境での Dataverse インポートロック。 ImportSolutionAsync は環境レベルのロックを取得するため、環境ごとに一度にインポートできるソリューションは 1 つだけです。このスキルが N 個の DeployPackageAsync 呼び出しを並列に実行しても、ホストがキューに入れて、結局は逐次実行します。並列デプロイによる実時間の短縮は実質的にありません。
  2. 4 つの分割戦略のうち 3 つで、分割間に依存関係があります。 変更頻度(Foundation → Integration → Config → Content)、スキーマ(Domain_1..N → Site)、レイヤー(Core → WebAssets。WebAssets の ppc 行は Core の powerpagesite レコードを参照します)は、いずれも厳密な実行順序を定めています。順序を変えるとインポートに失敗します。たとえば、ターゲットにまだないテーブルを参照するフローは MissingDependency で失敗します。
  3. イテレーションごとの同意ゲート。 Phase 6.0(deploy-pipeline:6.0.final-consent)は、すべての DeployPackageAsync の実行前に発生します。Phase 5 の環境変数プロンプトも、イテレーションごとに発生します。並列実行するには、ゲートをまとめて処理する(明示的に禁止されています。下記のイテレーションごとの呼び出しに関する注意を参照)か、AskUserQuestion を同時に実行する必要がありますが、どちらもハーネスではサポートされていません。
  4. 失敗を確実に処理できます。 逐次実行と最初の失敗時の停止により、docs/alm/last-deploy.json にソリューションごとの status が明確に記録されます。再試行時にはループが最初から反復されます。Dataverse の同一バージョンに対する冪等性により、すでに反映済みのソリューションは何もせずにスキップされます。

イテレーションを Promise.all/Promise.allSettled/await Promise.race でラップして、このループを「最適化」しないでください。 検証フェーズ(Phase 3.6)は並列化されています。ValidatePackageAsync はインポートロックを取得しません。しかし、デプロイフェーズは意図的に逐次実行されます。将来の Dataverse リリースで環境レベルのインポートロックがなくなった場合は、この設計上の理由を見直してください。それまでは、これは見落としではなく、不可欠な前提です。

MULTI_RUN_MODE(v3 — 推奨)の場合: 選択されたステージは、単一の stages[] 配列から一度だけ検索されます。その後、スキルは DEPLOYMENT_ORDER を order 順に ループし、同じ stageId に対してソリューションごとに 1 つのステージ実行を作成します。

  1. 最初に Phase 3.6 を実行します(ループの前に 1 回)。スキップ対象ではない各ソリューションについて、create-stage-run + ValidatePackageAsync + poll-validation-status を並列実行します。いずれかのソリューションで検証に失敗した場合、デプロイ全体を停止します。ソリューションごとの stageRunId を VALIDATED_STAGE_RUNS に保存し、逐次デプロイループで再利用できるようにします。
  2. status !== "SkippedEmpty" を満たす DEPLOYMENT_ORDER の各エントリについて、solutionUniqueName + solutionId を解決し、VALIDATED_STAGE_RUNS[solutionUniqueName] から stageRunId を取得して、ARTIFACT_SOLUTION_NAME/ARTIFACT_SOLUTION_ID/STAGE_RUN_ID を設定します。その後、同じパイプラインに対して Phase 4.4(デプロイに関するメモを取得)→ 5(構成)→ 6.0(イテレーションごとに同意ゲートが発生)→ 6.1(デプロイ)→ 6.2(ポーリング)を実行します。Phase 4.1–4.3(ステージ実行の作成 + 検証 + 検証のポーリング)はスキップします。Phase 3.6 ですでに並列処理済みです。
  3. いずれかのイテレーションでデプロイに失敗した場合は、ループを停止し、失敗したソリューションと、すでに反映済みのソリューションを報告します。
  4. 最後に、選択されたステージのすべての実行をまとめた docs/alm/last-deploy.json を 1 つ書き込みます。ソリューションごとの status(Succeeded/Failed/NotAttempted/SkippedEmpty)と、共有の pipelineId を記録します。

⚠ 反復ごとにゲートを実行 — 例外は認められません。 ループ内では、各ソリューションに対して Phase 3 → 3.5 → 4 → 5 → 6.0 → 6.1 → 6.2 → 7 の全シーケンスを実行します。 ソリューション間で検証をまとめて実行したり、Phase 6.0 の同意ゲートをまとめて実行したりしないでください。また、上流の回答(Phase 2 のステージ選択、--stage 引数、前の反復における「今すぐデプロイ」)が後続の反復にも適用されると考えないでください。DEPLOYMENT_ORDER 内のスキップされていないソリューションが N 個ある場合、Phase 6.0 のゲートは N 回実行されます。反復 1 の成功後、新たな Phase 6.0 の確認なしに反復 2 の DeployPackageAsync へ進んでいる場合、ゲートをスキップしています。

MULTI_PIPELINE_MODE(v2 — レガシー)では: 選択したステージラベル(例:「Staging」)を各パイプラインの stages[] と照合します。同じターゲット環境でも、パイプラインごとに独自の stageId があります。以降のすべてのフェーズ(検証、デプロイ、ポーリング)は、order に従って PIPELINES_LIST をループします。

  1. ループの反復 i:ステージラベルが SELECTED_STAGE.name と一致する pipelines[i].stageId、pipelines[i].solutionName などを使用します。
  2. いずれかの反復で失敗(検証またはデプロイ)した場合は、ループを停止し、失敗したパイプラインとデプロイ済みのパイプラインを報告します。
  3. 最後に、当該ステージのすべてのパイプライン実行を要約した docs/alm/last-deploy.json を 1 つ書き込みます。パイプラインごとの status(Succeeded/Failed/NotAttempted)を記録し、再試行時にどれを実行する必要があるか判別できるようにします。

⚠ 反復ごとのゲート実行は、ここでも適用されます。 MULTI_RUN_MODE と同じルールです。ループ内の各パイプラインで、それぞれ独自の Phase 4/5/6.0/6.1/6.2 シーケンスを実行します。Phase 6.0 の同意ゲートはパイプラインごとに 1 回実行します。まとめて実行しないでください。

部分デプロイのリスク。 ループが停止した場合(例:Core は成功し、WebAssets は失敗)、すでにインポートされたソリューションは自動ロールバックされないため、ターゲット環境は混在した状態になります。docs/alm/last-deploy.json のソリューションごと(v3)またはパイプラインごと(v2)の status が、何が反映されたかを示す信頼できる情報源です。失敗を修正してユーザーが deploy-pipeline を再実行すると、ループは最初からすべての項目を再び処理します。スキップするのではなく、ソリューションインポートの冪等性(同じバージョンなら何も行わない)を利用してください。本番環境への複数ソリューションのデプロイを開始する前に、この点をユーザーに警告してください。

docs/alm/last-deploy.json を確認し、このステージへの前回のデプロイが失敗していた場合は、ユーザーに警告します。

「{stageName} への前回のデプロイのステータスは Failed でした。再試行しますか? 1. はい、再試行する/2. いいえ、キャンセルする」

Phase 2.5 — 事前確認:ターゲット環境でのブロック対象添付ファイルの確認

Power Pages の SPA ソリューションには、ほぼ必ず .js のバンドルチャンク(Vite/Rollup の出力)が Web File コンポーネントとして含まれています。ターゲット環境の blockedattachments 設定に .js が含まれている場合、ImportSolutionAsync はすべての Web ファイル書き込みを拒否します。バンドルチャンクが数千個あるサイトでは、通常、インポート開始から 50~75 分後に発生します(実例:Dev では同じ問題をすでに修正していたものの、Staging では Content ソリューションの .js ファイル 3,909 個が拒否され、インポートに失敗しました)。事後対応の Phase 7.6 ハンドラーでこれを検出し、ブロック解除と再試行を提案できますが、その時点でユーザーはすでに 1 時間を費やしています。この事前確認なら 10 秒で検出できます。

スキップ規則。 この確認は Power Pages プロジェクトのみを対象とします。powerpages.config.json に websiteRecordId がない場合(純粋なデータモデルソリューションなど、Power Pages 以外の ALM 実行)はスキップします。ユーザーの計画やマニフェストから、デプロイするソリューションに Web File の componentType が含まれないと分かる場合もスキップします(SPA プロジェクトではまれですが、バックエンドのみのソリューションではあり得ます)。

検出シグナル。 MULTI_RUN_MODE/MULTI_PIPELINE_MODE では、.solution-manifest.json を読み込み、solutions[] のいずれかのエントリで componentTypes に "Web File" が含まれているか確認します。単一ソリューションモードでは、Power Pages プロジェクトならすべて true と見なします(アンブレラソリューションに Web ファイルが含まれるため)。

手順:

  1. PAC CLI のコンテキストをターゲット環境に切り替え、fix-blocked-attachments.js が正しい環境を照会するようにします。

    pac env select --environment "{SELECTED_STAGE.targetEnvironmentUrl}"
    
  2. 現在の状態を検出するため、ヘルパーをドライランモードで実行します。

    node "${PLUGIN_ROOT}/scripts/lib/fix-blocked-attachments.js" \
      --envUrl "{SELECTED_STAGE.targetEnvironmentUrl}" \
      --extensions js,css \
      --dry-run
    
  3. 出力を JSON として取得します。wasBlocked[] を確認します。

    • wasBlocked: [] → 対象環境では、該当する拡張子はブロックされていません。PAC CLI をソース環境に戻し(pac env select --environment "{sourceEnvUrl}")、フェーズ 3 に進みます。プロンプトは表示されず、余計な通知もありません。

    🚦 ゲート(同意 · deploy-pipeline:2.5.blocked-attachments): デプロイ前チェック — 対象環境の blockedattachments セキュリティ設定を変更します(テナント全体に影響します)。PPAC から元に戻せます。スキップすると、インポートで 50~75 分が無駄になります。

    • wasBlocked: ["js"]、またはメディアに関連する他の拡張子を含む場合 → デプロイはインポートの途中で必ず失敗します。AskUserQuestion を使って直ちにユーザーに確認します(チャット内に埋もれさせないでください。フェーズ 3 への進行を必ず止めて確認する必要があります)。

      デプロイ前チェックで問題が検出されました。 対象環境 {targetEnvName} では現在、このソリューションに必要なファイル形式がブロックされています:{wasBlocked.join(', ')}。Power Pages の SPA サイトでは、.js バンドルチャンクを Web ファイルとして配置します。ブロックを解除せずに進めると、デプロイは約 50~75 分実行された後に失敗します(フェーズ 7.6 の再試行手順で復旧できますが、費やした時間は戻りません)。ブロックは 10 秒で解除できます。

      注: これは環境レベルのセキュリティ設定を変更するもので、{targetEnvName} の全ユーザーに影響します。PPAC → Environments → {targetEnvName} → Settings → Product → Features → Blocked Attachments から元に戻せます。

      質問ヘッダー選択肢
      デプロイを続行できるように、{targetEnvName} 環境で {wasBlocked.join(', ')} のブロック解除を許可しますか?添付ファイルのブロック解除はい — これらの形式のブロックを解除して続行する、いいえ — そのまま続行する(フェーズ 7.6 でデプロイ後に失敗を検出して再度確認します)、デプロイをキャンセルする
  4. 回答に応じて分岐します。

    • はい — ブロックを解除して続行:--dry-run を付けずに fix-blocked-attachments.js を実行します(同じ --extensions を使用)。結果を読み取り、changed: true であり、removed[] が空でないことを確認します。PAC CLI をソース環境に戻し(pac env select --environment "{sourceEnvUrl}")、フェーズ 3 に進みます。デプロイの概要に監査記録を残せるよう、ブロック解除の操作を、最終的に作成する docs/alm/last-deploy.json の preflightActions[] ブロックに記録します。

    • いいえ — そのまま続行:設定は変更しません。PAC CLI をソース環境に戻します。フェーズ 3 に進みます。ユーザーに次の内容を明確に伝えます:「ブロックを解除せずに続行します。デプロイが AttachmentBlocked で失敗した場合、フェーズ 7.6 で同じブロック解除の確認が表示されますが、そこに到達するまでに約 50~75 分かかります。」

    • デプロイをキャンセル:問題が起きないように停止します。環境設定は変更しません。ステージ実行も作成しません。準備ができたときの再実行方法をユーザーに伝えます。

  5. このフェーズを終了する前に、必ず PAC CLI をソース環境に戻します。後続のフェーズでは、対象環境に明示的に切り替える場合を除き、PAC はソース環境を指しているものとします。

デプロイ前チェックと事後対応の両方がある理由。 事後対応のフェーズ 7.6 ハンドラーを残す理由は、(a)デプロイ前チェックでは環境レベルの blockedattachments 設定のみを確認し、テーブルごとのファイル列の添付ファイルポリシーなど、実際のインポート中に初めて判明するまれなブロック原因がほかにもあること、(b)デプロイ前チェックからインポートまでの間に環境のブロックリストが変更される可能性があること(まれですが、別の管理者が同時に編集すれば起こり得ます)、(c)ユーザーが deploy-pipeline を直接実行し、従来の SKILL.md によりフェーズ 2.5 をスキップした既存のフローとの後方互換性を保つことです。この 2 つの経路は相互補完するものであり、重複ではありません。

Phase 3 — パイプライン情報の解決

RetrieveDeploymentPipelineInfo を呼び出して、信頼できるソース環境 ID と利用可能なソリューション成果物を取得します。

GET {hostEnvUrl}/api/data/v9.1/RetrieveDeploymentPipelineInfo(DeploymentPipelineId={pipelineId},SourceEnvironmentId='{BAP_SOURCE_ENV_ID}',ArtifactName='{solutionName}')
Authorization: Bearer {HOST_TOKEN}
OData-MaxVersion: 4.0
OData-Version: 4.0
Accept: application/json

ここで、BAP_SOURCE_ENV_ID は開発環境の BAP GUID です(pac env list から取得し、docs/alm/last-pipeline.json に保存されているか、pac env who で確認できます)。

次の情報を抽出します。

  • SourceDeploymentEnvironmentId — ステージ実行時の devdeploymentenvironment バインディングとして使用します。sourceDeploymentEnvironmentId として保存します。
  • StageRunsDetails[].DeploymentStage — 利用可能なステージとその ID を確認します。
  • EnableAIDeploymentNotes — AI_NOTES_ENABLED(bool)として保存します。

.solution-manifest.json の solutionId を ARTIFACT_SOLUTION_ID として、uniqueName を ARTIFACT_SOLUTION_NAME として使用します。

RetrieveDeploymentPipelineInfo が 404 を返す場合(古い Pipelines パッケージの場合):ナビゲーションプロパティを使用して、ソースのデプロイ環境を特定します。

GET {hostEnvUrl}/api/data/v9.1/deploymentpipelines({pipelineId})/deploymentpipeline_deploymentenvironment?$select=deploymentenvironmentid,name,environmenttype

environmenttype = 200000000 でフィルターして、ソースレコードを取得します。deploymentenvironmentid を sourceDeploymentEnvironmentId として使用します。成果物/ソリューションの一覧については、フォールバックとして docs/alm/last-pipeline.json の sourceDeploymentEnvironmentId と .solution-manifest.json の solutionName を使用します。フラグ VALIDATE_PACKAGE_UNAVAILABLE = true を設定して Phase 4.2–4.3 をスキップし、Phase 6 の PAC CLI パスを使用します。

RetrieveDeploymentPipelineInfo が 404 以外のエラー(例:400/4xx/5xx)を返す場合 — 観測例:ValidatePackageAsync は問題なく動作するのに、一部の Pipelines パッケージではこの呼び出しが 400 を返します — VALIDATE_PACKAGE_UNAVAILABLE を設定しては いけません。上記の 404 分岐は、OData 検証 API がない古いパッケージ専用です。400 は、このメタデータ呼び出しが失敗しただけであり、検証 API が存在しないという意味ではありません。代わりに、フォールバックとして docs/alm/last-pipeline.json の sourceDeploymentEnvironmentId(および .solution-manifest.json の solutionName)を使用し、通常の ValidatePackageAsync フロー(Phase 4 以降)を続行します。docs/alm/last-pipeline.json に sourceDeploymentEnvironmentId がない場合は、上記 404 分岐と同じ deploymentpipeline_deploymentenvironment ナビゲーションプロパティの GET を使用して値を取得します(この場合も VALIDATE_PACKAGE_UNAVAILABLE は設定しません)。PAC CLI パスに移るのは、本当の 404、または後続の ValidatePackageAsync の 404(Phase 4.2)が発生した場合のみです。

Phase 3.5 — デプロイ前の完全性チェック

パイプラインの ValidatePackageAsync は、ソリューション ZIP をターゲットにインポートできることを確認しますが、ソリューション ZIP 自体がソースサイトに存在するすべてのコンポーネントを網羅しているかどうかは確認しません。前回 setup-solution を実行した後に追加されたコンポーネント(サーバーロジック、クラウドフロー、ボット、環境変数など)は、気付かれないまま取り残される可能性があります。

共有サイトインベントリヘルパーをソース(開発)環境に対して実行します。

node "${PLUGIN_ROOT}/scripts/lib/discover-site-components.js" \
  --envUrl "{devEnvUrl}" --token "{DEV_TOKEN}" \
  --siteId "{websiteRecordId from .solution-manifest.json}" \
  --publisherPrefix "{publisherPrefix from .solution-manifest.json}" \
  --solutionId "{solutionId from .solution-manifest.json}" \
  --projectRoot "."

標準出力を解析し、missing.* を評価します。ほかの作業を始める前に、同期後の再確認ゲートで変更点を示せるよう、同期前の状態を記録します。

PRE_SYNC_VERSION = solutionManifest.solution.version   // from .solution-manifest.json read in Phase 1
PRE_SYNC_MISSING = { siteComponents, siteLanguages, cloudFlows, envVarDefinitions, customTables, ... }   // from the discovery stdout above

次に、以下のとおり処理します。

  • すべての missing.* が空 → Phase 4 に進みます。

🚦 ゲート(進捗 · deploy-pipeline:3.5.completeness): ソースソリューションが稼働中のサイトに対して不完全です。先に同期する、ギャップを残したままデプロイする、またはキャンセルしてください。

  • 空でない missing.* がある → 簡単な概要(「ソリューションに不足しているコンポーネントが {N} 個あります」)を報告します。AskUserQuestion で次のように確認します。

    「ソースソリューションは稼働中のサイトに対して不完全なようです。どうしますか?

    1. 今すぐ /power-pages:setup-solution を実行する(同期モード)— 不足しているコンポーネントを取り込み、バージョンを上げてから、デプロイ前にもう一度確認します(推奨)
    2. このままデプロイする — 不足しているコンポーネントはターゲットに反映されません
    3. キャンセルする — 先に調査します」
    • オプション 1 — 先に同期し、デプロイ前に再確認する:

      1. /power-pages:setup-solution を実行します(既存のマニフェストを自動検出し、同期モードに入り、不足しているコンポーネントを取り込み、バージョンを上げます)。完了するまで待ちます。setup-solution の最後の更新ステップでは、docs/.alm-plan-data.json に LAST_SYNC_AT が書き込まれます。これにより、同期で solutions.modifiedon が GENERATED_AT より後になったという理由だけで、後続の check-alm-plan.js の呼び出しがプランを古いと誤判定することはありません。鮮度の基準は max(GENERATED_AT, LAST_SYNC_AT) になります。
      2. .solution-manifest.json を再度読み込み、POST_SYNC_VERSION = solutionManifest.solution.version を取得します。
      3. 検出ヘルパーを再実行します。missing.* に空でない項目が残っている場合は、上記の Phase 3.5 のプロンプトを繰り返します。
      4. それ以外の場合は、PRE_SYNC_MISSING と 2 回目の検出実行における missing.* のカテゴリごとの差集合として NEWLY_ADOPTED を計算します(消えた項目は、setup-solution がソリューションに取り込んだものです)。合計数は、すべてのカテゴリの項目数の合計です。

      🚦 ゲート(進行状況 · deploy-pipeline:3.5.post-sync): 同期後の再確認。ソリューションのバージョンが上がり、コンポーネントが取り込まれたため、デプロイの続行前にユーザーが差分を確認します。

      1. Phase 4 に進む前に、ユーザーに再確認します — これからデプロイするソリューションは、ユーザーがデプロイを開始したときに最初に確認したものとは異なります。AskUserQuestion を使用します。

        「同期が完了しました。

        {solutionUniqueName} は v{POST_SYNC_VERSION} になりました(以前は v{PRE_SYNC_VERSION})。{NEWLY_ADOPTED.total} 個のコンポーネントが新たに取り込まれました:

        • {カテゴリ別にシグナルの強いものを優先して、最初の 3~5 件の名前を表示:クラウドフロー、サーバーロジック、環境変数定義、サイトコンポーネントの順}
        • {残りがある場合:+ {N} 件(カテゴリ一覧)}

        この更新済みソリューションを {SELECTED_STAGE.name}({targetEnvUrl})にデプロイしようとしています。

        デプロイを続行しますか?」

        質問ヘッダー選択肢
        デプロイを続行しますか?同期後の承認はい — v{POST_SYNC_VERSION} を {SELECTED_STAGE.name} にデプロイする(推奨)、一時停止 — まず新しいソリューションの内容を確認する、キャンセル — デプロイを中止する
        • はい → 同期後のソリューションで Phase 4 に進みます。
        • 一時停止 → デプロイパイプラインを正常に終了し、短いメモ(「同期後に一時停止しました。v{POST_SYNC_VERSION} を {SELECTED_STAGE.name} にリリースする準備ができたら、/power-pages:deploy-pipeline を再実行してください。」)を表示します。ユーザーは同期済みのマニフェスト/Dataverse の状態を確認し、手動で再開できます。docs/alm/last-deploy.json は書き込みません — デプロイは行われていません。スキルトラッキングの呼び出しもスキップします。
        • キャンセル → スキルを停止します。同じく、マーカーもトラッキングも行わないルールが適用されます。
    • オプション 2 — 監査証跡を保持するため、意図的な差分を docs/alm/last-deploy.json の knownGaps フィールドに記録します。

    • オプション 3 — 停止します。

同期後ゲートがある理由:このスキルは、ソリューションをステージングまたは本番環境に昇格するためのゲートです。ステージングへの昇格時は、予期しない問題を見つける最後の機会です。デプロイの途中で同期モードを実行すると、ユーザーがスキルを実行したときに想定していたものとは異なるバージョンのソリューションが生成されます。同期後に再確認することで、ユーザーはバージョンの変更と新たに取り込まれたコンポーネントの一覧を確認してから、ターゲット環境に反映できます。Phase 3.5 のトリガーは意図的なものであり、同期後の再確認はそれに加わる安全策です。このスキルを plan-alm のオーケストレーションから呼び出す場合も、同じ原則が適用されます。plan-alm のプラン承認(Phase 4)は同期前の状態を対象とし、このゲートはデプロイ途中の同期による差分を対象とします。

そもそも Phase 3.5 がある理由:AGENTS.md の ALM をデフォルトで考慮するルールでは、ソリューションがソース環境を離れるすべてのゲートで完全性を確認することが求められています。

Phase 3.6 — 並列検証バッチ(MULTI_RUN_MODE の場合のみ)

MULTI_RUN_MODE = false の場合は、このフェーズ全体をスキップしてください(単一ソリューションモード、またはレガシーの MULTI_PIPELINE_MODE v2)。単一ソリューションモードと v2 では、どちらも以下のフェーズ 4 でステージ実行をちょうど 1 つ作成して検証します。並列化するものはありません。フェーズ 4 から再開してください。

このフェーズでは、ソリューションごとの create-stage-run → ValidatePackageAsync → poll-validation-status チェーンを、N 個すべてのソリューションを同時に実行することで短縮します。ValidatePackageAsync は、DeployPackageAsync の実行を直列に固定する環境レベルのインポートロックを取得しません。これはソリューションパッケージとステージ実行ごとの状態に対する構造チェックであるため、プラットフォームは N 件の検証を並行して処理できます。一般的な 5 ソリューションへの分割で、各検証に 60~180 秒かかる場合、この方法により検証フェーズを N × ~120s(約 10 分)から、最も遅い単一の検証と同程度(約 3 分)まで短縮できます。

デプロイフェーズ(6.1/6.2)は引き続き厳密に直列で実行します。フェーズ 2 の 設計上の理由 の注記を参照してください。

3.6.1 入力ファイルを作成します。

DEPLOYMENT_ORDER をフィルタリングし、検証が必要な項目に絞り込みます。

  • 含める:status !== "SkippedEmpty" かつ isFutureBuffer !== true の項目。
  • 除外する:SkippedEmpty と isFutureBuffer: true の項目。Future バッファーはコンポーネント数 0 の予約済みプレースホルダーであり、検証するものがありません。

残りの各項目の solutionId がデプロイ順の項目にまだ設定されていない場合は、.solution-manifest.json(schemaVersion: 2 の solutions[])から解決します。tmp ファイルに書き込みます。

node -e "require('fs').writeFileSync('./docs/alm/.validation-batch.json', JSON.stringify({{VALIDATION_SPECS}}))"

{{VALIDATION_SPECS}} は、配列 [{ solutionUniqueName, solutionId }, …] です。

3.6.2 バッチバリデーターを実行します。

node "${PLUGIN_ROOT}/scripts/lib/validate-stage-runs-batch.js" \
  --hostEnvUrl "{hostEnvUrl}" \
  --token "{HOST_TOKEN}" \
  --pipelineId "{pipelineId}" \
  --stageId "{SELECTED_STAGE.stageId}" \
  --sourceDeploymentEnvironmentId "{sourceDeploymentEnvironmentId}" \
  --solutionsFile ./docs/alm/.validation-batch.json

標準出力を JSON として取得します:const batch = JSON.parse(output)。tmp ファイル(./docs/alm/.validation-batch.json)を削除します(このファイルは一時的なものです)。batch.results から VALIDATED_STAGE_RUNS = { [solutionUniqueName]: { stageRunId, validationResults } } を作成します。

VALIDATE_PACKAGE_UNAVAILABLE が伝播した場合(ソリューションごとの error のいずれかが ValidatePackageAsync not available on this Pipelines package に一致する場合):グローバルに VALIDATE_PACKAGE_UNAVAILABLE = true を設定し、フェーズ 3.6 の残りをスキップして、フェーズ 4 に単一ソリューションへのフォールバック形式で進みます。これまでに作成されたステージ実行は残りますが、検証済みで未デプロイのレコードなので問題ありません。この形式では、各反復がフェーズ 6 の pac pipeline deploy CLI フォールバックを経由します。これは、以前のバージョンの Pipelines パッケージで使用されるものと同じコードパスです。

3.6.3 バッチの結果に応じて分岐します。

batch.allPassedbatch.pendingApprovalbatch.failed + batch.timedOut動作
true00すべての検証に合格しました。1 行で報告します:「{N} 個のソリューションを並行して検証しました。すべて合格しました。」 フェーズ 4 に進みます。
false> 001 つ以上の検証が承認待ちです。以下の 3.6.4(承認待ちのバッチ処理) を参照してください。
false—> 01 つ以上の検証が失敗またはタイムアウトしました。以下の 3.6.5(バッチ検証失敗時の停止) を参照してください。

3.6.4 承認待ちのバッチ処理。

🚦 ゲート(一時停止 · deploy-pipeline:3.6.batch-pending-approval): 外部待機 — 並行検証中に 1 つ以上のソリューションが stagerunstatus=200000005(承認待ち)になりました。ユーザーが PPAC ですべてを承認した後、再ポーリングします。キャンセルすると、ホスト上に N 個の検証済み・承認待ちのステージ実行が残ります(ユーザーは後で承認して再実行するか、PPAC でキャンセルできます)。保留中のソリューションごとではなく、バッチごとに 1 回実行されます。

影響を受けるソリューションを、ソリューションごとではなく 1 つのメッセージで提示し、一時停止します。AskUserQuestion を使用します。

{batch.total} 個のソリューションのうち {batch.pendingApproval} 個の検証は、完了前の承認待ちです: {status === 'PendingApproval' である result.solutionUniqueName の箇条書きリスト}

Power Platform でそれらをすべて承認してください:make.powerapps.com → Solutions → Pipelines → 上記の各ステージ実行 → Approve。その後、ここに戻ってください。

残りの {batch.succeeded} 個のソリューションはすでに正常に検証されています — 承認後にデプロイされます。"

質問ヘッダー選択肢
承認は完了しましたか?バッチ検証の承認はい — すべて承認しました。再ポーリングする、いいえ — デプロイをキャンセルする
  • はい:--rePoll モードで validate-stage-runs-batch.js を再実行します。このヘルパーは既存のステージ実行 ID を受け取り、create-stage-run と ValidatePackageAsync の呼び出しをスキップします — 各 stageRunId に対してポーリングとプローブのパターンを実行するだけです。ユーザーの承認後、ステージ実行は 200000005 (PendingApproval) → 200000006 (Validating) → 200000007 (ValidationSucceeded) と遷移します。ヘルパーのプローブは「まだ承認待ち」(ユーザーが早まって「はい」をクリックした場合)と「実際のタイムアウト」を正しく区別するため、エージェントが一般的なタイムアウトエラーを解釈する必要はありません。

    以前保留中だったエントリのみを含む tmp ファイルを作成します(元のバッチ結果から stageRunId を引き継ぎます):

    node -e "require('fs').writeFileSync('./docs/alm/.repoll-batch.json', JSON.stringify({{PENDING_SPECS_WITH_STAGERUNIDS}}))"
    node "${PLUGIN_ROOT}/scripts/lib/validate-stage-runs-batch.js" \
      --hostEnvUrl "{hostEnvUrl}" \
      --token "{HOST_TOKEN}" \
      --rePoll \
      --solutionsFile ./docs/alm/.repoll-batch.json
    

    {{PENDING_SPECS_WITH_STAGERUNIDS}} は、元のバッチから status === 'PendingApproval' のエントリに絞り込んだ [{ solutionUniqueName, solutionId, stageRunId }, …] 配列です。

    stdout を JSON として取得し、tmp ファイル(./docs/alm/.repoll-batch.json)を削除します。更新された結果を solutionUniqueName をキーにして VALIDATED_STAGE_RUNS にマージします。その後、rePoll バッチの集計結果に基づいて分岐します。

    • すべて成功 → 検証済みステージ実行の完全なセットを使ってフェーズ 4 に進みます。
    • 1 件以上が引き続き PendingApproval → 同じゲートを再度表示します(承認が反映されていなかったため、ユーザーに「PPAC で承認してから再ポーリングする」プロンプトを改めて表示します)。すべてが承認されるか、ユーザーがキャンセルするまで繰り返します。
    • 1 件以上が Failed / Timeout / Error → 3.6.5 に進みます(バッチ検証の失敗として扱います)。
  • いいえ:正常に停止します。検証済みおよび保留中のステージ実行はホスト上に残ります。スキルを再実行すると、続きから再開できます(ユーザーは承認して再実行できます)。

3.6.5 バッチ検証失敗時に停止する。

🚦 ゲート(計画 · deploy-pipeline:3.6.batch-validation-failed): 並列バッチで 1 つ以上のソリューションの検証に失敗しました。失敗したエントリのソリューションごとの validationResults を提示し、デプロイ全体を中止するか、成功したソリューションのみで続行するか(上級者向け — ターゲットに既知の依存関係の欠落が生じます)をユーザーに選択してもらいます。キャンセルすると、検証済みのステージ実行 N 件がホスト上に残ります。ユーザーは PPAC でクリーンアップするか、ソースを修正してから再実行できます。

失敗したエントリと validationResults を提示します(これは Dataverse の validationresults フィールドにある二重エンコードされた JSON 文字列です — 表示時に JSON.parse を 2 回実行して SolutionValidationResults[].Message を取り出します)。AskUserQuestion を使用します。

{batch.total} 個のソリューションのうち {batch.failed + batch.timedOut} 個が並列検証に失敗しました:

{失敗した各結果について:solutionUniqueName、status、validationResults の先頭の Message を含む短いブロック}

残りの {batch.succeeded} 個のソリューションは検証に合格し、デプロイ可能な検証済みステージ実行があります。成功したものだけをデプロイすると、ターゲットに依存関係の欠落が生じるリスクがあります。たとえば、前提となる _Foundation なしで _Content を出荷すると、サイトの動作が壊れます。推奨:中止し、ソースを修正してから再実行してください。

どのようにしますか?"

質問ヘッダー選択肢
次のステップは?バッチ検証に失敗しましたデプロイ全体を中止する(推奨)、成功したものだけをデプロイする(上級者向け — 欠落を許容する)、キャンセルして調査する
  • 中止/キャンセル:正常に停止します。失敗したソリューションごとに status: "ValidationFailed"、残りには status: "NotAttempted" を設定した最小限の docs/alm/last-deploy.json を書き込み、次回の実行で何が起きたか確認できるようにします。DeployPackageAsync は呼び出さないでください。
  • 成功したサブセットのみをデプロイ:DEPLOY_SUBSET_ACK = true を設定し、DEPLOYMENT_ORDER を VALIDATED_STAGE_RUNS 内で status === 'Succeeded' のエントリーのみに絞り込みます。スキップしたエントリーを docs/alm/last-deploy.json の knownGaps に記録します。Phase 4 に進みます。このオプションをデフォルトとして提示しないでください — リスクの高い選択肢であり、常に中止することが推奨されます。

3.6.6 バッチの概要を永続化します。

Phase 7 で docs/alm/last-deploy.json に書き込まれるインメモリ状態に、batchValidation オブジェクトを追加します。ほとんどのフィールドは、validate-stage-runs-batch.js が返す batch JSON から直接取得します。

{
  "totalSolutions": <batch.total>,
  "succeeded": <batch.succeeded>,
  "failed": <batch.failed>,
  "pendingApproval": <batch.pendingApproval>,
  "timedOut": <batch.timedOut>,
  "elapsedSeconds": <batch.elapsedSeconds>,
  "perSolutionStageRunIds": { "<solutionUniqueName>": "<stageRunId>", ... }
}

batch.results をリデュースして、stageRunId が null でないすべてのエントリーについて { [r.solutionUniqueName]: r.stageRunId } を含む perSolutionStageRunIds を作成します(失敗したもののステージ実行が作成されたエントリーも含めます — デバッグ用に PPAC へのディープリンクを保持します)。elapsedSeconds はヘルパーから直接取得します(ファンアウトの経過時間は内部で計測されるため、bash の呼び出しをタイマーで囲む必要はありません)。

これにより、次回の実行(および監査で利用するあらゆる処理)に、直列デプロイの結果とは別に、並列検証の結果を記録できます。refresh-alm-plan-data.js の deploy-pipeline フェーズは、このブロックを planData.pipelineMeta.lastDeploy.batchValidation に取り込み、レンダリングされた ALM プランに並列検証の所要時間を表示できるようにします。

Phase 4 — ステージ実行の作成とパッケージの検証

MULTI_RUN_MODE では、Phase 3.6 ですでに現在のイテレーションのソリューションのステージ実行を作成し、兄弟ソリューションと並行して検証を実行しています。 イテレーションごとのループ内では、Steps 4.1~4.3 をすべてスキップします。VALIDATED_STAGE_RUNS[solutionUniqueName].stageRunId から STAGE_RUN_ID を取得し、同じレコードから validationResults を取得します。Step 4.4(デプロイノートの取得)に直接進み、その後 Phase 5 に進みます。

単一ソリューションモードおよび従来の MULTI_PIPELINE_MODE(v2)では、以下の説明に従って Steps 4.1~4.4 をインラインで実行します。

Dataverse の呼び出しには、すべて Node.js の https モジュールを使用してください(Windows では curl のエンコーディングに問題があります)。

4.1 create-stage-run.js を使用してステージ実行を作成します:

node "${PLUGIN_ROOT}/scripts/lib/create-stage-run.js" \
  --hostEnvUrl "{hostEnvUrl}" \
  --token "{HOST_TOKEN}" \
  --pipelineId "{pipelineId}" \
  --stageId "{SELECTED_STAGE.stageId}" \
  --sourceDeploymentEnvironmentId "{sourceDeploymentEnvironmentId}" \
  --solutionId "{ARTIFACT_SOLUTION_ID}" \
  --artifactName "{ARTIFACT_SOLUTION_NAME}"

標準出力を JSON として取得します:const result = JSON.parse(output)。result.stageRunId を抽出し、STAGE_RUN_ID として保存します。

スクリプトがゼロ以外の値で終了した場合は、エラーを表示します。パイプラインの設定問題(400)または競合(409)の可能性が高く、どちらの場合もメッセージに Dataverse のエラーボディが含まれます。

フィールドバインディングに関する注意:このスクリプトは v9.2 API と msdyn_ プレフィックス付きのナビゲーションプロパティ([email protected]、[email protected]、[email protected])を使用します。これらは現在の Pipelines パッケージで HAR により確認された名前です。以前のパッケージバージョンでは異なるフィールド名(例:deploymentstageid)が使用されていました。このスクリプトは、201(JSON ボディ)と 204(OData-EntityId ヘッダー)の両方のレスポンスコードに対応しています。

STAGE_RUN_ID として保存します。

4.2 パッケージの検証をトリガーします(204 を返します — 200 ではありません):

POST {hostEnvUrl}/api/data/v9.0/ValidatePackageAsync
Content-Type: application/json
Authorization: Bearer {HOST_TOKEN}

{"StageRunId": "{STAGE_RUN_ID}"}

HTTP 204 を成功として扱います。

ValidatePackageAsync が 404 を返す場合:この Pipelines パッケージのバージョンは、直接の OData 検証 API をサポートしていません。VALIDATE_PACKAGE_UNAVAILABLE = true を設定します。Phase 4.2~4.3 をスキップして、Phase 5(デプロイ設定)に直接進み、その後 Phase 6 で pac pipeline deploy の CLI フォールバックを使用します。

4.3 poll-validation-status.js を使用して検証をポーリングします:

node "${PLUGIN_ROOT}/scripts/lib/poll-validation-status.js" \
  --hostEnvUrl "{hostEnvUrl}" \
  --token "{HOST_TOKEN}" \
  --stageRunId "{STAGE_RUN_ID}" \
  --intervalMs 5000 \
  --maxAttempts 36

標準出力を JSON として取得します:const result = JSON.parse(output)。ゼロ以外の値で終了した場合、エラーメッセージに検証失敗の詳細またはタイムアウトメッセージが含まれます。 スクリプトは、ステージ実行レコードの msdyn_operation をポーリングします。値が 200000201 の間は検証が進行中です。値が変わると、スクリプトは msdyn_stagerunstatus を確認します。値が 200000003(失敗)の場合は msdyn_validationresults を含む例外をスローし、それ以外の場合は { stageRunId, validationResults, stageRunStatus } を返します。

検証の終了値:

  • stageRunStatus 200000007(検証成功)→ フェーズ 5 に進みます
  • 200000003(失敗)の場合はスクリプトが例外をスローします — 停止し、エラーメッセージの validationresults を表示します
  • タイムアウト時はスクリプトが例外をスローします — メッセージを表示して停止します

重要:validationresults は 二重エンコードされた JSON 文字列です。オブジェクトを取得するには、JSON.parse() を 2 回呼び出してください。オブジェクトの形状は { ValidationStatus, SolutionValidationResults: [{ SolutionValidationResultType, Message, ErrorCode }], SolutionDetails, MissingDependencies } です。

SolutionValidationResults の項目はすべて警告としてユーザーに提示してください。特に次の点に注意してください。

  • ErrorCode: -2147188672 — マネージド/アンマネージドの競合:「このパッケージはマネージドですが、ソリューションはすでにアンマネージドとしてインストールされています。」ユーザーは対象環境から既存のソリューションを先にアンインストールしてから、再試行する必要があります。
  • 接続参照の不足や環境変数の不足

🚦 ゲート(停止 · deploy-pipeline:4.pending-approval): 外部待機 — PP Pipelines の stagerunstatus=200000005(承認待ち)。ユーザーは PPAC で承認する必要があります。キャンセルしても、ホスト上では実行が保留状態のままになります。MULTI_RUN_MODE / MULTI_PIPELINE_MODE では、このゲートはスキルの呼び出しごとに 1 回ではなく、承認待ちになったループの反復ごとに発生します。

stageRunStatus = 200000005(承認待ち)の場合:ユーザーに Power Platform(make.powerapps.com → Solutions → Pipelines → この実行を探す → Approve)で承認する必要があることを伝えてください。AskUserQuestion を使って次のように尋ねてください:「検証を承認しましたか? 1. はい、続行する / 2. いいえ、キャンセルする」

4.4 AI 生成のデプロイメモを取得する(AI_NOTES_ENABLED = true の場合):

GET {hostEnvUrl}/api/data/v9.0/deploymentstageruns({STAGE_RUN_ID})?$select=aigenerateddeploymentnotes,deploymentstagerunid
Authorization: Bearer {HOST_TOKEN}

aigenerateddeploymentnotes を AI_DEPLOY_NOTES として保存します。

フェーズ 5 — デプロイ設定を構成する

5.0a deployment-settings.json を確認する:

プロジェクトのルートに deployment-settings.json が存在するか確認します。

  • 存在する場合:読み込み、構成済みのステージ数と環境変数の数の概要を表示します。「既存の deployment-settings.json が見つかりました。{N} 個のステージが構成されています。」と伝えます。(トップレベルのキーをステージ名として数え、各ステージの EnvironmentVariables エントリを数えます。)

  • 存在せず、ソリューションマニフェストに環境変数の定義がある場合(利用可能であれば solutionManifest.envVars[] から、または 5.1 のクエリから):テンプレートファイルを生成し、ユーザーに伝えます。テンプレートの構造:

    {
      "{stageName}": {
        "EnvironmentVariables": [
          { "SchemaName": "{envVarSchemaName}", "Value": "" }
        ],
        "ConnectionReferences": []
      }
    }
    

    SELECTED_STAGE.name のステージ名と、.solution-manifest.json(利用可能な場合)または 5.1 のクエリから取得した環境変数のスキーマ名を使用します。プロジェクトのルートに deployment-settings.json を書き込みます。「deployment-settings.json のテンプレートを生成しました。デプロイ前に値を入力するか、プロンプトが表示されたときに値を指定してください。」と伝えます。

    注:この時点(5.0a)は 5.1 より前に実行されるため、まだ環境変数が不明な場合は、5.1 の完了後に環境変数が判明してからテンプレートファイルを生成し、5.1 のプロンプトに進む前にユーザーに伝えてください。

  • 存在せず、ソリューションに環境変数もない場合:「環境変数の上書きは不要です」と記録して、スキップします。

5.0b ファイルパスを提示する:

作成直後か既存かにかかわらず、ユーザーが場所を確認できるよう、解決済みのパス {projectRoot}/deployment-settings.json を必ず表示します。

5.1 ソリューション内の環境変数の定義を検出し、ステージごとの値を解決する:

ソース環境でソリューションコンポーネントをクエリし、すべての環境変数の定義(componenttype 380)を検索します。

GET {sourceEnvUrl}/api/data/v9.2/solutioncomponents?$filter=_solutionid_value eq '{solutionId}' and componenttype eq 380&$select=objectid
Authorization: Bearer {SOURCE_TOKEN}

各 objectid について、スキーマ名を取得します。

GET {sourceEnvUrl}/api/data/v9.2/environmentvariabledefinitions({objectid})?$select=schemaname,displayname,type,defaultvalue

これにより、対象に移行する環境変数の一覧 SOLUTION_ENV_VARS が得られます。 deployment-settings.json を読み取る(プロジェクトルートに存在する場合)、選択したステージ名を検索して、事前構成済みの値を取得します。

const stageSettings = deploymentSettings?.stages?.[selectedStageName] || {};
const preconfigured = stageSettings.EnvironmentVariables || []; // [{ SchemaName, Value }]

未構成の環境変数を特定する — SOLUTION_ENV_VARS のうち、preconfigured にエントリがないものです。

const unconfigured = SOLUTION_ENV_VARS.filter(v =>
  !preconfigured.find(p => p.SchemaName === v.schemaname)
);

🚦 ゲート(plan · deploy-pipeline:5.env-vars): ステージごとの未構成環境変数 — ユーザーが値を指定するか、スキップします(デフォルトを使用)。値がない場合、実行時はデフォルトを読み取りますが、これは開発専用である可能性があります。MULTI_RUN_MODE / MULTI_PIPELINE_MODE では、このゲートは未構成の環境変数を持つループの各イテレーションで発火します — イテレーション 1 で指定した値はイテレーション 2 には引き継がれません。

未構成の環境変数がある場合、AskUserQuestion を介してユーザーに提示します。

「このソリューションには {stageName} に対して値が構成されていない {N} 個の環境変数があります。それぞれの値を入力してください(デフォルトを使用する場合は空欄のままにし、該当しない場合はスキップしてください):

  1. {schemaname} ({displayname}) — デフォルト: {defaultvalue ?? 'none'}
  2. ...」

回答を収集し、preconfigured とマージして最終的な ENV_VAR_OVERRIDES 配列を形成します。今後の実行のために、値を deployment-settings.json に保存することを提案します。

「これらの値を {stageName} への今後のデプロイのために deployment-settings.json に保存しますか?

  1. はい — 次回のために保存する
  2. いいえ — 今回のみ使用する」

はいの場合:収集した値を stages.{stageName}.EnvironmentVariables の下に deployment-settings.json へ書き込み/更新します。

すべての環境変数が事前構成済みの場合(または存在しない場合):プロンプトをスキップし、preconfigured を直接使用します。

5.1b deployment-settings.json の Secret 参照の Pre-PATCH 検証。

このゲートが存在する理由。 Power Platform Pipelines ハンドラーは、ステージ実行がキューに入れられた後、場合によってはシリアル化されたインポートの後ろで長時間待機した後に、インポート時に deploymentsettingsjson の PATCH を検証します。不適切な Secret 参照値 — @KeyVault(vaultName=...;secretName=...) のようなプレースホルダー構文、ファイルにコミットされた生のシークレット値、不正な形式の URI — は、インポートを 「ImportAsHolding failed: The value provided as a secret reference does not match a valid secret reference format.」 で失敗させます。実際の証拠:最近のセッションで 4時間41分のキュー待機 + 失敗。ここで不適切な参照を捕捉することで、何時間もの無駄なコンピューティングを、正確な修復ポインタを伴うサブ秒のハードストップに変えることができます。

ENV_VAR_OVERRIDES が空で、かつ deployment-settings.json が存在しない場合は、このステップを完全にスキップします — 検証するものが何もありません。

それ以外の場合は、共有ヘルパーを実行します。

node "${PLUGIN_ROOT}/scripts/lib/validate-deployment-settings.js" \
  --settingsFile "./deployment-settings.json" \
  --envUrl "{sourceEnvUrl}" \
  --stageLabel "{SELECTED_STAGE.name}"

stdout を JSON としてキャプチャします。ヘルパーは各 EnvironmentVariables[] エントリを valueFormat(kv-uri / kv-resource-id / kv-placeholder / empty / plain-text / invalid-uri)と status(valid / invalid / unknown-type / skipped)によって分類します。--envUrl が指定された場合(上記のように)、Secret タイプのエントリは正規の Key Vault 参照形式に対して検証され、その他のタイプは構造的に検証されます。

summary で分岐します:

  • summary.invalid === 0 → すべてのエントリが有効、フェーズ 5.2 へ進みます。

  • summary.invalid > 0 → 停止します。無効な findings[] を、各エントリの schemaName、valueFormat、value、message とともにユーザーに表示します。次に修復メッセージを提示します。

    「デプロイ前検証で、deployment-settings.json 内に {summary.invalid} 個の無効な環境変数値が見つかりました。Power Platform Pipelines ハンドラーはインポート時にこれらを拒否します(長時間のキュー待機の後になる可能性があります)。このスキルを再実行する前にファイルを修正してください。

    Secret 環境変数の正規形式:

    1. Key Vault シークレット識別子 URI: https://<vault>.vault.azure.net/secrets/<name>[/<version>]
    2. Azure リソース ID: /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.KeyVault/vaults/<vault>/secrets/<name>
    3. 空(環境変数定義のデフォルトを使用)

    エンドツーエンドのフロー(ボールトの選択 → シークレットの保存 → URI の引き渡し)については、configure-env-variables フェーズ 3.B および add-server-logic フェーズ 7.2a を参照してください。」 「とにかく続行」を促してはいけません — 不正な PATCH を強行してもインポートが成功する部分的有効性のケースは存在しません。デプロイは失敗します。変わるのは待ち時間だけです。

  • summary.invalid === 0 && summary.['unknown-type'] > 0 → 型を照会できなかったスキーマ(おそらく認証エラーか一時的なエラー)について 1 行の警告をログに出力し、続行します。ダウンストリームのハンドラーは明らかな不正データを依然として拒否します。PATCH 前のゲートはファストパスであり、唯一の防御線ではありません。

5.2 成果物バージョン、デプロイに関する注記、環境変数を指定して PATCH ステージを実行(常に実行):

まず、ソース(開発)環境における現在のソリューションバージョンを確認します — これは完全に一致している必要があります:

GET {sourceEnvUrl}/api/data/v9.0/solutions?$filter=uniquename eq '{SOLUTION_NAME}'&$select=version
Authorization: Bearer {SOURCE_TOKEN}

返された version を artifactdevcurrentversion として使用します。.solution-manifest.json のバージョンは使用しないでください — それは古くなっている可能性があります。

artifactversion には、ソースバージョンのパッチ番号をインクリメントした値を使用します(例: 1.0.0.2 → 1.0.0.3)。これは、対象ステージにすでにデプロイされているバージョンより厳密に大きい必要があります。同じステージに複数回デプロイする場合は、docs/alm/last-deploy.json で最後の artifactVersion を確認し、より大きい値を使用してください。

次に PATCH を実行します(ENV_VAR_OVERRIDES が空でない場合にのみ deploymentsettingsjson を含めます):

PATCH {hostEnvUrl}/api/data/v9.0/deploymentstageruns({STAGE_RUN_ID})
Content-Type: application/json
Authorization: Bearer {HOST_TOKEN}

{
  "artifactdevcurrentversion": "{current version from source env — must match exactly}",
  "artifactversion": "{new version — must be > current version in target stage}",
  "deploymentnotes": "{AI_DEPLOY_NOTES if available, otherwise a brief description of what is being deployed}",
  "deploymentsettingsjson": "{JSON.stringify({ EnvironmentVariables: ENV_VAR_OVERRIDES, ConnectionReferences: [] })}"
}

deploymentsettingsjson の値は JSON エンコードされた文字列(二重シリアライズ)である必要があります:

const deploymentsettingsjson = JSON.stringify({
  EnvironmentVariables: ENV_VAR_OVERRIDES,
  ConnectionReferences: stageSettings.ConnectionReferences || [],
});

ENV_VAR_OVERRIDES が空で、かつ接続参照もない場合は、deploymentsettingsjson を完全に省略します。

レスポンスは HTTP 204 です。PATCH がバージョン競合エラーで失敗した場合は、両方のバージョン値を確認して再試行してください。

注意 — deploymentsettingsjson は、デプロイ後のターゲットに常に environmentvariablevalues レコードを書き込むわけではありません。 実環境で観測された例: 環境変数定義がまだ mspp_sitesetting レコードにリンクされていない Power Pages サイトでは、値が設定された deploymentsettingsjson を指定してデプロイが正常に完了しても、ターゲット環境の environmentvariablevalues テーブルではそれらのエントリが空のままになることがあります。Power Platform Pipelines のハンドラーは、既存のサイト設定バインディング(またはプラットフォームが認識する別のコンシューマー)を持つ定義に対してのみ値を書き込むようです。これはプラットフォームのバグか、別途 Power Pages 管理 UI での手順が必要な仕様上の挙動である可能性があります。Secret 環境変数や、ターゲットで setup-auth/configure-env-variables が実行される前にユーザーが反映されることを期待するその他の型をデプロイする場合は、デプロイ完了後にターゲットで environmentvariablevalues レコードが存在することを以下の Phase 7 で確認し、存在しない場合は明確なプロンプトを表示してください。回避策: デプロイ後にターゲットで configure-env-variables を呼び出す(または定義ごとに link-site-setting-to-env-var.js を実行する)ことで、値を明示的に作成します。これが繰り返し発生するブロッカーになる場合は、次の PR で追跡してください。

Phase 6 — デプロイと監視

🚦 ゲート(最終 · deploy-pipeline:6.0.final-consent): 各 DeployPackageAsync / pac pipeline deploy 呼び出しの前の最終確認です。検証はすでに通過しています。非トランザクションのインポート — 部分的な失敗は、すでにインポートされたものをターゲットに残します。

⚠ MULTI_RUN_MODE / MULTI_PIPELINE_MODE ではループの各イテレーションごとに発火します。 deploymentOrder に 3 つのソリューションがある → 3 回の Phase 6.0 プロンプト(各イテレーションの DeployPackageAsync の前に 1 回ずつ)。上流の Phase 2 のステージ選択 — 対話的な AskUserQuestion 経由でも --stage 引数経由でも — がカバーするのはステージの選択のみであり、個々のデプロイの許可ではありません。デプロイループをまとめて実行しないでください。 イテレーションごとのプロンプトをスキップし、ソリューション 2..N について Phase 5 → Phase 6.1 へ直接進むことは、このゲートが防止するために存在する、文書化された戦略違反です。 6.0 最終デプロイ同意ゲート。 各デプロイを開始する前に、DeployPackageAsync(6.1)を使用する場合も、PAC CLI のフォールバックとして pac pipeline deploy を使用する場合も、また MULTI_RUN_MODE で最初のソリューションをデプロイする場合も N 番目のソリューションをデプロイする場合も、必ずユーザーに明示的に確認してください。前の各ゲート(Phase 2 のステージ選択、Phase 2.5 のブロック解除、Phase 3.5 の完全性確認、Phase 5 の環境変数の値)は、それぞれ個別の判断を対象としていますが、いずれも反復ごとに「このソリューションをデプロイする準備はできていますか?」と確認するものではありません。また、デプロイ自体はトランザクションではありません。部分的な失敗が発生すると、すでにターゲットにインポートされたものはそのまま残ります。このゲートにより、本番環境への昇格を行うたびに、明示的な確認を取ります。AskUserQuestion を使用してください。

「{ARTIFACT_SOLUTION_NAME}(v{newVersion})を {SELECTED_STAGE.name}({targetEnvUrl})にデプロイしますか?

ソリューションのサイズによって、実行に約 3~60 分かかります。インポートはトランザクションではありません。途中で失敗した場合、すでにインポートされたものはターゲットに残り、復旧には手動でのクリーンアップ(または、より新しいアーティファクトバージョンでの再デプロイ)が必要です。docs/alm/last-deploy.json は結果にかかわらず書き込まれます。

  1. 今すぐデプロイ — DeployPackageAsync を POST します(または CLI のフォールバックとして pac pipeline deploy を実行します)。終端状態になるまでポーリングします。
  2. キャンセル — ステージ実行を現在の状態(検証済み、未デプロイ)のままにします。準備ができたら、後で /power-pages:deploy-pipeline を再実行します。」

回答に応じて分岐します。

  • 今すぐデプロイ → 以下の 6.1(または PAC CLI のフォールバックボックス)に進みます。
  • キャンセル → 正常に停止します。DeployPackageAsync または pac pipeline deploy は呼び出さないでください。次のようにユーザーに伝えます。「キャンセルしました。ステージ実行 {STAGE_RUN_ID} は検証済みですが、デプロイされていません。再開するには /power-pages:deploy-pipeline を再実行してください。再実行する前にソースソリューションのバージョンが変わった場合は、デプロイ前にステージ実行の artifactversion フィールドを新たに PATCH(Phase 5.2)する必要があります。スキルを再実行すれば自動的に処理されます。」 キャンセル時は docs/alm/last-deploy.json を書き込まないでください。記録すべきデプロイ結果がないためです。

ターゲットが Production の場合、このゲートをスキル内で最も重要な確認として扱ってください。キャンセルのコスト(ステージ実行はすでに検証済み)は、誤ったステージへのインポートに比べて小さいものです。

ValidatePackageAsync を利用できなかった場合(VALIDATE_PACKAGE_UNAVAILABLE = true):6.1 の代わりに PAC CLI を主なデプロイ手段として使用してください。この経路にも上記の Phase 6.0 の同意ゲートが適用されます。ユーザーが「今すぐデプロイ」と回答するまで pac pipeline deploy を実行しないでください。

ユーザーに currentVersion(利用可能な場合は .solution-manifest.json の solution.version から事前入力)と newVersion(例:1.0.0.0 → 1.0.0.1 のようにパッチ番号を上げることを提案)を確認します。

pac pipeline deploy \
  --environment "{devEnvUrl}" \
  --solutionName "{ARTIFACT_SOLUTION_NAME}" \
  --stageId "{SELECTED_STAGE.stageId}" \
  --currentVersion "{currentSolutionVersion}" \
  --newVersion "{newVersion}" \
  --wait

CLI が「Resource not found for the segment 'deploymentenvironments'」を返した場合:開発環境が Pipelines ホストに接続されていません。Power Platform 管理センター(Environments → 環境を選択 → Pipelines)でホストを構成してから、再試行するようユーザーに案内してください。

CLI が成功した場合:出力からステージ実行のステータスを解析し、status: "Succeeded"(または解析したステータス)を含めて docs/alm/last-deploy.json を書き込み、6.1~6.2 の DeployPackageAsync 呼び出しとポーリングはスキップします。

6.1 デプロイを開始する(VALIDATE_PACKAGE_UNAVAILABLE = true の場合はスキップし、上記の PAC CLI 経路を使用します)。Phase 6.0 の同意ゲートで「今すぐデプロイ」と回答された後にのみ実行してください。

POST {hostEnvUrl}/api/data/v9.0/DeployPackageAsync
Content-Type: application/json
Authorization: Bearer {HOST_TOKEN}

{"StageRunId": "{STAGE_RUN_ID}"}

注:古いバージョンの Pipelines パッケージでは、DeployPackageAsync も 404 を返します。この場合は、上記の pac pipeline deploy CLI 経路を使用してください。

6.2 poll-deployment-status.js を使用して、終端状態になるまで stagerunstatus をポーリングする:

node "${PLUGIN_ROOT}/scripts/lib/poll-deployment-status.js" \
  --hostEnvUrl "{hostEnvUrl}" \
  --token "{HOST_TOKEN}" \
  --stageRunId "{STAGE_RUN_ID}" \
  --intervalMs 8000 \
  --maxAttempts 75

標準出力を JSON として取得します:const result = JSON.parse(output)。 このスクリプトは、終端状態になるまで msdyn_stagerunstatus をポーリングします:

  • result.status === 'Succeeded' → フェーズ 7 に進みます
  • result.status === 'Awaiting' → 承認ゲート(下記参照)。エラーとして扱わないでください
  • 200000003(Failed)または 200000004(Canceled)の場合、スクリプトは msdyn_errordetails を含むエラーメッセージを出して終了します
  • 約 10 分後にタイムアウトすると、スクリプトはエラーを出して終了します

suboperation フィールド(スクリプトではポーリングされませんが、Power Platform 上で確認できます)には、進行状況の詳細が表示されます:

  • 200000100 = None(開始/終了)
  • 200000105 = Deploying Artifact(ソリューションをインストール中)

🚦 ゲート(停止 · deploy-pipeline:6.pending-approval): 外部待機 — デプロイ中に PP Pipelines の stagerunstatus=200000005 になります。ユーザーは PPAC で承認します。ここでキャンセルすると、実行に対して iscanceled: true が PATCH されます。MULTI_RUN_MODE / MULTI_PIPELINE_MODE では、保留中の承認が発生したループ反復ごとにこのゲートが作動します。

承認ゲートの処理:result.status === 'Awaiting'(msdyn_stagerunstatus = 200000005)の場合:

  • ユーザーに通知します:「このデプロイは承認待ちです。Power Platform で承認してください:make.powerapps.com → Solutions → Pipelines → {STAGE_RUN_ID} のデプロイを探す → Approve。」
  • AskUserQuestion で質問します:「デプロイを承認しましたか? 1. はい、承認しました — ポーリングを続行 / 2. デプロイをキャンセル」
  • はいの場合:ポーリングを続行するために poll-deployment-status.js を再実行します。
  • キャンセルの場合:ステージ実行をキャンセルするために PATCH します:
    PATCH {hostEnvUrl}/api/data/v9.0/deploymentstageruns({STAGE_RUN_ID})
    {"iscanceled": true}
    
    その後、ステータスを「Canceled」として記録します。

トークンの更新:ポーリングサイクルを 10 回(約 80 秒)実行するごとに、az account get-access-token で HOST_TOKEN を更新し、更新したトークンを指定して、--maxAttempts を減らした新しい poll-deployment-status.js の呼び出しに渡します。

ポーリングの継続中は、デプロイの進行状況を報告します。

フェーズ 7 — デプロイ記録と概要の作成

7.1 最終ステータス文字列を決定します:

  • 200000002 → "Succeeded"
  • 200000003 → "Failed"
  • 200000004 → "Canceled"
  • 200000005 → "PendingApproval"(ユーザーが待機中にキャンセルした場合)
  • ポーリングがタイムアウトした場合 → "Unknown"

7.2 デプロイ後の警告(デプロイが Succeeded の場合のみ):

フェーズ 1 で detect-project-context.js から取得した solutionManifest を使用して、対象環境で手動の追加対応が必要なコンポーネントを確認します。

接続参照に関する警告 — solutionManifest.cloudFlows が存在し、空でない場合:

⚠️ 接続参照のバインドが必要な場合があります このソリューションにはクラウドフローが含まれています。フローで接続参照(Dataverse、SharePoint など)を使用する場合、対象環境の有効な接続にバインドする必要があります。バインドしないと、フローは無効のままになります。

バインド方法:Power Automate → 対象環境 → 各フロー → Edit → 接続をバインドします。

solutionManifest.cloudFlows が存在しないか空の場合、この警告は完全に省略します。

ボットの再公開に関する警告 — solutionManifest.botComponents が存在し、空でない場合:

⚠️ ボットの再公開が必要です このソリューションには Copilot Studio のボットが含まれています。デプロイ後、プロビジョニングを完了するには、対象環境でボットを再公開する必要があります。

再公開方法:Power Pages Management → 対象環境 → Edit site → Copilot → 再公開します。

solutionManifest.botComponents が存在しないか空の場合、この警告は完全に省略します。

これらの警告は情報提供のみを目的としています。概要の作成を妨げたり、AskUserQuestion を使用したりしないでください。

7.3 docs/alm/last-deploy.json を作成します(存在しない場合は、先に docs/alm/ ディレクトリを作成します — node -e "require('fs').mkdirSync('docs/alm',{recursive:true})"):

{
  "pipelineId": "{pipelineId}",
  "pipelineName": "{pipelineName}",
  "stageId": "{SELECTED_STAGE.stageId}",
  "stageRunId": "{STAGE_RUN_ID}",
  "stageName": "{SELECTED_STAGE.name}",
  "solutionName": "{ARTIFACT_SOLUTION_NAME}",
  "solutionId": "{ARTIFACT_SOLUTION_ID}",
  "status": "{final status string}",
  "deployedAt": "{ISO timestamp}",
  "hostEnvUrl": "{hostEnvUrl}",
  "targetEnvironmentUrl": "{SELECTED_STAGE.targetEnvironmentUrl}",
  "artifactVersion": "{artifactVersion from Phase 5.2 PATCH}",
  "deployHistoryFile": "docs/deploy-history/{YYYY-MM-DD}-{stageName}-{artifactVersion}.html",
  "activationStatus": null,
  "siteUrl": null
}

activationStatus と siteUrl は最初に null に設定し、アクティベーションの結果が判明した後、フェーズ 7.7 の最後にパッチします。

{YYYY-MM-DD} は deployedAt の日付部分、{stageName} はステージ名の空白をハイフンに置き換えて小文字にしたものです。例:2026-04-06-staging-1.0.0.3.md。

再試行は、runs[i].lastAttempt の下にネストするのではなく、runs[] 内の同列エントリとして追加します。 MULTI_RUN_MODE(複数ソリューション)では、マーカーに runs[] 配列が含まれ、試行ごとに各ソリューションにつき1つのエントリを格納します。失敗したソリューションをユーザーが再試行する場合(たとえば、環境変数の値を修正した後、同じステージに対して deploy-pipeline を再実行する場合)、再試行は独自の artifactVersion と attemptedAt を持つ、新しい runs[] の同列エントリになります。元の失敗エントリの下に runs[i].lastAttempt: {...} として再試行をネストしないでください。 これではスキーマが混在し、監査時の走査が曖昧になります(1.0.0.4 はデプロイされたバージョンなのか、それとも単に最新の試行なのか)。同列エントリによるフラットな配列形式なら、すべてのコンシューマー(refresh-alm-plan-data、レンダリングされた Pipelines タブ、deploy history HTML)が runs[] を1回走査するだけで、タイムライン全体を確認できます。

このスキルのマーカー書き込み処理では、変更ではなく追記を行います。失敗したソリューションを再試行するたびに、ステータスが='Succeeded'(失敗が続く場合は 'Failed')で、バージョン更新後の artifactVersion を持つ新しい runs[] エントリを書き込みます。元の失敗エントリは履歴としてそのまま保持します。

7.4 デプロイ履歴エントリ(HTML)を書き込む:

履歴ファイル名を計算します:{YYYY-MM-DD}-{stageName}-{artifactVersion}.html(docs/alm/last-deploy.json の deployHistoryFile フィールドと同じ方法で導出します。スペースをハイフンに置き換え、ステージ名を小文字にします)。

まだ存在しない場合は、docs/deploy-history/ を作成します:

mkdir -p docs/deploy-history

${PLUGIN_ROOT}/skills/deploy-pipeline/assets/deploy-history-template.html のテンプレートを読み込み、以下の __PLACEHOLDER__ トークンを置き換えます:

Overview タブ:

PlaceholderValue
__SOLUTION_FRIENDLY_NAME__ソリューションのフレンドリー名(.solution-manifest.json から取得)、または {solutionUniqueName}
__SOLUTION_NAME__{ARTIFACT_SOLUTION_NAME}
__STAGE_NAME__{SELECTED_STAGE.name}
__TARGET_ENV_URL__{SELECTED_STAGE.targetEnvironmentUrl}
__STAGE_RUN_ID__{STAGE_RUN_ID}
__PIPELINE_NAME__{pipelineName}
__DEPLOYED_AT__{deployedAt ISO string}
__ARTIFACT_VERSION__{Phase 5.2 の artifactVersion}
__PREV_ARTIFACT_VERSION__{artifactDevCurrentVersion} — このデプロイ前に開発環境にあったバージョン
__STATUS_CLASS__succeeded / failed / pending-approval
__STATUS_ICON__Succeeded の場合は ✓、Failed の場合は ✗、PendingApproval の場合は ⏳
__STATUS_LABEL__Succeeded / Failed / Pending Approval
__ACTIVATION_SECTION__最初は '' — 有効化の結果が判明したら Phase 7.7 で置き換えます

Solution タブ — .solution-manifest.json を読み込み、以下のセクションを作成します:

PlaceholderValue
__SOLUTION_META_ROWS__以下の <tr> 行:フレンドリー名、一意の名前、バージョン(新しいバージョン → 以前のバージョン)、タイプ(Managed/Unmanaged)、発行者、コンポーネント総数。ソース:Phase 6 のマニフェストと validationResults.SolutionDetails。
__VALIDATION_SECTION__検証に合格した場合:<div class="note-box succeeded"><span class="validation-badge passed">✓ Validation Passed</span> — No missing dependencies.</div>。失敗した場合、または依存関係が存在する場合:不足している依存関係の名前を一覧表示する <div class="note-box warning">。
__SOLUTION_CONTENTS_SECTION__.solution-manifest.json から作成します。2つの <div class="contents-card"> ブロック(Dataverse テーブルはテーブルごとに <span class="table-chip">、ボットコンポーネントは名前をカンマ区切り)を含む <div class="contents-grid"> を作成します。グリッドの下に、{totalAdded} components added to solution(components.totalAdded から取得)を含む <div class="note-box neutral"> を追加します。マニフェストが利用できない場合は、中立的な注記を表示します。

Config & Notes タブ:

プレースホルダー値
__ENV_VARS_SECTION__ENV_VAR_OVERRIDES が空でない場合:スキーマ名とオーバーライド値の列を含む <div class="card"><h3>Environment Variable Overrides</h3> テーブル。それ以外の場合:<div class="note-box neutral">No environment variable overrides applied.</div>
__DEPLOYMENT_NOTES_SECTION__AI_DEPLOY_NOTES が利用可能な場合:<div class="card"><h3>AI Deployment Notes</h3><p>…</p></div>。それ以外の場合:''
__POST_DEPLOY_WARNINGS__デプロイ後の警告(接続参照、ボットの再公開)ごとに、<div class="note-box warning"> を1つ配置します。該当する警告がない場合は空文字列です。

レンダリングされた HTML を docs/deploy-history/{filename}.html に書き込みます。

次に、ステージングエリアに追加します:

git add docs/alm/last-deploy.json docs/deploy-history/{filename}.html
git commit -m "Deploy {solutionUniqueName} v{artifactVersion} to {stageName} ({status})"

プロジェクトのルートで Git が初期化されていない場合(つまり、git rev-parse --git-dir が失敗する場合)、コミットを黙ってスキップします。

7.5 スキルの使用状況を記録する:

参照:${PLUGIN_ROOT}/references/skill-tracking-reference.md

参照先のスキル追跡手順に従って、このスキルの使用状況を記録します。--skillName "DeployPipeline" を使用します。

7.5b ALM プランを更新する(存在する場合):

node "${PLUGIN_ROOT}/scripts/lib/refresh-alm-plan-data.js" \
  --projectRoot "." \
  --phase deploy-pipeline \
  --live \
  --render

このヘルパーは、先ほど書き込んだ docs/alm/last-deploy.json を読み取り、その内容を planData.pipelineMeta.lastDeploy に取り込み、ステージごとの環境変数値(deployment-settings.json から取得し、さらに --live を指定すると各プランステージのライブの environmentvariablevalues テーブルからも取得。ファイルの値が優先)をマージします。また、デプロイ前の「ホストがまだプロビジョニングされていない」リスクを削除し、docs/alm-plan.html を再レンダリングして、Pipelines タブに実際の実行状態(ステータス、バージョン、コンポーネント数、有効化、サイト URL)が表示されるようにします。docs/.alm-plan-data.json がない場合(ALM プランの一部ではなく、単独でスキルが実行された場合)、ヘルパーは ok:false を返します。これはソフトなノーオペレーションなので、無条件に実行しても安全です。

このステップにより、レンダリングされたプランが最新の状態に保たれます。plan-alm はプランナーであり、プラン自体は更新しないため、各実行スキルが自身の実行後の更新を担当します。複数回実行しても冪等です(同じ入力 → 同じ出力)。

ライブクエリの失敗をユーザーに伝える。 ヘルパーの stdout JSON に空でない liveEnvVars.errors[] が含まれる場合、読み取れなかったステージを1行ずつユーザーに伝えます:"Could not read live environment variable values for {stage}: {error}. That column of the Values by Environment matrix was left unchanged, so values set in Power Platform Admin Center for it may be missing or stale." エラーが HTTP 401/403 の場合、またはトークンを取得できなかったことを示す場合、Azure CLI はその環境とは異なるテナントにサインインしている可能性が最も高いです(az は既定のサブスクリプションのテナント用トークンを発行しますが、これは PAC CLI プロファイルと異なる場合があります)。そのため、az login --tenant <environment tenant id>(または az account set --subscription <a subscription in that tenant>)を実行してから、上記の更新コマンドを再実行するよう提案します。これは情報提供のみを目的とします。デプロイを失敗扱いにしたり、7.6 のサマリーを妨げたりしないでください。liveEnvVars がない場合、または errors が空の場合は何も伝えません。

次のステップをユーザーに案内する(ユーザー主導の順序制御)。 ヘルパーの stdout JSON には nextStep: { name, skill: string | null } | null が含まれます。null でない場合は、skill の値に応じて分岐します。skill が null でない場合、ユーザーに "Plan updated. Next in your plan: {nextStep.name} → run {nextStep.skill} when you're ready." と伝えます。skill が null(Finalize などの内部ステップで、ユーザーが実行するコマンドがない場合)の場合、ステップ名だけを示します — "Plan updated. Next in your plan: {nextStep.name}." — run null は決して出力しないでください。(複数ステージのパイプラインでは、通常、次のステージのデプロイ、またはそれらが個別のステップの場合は次のステージの有効化/テストです。)null(すべてのステップが完了)またはヘルパーが ok:false を返した場合(プランがない場合)は、次のステップについて何も伝えません。次のスキルを自動的に呼び出してはいけません — 実行するのはユーザーです。

7.6 サマリーを提示する:

Succeeded の場合:

✓ Deployment succeeded

  Solution:     {solutionName}
  Stage:        {stageName}
  Target:       {targetEnvironmentUrl}
  Completed at: {deployedAt}
  Stage run ID: {STAGE_RUN_ID}
  Site URL:     {siteUrl from 7.7, or "— activation pending" if not yet activated, or "— checking…" before 7.7 runs}

Failed の場合:

✗ Deployment failed

  Stage run ID: {STAGE_RUN_ID}
  Status:       Failed

  To investigate: open Power Platform make.powerapps.com → Solutions → Pipelines
  and find the failed run for details on what caused the failure.

7.6.1 失敗を診断します。 ユーザーに対応方法を尋ねる前に、ステージ実行レコードを照会してエラーの詳細を確認し、的を絞った修正案を提示できるようにします。

GET {hostEnvUrl}/api/data/v9.1/deploymentstageruns({STAGE_RUN_ID})?$select=errordetails,validationresults,stagerunstatus
Authorization: Bearer {HOST_TOKEN}

errordetails と validationresults を JSON/テキストとして解析します。次のパターンを確認してください(大文字と小文字は区別しません)。

エラーテキスト内のパターン診断修正プロンプト
AttachmentBlocked OR -2147188706 OR not a valid type OR \.js.*blockedブロックされた添付ファイル — 対象環境の blockedattachments 設定により、ソリューション内のファイル形式が拒否されています以下の 7.6.2 を参照
secret reference does not match a valid OR ImportAsHolding failed.*secret reference OR KeyVault.*format無効な Secret 参照 — deployment-settings.json に、正規形式ではない Secret 値が含まれています(例:@KeyVault(vaultName=...;secretName=...)、シークレットの生テキスト、不正な URI)以下の 7.6.4 を参照
MissingDependency OR Missing dependency対象環境にソリューションの依存関係がありません依存関係を提示し、インストールして再試行するようユーザーに勧めます
(その他すべて)不明な失敗一般的な再試行/終了プロンプトに進みます

7.6.2 添付ファイルのブロックに対する修正(ゲートあり)。 7.6.1 の診断で添付ファイルのブロックパターンに一致した場合にのみ実行します。明示的な AskUserQuestion ゲートなしに、環境の blockedattachments 設定を変更してはいけません。 これはテナント全体に適用されるセキュリティ設定です。自動的に変更すると、同じ環境内の他のアプリ全体でセキュリティレベルが気付かれないまま低下します。

  1. PAC CLI を対象環境に切り替えて、ヘルパーが正しい環境の設定を照会するようにしてから、ブロックされているファイル形式を特定します。デフォルトではヘルパーは js を確認します。エラーに他の形式(例:js,css)が記載されている場合は、--extensions を渡します。

    pac env select --environment "{TARGET_ENV_URL}"
    node "${PLUGIN_ROOT}/scripts/lib/fix-blocked-attachments.js" \
      --envUrl "{TARGET_ENV_URL}" \
      --extensions js \
      --dry-run
    

    出力 JSON を読み取ります。確認するフィールドは、wasBlocked[](環境で現在ブロックされており、--extensions リストにも含まれる拡張子。これらが削除対象です)と unchanged[](削除を指定したものの、実際にはブロックされていない拡張子。変更は行われません)です。

    wasBlocked が空の場合、この失敗はこのリストに含まれる添付ファイルのブロックが原因ではありません。7.6.3 の一般的な再試行プロンプトに進み、errordetails の生のエラーテキストを提示します。

  2. ユーザーに次の内容を明確に伝えます。

    「対象環境 {targetEnvName} では、このソリューションが必要とするファイル形式がブロックされているため、デプロイに失敗しました:{wasBlocked.join(', ')}。これは環境レベルのセキュリティ設定であり、その環境のすべてのユーザーに影響します。続行するには、これらの特定の形式のブロックを解除する必要があります。この変更は、Power Platform 管理センター → 環境 → {targetEnvName} → 設定 → 製品 → 機能 → ブロックされた添付ファイルから元に戻せます。」

🚦 ゲート(同意 · deploy-pipeline:7.6.2.blocked-attachments): AttachmentBlocked へのリアクティブな修正 — 環境レベルの blockedattachments 設定を変更します(テナント全体に影響)。PPAC から元に戻せます。AttachmentBlocked パターンに一致する失敗ごとに実行されます。 MULTI_RUN_MODE ではまれです。通常、Phase 2.5 の事前チェックでループ開始前にブロックが検出されます。ただし、Phase 2.5 の成功後に反復 N で AttachmentBlocked による失敗が発生した場合は、その失敗に対してゲートが再び実行されます。失敗ごとに個別の同意判断が必要です(ソリューションが異なり、ブロック対象の拡張子も異なる可能性があります)。失敗をまたいで同意を引き継いではいけません。

  1. AskUserQuestion を呼び出します(チャット内でこの確認を済ませてはいけません。変更を行う前にユーザーの回答が必要です)。

    質問ヘッダー選択肢
    デプロイを再試行できるように、{targetEnvName} 環境で {wasBlocked.join(', ')} のブロックを解除しますか? これにより、テナントレベルのセキュリティ設定が変更されます。添付ファイルのブロック解除はい — これらの形式のブロックを解除して再試行する、いいえ — 設定は変更せず(自分で調査する)、キャンセル
  2. 回答に応じて分岐します:

    • はい — ブロックを解除して再試行:--dry-run を付けずに(同じ --extensions を指定して)fix-blocked-attachments.js を実行し、その後 RetryFailedDeploymentAsync を呼び出して、Phase 6.2 からポーリングを再開します。ユーザーが明確な監査記録を確認できるよう、デプロイの概要に変更内容を記載します。再試行が解決したら PAC CLI をソース環境に戻し、後続のスキル手順がデフォルトでソース環境に対して実行されるようにします。
    • いいえ/キャンセル:次の修復手順を案内して終了します:

      "手動でブロックを解除するには、Power Platform Admin Center → Environments → {targetEnvName} → Settings → Product → Features → Blocked Attachments を開き、{blockedTypesPresent.join(', ')} を削除して Save を選択します。その後、/power-pages:deploy-pipeline を再実行してください。"

7.6.3 一般的な再試行/終了のプロンプト(7.6.1 が既知のパターンに一致しなかった場合、またはユーザーが対象を絞った修復を拒否した場合):

🚦 ゲート(計画 · deploy-pipeline:7.6.3.retry-exit): デプロイに失敗し、既知のパターンにも一致しませんでした — RetryFailedDeploymentAsync を呼び出すか、手動調査のために終了してください。

AskUserQuestion で質問します:

"デプロイに失敗しました。どのようにしますか?

  1. 再試行 — RetryFailedDeploymentAsync を呼び出して、同じステージの実行を再試行します
  2. 終了 — 手動で調査します"

再試行の場合:次を呼び出します:

POST {hostEnvUrl}/api/data/v9.1/RetryFailedDeploymentAsync
Content-Type: application/json
Authorization: Bearer {HOST_TOKEN}

{"StageRunId": "{STAGE_RUN_ID}"}

その後、Phase 6.2 からポーリングを再開します。

終了の場合:停止し、上記の失敗概要を提示します。

7.6.4 無効な Secret 参照の修復(ゲートあり)。 7.6.1 の診断が Secret 参照パターンに一致した場合にのみ実行します。これは、元の Citizens-portal 検証レポートで説明されている、値を除去して再試行する方法です。インポート時に deployment-settings.json の Secret 値が拒否された場合、その値をファイル内で "" に置き換えます(Dataverse はこれを「環境変数定義のデフォルトを使用する」と解釈します)。その後、デプロイを再試行します。ファイルの変更は保持されるため、次回の実行では不正な値が再送信されません。

これは最終手段です。 configure-env-variables の Phase 6.1 にある書き込み前バリデーターと、このスキルの Phase 5.1b にある PATCH 前バリデーターで、ほとんどの無効な Secret 値を事前に検出できるはずです。Phase 7.6.4 が対象とするのは、次のケースです:

  • configure-env-variables の実行後に、ユーザーが deployment-settings.json を手動で編集した場合。
  • Phase 6.1 より前に作成されたレガシーファイルがコミットされた場合。
  • PATCH 時に Dataverse の型を解決できなかった項目に対して、事前 PATCH ゲートが status: "unknown-type" を返したものの、インポート時にホストのバリデーターが拒否した場合。

手順:

  1. 不正な値があるスキーマを特定します。 Phase 5.1b と同じヘルパーを使用して、現在のファイルに対して validate-deployment-settings.js を実行し、無効な項目をすべて検出します:

    node "${PLUGIN_ROOT}/scripts/lib/validate-deployment-settings.js" \
      --settingsFile "./deployment-settings.json" \
      --envUrl "{sourceEnvUrl}" \
      --stageLabel "{SELECTED_STAGE.name}"
    

    標準出力を JSON として取得し、status === "invalid" かつ valueFormat が kv-placeholder/plain-text/invalid-uri のいずれかである findings[] を収集します。収集した schemaName のリストが、値を除去する対象です。

  2. validate-deployment-settings.js で無効な項目が見つからない場合(ホストのエラーは Secret 形式を指しているものの、ローカルファイルには問題がない場合 — 編集が同時に行われた可能性や、パターンには一致したものの別のフィールドに関するエラーだった可能性があります)、7.6.3(一般的な再試行/終了のプロンプト)に進みます。

  3. それ以外の場合は、ユーザーに同意を求めます。

    🚦 ゲート(同意 · deploy-pipeline:7.6.4.strip-secret-values): deployment-settings.json から無効な Secret 参照値を除去して、デプロイを再試行します。不正な値は空文字列(定義のデフォルトを使用)に置き換えられ、ファイルの変更は保持されます。次回の実行では不正な値は再送信されません。キャンセルするとファイルはそのまま残るため、ユーザーは正規の Key Vault URI を使って手動で修正できます。

    AskUserQuestion を使用します:

    質問ヘッダー選択肢
    deployment-settings.json に無効な形式の Secret 値が含まれているため、デプロイに失敗しました:{list of schema names}。これらの値を削除して("" に設定して定義の既定値を使用し)、デプロイを再試行しますか?ファイルは更新されます。正規の Key Vault URI は後で /power-pages:configure-env-variables から指定できます。無効な Secret 値を削除はい — 削除して再試行(推奨)、いいえ — 終了して、自分で deployment-settings.json を正規の URI に手動修正する
  4. 回答に応じて処理します。

    • はい — 削除して再試行:ファイル変更ヘルパーを実行し、修正済みの deploymentsettingsjson を使ってステージ実行を再度 PATCH してから、RetryFailedDeploymentAsync を呼び出し、フェーズ 6.2 からポーリングを再開します。

      node "${PLUGIN_ROOT}/scripts/lib/strip-invalid-secret-values.js" \
        --settingsFile "./deployment-settings.json" \
        --schemaNames "{comma-separated schema names from step 1}" \
        --stageLabel "{SELECTED_STAGE.name}"
      

      stripped.length > 0 であることを確認し、監査サマリー用に一覧を記録します(フェーズ 7.5b の更新時に、レンダリングされたプランに取り込まれます)。修正済みの deployment-settings.json から ENV_VAR_OVERRIDES を再構築し(フェーズ 5.1 の「deployment-settings.json を読み取る」ステップと同じロジックを再実行)、ステージ実行を再度 PATCH します。

      PATCH {hostEnvUrl}/api/data/v9.0/deploymentstageruns({STAGE_RUN_ID})
      Content-Type: application/json
      Authorization: Bearer {HOST_TOKEN}
      
      {
        "deploymentsettingsjson": "{JSON.stringify({ EnvironmentVariables: ENV_VAR_OVERRIDES, ConnectionReferences: ... })}"
      }
      

      次に、インポートを再試行します。

      POST {hostEnvUrl}/api/data/v9.1/RetryFailedDeploymentAsync
      {"StageRunId": "{STAGE_RUN_ID}"}
      

      フェーズ 6.2 からポーリングを再開します。削除したスキーマとその以前の値がデプロイサマリーに表示されるよう、削除処理を docs/alm/last-deploy.json の secretRemediation[] に記録します。

    • いいえ — 終了:修正方法を案内して停止します。正規の Secret 参照形式をユーザーに伝え、ガイド付きの修正手順として /power-pages:configure-env-variables を案内します。

      「手動で修正するには、deployment-settings.json を開き、無効な Secret 値を次のいずれかに置き換えます。

      1. Key Vault Secret Identifier URI:https://<vault>.vault.azure.net/secrets/<name>[/<version>]
      2. Azure リソース ID:/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.KeyVault/vaults/<vault>/secrets/<name>
      3. 空文字列(環境変数定義の既定値を使用)

      その後、/power-pages:deploy-pipeline を再実行してください。または、フェーズ 6.1 の書き込み前検証を再実行するガイド付き編集を行うには、/power-pages:configure-env-variables を実行してください。」

7.6.5 environmentvariablevalues がターゲットに反映されたことを確認する(デプロイが成功し、ENV_VAR_OVERRIDES が空でなく、フェーズ 5.2 で deploymentsettingsjson を PATCH した場合のみ):

ステージ実行が成功を報告していても、Power Platform Pipelines ハンドラーは、deploymentsettingsjson 内のすべての環境変数定義に対して environmentvariablevalues レコードを書き込むとは限りません。mspp_sitesetting(またはプラットフォームが認識する別の利用先)に紐付けられていない定義は、値が空のままターゲットに反映されることがあります。実際に確認された証拠については、フェーズ 6 の前にある注意事項を参照してください。このステップでは、デプロイ後にターゲットをクエリして、反映されなかった値を特定します。

共通ヘルパー scripts/lib/verify-env-var-values.js を使用します。これは deployment-settings.json からスキーマ名とステージごとの期待値を読み取り、スキーマごとの構造化 JSON 結果(landed/missing-value-record/missing-definition/value-mismatch/query-error)を返します。

node "${PLUGIN_ROOT}/scripts/lib/verify-env-var-values.js" \
  --envUrl "{targetEnvUrl}" \
  --settingsFile "./deployment-settings.json" \
  --stageLabel "{SELECTED_STAGE.name}"

stdoutをJSONとして取得します:const verifyResult = JSON.parse(output)。このヘルパーは{targetEnvUrl}を対象にAzure CLI経由で独自のトークンを取得するため、この呼び出しではPAC CLIを切り替える必要はありません(ヘルパーは完全に読み取り専用で、PACを一切経由しません)。

verifyResult.summaryに基づいて分岐します。

  • summary.missing === 0 && summary.mismatched === 0 → すべての環境変数の値が問題なく反映されています。警告はありません。続行してください。

  • summary.missing > 0 OR summary.mismatched > 0 → docs/alm/last-deploy.jsonの新しいenvVarLandingWarnings[]配列に、構造化された警告を記録します。verifyResult.resultsのうちlandedではないエントリから配列を作成し、schemaName、status、および存在する場合はexpected/valueフィールドを保持します。その後、デプロイの概要でユーザーに次のように通知します。

    "{summary.missing + summary.mismatched}個の環境変数の値が、deploymentsettingsjsonから{targetEnvName}に正常に反映されませんでした。missing-value-recordの最も可能性の高い原因は、対象のサイト設定に定義がまだリンクされていないことです。value-mismatchの最も可能性の高い原因は、deployment-settings.jsonのステージ別の値が、対象のenvironmentvariablevaluesテーブルに現在存在する値と異なることです(デプロイ後にPPAC経由で誰かが編集した可能性があります)。{targetEnvName}に対して/power-pages:configure-env-variablesを実行して調整するか、Power Platform Admin Center → Solutions → Environment Variablesから値を設定してください。"

  • summary.error > 0(認証、一時的な問題、5xx)→ 次の1行のメモを記録します。"Env var landing check was inconclusive ({summary.error} schema queries errored). Verify manually in PPAC." 判定できなかった結果を理由にデプロイの概要をブロックしないでください。デプロイ自体は成功しています。

インラインODataではなくヘルパーを使う理由:以前のインライン記述版は脆弱でした。エージェントの実行ごとにクエリを手作業で再構築し、PAC CLIの環境切り替えは手動で、結果の形式も構造化されていませんでした。このヘルパーには、すべての結果ステータス分岐(landed/missing-value-record/missing-definition/value-mismatch/query-error)を網羅する21件のテストがあります。また、呼び出し元とヘルパーの間で差異が生じないようdeployment-settings.jsonを直接読み込み、呼び出し元が文章を再解析することなくlast-deploy.jsonに保存できる、安定したJSONコントラクトを生成します。

7.7 サイトの有効化を確認する(デプロイが成功し、Power Pagesプロジェクトの場合のみ)

実行条件(2026-04-22更新):ソースプロジェクトのpowerpages.config.jsonにwebsiteRecordIdがある場合は、必ずこの確認を実行します。つまり、このプロジェクトがPower Pagesサイトプロジェクトである場合です。以前のルール(「今回デプロイしたソリューションにwebsiteのcomponentType 10374が含まれる場合のみ」)では、実際に起こりうるケースを見逃します。対象環境にサイトがすでに存在し、今回デプロイしたソリューションにはテーブル/フロー/ボットしか含まれていない場合があります。今回どのソリューションを出荷したかにかかわらず、対象環境でサイトが有効化されていなければ、Power Pagesプロジェクトのデプロイ後の作業は常に未完了です。

powerpages.config.jsonからwebsiteRecordIdを読み取ります。このフィールドがない場合は、7.7の残りをスキップします(純粋なデータモデルソリューションなど、Power Pages以外のALM実行です)。

二次確認は任意です。ソースソリューションを照会し、website componentType 10374があるかを確認して、この特定のソリューションにサイトが含まれていたかどうかをログに記録する目的でのみ使用します。これは参考情報であり、実行条件ではありません。

GET {sourceEnvUrl}/api/data/v9.2/solutioncomponents?$filter=_solutionid_value eq '{solutionId}' and componenttype eq 10374&$select=objectid
Authorization: Bearer {SOURCE_TOKEN}

見つかった場合は、check-activation-status.jsが正しい環境を照会できるよう、PAC CLIを一時的に対象環境に切り替えます。

pac env select --environment "{SELECTED_STAGE.targetEnvironmentUrl}"

有効化の確認を実行します。

node "${PLUGIN_ROOT}/scripts/check-activation-status.js" --projectRoot "."

結果にかかわらず、その後PAC CLIをソース(開発)環境に戻します。

pac env select --environment "{sourceEnvUrl}"

結果を評価し、結果に応じて対応します。いずれの場合も、結果への対応が完了した後に、docs/alm/last-deploy.jsonとデプロイ履歴ファイル(以下で説明)を更新します。

  • activated: true:サイトはすでに公開されています。ACTIVATION_OUTCOME = { status: "Activated", siteUrl: "{result.websiteUrl}" }に設定します。

🚦 ゲート(plan · deploy-pipeline:7.7.activate): サイトはターゲットにデプロイされましたが、有効化されていません。有効化を呼び出すか、後で行うかをユーザーに確認します。

  • activated: false:AskUserQuestion を使ってユーザーに質問します。

    質問ヘッダー選択肢
    Power Pages サイトは {SELECTED_STAGE.targetEnvironmentUrl} にデプロイされましたが、まだ有効化(プロビジョニング)されていません。一般公開するために今すぐ有効化しますか?サイトの有効化はい、今すぐ有効化する(推奨)、いいえ、後で有効化する
    • 「はい」の場合:/power-pages:activate-site を呼び出します。activate-site スキルがサブドメインの選択、確認、プロビジョニングを処理します。完了後、ACTIVATION_OUTCOME = { status: "Activated", siteUrl: "{activate-site から取得したサイト URL}" } を設定します。
    • 「いいえ」の場合:ACTIVATION_OUTCOME = { status: "Pending", siteUrl: null } を設定します。
  • error が存在する場合:ACTIVATION_OUTCOME = null を設定し、以下の更新手順を通知なしでスキップします。

有効化の結果が確定した後、実際の値を使って docs/alm/last-deploy.json をインプレースで Edit します。

  • "activationStatus": "{ACTIVATION_OUTCOME.status}"(または ACTIVATION_OUTCOME が null の場合は null のまま)
  • "siteUrl": "{ACTIVATION_OUTCOME.siteUrl}"(または null のまま)

ALM プランを再更新して、有効化の結果を反映します。 Phase 7.5b の更新は有効化の結果が確定する前に実行されたため、last-deploy.json に activationStatus が記録されても、プランの「{stage} でサイトを有効化」ステップはまだ保留状態です。マーカーを更新したら、更新を再実行してください。deploy-pipeline フェーズでは、activationStatus が "Activated" の場合に有効化ステップが自動的に完了します(後回しにした "Pending" の場合は保留状態のままです)。

node "${PLUGIN_ROOT}/scripts/lib/refresh-alm-plan-data.js" \
  --projectRoot "." \
  --phase deploy-pipeline \
  --render

(ALM プランが存在しない場合は何も行いません。docs/.alm-plan-data.json が存在しないとき、refresh-alm-plan-data.js は ok:false を返します。)

次に、デプロイ履歴 HTML ファイルの __ACTIVATION_SECTION__ を適切な HTML に置き換え、インプレースで Edit します。

  • status: "Activated" の場合:

    <div class="card">
      <h2>Site Activation</h2>
      <table><tbody>
        <tr><td class="label-col">Status</td><td style="color:var(--succeeded);font-weight:600;">✓ Activated</td></tr>
        <tr><td class="label-col">Site URL</td><td><a href="__SITE_URL__" style="color:var(--accent);">__SITE_URL__</a></td></tr>
      </tbody></table>
    </div>
    

    (__SITE_URL__ を ACTIVATION_OUTCOME.siteUrl に置き換えます)

  • status: "Pending" の場合:

    <div class="note-box neutral">
      <strong>Site activation pending.</strong> The solution was deployed but the site has not yet been provisioned in this environment. Run <code>/power-pages:activate-site</code> (with PAC CLI authenticated to the target environment) to activate it.
    </div>
    

ACTIVATION_OUTCOME が null(確認中にエラーが発生した場合)の場合は、__ACTIVATION_SECTION__ のプレースホルダーを空文字列にして、ファイルから削除します。

7.8 クラウドフローの登録を検出して案内する(デプロイが Succeeded の場合のみ):

ホスト環境でソリューションのコンポーネントを照会し、クラウドフローを検索します(componenttype 29 = Workflow)。

GET {hostEnvUrl}/api/data/v9.2/solutioncomponents?$filter=solutionid eq '{ARTIFACT_SOLUTION_ID}' and componenttype eq 29&$select=objectid,componenttype
Authorization: Bearer {HOST_TOKEN}
  • 結果がない場合:この手順を完全にスキップします。ソリューションにクラウドフローは含まれていません。

  • 結果がある場合:

    1. フローの数を数え、結果の件数を N に格納します。

    2. 各 objectid について、ホスト環境で workflows({objectid})?$select=name を照会し、フロー名の解決を試みます。いずれかの照会が失敗するか、名前が返されない場合は、生のオブジェクト ID を表示します。

    3. ユーザーに次のように伝えます。

      「ソリューションには {N} 個のクラウドフロー が含まれています。デプロイ後、正常に動作させるには、ターゲット環境でクラウドフローを Power Pages サイトに登録する必要があります。

      検出されたフロー: {フロー名または ID の箇条書きリスト}

      登録するには、Power Pages を開き、ターゲット環境 を選択してサイトを開き、セットアップ → クラウドフロー の順に選択し、上記の各フローを登録してください。」

    🚦 ゲート(plan · deploy-pipeline:7.cloud-flow-register): デプロイされたソリューション内のクラウドフローは、ターゲット環境で手動登録が必要です。確認するか、後で行うかを選択してください(ブロッキングではありません)。

    1. AskUserQuestion を使って質問します。

      質問ヘッダー選択肢
      ターゲット環境でクラウドフローを登録しましたか?クラウドフローの登録フローを登録しました。続行する、後で登録する
    2. ブロックしない:回答にかかわらず、サマリーのステップ(Phase 7.6)に進みます。クラウドフローの登録状況をサマリーテーブルに記録します。

      • 「Flows registered — continue」と回答した場合 → サマリーに Registered と表示します
      • 「I'll register them later」と回答した場合 → サマリーに Pending registration と表示します

    Note:登録をスキップまたは延期しても、デプロイが失敗したことを意味するものではありません。登録済みフローを呼び出すページのライブサイト機能にのみ影響します。

主な判断ポイント(ユーザーの応答待ち)

  1. Phase 2:対象ステージの選択(デプロイ先の環境)
  2. Phase 2:このステージへの前回のデプロイが失敗していた場合の再試行確認
  3. Phase 2.5:デプロイ前のブロックされた添付ファイルのブロック解除(Yes — unblock / No — proceed anyway / Cancel deploy)。対象環境の blockedattachments 設定がソリューションに必要な拡張子(通常は SPA サイトの .js)をブロックしている場合にのみ実行されます。テナント全体に適用されるセキュリティ設定を変更するため、明示的な同意が必要です。
  4. Phase 3.5:ライブサイトにソリューションに含まれていないコンポーネントがある場合の完全性ギャップの確認(まず同期/そのままデプロイ/キャンセル)
  5. Phase 3.5:同期後の承認ゲート — デプロイ途中の同期(Option 1)の後にのみ実行されます。新しいソリューションバージョンと新たに採用されたコンポーネントを表示し、対象ステージに昇格する前に同期後のソリューションを承認するようユーザーに求めます。一時停止すると正常に終了し、キャンセルすると中止します。
  6. Phase 3.6(MULTI_RUN_MODE のみ):バッチ検証の結果 — ここでは、次の2つのゲートが実行される可能性があります。
    • Batch Pending Approval:並列検証バッチ内の1つ以上のソリューションが Pending Approval になりました。ユーザーが PPAC ですべてを承認した後、再度ポーリングします。キャンセルすると、N 個の保留中ステージ実行が残ります。
    • バッチ検証失敗:1つ以上のソリューションの検証に失敗しました。デフォルトでは中止されます — 再エクスポートして再度呼び出してください。上級者向けオプションを選ぶと、成功したソリューションだけをデプロイできます(ギャップは last-deploy.json の knownGaps に記録されます)。
  7. Phase 4:検証承認ゲート — 単一ソリューション/v2 モードでのみ実行されます(MULTI_RUN_MODE では代わりに Phase 3.6 で処理されます)
  8. Phase 5:deployment-settings.json を事前に提示します(5.0a:概要を表示するかテンプレートを生成、5.0b:ファイルパスを表示)。選択したステージの事前設定値がない環境変数定義がソリューションに含まれている場合、環境変数の値は必ず表示されます。今後の実行用に値を保存するオプションを提示します。
  9. Phase 6.0:最終デプロイ同意ゲート — Deploy now / Cancel。DeployPackageAsync(または pac pipeline deploy のフォールバック)の直前に実行されます。本番環境への昇格時点を明確にします。このゲートがないと、検証が問題なく完了した際に、最終確認なしで Phase 5 から Phase 6.1 に進む可能性があります。本番環境を対象とする場合、最も重要な確認プロンプトとして扱ってください。
  10. Phase 6:デプロイ承認ゲート — デプロイ途中で Pending Approval になった場合、ユーザーが承認するまで待機します。
  11. Phase 7.6.2:ブロックされた添付ファイルの事後的なブロック解除(Yes — unblock and retry / No — leave settings unchanged / Cancel)。デプロイが AttachmentBlocked で失敗し、デプロイ前の確認(Phase 2.5)がスキップまたは拒否された場合にのみ実行されます。Phase 2.5 と同じセキュリティ設定への同意が必要です。
  12. Phase 7.7:サイトの有効化 — デプロイが Succeeded で、Power Pages の Web サイトコンポーネントが含まれており、対象環境でサイトがまだ有効化されていない場合にのみ実行されます。結果(activationStatus、siteUrl)は docs/alm/last-deploy.json とデプロイ履歴 HTML に書き戻されます。
  13. Phase 7.8:クラウドフローの登録 — デプロイが Succeeded で、ソリューションにクラウドフローコンポーネント(componenttype 29)が含まれている場合にのみ実行されます。ユーザーの回答にかかわらず、処理はブロックされません。

エラー処理

  • docs/alm/last-pipeline.json がない場合:停止し、/power-pages:setup-pipeline を案内します
  • ホスト環境のトークンが失敗した場合:az login の手順を案内して停止します
  • RetrieveDeploymentPipelineInfo が失敗した場合:フォールバックとして docs/alm/last-pipeline.json の sourceDeploymentEnvironmentId を使用します。アーティファクト一覧を取得できなかったことを警告し、ソリューションの確認をユーザーに求めます
  • ステージ実行の作成が失敗した場合(4xx):エラー本文全体を報告します。パイプラインの構成に問題がある可能性が高いです
  • ValidatePackageAsync が失敗した場合:エラーを報告します。通常、ソリューションのデプロイ準備ができていないことを意味します
  • 検証時の stagerunstatus = 200000003(Failed):検証の詳細を示して停止します。再試行の前に、ユーザーが問題を解決する必要があります(新しいステージ実行が必要です)
  • デプロイ時の stagerunstatus = 200000003(Failed):停止する前に、RetryFailedDeploymentAsync(POST /api/data/v9.1/RetryFailedDeploymentAsync {"StageRunId": "..."})での再試行を提案します
  • DeployPackageAsync 呼び出しが失敗した場合:エラーを報告して停止します
  • ポーリングがタイムアウトした場合(最大試行回数に到達):「デプロイに予想以上の時間がかかっています。Power Platform で状態を確認してください。」と伝えて停止します

進捗管理テーブル

タスクの内容実行中の状態説明
前提条件の確認前提条件を確認中PAC/az/WhoAmI のために verify-alm-prerequisites.js(--require-manifest --expectedEnvUrl はプロジェクト設定から取得。PAC 環境の不整合がある場合は強制停止)を実行し、solutionManifest/siteName のために detect-project-context.js を実行し、pipelineId/stages のために docs/alm/last-pipeline.json を読み取り、ホスト環境のトークンを取得します
対象ステージの選択対象ステージを選択中docs/alm/last-pipeline.json から利用可能なステージを表示し、ユーザーに対象を選択してもらいます。このステージへの前回のデプロイが失敗している場合は警告します
パイプライン情報の解決パイプライン情報を解決中RetrieveDeploymentPipelineInfo(v9.1)を呼び出して SourceDeploymentEnvironmentId と DeployableArtifacts を取得し、ソリューションを照合します
パッケージの検証パッケージを検証中MULTI_RUN_MODE:Phase 3.6 を1回(並列バッチ)実行します。validate-stage-runs-batch.js は、スキップされていないすべてのソリューションについて create-stage-run + ValidatePackageAsync + poll-validation-status を並行して実行します。いずれかの失敗、または承認待ちのバッチがある場合はデプロイを停止し、ソリューションごとの stageRunIds を保存して、直列デプロイループで再利用します。単一ソリューション/レガシー v2:Phase 4 をインラインで実行します。deploymentstageruns に POST(→ 201 または 204+header)、ValidatePackageAsync のトップレベルアクションに POST(204)、stagerunstatus が 200000006 以外になるまでポーリングし、JSON.parse で validationresults を2回解析し、aigenerateddeploymentnotes を取得し、artifactversion + deploymentnotes + deploymentsettingsjson(deployment-settings.json から取得)を PATCH します
デプロイ設定の構成デプロイ設定を構成中deployment-settings.json を確認/表示します(5.0a:読み取るかテンプレートを生成、5.0b:パスを提示)。環境変数の定義をソリューションに照会します(componenttype 380)。選択したステージについて deployment-settings.json との差分を確認し、未設定の値があればユーザーに入力を促します。deployment-settings.json への保存を提案し、ステージ実行に deploymentsettingsjson を PATCH します
デプロイと監視デプロイと監視中DeployPackageAsync のトップレベルアクションに POST(204)し、stagerunstatus が終端状態になるまでフィルター付き GET でポーリング(10秒間隔)します。承認ゲートに対応し(iscanceled=true を PATCH してキャンセル)、失敗時は RetryFailedDeploymentAsync の実行を提案し、10サイクルごとにトークンを更新します
デプロイ記録の作成デプロイ記録を作成中docs/alm/last-deploy.json(artifactVersion + deployHistoryFile フィールドを含む)を書き込み、docs/deploy-history/{date}-{stage}-{version}.md を作成し、git add + commit で履歴ファイルをコミットし、スキルの追跡を実行します。状態が Succeeded の場合:solutionManifest.cloudFlows が空でなければ接続参照に関する警告を表示し、solutionManifest.botComponents が空でなければボットの再公開に関する警告を表示して、概要を提示します。状態が Succeeded で Power Pages コンポーネントがある場合:PAC を対象環境に切り替え、check-activation-status.js を実行してから元に戻し、まだプロビジョニングされていない場合はユーザーに有効化を依頼します。状態が Succeeded でクラウドフローコンポーネント(componenttype 29)がある場合:solutioncomponents を照会し、フロー名を解決してユーザーに通知し、AskUserQuestion(ブロックしない)を呼び出し、概要に登録状況を記録します

コメント