这是一个简单的 Azure Pipeline,它说明了我的问题:-
jobs:
- job: BuildAndTest
steps:
- script: |
echo "##vso[task.setvariable variable=nuGetPackagesToBuild;isoutput=true]Configuration,Logging,UnitTests.Core"
name: GetChangedProjects
- job: CreateChangedNuGetPackages
dependsOn: BuildAndTest
variables:
nuGetPackagesToBuildFromBuildAndTestJob: $[ dependencies.BuildAndTest.outputs['GetChangedProjects.nuGetPackagesToBuild'] ]
steps:
- ${{ each nuGetPackageToBuild in split(variables.nuGetPackagesToBuildFromBuildAndTestJob, ',') }} :
- script: echo $(nuGetPackagesToBuildFromBuildAndTestJob) # Configuration,Logging,UnitTests.Core
- script: echo 'NuGet Packages to Build $(nuGetPackagesToBuild)' # $(nuGetPackagesToBuild)
- script: echo 'Creating NuGet Package1 ${{nuGetPackageToBuild}}' # $[ dependencies.BuildAndTest.outputs['GetChangedProjects.nuGetPackagesToBuild'] ]'
- script: echo 'Creating NuGet Package2 $(nuGetPackageToBuild)' # $(nuGetPackageToBuild)
我有一项工作(BuildAndTest),它创建需要重建的 NuGet 包数组(字符串)。在上面的示例中,列表是硬编码的,但在我的真实脚本中,列表是通过查看 Git 提交中的文件列表动态生成的。
第二个作业 (CreateChangedNuGetPackages) 从 BuildAndTest 作业中读取包列表。它有一个“each”语句,尝试迭代数组中的项目(使用 split() 将字符串转换为数组)。
您可以从 4 个 echo 语句中看到,无论我使用什么语法,nuGetPackageToBuild 变量都不会保留有用的值(例如“Configuration”)。相反,它保存文字字符串“$[ dependency.BuildAndTest.outputs['GetChangedProjects.nuGetPackagesToBuild'] ]”。它不应该这样做,因为我们可以从第一个 echo 语句中看到该变量已正确计算为“Configuration,Logging,UnitTests.Core”。
看起来好像“each”语句是在编译时而不是运行时评估的,因此不可能将“each”与动态生成的数组一起使用。
如果我在 CreateChangedNuGetPackages 作业中对列表进行硬编码,如下所示:-
nuGetPackagesToBuildFromBuildAndTestJob: 'Configuration,Logging,UnitTests.Core'
然后“each”语句似乎正确执行,并且 nuGetPackagesToBuild 变量包含正确的值,并且循环执行 3 次而不是一次(因为数组中有 3 个元素)。
我期望“每个”变量在运行时被分配正确的值。
如何为动态生成的数组中的每个元素执行管道步骤?
YAML 示例中的每个表达式都需要在编译时读取变量值。但跨作业变量:strong textnuGetPackagesToBuild 将在Runtime展开。
这种情况下,Each 表达式在编译时无法获取跨作业变量。所以它无法成功拆分变量。
恐怕没有现成的方法可以直接满足您的要求。
作为解决方法,我建议您可以将管道拆分为两个管道(作业 BuildAndTest -> 管道一和作业 CreateChangedNuGetPackages -> 管道二)。第一个管道将使用 PowerShell/Bash 脚本将变量值传递给第二个管道中的参数值。
这是一个例子:
管道一:
jobs:
- job: BuildAndTest
steps:
- task: PowerShell@2
inputs:
targetType: 'inline'
script: |
$token = "$(pat)"
$url="https://dev.azure.com/{Orgname}/{Projectname}/_apis/pipelines/{PipelineRunID}/runs?api-version=5.1-preview"
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($token)"))
$JSON = "
{
`"resources`": {
`"repositories`": {
`"self`": {
`"ref`": `"refs/heads/main`"
}
}
},
`"templateParameters`": {
`"nuGetPackagesToBuild`":`"Configuration,Logging,UnitTests.Core`"
},
}"
$response = Invoke-RestMethod -Uri $url -Headers @{Authorization = "Basic $token"} -Method Post -Body $JSON -ContentType application/json
管道二
parameters:
- name: nuGetPackagesToBuild
type: string
jobs:
- job: CreateChangedNuGetPackages
steps:
- ${{ each nuGetPackageToBuild in split(parameters.nuGetPackagesToBuild, ',') }} :
- script: echo 'Creating NuGet Package1 ${{nuGetPackageToBuild}}'
结果: