通过模板作业跨阶段使用管道变量

Using pipeline variables across stages with template jobs

问题描述

我在尝试将在一个阶段创建的变量用于另一个阶段时遇到了一些问题,并设法找到了描述如何完成此操作的各种新旧文章。最近的 articles/posts 识别新语法

$[stageDependencies.{stageName}.{jobName}.outputs['{stepName}.{variableName}']

这样使用:

variables:
  myVariable: $[stagedependencies.CreateStageVarStage.CreateStageVarJob.outputs['SetValueStep.VariableFromFirstStage']]

在您需要使用作业模板之前,这非常有效。

我在网上找到的

None个样本涵盖了模板的情况。他们只是演示了同一个yaml文件中的多个阶段如何获取值。

语法取决于能否将表达式放入变量中。不幸的是,当您将模板用于作业时,无法声明变量并将其作为参数传递会导致它未被评估。

- stage: UseJobTemplateStage
  displayName: 'Use Job Template Stage'
  dependsOn: CreateStageVarStage
  jobs:
  - template: templates/job-showstagevars.yml
    parameters:
      ValueToOutput: $[ stagedependencies.CreateStageVarStage.CreateStageVarJob.outputs['SetValueStep.VariableFromFirstStage'] ]

在此代码段中,它按原样出现。该值未被替换。

理论上,您可以将作业设置为在变量块中显示表达式,但这种硬编码破坏了模板的主要优点之一。

相关文章


Azure DevOps Release Notes - sprint 168

解决方案

答案其实并不遥远。原始表达式只需要通过模板作业中的变量传递。基本上,将变量设置为参数的值并使用宏语法来评估变量。

parameters:
- name: ValueToOutput
  type: string

...

  variables:
  - name: LocalVarOfValueToOutputParam
    value: ${{ parameters.ValueToOutput }}

使用 $(LocalVarOfValueToOutputParam) 的宏语法将导致值正确进入模板作业。

例子

如果我们有构建定义的 yaml 文件:

stages:
- stage: CreateStageVarStage
  displayName: 'Create StageVar Stage'
  jobs:
  - job: CreateStageVarJob
    displayName: 'Create StageVar Job'
    timeoutInMinutes: 5
    pool:
      name:    'Azure Pipelines'
      vmImage: 'windows-2019'
    steps:
      - checkout: none 
      - pwsh: |
          [string]$message = 'This is the value from the first stage'
          Write-Host "Setting output variable 'VariableFromFirstStage' to '$message'"
          Write-Output "##vso[task.setvariable variable=VariableFromFirstStage;isOutput=$true]$message"
        name: SetValueStep

- stage: UseJobTemplateStage
  displayName: 'Use Job Template Stage'
  dependsOn: CreateStageVarStage
  jobs:
  - template: templates/job-showstagevars.yml
    parameters:
      ValueToOutput: $[ stagedependencies.CreateStageVarStage.CreateStageVarJob.outputs['SetValueStep.VariableFromFirstStage'] ]

使用作业模板templates/job-showstagevars.yml

parameters:
- name: ValueToOutput
  type: string

jobs:
- job: ShowStageVarJob
  displayName: 'Show stage var'
  timeoutInMinutes: 5
  pool:
    name:    'Azure Pipelines'
    vmImage: 'windows-2019'

  variables:
  - name: LocalVarOfValueToOutputParam
    value: ${{ parameters.ValueToOutput }}

  steps:
  - checkout: none
  - pwsh: |
      Write-Host "ValueToOutput parameter=${{ parameters.ValueToOutput }}"
      Write-Host "LocalVarOfValueToOutputParam (pre-processor syntax)=${{ variables.LocalVarOfValueToOutputParam }}"
      Write-Host "LocalVarOfValueToOutputParam (macro syntax)=$(LocalVarOfValueToOutputParam)"
    displayName: 'Show StageVariable'

我们在第二阶段的输出中得到的是:

ValueToOutput parameter=$[ stagedependencies.CreateStageVarStage.CreateStageVarJob.outputs['SetValueStep.VariableFromFirstStage'] ]
LocalVarOfValueToOutputParam (pre-processor syntax)=$[ stagedependencies.CreateStageVarStage.CreateStageVarJob.outputs['SetValueStep.VariableFromFirstStage'] ]
LocalVarOfValueToOutputParam (macro syntax)=This is the value from the first stage

我知道这个问题问的是模板作业,但为了将来参考,我也想描述如何使用模板阶段来实现它。

它是通过接受的答案中的可变解决方法完成的,并且在不存在 dependsOn 时引用了 stagedependencies。 (模板不允许 dependsOn)。不知何故,这仍然有效。

使用阶段模板的 YAML 示例(我修改了接受的答案中的代码):

stages:
- stage: CreateStageVarStage
  displayName: 'Create StageVar Stage'
  jobs:
  - job: CreateStageVarJob
    displayName: 'Create StageVar Job'
    timeoutInMinutes: 5
    pool:
      name:    'Azure Pipelines'
      vmImage: 'windows-2019'
    steps:
      - checkout: none 
      - pwsh: |
          [string]$message = 'This is the value from the first stage'
          Write-Host "Setting output variable 'VariableFromFirstStage' to '$message'"
          Write-Output "##vso[task.setvariable variable=VariableFromFirstStage;isOutput=$true]$message"
        name: SetValueStep

# stage template cannot use dependsOn, but is still allowed to refer to stagedependencies...
- template: templates/stage-showstagevars.yml
  parameters:
      ValueToOutput: $[ stagedependencies.CreateStageVarStage.CreateStageVarJob.outputs['SetValueStep.VariableFromFirstStage'] ]

阶段模板:

parameters:
- name: ValueToOutput
  type: string

stages:
- stage: ShowStageVarStage

variables:
- name: LocalVarOfValueToOutputParam
  value: ${{ parameters.ValueToOutput }}

jobs:
- job: ShowStageVarJob
  displayName: 'Show stage var'
  pool:
    name:    'Azure Pipelines'
    vmImage: 'windows-2019'

  steps:
  - checkout: none
  - pwsh: |
      Write-Host "ValueToOutput parameter=${{ parameters.ValueToOutput }}"
      Write-Host "LocalVarOfValueToOutputParam (pre-processor syntax)=${{ variables.LocalVarOfValueToOutputParam }}"
      Write-Host "LocalVarOfValueToOutputParam (macro syntax)=$(LocalVarOfValueToOutputParam)"
    displayName: 'Show StageVariable'