Azure Pipelines:在YAML之间共享值的问题
我是Azure pipeline yaml的新手。
以下是一些背景信息:我这里有一个 azure-pipelines.yml,如下所示,它调用了另一个 dotnet-test-build-and-deploy-to-aks-template.yaml。
在这个 dotnet-test-build-and-deploy-to-aks-template.yaml 中,我收集了 WorkItemIds,打算把它推送到另一个级联的 dotnet-deployment-stage.yaml@templates,但我所做的所有测试都不起作用。
在 dotnet-deployment-stage.yaml@templates 中得到的值始终是空白或空值。
从我目前的观察来看,WorkItemIds 已经被正确收集并在 Write-Host "Work Item IDs: $wiIds" 中显示,因此我得到了这个值。
在Debug WI的输出中,我得到的是空字符串,在级联的dotnet-deployment-stage.yaml中也同样是空字符串。
有人能帮忙把这些 $wiIds 推送到级联模板吗?
这是我的 azure-pipelines.yml:
trigger:
branches:
include:
- master
paths:
include:
- 'src/*'
- 'helm/*'
resources:
repositories:
- repository: templates
type: git
name: "Test/Test-Pipeline-Templates"
ref: 'refs/heads/users/Bob/Task-1623737-report-status-back-to-US'
stages:
- template: dotnet-test-build-and-deploy-to-aks-template.yaml@templates
parameters:
projectPath: 'src/Wrs.RuleService'
helmFilesPath: 'helm'
dockerfilePath: './Dockerfile'
dockerfileContext: '.'
appName: 'businessrule-service'
dotnetVersion: '8.x'
sonar: true
sonarProjectKey: 'Wrs-teams_AKS_RuleService'
这是 dotnet-test-build-and-deploy-to-aks-template.yaml:
parameters:
- name: projectPath
type: string
- name: helmFilesPath
type: string
- name: dockerfilePath
type: string
- name: dockerfileContext
type: string
- name: appName
type: string
- name: dockerRegistry
default: 'ACR Service Connection - Staging'
type: string
- name: dockerRegistriesToPushImages
default: ['ACR Service Connection - Staging', 'ACR Service Connection - Prod']
type: object
- name: dotnetVersion
default: '8.x'
type: string
- name: sonar
type: boolean
default: false
- name: sonarProjectKey
type: string
default: ''
- name: skipDeploymentEnvironments
default: ['test']
type: object
stages:
# ===============================================================
# 1) BUILD STAGE
# ===============================================================
- stage: Build
displayName: Build
pool:
vmImage: 'ubuntu-latest'
jobs:
# ------------------------------------------------------------
# 1. Build template
# ------------------------------------------------------------
- template: dotnetcore-docker-test-build.yaml@templates
parameters:
projectPath: '${{ parameters.projectPath }}'
helmFilesPath: '${{ parameters.helmFilesPath }}'
dockerfilePath: '${{ parameters.dockerfilePath }}'
dockerfileContext: '${{ parameters.dockerfileContext }}'
appName: '${{ parameters.appName }}'
dockerRegistry: '${{ parameters.dockerRegistry }}'
dockerRegistriesToPushImages: ${{ parameters.dockerRegistriesToPushImages }}
dotnetVersion: '${{ parameters.dotnetVersion }}'
# ------------------------------------------------------------
# 2. Collect WI IDs
# ------------------------------------------------------------
- job: collect_workitems
displayName: "Collect Work Item IDs"
pool:
vmImage: ubuntu-latest
steps:
- task: PowerShell@2
name: extract_pr_and_wi
displayName: "Extract PR ID and Work Item IDs"
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
inputs:
targetType: 'inline'
script: |
$ErrorActionPreference = "Stop"
$msg = "$(Build.SourceVersionMessage)"
Write-Host "Commit message: $msg"
$patterns = @(
'Merged PR (\d+):',
'Merge pull request #(\d+)',
'Merge PR (\d+)'
)
$prId = $null
foreach ($p in $patterns) {
if ($msg -match $p) {
$prId = $matches[1]
break
}
}
if (-not $prId) {
Write-Host "No PR ID found."
Write-Host "##vso[task.setvariable variable=PR_ID;isOutput=true]0"
Write-Host "##vso[task.setvariable variable=WI_IDS;isOutput=true]''"
exit 0
}
Write-Host "Extracted PR ID: $prId"
Write-Host "##vso[task.setvariable variable=PR_ID;isOutput=true]$prId"
$org = "$(System.CollectionUri)"
$project = "$(System.TeamProject)"
$repoId = "$(Build.Repository.ID)"
$token = "$(System.AccessToken)"
$headers = @{ Authorization = "Bearer $token" }
$uri = "$org$project/_apis/git/repositories/$repoId/pullRequests/$prId/workitems?api-version=7.1"
Write-Host "Fetching WI IDs from PR: $uri"
try {
$result = Invoke-RestMethod -Uri $uri -Headers $headers -Method Get
}
catch {
Write-Host "Failed to fetch WI IDs from PR"
throw
}
$wiIds = ($result.value.id | Sort-Object -Unique) -join ','
Write-Host "Work Item IDs: $wiIds"
Write-Host "##vso[task.setvariable variable=WI_IDS;isOutput=true]$wiIds"
# ------------------------------------------------------------
# 3. Debug WI output
# ------------------------------------------------------------
- job: debug_stageDeps
displayName: "DEBUG - stageDependencies"
dependsOn: collect_workitems
variables:
WI_TEST: $[ stageDependencies.Build.collect_workitems.outputs['extract_pr_and_wi.WI_IDS'] ]
steps:
- script: |
echo "DEBUG: WI_TEST = '$(WI_TEST)'"
displayName: "Print WI_TEST output"
# ===============================================================
# 2) DEPLOYMENT STAGE (must NOT be nested under Build.jobs)
# ===============================================================
- template: dotnet-deployment-stage.yaml@templates
parameters:
appName: '${{ parameters.appName }}'
skipDeploymentEnvironments: ${{ parameters.skipDeploymentEnvironments }}
workItemIds: $[ stageDependencies.Build.collect_workitems.outputs['extract_pr_and_wi.WI_IDS'] ]
appEnvironments:
- name: Dev
serviceConnection: 'staging-sc'
- name: Staging2
serviceConnection: 'staging-sc'
- name: Staging
serviceConnection: 'staging-sc'
- name: Prod
serviceConnection: 'prod-sc'
以及这里的最后一个阶段模板:
# dotnet-deployment-stage.yaml
parameters:
- name: appEnvironments
type: object
- name: appName
type: string
- name: helmArtifactName
type: string
default: 'helm-values'
- name: skipDeploymentEnvironments
default: ['test']
type: object
- name: workItemIds
type: string
stages:
- ${{ each appEnvironment in parameters.appEnvironments }}:
- stage: Release_${{ replace(parameters.appName, '-','_') }}_to_${{ appEnvironment.name }}
displayName: 'Deploy to ${{ appEnvironment.name }}'
condition: ${{ not(in(parameters.skipDeploymentEnvironments, appEnvironment.name)) }}
pool: Cloud-Stag2-DeploymentAgentPool
variables:
- template: envs/${{ lower(appEnvironment.name) }}.yaml
jobs:
- job: Trace_Stage_Inputs
displayName: "TRACE: dotnet-deployment-stage.yaml — inputs for ${{ appEnvironment.name }}"
steps:
- script: |
echo "=== TRACE: Entering dotnet-deployment-stage.yaml ==="
echo "Template: dotnet-deployment-stage.yaml"
echo "AppName: ${{ parameters.appName }}"
echo "Environment: ${{ appEnvironment.name }}"
echo "workItemIds param: '${{ parameters.workItemIds }}'"
displayName: "TRACE — Show template params"
- template: dotnet-deployment-job.yaml
parameters:
appName: '${{ parameters.appName }}'
helmArtifactName: '${{ parameters.helmArtifactName }}'
appEnvironment: ${{ appEnvironment }}
workItemIds: '${{ parameters.workItemIds }}'
解决方案
根据 Azure Doc's,你必须添加一个 dependsOn: collect_workitems,并在变量映射中传递输出的值,就像你在调试阶段所做的那样。
因此,正确的设置应该是:
- template: dotnet-deployment-job.yaml
dependsOn: collect_workitems
variables:
workItemIds: $[ stageDependencies.Build.collect_workitems.outputs['extract_pr_and_wi.WI_IDS'] ]
parameters:
appName: '${{ parameters.appName }}'
helmArtifactName: '${{ parameters.helmArtifactName }}'
appEnvironment: ${{ appEnvironment }}
workItemIds: $(workItemIds)
如果你想在同一个作业中使用该变量,你只需使用 $(workItemIds),但要跨越 jobs or stages 传递变量,你需要这个设置。