mcpField
C
configure-env-variables

configure-env-variables

github.com/microsoft云与 DevOps1.1k164 次安装今天更新
代码仓库

关于 configure-env-variables

此 Power Pages 技能为 Dataverse 站点设置创建环境变量,并将两者关联,以便不同部署环境使用各自的配置值。它还会生成供 deploy-pipeline 使用的 deployment-settings.json。

主要功能

  1. 01创建 Dataverse 环境变量定义
  2. 02将站点设置关联到环境变量
  3. 03按部署阶段收集配置值
  4. 04生成 deployment-settings.json

适用场景

  1. 01为开发、预发布和生产环境配置不同值
  2. 02将静态站点设置改为环境变量来源
  3. 03为部署流水线准备阶段配置

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/microsoft/power-platform-skills --skill configure-env-variables

安装后在 Claude Code 中输入/configure-env-variables确认已加载。

附带文件scripts/validate-env-variables.js

详细介绍

插件检查:运行 node "${PLUGIN_ROOT}/scripts/check-version.js" — 如果输出了消息,请先向用户显示,然后再继续。

configure-env-variables

创建 Dataverse 环境变量,并将其关联到 Power Pages 网站设置,以便为不同部署环境(开发、预发布、生产)配置不同的值。生成供 deploy-pipeline 使用的 deployment-settings.json。

背景

Power Pages 网站设置可以由环境变量提供值(2025 年 3 月正式发布,仅适用于增强型数据模型)。关联后:

  • 网站设置的 mspp_source 从 0(静态值)变为 1(环境变量)
  • 运行时会读取当前环境的环境变量值,而不是静态的 mspp_value
  • 在管道部署期间,目标环境的值会通过 deploymentsettingsjson 注入

API 说明:网站设置 → 环境变量的关联通过经 HAR 确认的 OData PATCH 模式设置(v9.0,需要 EnvironmentValue 导航属性、if-match: * 和 clienthost: Browser 标头)。此操作由 scripts/lib/link-site-setting-to-env-var.js 处理。所有步骤均已完全自动化。

前置条件

  • PAC CLI 已通过身份验证:pac auth who
  • Azure CLI 令牌可用:az account get-access-token
  • 项目根目录下存在 .solution-manifest.json(请先运行 setup-solution)
  • Power Pages 网站已部署到开发环境(存在 .powerpages-site/ 文件夹)

阶段 0 — ALM 计划关卡

plan-alm 是入口。 当用户表达 ALM 意图(提升 / 发布 / 部署 / 设置 CI-CD / 移至预发布环境 / 推送到生产环境)时,应首先运行协调器(/power-pages:plan-alm)。此阶段 0 用于强制执行这一要求;如果没有计划,应默认拒绝,而不是只检查一次后就允许用户永久忽略。

跳过规则。 如果此技能是作为正在执行的 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 "."

辅助程序会返回包含 { exists, deferred, stale, staleness: { reason, detail }, generatedAt, planStatus, ... } 的 JSON。如果也需要检查计划是否为最新,请在阶段 1 获取 --envUrl、--token、--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 会生成计划——检测项目状态,询问你的提升策略(PP Pipelines 或手动导出/导入),将应设为环境变量的网站设置分类,并按正确顺序编排相应技能(包括当前技能)。要我现在运行 plan-alm 吗?”

🚦 Gate(意图 · configure-env-variables: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,从 docs/alm/alm-plan-context.json 中获取预先分类的 siteSettings。
  • 不使用计划继续 → 设置 BYPASSED_PLAN_GATE = true 并继续执行 Phase 1。
  • 取消 → 正常退出。

步骤 4 — 计划已过期。 告知用户:

“ALM 计划生成于 {generatedAt},但源解决方案此后已修改(修改时间:{solution.modifiedon})。组件可能已发生变化。重新运行 plan-alm 将刷新分析结果和渲染后的 HTML。”

🚦 Gate(意图 · configure-env-variables: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。
  • 取消 → 正常退出。

此门禁存在的原因。 直接调用 configure-env-variables 会创建环境变量定义和 deployment-settings.json,但不会执行编排器提供的逐阶段值收集、网站设置分类(keepAsIs / promoteToEnvVar / authNoValue / excluded)以及管道策略对齐。单独运行此技能的用户经常会选用与计划中的解决方案拆分不一致的环境变量架构名称,遗漏计划分类为需纳入的 authNoValue 设置,或生成与稍后由 setup-pipeline 配置的管道不匹配的阶段名称。此门禁确保 plan-alm 已运行(从而使环境变量决策与部署计划的其他部分保持一致),或者用户明确选择绕过它。

Phase 1 — 发现现有状态

读取项目上下文并查询 Dataverse,以了解已配置的内容。

1.1 读取项目文件:

cat .solution-manifest.json          # get solutionUniqueName, environmentUrl, publisher.prefix
cat docs/alm/last-pipeline.json              # get hostEnvUrl, stages[].name
ls .powerpages-site/site-settings/   # list all site setting YAML files

1.2 获取令牌并验证先决条件:

node "${PLUGIN_ROOT}/scripts/lib/verify-alm-prerequisites.js" \
  --envUrl "{devEnvUrl}" \
  --require-manifest

将输出捕获为 JSON;提取 .envUrl(保存为 devEnvUrl)和 .token(保存为 TOKEN)。

1.3 查询环境中现有的环境变量:

GET {devEnvUrl}/api/data/v9.2/environmentvariabledefinitions?$select=schemaname,displayname,type,defaultvalue,environmentvariabledefinitionid&$orderby=schemaname

1.4 查询已关联环境变量的网站设置(mspp_source = 1):

GET {devEnvUrl}/api/data/v9.2/mspp_sitesettings?$filter=mspp_source eq 1 and _mspp_websiteid_value eq {WEBSITE_ID}&$select=mspp_name,mspp_source,_mspp_environmentvariable_value,mspp_envvar_schema

从 .powerpages-site/website.yml 的 id 字段获取 WEBSITE_ID。

1.5 解析网站设置 YAML 文件,列出所有设置及其当前来源:

  • source: 1 的文件已由环境变量提供
  • source: 0 或不含 source 字段的文件为静态设置

向用户展示汇总表:

Current site settings (static):   48
Already env-var-backed:             3
Existing env var definitions:       2

阶段 2 — 选择站点设置并规划环境变量

询问用户哪些站点设置应由环境变量提供。将静态站点设置列表作为候选项列出。建议选择可能因环境而异的设置:

常见候选项:

  • Authentication/OpenIdConnect/AzureAD/ClientId — Entra ID 应用注册信息因环境而异
  • Authentication/OpenAuth/Microsoft/ClientId — OAuth 应用 ID
  • Authentication/OpenAuth/Microsoft/ClientSecret — OAuth 密钥(使用 Secret 类型)
  • Authentication/Registration/LocalLoginEnabled — 开发环境与生产环境中的设置可能不同
  • 任何 Authentication/Registration/OpenRegistrationEnabled — 开放注册策略
  • 用户添加的任何自定义站点设置

🚦 关卡(规划 · configure-env-variables:2.selection): 用户选择要提升为环境变量的站点设置。支持多选。取消操作将在创建任何环境变量定义之前退出。

通过 AskUserQuestion 询问:

“哪些站点设置应由环境变量提供?我会为每项设置创建一个环境变量,并引导你完成关联。

以下是候选项(输入编号,以逗号分隔):

  1. Authentication/Registration/LocalLoginEnabled(当前值:true)
  2. Authentication/OpenIdConnect/AzureAD/ClientId(当前值:空)
  3. [其他设置……] N. 我会输入自己的设置名称”

对于每个选定的设置,询问:

  1. 环境变量架构名称 — 使用 ${PLUGIN_ROOT}/scripts/lib/generate-env-var-schema-name.js 生成(与 setup-solution 共用的唯一来源):
    node "${PLUGIN_ROOT}/scripts/lib/generate-env-var-schema-name.js" \
      --publisherPrefix "{publisherPrefix}" --settingName "{settingName}"
    
    输出:{ schemaName, sanitized }。规范规则为 {prefix}_{settingName.replace(/[^A-Za-z0-9]+/g,'_').toLowerCase()} — 例如,Authentication/Registration/LocalLoginEnabled 会变为 ids_authentication_registration_localloginenabled。此处不得内置自定义规则:setup-solution 会通过此辅助工具生成架构名称,而 configure-env-variables 必须与 setup-solution 已创建的名称一致(否则无法关联现有站点设置)。如果用户有理由,可以覆盖建议值,但默认值必须由此辅助工具生成。
  2. 显示名称(便于阅读)
  3. 类型:String(默认)、Boolean、Number、Secret
  4. 开发/源值(默认值 = YAML 中当前的 mspp_value)
  5. 各阶段的值 — 对于 docs/alm/last-pipeline.json 中的每个阶段,应使用什么值?

示例:

Setting: Authentication/Registration/LocalLoginEnabled
  Schema name: ids_authentication_registration_localloginenabled
  Display name: IdeaSphere Local Login Enabled
  Type: String (site settings always resolve as strings)
  Dev value: true
  Staging value: false
  Production value: false

阶段 3 — 创建环境变量定义

对于每个规划的环境变量,根据 typeCode 分支处理:

{displayName} 替换规则 — 选择易读的标签,而不是架构名称。 Dataverse 中 environmentvariabledefinition 的 displayname 列会显示在 PPAC、渲染后的 ALM 计划的 Env Variables 选项卡以及 last-env-vars.json 中。如果将架构名称(例如 c311_api_secret)代入 --displayName,计划和 PPAC 中都会显示原始标记。请从源站点设置中选择易读的标签(例如,从 c311/api_secret 的 Description 或其在 planData 中易读的标题提取 API Secret)。如果没有易读的标签,则根据架构名称生成一个:去掉前缀,将剩余部分转换为标题式大小写(例如,c311_api_secret → Api Secret → 手动调整为 API Secret)。请让 displayName 和 schemaName 保持明显不同,因为它们面向不同的受众。

3.A — 字符串环境变量(typeCode = 100000000)

仅定义流程——每个阶段的值会在部署时通过 deploymentsettingsjson PATCH 从 deployment-settings.json 中获取。

3.A.1 检查并按需创建,使用 create-env-var-definition.js(脚本会在提交前按 schemaName 检查是否已有定义):

node "${PLUGIN_ROOT}/scripts/lib/create-env-var-definition.js" \
  --envUrl "{devEnvUrl}" \
  --token "{TOKEN}" \
  --schemaName "{schemaName}" \
  --displayName "{displayName}" \
  --type 100000000 \
  --defaultValue "{devValue}"

将输出捕获为 JSON;提取 .definitionId(存储为 envVarDefId),并检查 .created(true = 新建,false = 已存在)。如果定义已存在,请先确认其符合预期,再继续操作。

3.A.2 创建当前环境的值(当前有效的开发值,与 defaultvalue 分开):

POST {devEnvUrl}/api/data/v9.2/environmentvariablevalues
Content-Type: application/json

{
  "[email protected]": "/environmentvariabledefinitions({envVarDefId})",
  "value": "true"
}

响应:HTTP 204。

3.B — 有 Key Vault 密钥 URI 时的密钥环境变量(typeCode = 100000005)
可接受的密钥引用格式

Dataverse / Power Platform Pipelines 处理程序对密钥类型环境变量的值仅接受以下三种格式。其他格式会在导入时被拒绝,并显示 "ImportAsHolding failed: The value provided as a secret reference does not match a valid secret reference format"——由于主机会串行处理导入,部署排队数小时后才可能出现此拒绝。部署前验证器(deploy-pipeline Phase 5.1b,辅助程序位于 scripts/lib/validate-deployment-settings.js)会提前检查这些格式;这里也列出它们,以便编写 deployment-settings.json 的 SKILL.md 作者从一开始就使用正确格式。

可接受的格式:

  1. Key Vault 密钥标识符 URI——store-keyvault-secret.js 在其 secretUri 输出中生成的格式:

    https://<vault>.vault.azure.net/secrets/<name>
    https://<vault>.vault.azure.net/secrets/<name>/<32-char-hex-version>
    

    Vault 名称必须为 3–24 个字符,仅包含小写字母、数字和连字符,以字母开头,以字母或数字结尾。这是规范格式,也是 add-server-logic Phase 7.2a 通过面向用户的“分享 secretUri 输出”步骤返回的格式。

  2. Azure 资源 ID——完整的 ARM 风格路径,适用于制作者手边没有 URI 格式的情况:

    /subscriptions/<subscriptionId>/resourceGroups/<rg>/providers/Microsoft.KeyVault/vaults/<vault>/secrets/<name>
    

    Dataverse 同时接受 resourceGroups 和 resourcegroups 两种大小写形式。

  3. 空字符串 ""——如果环境变量定义中已设置合理的默认值,这就是有效值。在 deployment-settings.json 中按阶段设置 Value: "",表示 “此阶段使用定义中的默认值。”

不接受的格式(验证器会标记):

  • @KeyVault(vaultName=<vault>;secretName=<name>)——模板风格的占位符。**Dataverse 无法识别。**真实使用中的失败案例:这种格式导致排队等待 4 小时 41 分钟后出现 ImportAsHolding 失败。请替换为格式(1)或(2)。
  • <TODO>、<KEY_VAULT_URI>、<PLACEHOLDER>、${ENV_VAR}——任何尖括号或 shell 风格的占位符。同样,这些是 Dataverse 无法解析的制作者惯用写法。
  • 纯文本密钥值——既不安全(文件会提交到 git),也会被 Dataverse 拒绝,因为环境变量类型是 Secret。如果制作者原本想用纯文本,环境变量类型应为 String(100000000),而不是 Secret(100000005)。
  • 看起来像 Key Vault URI、但不符合规范格式的 HTTPS URL(例如主机后缀为 .com 而不是 .net、缺少 /secrets/ 段或版本后缀过短)。验证器会将这些情况明确标记为 invalid-uri,方便制作者修正拼写错误,而不是重新生成值。
实现

当用户已将密钥存储在 Azure Key Vault 中,并拥有规范形式的 Secret Identifier URI 时,请使用原子深度插入路径 — 与 add-server-logic Phase 7.2a 使用的流程相同:

node "${PLUGIN_ROOT}/scripts/create-environment-variable.js" "{devEnvUrl}" \
  --schemaName "{schemaName}" \
  --displayName "{displayName}" \
  --type secret \
  --value "{secretUri}"

此脚本会执行一次 POST 深度插入,同时创建 environmentvariabledefinition(类型 100000005)和 environmentvariablevalues 行,并将 Key Vault URI 写入 value — Dataverse 会在运行时通过解引用 URI 来解析密钥。该脚本支持 ALM,并通过 AddSolutionComponent 将新定义添加到目标解决方案中(与该系列其余脚本使用相同的 resolve-target-solution.js 解析顺序)。

交叉引用:请参阅 ${PLUGIN_ROOT}/skills/add-server-logic/SKILL.md Phase 7.2a,了解完整的 Key Vault 端到端流程:选择保管库(list-azure-keyvaults.js / create-azure-keyvault.js)、存储密钥(使用 stdin 调用 store-keyvault-secret.js,以避免密钥出现在对话中),以及将 URI 传回以创建环境变量。实现完全相同;我们会复用相同的辅助脚本。

3.C — 不含 Key Vault URI 的 Secret 环境变量(旧版 / 延后处理)

如果用户尚未选择 Key Vault,或尚未存储密钥,请使用空值占位符创建定义,并告知用户在导入后通过 Power Platform Admin Center 设置该值:

node "${PLUGIN_ROOT}/scripts/lib/create-env-var-definition.js" \
  --envUrl "{devEnvUrl}" \
  --token "{TOKEN}" \
  --schemaName "{schemaName}" \
  --displayName "{displayName}" \
  --type 100000005

(省略 --defaultValue — 添加 environmentvariablevalues 行之前,Dataverse 会将 Secret 类型定义存储为没有默认值)。告知用户必须在每个目标环境中通过 PPAC → Solutions → Environment Variables → select → set value 来设置该值。此路径是旧版回退方案;专用的 configure-secrets 技能(已排入后续 PR)最终将负责端到端编排凭据类设置的 3.B 路径。

类型代码参考
  • 100000000 = String — 通过路径 3.A 处理。
  • 100000005 = Secret — 通过路径 3.B 处理(有 Key Vault URI 时优先使用),或通过路径 3.C 处理(延后处理 / 旧版)。

其他规范类型(100000001 Number、100000002 Boolean、100000003 JSON、100000004 DataSource)均通过路径 3.A 处理,并使用相应的 --type 代码。

跟踪已创建的环境变量 ID:{ schemaName, envVarDefId, siteSettingName, devValue, stageValues: { stageName: value } }。

第 4 阶段 — 将站点设置链接到环境变量

对于要链接的每个站点设置,运行 link-site-setting-to-env-var.js(已通过 HAR 确认的 v9.0 API PATCH — 无需 UI 步骤):

node "${PLUGIN_ROOT}/scripts/lib/link-site-setting-to-env-var.js" \
  --envUrl "{devEnvUrl}" \
  --token "{TOKEN}" \
  --siteSettingId "{siteSettingId}" \
  --definitionId "{envVarDefId}" \
  --schemaName "{schemaName}"

将输出捕获为 JSON;检查 .ok 和 .verified 是否都为 true。脚本会使用必需的 if-match: * 和 clienthost: Browser 标头应用 PATCH,然后验证 mspp_source === 1 且 _mspp_environmentvariable_value 与定义 ID 匹配。

如果 .ok 为 false 或 .verified 为 false,请报告错误并询问用户:

"将 {settingName} 链接到环境变量 {schemaName} 失败。你希望如何继续?

  1. 重试
  2. 跳过此设置 — 保留为静态值
  3. 取消"

第 5 阶段 — 将环境变量添加到解决方案

对于每个环境变量定义,将其添加到解决方案中:

POST {devEnvUrl}/api/data/v9.2/AddSolutionComponent
Content-Type: application/json

{
  "ComponentId": "{envVarDefId}",
  "ComponentType": 380,
  "SolutionUniqueName": "IdeaSphereSolution",
  "AddRequiredComponents": false,
  "DoNotIncludeSubcomponents": false
}

响应:HTTP 200,包含 { "id": "..." }。

注意:不要将 environmentvariablevalues 记录添加到解决方案中 — 这些记录因环境而异,必须保留在各自环境中。只有定义(类型 380)才应添加到解决方案中。

验证环境变量是否出现在解决方案组件中:

GET {devEnvUrl}/api/data/v9.2/solutioncomponents?$filter=_solutionid_value eq {solutionId} and componenttype eq 380&$select=objectid

第 6 阶段 — 生成 deployment-settings.json

在项目根目录中写入 deployment-settings.json。此文件存储各阶段的环境变量覆盖值,并由 deploy-pipeline 读取。

{
  "$schema": "https://schemas.microsoft.com/power-platform/deployment-settings/2024",
  "description": "Per-stage environment variable values for IdeaSphereSolution pipeline deployments. Commit this file. Do not store secrets here — use Secret type env vars backed by Key Vault instead.",
  "stages": {
    "Deploy to Staging": {
      "EnvironmentVariables": [
        {
          "SchemaName": "ids_LocalLoginEnabled",
          "Value": "false"
        }
      ],
      "ConnectionReferences": []
    }
  }
}

阶段名称必须与 docs/alm/last-pipeline.json 中的 stages[].name 值完全一致。

对于 Secret 类型环境变量:写入 "Value": "",并添加注释,指示用户通过 Azure Key Vault 或管道密钥填入值 — 切勿在此文件中存储原始密钥。

阶段 6.1 — 写入前验证(必需,不得跳过)

将 deployment-settings.json 写入磁盘之前,先根据规范的 Secret 引用格式验证每个条目。Power Platform Pipelines 处理程序会在导入时验证 deploymentsettingsjson PATCH,而此时阶段运行可能已排队等待串行导入数小时。这里的错误值(例如模板风格的 @KeyVault(vaultName=...;secretName=...) 占位符、原始 Secret 内容或格式错误的 URI)会导致导入失败,并显示 "ImportAsHolding failed: The value provided as a secret reference does not match a valid secret reference format";用户可能要数小时后才能发现。实时证据(2026-05-21 Citizens portal 部署):deployment-settings.json 中的 @KeyVault(...) 占位符被发送到主机,排在其他导入之后,等待 4 小时 41 分钟后遭到拒绝。

在写入时捕获无效值,决定了是不到一秒就硬性拦截,还是陷入数小时的盲目等待。

node "${PLUGIN_ROOT}/scripts/lib/validate-deployment-settings.js" \
  --settingsFile "./deployment-settings.json" \
  --envUrl "{devEnvUrl}" \
  --token "{token}"

此辅助程序会读取刚写入的文件,根据 valueFormat(kv-uri / kv-resource-id / kv-placeholder / empty / plain-text / invalid-uri)对每个 EnvironmentVariables[] 条目分类;如果提供了 --envUrl,还会将 Secret 类型条目与 Dataverse 类型查找结果交叉核对,并输出 { summary: { valid, invalid, "unknown-type", skipped }, findings[] }。根据 summary.invalid 采取操作:

  • summary.invalid === 0 → 继续执行阶段 7。
  • summary.invalid > 0 → 停止。将每个无效的 findings[] 条目及其 schemaName、valueFormat、value 和 message 提示给用户。常见问题:
    • @KeyVault(vaultName=...;secretName=...) → kv-placeholder(Dataverse 永远不会识别的模板风格格式)。修复方法:替换为 Key Vault Secret Identifier URI https://<vault>.vault.azure.net/secrets/<name>[/<version>] 或完整的 Azure 资源 ID /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.KeyVault/vaults/<vault>/secrets/<name>,也可以使用空字符串,以回退到环境变量定义的默认值。
    • 原始 Secret 内容(任何不符合 URI 或资源 ID 模式的普通字符串)→ plain-text。修复方法:切勿提交原始 Secret;改用 Key Vault URI/资源 ID,或者使用空字符串,并通过管道 Secret 按阶段填充。
    • 格式错误的 URI → invalid-uri。修复方法:重新根据上述规范格式检查。

用户提供修正后的值后,重新运行验证。只有在 summary.invalid === 0 时才能继续执行阶段 7。

🚦 门槛(同意 · configure-env-variables:6.1.invalid-secret-values): 写入前验证发现了格式无效的 Secret 引用。拒绝提交包含这些值的文件——修正或中止。调用方无法绕过此门槛:每个已记录的无效值都会导致导入失败。

为何此门槛会硬性拦截,而不是“仍然继续”: 对已知无效的 Secret 引用,不存在“强制写入”的意义。Pipelines 处理程序会在导入时确定性地拒绝该引用。仍然写入只会白白浪费排队等待时间。如果用户确实还没有规范的 Key Vault URI,正确做法是保留 Value: ""(定义默认值),等 Secret 引用准备就绪后再处理。

阶段 7 — 验证并提交

7.1 同步站点设置 YAML — 运行 pac pages upload-code-site,将更新后的站点设置(现在 Dataverse 中已显示 source: 1)推送回 YAML:

pac pages upload-code-site --rootPath "." --environment {devEnvUrl}

上传后,检查更新后的 YAML 文件——其中现在应包含 source: 1,并引用环境变量架构名称。

7.2 验证解决方案包含环境变量:

GET {devEnvUrl}/api/data/v9.2/solutioncomponents?$filter=_solutionid_value eq {solutionId} and componenttype eq 380

7.2b 验证值已写入开发环境。 创建定义和值后,查询开发环境,确认每条 environmentvariablevalues 记录都已存在。共享辅助程序 scripts/lib/verify-env-var-values.js 会执行此只读检查:

node "${PLUGIN_ROOT}/scripts/lib/verify-env-var-values.js" \
  --envUrl "{devEnvUrl}" \
  --schemaNames "{comma-separated schema names just created}"

将 stdout 捕获为 JSON。如果 summary.landed === summary.total,则本地定义 + 值链正常,deploy-pipeline Phase 5.2 的 deploymentsettingsjson PATCH 将具备所需内容。如果 summary.missing > 0,则记录一行警告,并建议重新运行 configure-env-variables——最可能的原因是临时 OData 写入失败,导致某个定义没有与之配对的值。同一个辅助程序也会在部署时针对目标环境运行(deploy-pipeline Phase 7.6.5);将此检查集中起来,可确保开发端写入和目标端落地的诊断格式一致。

7.2b.bump 提升源解决方案版本并同步清单。 创建新的环境变量定义并通过 AddSolutionComponent 将其添加到解决方案,会修改 solutions.modifiedon。提升补丁版本段,让下游技能看到严格递增的版本标签,并确保本地 .solution-manifest.json 跟踪此变更:

node "${PLUGIN_ROOT}/scripts/lib/bump-solution-version.js" \
  --envUrl "{devEnvUrl}" \
  --token "{token}" \
  --uniqueName "{solutionUniqueName}" \
  --projectRoot "."

辅助程序返回 { previous, next, bumped: true, manifestUpdated, manifestUpdateReason }。--projectRoot "." 会使其以原子方式更新 .solution-manifest.json 中的 solution.version(或多解决方案模式下匹配的 solutions[].version)。若不进行此提升,.solution-manifest.json 将落后于 Dataverse——在一次真实的 Citizens 门户运行中,已验证清单版本为 1.0.0.2,而在 configure-env-variables 和 deploy-pipeline 各自修改源之后,Dataverse 版本已升至 1.0.0.4。

7.2c 刷新配置后的环境变量快照。 重新运行发现辅助程序,将新创建的定义写入 docs/alm/last-env-vars.json。否则,渲染后的 ALM 计划中的 Env Variables 选项卡会停留在 setup-solution 上次写入的状态——新创建的定义要等到再次运行 plan-alm 才会显示。本阶段末尾调用的刷新辅助程序会将此旁文件载入 planData.envVars[],并将其同步到 docs/alm/alm-env-vars.json,确保两个快照都保持最新:

node "${PLUGIN_ROOT}/scripts/lib/discover-env-var-definitions.js" \
  --envUrl "{devEnvUrl}" \
  --publisherPrefix "{publisherPrefix}" \
  --websiteRecordId "{websiteRecordId}" \
  --token "{token}" \
  --solutionId "{solutionId}" > docs/alm/last-env-vars.json.tmp \
  && mv docs/alm/last-env-vars.json.tmp docs/alm/last-env-vars.json

临时文件写入模式可在发现过程遇到暂时性故障时保留之前的有效快照。传入 --solutionId,以便将结果限定到目标解决方案——若不传入,通用发布者前缀会返回同一租户中无关项目的环境变量。

7.3 提交:

git add .powerpages-site/site-settings/ deployment-settings.json
git commit -m "Configure env vars: {list of schema names} — link {setting names} to env vars for ALM"

7.4 显示摘要:

✅ Environment variables configured

Env vars created/confirmed:
  ids_LocalLoginEnabled → Authentication/Registration/LocalLoginEnabled
    Dev value: true
    Staging: false

Added to solution: IdeaSphereSolution (1 env var component)

deployment-settings.json written with:
  Stage "Deploy to Staging": ids_LocalLoginEnabled = false

Next steps:
  1. Run /power-pages:export-solution to export the updated solution
  2. Run /power-pages:deploy-pipeline — it will automatically read deployment-settings.json
     and inject the env var values during deployment
  3. After deployment, verify in staging: the Sign In button should be hidden
     (Authentication/Registration/LocalLoginEnabled = false)

7.5 记录技能使用情况:

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

按照参考中的技能跟踪说明记录此技能的使用情况。使用 --skillName "ConfigureEnvVariables"。

7.5b 刷新 ALM 计划(如果存在):

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

辅助程序会重新读取 docs/alm/last-env-vars.json,使新创建的定义出现在 planData.envVars[] 中;将 deployment-settings.json 中的各阶段值回填到“按环境划分的值”矩阵(--live 还会合并从计划中各阶段的实时 environmentvariablevalues 表读取的值,因此在 Power Platform 管理中心设置的值也会显示;deployment-settings.json 中的值优先,查询失败的阶段会列在输出的 liveEnvVars.errors 中,并保持不变);将 plannedEnvVarCount 置零,写入 LAST_SYNC_AT,并重新渲染 docs/alm-plan.html。当 docs/.alm-plan-data.json 不存在时(独立调用,不属于 ALM 计划),辅助程序会返回 ok:false,作为软性空操作——可安全地无条件运行。 呈现实时查询失败。 当辅助程序的 stdout JSON 中 liveEnvVars.errors[] 非空时,告诉用户哪些阶段无法读取,每个阶段占一行:“无法读取 {stage} 的实时环境变量值:{error}。Values by Environment 矩阵中的该列保持不变,因此其中可能缺少或包含过时的 Power Platform Admin Center 值。” 当错误为 HTTP 401/403 或提示无法获取令牌时,最可能的原因是 Azure CLI 登录的租户与该环境的租户不同(az 会为其默认订阅的租户签发令牌,该租户可能与 PAC CLI 配置文件中的租户不同),因此建议运行 az login --tenant <environment tenant id>(或 az account set --subscription <a subscription in that tenant>),然后重新运行上面的刷新命令。这仅用于提供信息——不要因此导致技能失败或阻止摘要生成。当 liveEnvVars 缺失或 errors 为空时,不要提及此事。

告知用户下一步(由用户决定执行顺序)。 辅助程序的 stdout JSON 中包含 nextStep: { name, skill: string | null } | null。当其非空时,根据 skill 分支处理:当 skill 非空时,告诉用户 “计划已更新。计划中的下一步:{nextStep.name} → 准备好后运行 {nextStep.skill}。”;当 skill 为 null(例如 Finalize 这样的内部步骤,没有用户可运行的命令)时,只提及步骤名称——“计划已更新。计划中的下一步:{nextStep.name}。”——绝不要输出 run null。当其为 null 或辅助程序返回 ok:false 时,不要提及下一步。绝不要自动调用下一项技能——由用户决定执行顺序。

关键决策点(等待用户)

阶段决策选项
Phase 2选择要由环境变量支持的站点设置从列表中选择
Phase 2环境变量架构名称、类型及各阶段的值逐项输入
Phase 4链接失败时重试/跳过/取消重试/跳过/取消
Phase 7检查提交和后续步骤继续/调整

任务进度表

任务主题进行中的任务说明
发现现有状态正在发现现有状态读取清单,查询 Dataverse 中现有的环境变量和已链接的站点设置,并列出候选项
规划环境变量正在规划环境变量询问用户要由环境变量支持哪些站点设置,并收集架构名称、类型、开发环境值和各阶段的值
创建环境变量定义正在创建环境变量定义为每个计划中的环境变量 POST environmentvariabledefinitions + environmentvariablevalues
将站点设置链接到环境变量正在链接站点设置为每项设置运行 link-site-setting-to-env-var.js;根据输出验证 .ok 和 .verified
将环境变量添加到解决方案正在将环境变量添加到解决方案为每个环境变量定义运行 AddSolutionComponent(类型 380)
生成 deployment-settings.json正在生成部署设置写入包含各阶段环境变量值的 deployment-settings.json
验证并提交正在验证并提交同步 YAML,验证解决方案组件,提交并呈现摘要

评论

支持 Markdown