模板表达式可以扩展模板参数以及变量。 可以使用参数来影响模板的扩展方式。 parameters 对象的工作方式类似于表达式中的 variables 对象 。 在模板表达式中只能使用预定义变量。

只有 stages jobs steps containers (在 resources 内)的表达式会扩展。 例如,不能在 trigger 或类似 repositories 的资源中使用表达式。 此外,在 Azure DevOps 2020 RTW 上,不能在 containers 中使用模板表达式。

例如,定义模板:

# File: steps/msbuild.yml
parameters:
- name: 'solution'
  default: '**/*.sln'
  type: string
steps:
- task: msbuild@1
  inputs:
    solution: ${{ parameters['solution'] }}  # index syntax
- task: vstest@2
  inputs:
    solution: ${{ parameters.solution }}  # property dereference syntax

然后,引用模板并向其传递可选 solution 参数:

# File: azure-pipelines.yml
steps:
- template: steps/msbuild.yml
  parameters:
    solution: my.sln

在模板表达式中,可以访问 parameters 上下文,其中包含传入的参数值。 此外,还可以访问包含 YAML 文件中指定的所有变量以及许多预定义变量(注意该文章中的每个变量)的上下文 variables。 重要的是,它没有运行时变量,例如管道中存储的变量或在启动运行时给定的变量。 模板扩展发生在运行早期,因此这些变量不可用。

模板表达式函数

可以在模板中使用通用函数。 还可以使用一些模板表达式函数。

format

  • 简单字符串令牌替换
  • 最小参数:2。 最大参数:N
  • 示例:${{ format('{0} Build', parameters.os) }}'Windows Build'
  • coalesce

  • 求值为第一个非空、非 null 字符串参数
  • 最小参数:2。 最大参数:N
  • parameters:
    - name: 'restoreProjects'
      default: ''
      type: string
    - name: 'buildProjects'
      default: ''
      type: string
    steps:
    - script: echo ${{ coalesce(parameters.foo, parameters.bar, 'Nothing to see') }}
    

    可以使用模板表达式来更改 YAML 管道的结构。 例如,要插入序列:

    # File: jobs/build.yml
    parameters:
    - name: 'preBuild'
      type: stepList
      default: []
    - name: 'preTest'
      type: stepList
      default: []
    - name: 'preSign'
      type: stepList
      default: []
    jobs:
    - job: Build
      pool:
        vmImage: 'windows-latest'
      steps:
      - script: cred-scan
      - ${{ parameters.preBuild }}
      - task: msbuild@1
      - ${{ parameters.preTest }}
      - task: vstest@2
      - ${{ parameters.preSign }}
      - script: sign
    
    # File: .vsts.ci.yml
    jobs:
    - template: jobs/build.yml
      parameters:
        preBuild:
        - script: echo hello from pre-build
        preTest:
        - script: echo hello from pre-test
    

    将数组插入数组时,嵌套数组将平展。

    要插入到映射中,请使用特殊属性 ${{ insert }}

    # Default values
    parameters:
    - name: 'additionalVariables'
      type: object
      default: {}
    jobs:
    - job: build
      variables:
        configuration: debug
        arch: x86
        ${{ insert }}: ${{ parameters.additionalVariables }}
      steps:
      - task: msbuild@1
      - task: vstest@2
    
    jobs:
    - template: jobs/build.yml
      parameters:
        additionalVariables:
          TEST_SUITE: L0,L1
    

    有条件插入

    如果要有条件地插入到序列或模板中的映射中,请使用插入和表达式计算。 只要使用模板语法,就可以在模板外部使用 if 语句。

    例如,要插入到模板中的序列中,请执行以下操作:

    # File: steps/build.yml
    parameters:
    - name: 'toolset'
      default: msbuild
      type: string
      values:
      - msbuild
      - dotnet
    steps:
    # msbuild
    - ${{ if eq(parameters.toolset, 'msbuild') }}:
      - task: msbuild@1
      - task: vstest@2
    # dotnet
    - ${{ if eq(parameters.toolset, 'dotnet') }}:
      - task: dotnet@1
        inputs:
          command: build
      - task: dotnet@1
        inputs:
          command: test
    
    # File: azure-pipelines.yml
    steps:
    - template: steps/build.yml
      parameters:
        toolset: dotnet
    

    例如,要插入到模板中的映射中,请执行以下操作:

    # File: steps/build.yml
    parameters:
    - name: 'debug'
      type: boolean
      default: false
    steps:
    - script: tool
        ${{ if eq(parameters.debug, true) }}:
          TOOL_DEBUG: true
          TOOL_DEBUG_DIR: _dbg
    
    steps:
    - template: steps/build.yml
      parameters:
        debug: true
    

    还可以对变量使用条件插入。 在此示例中,start 始终输出,而 this is a test 仅在变量等于 foo 等于 test 时才会输出。

    variables:
      - name: foo
        value: test
    pool:
      vmImage: 'ubuntu-latest'
    steps:
    - script: echo "start" # always runs
    - ${{ if eq(variables.foo, 'test') }}:
      - script: echo "this is a test" # runs when foo=test
    

    还可以根据其他变量的值来设置变量。 在以下管道中,myVar 用于设置 conditionalVar 的值。

    trigger:
    - main
    pool: 
       vmImage: 'ubuntu-latest' 
    variables:
      - name: myVar
        value: 'baz'
      - name: conditionalVar
        ${{ if eq(variables['myVar'], 'foo') }}:
          value: 'bar'
        ${{ elseif eq(variables['myVar'], 'baz') }}:
          value: 'qux'
        ${{ else }}:
          value: 'default'
    steps:
    - script: echo "start" # always runs
    - ${{ if eq(variables.conditionalVar, 'bar') }}:
      - script: echo "the value of myVar is set in the if condition" # runs when myVar=foo
    - ${{ if eq(variables.conditionalVar, 'qux') }}:
      - script: echo "the value of myVar is set in the elseif condition" # runs when myVar=baz
    

    指令 each 允许基于 YAML 序列(数组)或映射(键值对)进行迭代插入。

    例如,可以使用其他步骤前和步骤后包装每个作业的步骤:

    # job.yml
    parameters:
    - name: 'jobs'
      type: jobList
      default: []
    jobs:
    - ${{ each job in parameters.jobs }}: # Each job
      - ${{ each pair in job }}:          # Insert all properties other than "steps"
          ${{ if ne(pair.key, 'steps') }}:
            ${{ pair.key }}: ${{ pair.value }}
        steps:                            # Wrap the steps
        - task: SetupMyBuildTools@1       # Pre steps
        - ${{ job.steps }}                # Users steps
        - task: PublishMyTelemetry@1      # Post steps
          condition: always()
    
    # azure-pipelines.yml
    jobs:
    - template: job.yml
      parameters:
        jobs:
        - job: A
          steps:
          - script: echo This will get sandwiched between SetupMyBuildTools and PublishMyTelemetry.
        - job: B
          steps:
          - script: echo So will this!
    

    还可以操作要循环访问的任何属性。 例如,要添加更多依赖项:

    # job.yml
    parameters:
    - name: 'jobs'
      type: jobList
      default: []
    jobs:
    - job: SomeSpecialTool                # Run your special tool in its own job first
      steps:
      - task: RunSpecialTool@1
    - ${{ each job in parameters.jobs }}: # Then do each job
      - ${{ each pair in job }}:          # Insert all properties other than "dependsOn"
          ${{ if ne(pair.key, 'dependsOn') }}:
            ${{ pair.key }}: ${{ pair.value }}
        dependsOn:                        # Inject dependency
        - SomeSpecialTool
        - ${{ if job.dependsOn }}:
          - ${{ job.dependsOn }}
    
    # azure-pipelines.yml
    jobs:
    - template: job.yml
      parameters:
        jobs:
        - job: A
          steps:
          - script: echo This job depends on SomeSpecialTool, even though it's not explicitly shown here.
        - job: B
          dependsOn:
          steps:
          - script: echo This job depends on both Job A and on SomeSpecialTool.
    

    如果需要对字面上包含 ${{ 的值进行转义,请将该值包装在表达式字符串中。 例如,${{ 'my${{value' }}${{ 'my${{value with a '' single quote too' }}