模板类型 & 用法

Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019

模板用于定义可重用的内容、逻辑和参数。 模板以两种方式发挥作用。 可以使用模板插入可重复使用的内容,也可以使用模板来控制管道中允许的内容。 第二种方法可用于 使用模板生成安全管道

如果使用模板来包含内容,它在许多编程语言中的工作方式类似于 include 指令。 一个文件中的内容插入到另一个文件中。 当模板控制管道中允许的内容时,该模板定义另一个文件必须遵循的逻辑。

使用模板定义逻辑一次,然后多次重复使用。 模板将多个 YAML 文件的内容合并到一个管道中。 可以将参数从父管道传递到模板中。

参数

可以在模板中指定参数及其数据类型,并将这些参数传递给管道。 还可以 在模板外部使用参数。 只能将文本用于参数默认值。

快速参考

参数必须包含名称和数据类型。 在 中 azure-pipelines.yml,当 参数 yesNo 设置为布尔值时,生成会成功。 当 设置为字符串(如 apples)时yesNo,生成将失败。

# File: simple-param.yml
parameters:
- name: yesNo # name of the parameter; required
  type: boolean # data type of the parameter; required
  default: false

steps:
- script: echo ${{ parameters.yesNo }}
# File: azure-pipelines.yml
trigger:
- main

extends:
  template: simple-param.yml
  parameters:
      yesNo: false # set to a non-boolean value to have the build fail

用于在运行时选择模板的参数

可以根据条件从管道 YAML 调用不同的模板。 在此示例中, experimental.yml 当 参数 experimentalTemplate 为 true 时,YAML 将运行。

#azure-pipeline.yml
parameters:
- name: experimentalTemplate
  displayName: 'Use experimental build process?'
  type: boolean
  default: false

steps:
- ${{ if eq(parameters.experimentalTemplate, true) }}:
  - template: experimental.yml
- ${{ if not(eq(parameters.experimentalTemplate, true)) }}:
  - template: stable.yml

参数数据类型

数据类型 说明
string 字符串
number 可能限制为 values:,否则接受任何类似数字的字符串
boolean truefalse
object 任何 YAML 结构
step 一个步骤
stepList 步骤序列
job 单个作业
jobList 作业序列
deployment 单个部署作业
deploymentList 部署作业序列
stage 单个阶段
stageList 阶段序列

步骤、stepList、作业、jobList、deployment、deploymentList、stage 和 stageList 数据类型都使用标准 YAML 架构格式。 此示例包括 string、number、boolean、object、step 和 stepList。

parameters:
- name: myString
  type: string
  default: a string
- name: myMultiString
  type: string
  default: default
  values:
  - default
  - ubuntu
- name: myNumber
  type: number
  default: 2
  values:
  - 1
  - 2
  - 4
  - 8
  - 16
- name: myBoolean
  type: boolean
  default: true
- name: myObject
  type: object
  default:
    foo: FOO
    bar: BAR
    things:
    - one
    - two
    - three
    nested:
      one: apple
      two: pear
      count: 3
- name: myStep
  type: step
  default:
    script: echo my step
- name: mySteplist
  type: stepList
  default:
    - script: echo step one
    - script: echo step two

trigger: none

jobs: 
- job: stepList
  steps: ${{ parameters.mySteplist }}
- job: myStep
  steps:
    - ${{ parameters.myStep }}

可以循环访问对象并打印对象中的每个字符串。

parameters:
- name: listOfStrings
  type: object
  default:
  - one
  - two

steps:
- ${{ each value in parameters.listOfStrings }}:
  - script: echo ${{ value }}

此外,还可以循环访问 对象中的嵌套元素。

parameters:
- name: listOfFruits
  type: object
  default:
  - fruitName: 'apple'
    colors: ['red','green']
  - fruitName: 'lemon'
    colors: ['yellow']

steps:
- ${{ each fruit in parameters.listOfFruits }} :
  - ${{ each fruitColor in fruit.colors}} :
    - script: echo ${{ fruit.fruitName}} ${{ fruitColor }}

从模板扩展

若要提高安全性,可以强制管道从特定模板进行扩展。 文件 start.yml 定义参数 ,该参数 buildSteps随后在管道 azure-pipelines.yml中使用。 在 中 start.ymlbuildStep 如果通过脚本步骤传递 ,则会拒绝该步骤,并且管道生成失败。 从模板扩展时,可以通过添加 所需的模板审批来提高安全性。

# File: start.yml
parameters:
- name: buildSteps # the name of the parameter is buildSteps
  type: stepList # data type is StepList
  default: [] # default value of buildSteps
stages:
- stage: secure_buildstage
  pool:
    vmImage: windows-latest
  jobs:
  - job: secure_buildjob
    steps:
    - script: echo This happens before code 
      displayName: 'Base: Pre-build'
    - script: echo Building
      displayName: 'Base: Build'

    - ${{ each step in parameters.buildSteps }}:
      - ${{ each pair in step }}:
          ${{ if ne(pair.value, 'CmdLine@2') }}:
            ${{ pair.key }}: ${{ pair.value }}       
          ${{ if eq(pair.value, 'CmdLine@2') }}: 
            # Step is rejected by raising a YAML syntax error: Unexpected value 'CmdLine@2'
            '${{ pair.value }}': error         

    - script: echo This happens after code
      displayName: 'Base: Signing'
# File: azure-pipelines.yml
trigger:
- main

extends:
  template: start.yml
  parameters:
    buildSteps:  
      - bash: echo Test #Passes
        displayName: succeed
      - bash: echo "Test"
        displayName: succeed
      # Step is rejected by raising a YAML syntax error: Unexpected value 'CmdLine@2'
      - task: CmdLine@2
        inputs:
          script: echo "Script Test"
      # Step is rejected by raising a YAML syntax error: Unexpected value 'CmdLine@2'
      - script: echo "Script Test"

从包含资源的模板进行扩展

还可以使用 extends 从 Azure 管道中包含资源的模板进行扩展。

# File: azure-pipelines.yml
trigger:
- none

extends:
  template: resource-template.yml
# File: resource-template.yml
resources:
  pipelines:
  - pipeline: my-pipeline 
    source: sourcePipeline

steps:
- script: echo "Testing resource template"

使用 templateContext 将属性传递给模板

可以使用 templateContext 将其他属性传递给用作模板中参数的阶段、步骤和作业。 具体而言,可以在 、 deploymentListstageList 参数数据类型中jobList指定 templateContext

可以使用 templateContext 在处理每个作业时更轻松地设置环境。 通过将作业及其环境属性对象捆绑在一起, templateContext 可帮助你拥有更易于维护且更易于理解的 YAML。

在此示例中,中的 testing-template.yml 参数testSet的数据类型jobList为 。 模板testing-template.yml使用 each 关键字创建新变量testJob。 然后,模板会引用 testJob.templateContext.expectedHTTPResponseCode,该元素在 中 azure-pipeline.yml 设置并传递给模板。

当响应代码为 200 时,模板会发出 REST 请求。 当响应代码为 500 时,模板将输出所有环境变量以供调试。

templateContext 可以包含属性。

#testing-template.yml

parameters: 
- name: testSet
  type: jobList

jobs:
- ${{ each testJob in parameters.testSet }}:
  - ${{ if eq(testJob.templateContext.expectedHTTPResponseCode, 200) }}:
    - job:
      steps: 
      - powershell: 'Invoke-RestMethod -Uri https://blogs.msdn.microsoft.com/powershell/feed/ | Format-Table -Property Title, pubDate'
      - ${{ testJob.steps }}    
  - ${{ if eq(testJob.templateContext.expectedHTTPResponseCode, 500) }}:
    - job:
      steps:
      - powershell: 'Get-ChildItem -Path Env:\'
      - ${{ testJob.steps }}
#azure-pipeline.yml

trigger: none

pool:
  vmImage: ubuntu-latest

extends:
  template: testing-template.yml
  parameters:
    testSet:
    - job: positive_test
      templateContext:
        expectedHTTPResponseCode: 200
      steps:
      - script: echo "Run positive test" 
    - job: negative_test
      templateContext:
        expectedHTTPResponseCode: 500
      steps:
      - script: echo "Run negative test" 

插入模板

可以从一个 YAML 复制内容,并在不同的 YAML 中重复使用它。 将内容从一个 YAML 复制到另一个 YAML 可避免在多个位置手动包含相同的逻辑。 文件 include-npm-steps.yml 模板包含在 中 azure-pipelines.yml重复使用的步骤。

注意

模板文件需要在管道运行开始时存在于文件系统上。 不能引用项目中的模板。

# File: templates/include-npm-steps.yml

steps:
- script: npm install
- script: yarn install
- script: npm run compile
# File: azure-pipelines.yml

jobs:
- job: Linux
  pool:
    vmImage: 'ubuntu-latest'
  steps:
  - template: templates/include-npm-steps.yml  # Template reference
- job: Windows
  pool:
    vmImage: 'windows-latest'
  steps:
  - template: templates/include-npm-steps.yml  # Template reference

步骤重用

可以插入模板,以便跨多个作业重复使用一个或多个步骤。 除了模板中的步骤外,每个作业还可以定义更多步骤。

# File: templates/npm-steps.yml
steps:
- script: npm install
- script: npm test
# File: azure-pipelines.yml

jobs:
- job: Linux
  pool:
    vmImage: 'ubuntu-latest'
  steps:
  - template: templates/npm-steps.yml  # Template reference

- job: macOS
  pool:
    vmImage: 'macOS-latest'
  steps:
  - template: templates/npm-steps.yml  # Template reference

- job: Windows
  pool:
    vmImage: 'windows-latest'
  steps:
  - script: echo This script runs before the template's steps, only on Windows.
  - template: templates/npm-steps.yml  # Template reference
  - script: echo This step runs after the template's steps.

作业重用

与步骤非常类似,作业可与模板一起重复使用。

# File: templates/jobs.yml
jobs:
- job: Ubuntu
  pool:
    vmImage: 'ubuntu-latest'
  steps:
  - bash: echo "Hello Ubuntu"

- job: Windows
  pool:
    vmImage: 'windows-latest'
  steps:
  - bash: echo "Hello Windows"
# File: azure-pipelines.yml

jobs:
- template: templates/jobs.yml  # Template reference

使用多个作业时,请记得在模板文件中删除作业的名称,以避免冲突

# File: templates/jobs.yml
jobs:
- job: 
  pool:
    vmImage: 'ubuntu-latest'
  steps:
  - bash: echo "Hello Ubuntu"

- job:
  pool:
    vmImage: 'windows-latest'
  steps:
  - bash: echo "Hello Windows"
# File: azure-pipelines.yml

jobs:
- template: templates/jobs.yml  # Template reference
- template: templates/jobs.yml  # Template reference
- template: templates/jobs.yml  # Template reference

阶段重用

阶段还可以与模板一起重复使用。

# File: templates/stages1.yml
stages:
- stage: Angular
  jobs:
  - job: angularinstall
    steps:
    - script: npm install angular
# File: templates/stages2.yml
stages:
- stage: Build
  jobs:
  - job: build
    steps:
    - script: npm run build
# File: azure-pipelines.yml
trigger:
- main

pool:
  vmImage: 'ubuntu-latest'

stages:
- stage: Install
  jobs: 
  - job: npminstall
    steps:
    - task: Npm@1
      inputs:
        command: 'install'
- template: templates/stages1.yml
- template: templates/stages2.yml

包含参数的作业、阶段和步骤模板

# File: templates/npm-with-params.yml

parameters:
- name: name  # defaults for any parameters that aren't specified
  default: ''
- name: vmImage
  default: ''

jobs:
- job: ${{ parameters.name }}
  pool: 
    vmImage: ${{ parameters.vmImage }}
  steps:
  - script: npm install
  - script: npm test

在管道中使用模板时,请指定模板参数的值。

# File: azure-pipelines.yml

jobs:
- template: templates/npm-with-params.yml  # Template reference
  parameters:
    name: Linux
    vmImage: 'ubuntu-latest'

- template: templates/npm-with-params.yml  # Template reference
  parameters:
    name: macOS
    vmImage: 'macOS-latest'

- template: templates/npm-with-params.yml  # Template reference
  parameters:
    name: Windows
    vmImage: 'windows-latest'

还可以将参数与步骤模板或阶段模板一起使用。 例如,包含参数的步骤:

# File: templates/steps-with-params.yml

parameters:
- name: 'runExtendedTests'  # defaults for any parameters that aren't specified
  type: boolean
  default: false

steps:
- script: npm test
- ${{ if eq(parameters.runExtendedTests, true) }}:
  - script: npm test --extended

在管道中使用模板时,请指定模板参数的值。

# File: azure-pipelines.yml

steps:
- script: npm install

- template: templates/steps-with-params.yml  # Template reference
  parameters:
    runExtendedTests: 'true'

注意

没有指定类型的标量参数被视为字符串。 例如, eq(true, parameters['myparam']) 将返回 true,即使 myparam 参数是单词 false,如果未 myparam 显式设置 boolean。 非空字符串在布尔上下文中强制转换为 true 。 可以重写该 表达式 以显式比较字符串: eq(parameters['myparam'], 'true')

参数不限于标量字符串。 请参阅 数据类型列表。 例如,使用 object 类型:

# azure-pipelines.yml
jobs:
- template: process.yml
  parameters:
    pool:   # this parameter is called `pool`
      vmImage: ubuntu-latest  # and it's a mapping rather than a string


# process.yml
parameters:
- name: 'pool'
  type: object
  default: {}

jobs:
- job: build
  pool: ${{ parameters.pool }}

变量重用

变量可以在一个 YAML 中定义,并包含在另一个模板中。 如果要将所有变量存储在一个文件中,这可能很有用。 如果使用模板在管道中包含变量,则包含的模板只能用于定义变量。 从模板进行扩展时,可以使用步骤和更复杂的逻辑。 如果要限制类型,请使用 参数 而不是变量。

在此示例中, 变量 favoriteVeggie 包含在 中 azure-pipelines.yml

# File: vars.yml
variables:
  favoriteVeggie: 'brussels sprouts'
# File: azure-pipelines.yml

variables:
- template: vars.yml  # Template reference

steps:
- script: echo My favorite vegetable is ${{ variables.favoriteVeggie }}.

带参数的变量模板

可以使用模板将参数传递给变量。 在此示例中,你要将 DIRECTORY 参数传递给变量 RELEASE_COMMAND

# File: templates/package-release-with-params.yml

parameters:
- name: DIRECTORY 
  type: string
  default: "." # defaults for any parameters that specified with "." (current directory)

variables:
- name: RELEASE_COMMAND
  value: grep version ${{ parameters.DIRECTORY }}/package.json | awk -F \" '{print $4}'  

在管道中使用模板时,请指定模板参数的值。

# File: azure-pipelines.yml

variables: # Global variables
  - template: package-release-with-params.yml # Template reference
    parameters:
      DIRECTORY: "azure/checker"

pool:
  vmImage: 'ubuntu-latest'

stages:
- stage: Release_Stage 
  displayName: Release Version
  variables: # Stage variables
  - template: package-release-with-params.yml  # Template reference
    parameters:
      DIRECTORY: "azure/todo-list"
  jobs: 
  - job: A
    steps: 
    - bash: $(RELEASE_COMMAND) #output release command

引用模板路径

模板路径应相对于执行 包含 的文件。 下面是一个示例嵌套层次结构。

|
+-- fileA.yml
|
+-- dir1/
     |
     +-- fileB.yml
     |
     +-- dir2/
          |
          +-- fileC.yml

然后,可以在 中 fileA.yml 引用 fileB.ymlfileC.yml ,如下所示。

steps:
- template: dir1/fileB.yml
- template: dir1/dir2/fileC.yml

如果 fileC.yml 是起点,则可以包括 fileA.ymlfileB.yml ,如下所示。

steps:
- template: ../../fileA.yml
- template: ../fileB.yml

当 是起点时 fileB.yml ,可以包括 fileA.ymlfileC.yml ,如下所示。

steps:
- template: ../fileA.yml
- template: dir2/fileC.yml

使用其他存储库

可以将模板保存在其他存储库中。 例如,假设你有一个核心管道,你希望所有应用管道都使用该管道。 可以将模板放在核心存储库中,然后从每个应用存储库中引用它:

# Repo: Contoso/BuildTemplates
# File: common.yml
parameters:
- name: 'vmImage'
  default: 'ubuntu 16.04'
  type: string

jobs:
- job: Build
  pool:
    vmImage: ${{ parameters.vmImage }}
  steps:
  - script: npm install
  - script: npm test

现在可以在多个管道中重复使用此模板。 使用 resources 规范提供核心存储库的位置。 引用核心存储库时,请使用 @ 并在 中 resources为其指定名称。

# Repo: Contoso/LinuxProduct
# File: azure-pipelines.yml
resources:
  repositories:
    - repository: templates
      type: github
      name: Contoso/BuildTemplates

jobs:
- template: common.yml@templates  # Template reference
# Repo: Contoso/WindowsProduct
# File: azure-pipelines.yml
resources:
  repositories:
    - repository: templates
      type: github
      name: Contoso/BuildTemplates
      ref: refs/tags/v1.0 # optional ref to pin to

jobs:
- template: common.yml@templates  # Template reference
  parameters:
    vmImage: 'windows-latest'

对于 type: githubname<identity>/<repo> 上面的示例中所示。 对于type: git (Azure Repos) , name<project>/<repo>。 如果该项目位于单独的 Azure DevOps 组织中,则需要配置类型Azure Repos/Team Foundation Server的服务连接,以访问该项目,并将其包含在 YAML 中:

resources:
  repositories:
  - repository: templates
    name: Contoso/BuildTemplates
    endpoint: myServiceConnection # Azure DevOps service connection
jobs:
- template: common.yml@templates

当管道启动时,存储库仅解析一次。 之后,在管道持续时间内使用相同的资源。 仅使用模板文件。 完全扩展模板后,最终管道将像完全在源存储库中定义一样运行。 这意味着不能在管道中使用模板存储库中的脚本。

如果要使用模板的特定固定版本,请确保固定到 ref。 是 refs 分支 () refs/heads/<name> 或标记 (refs/tags/<name>) 。 如果要固定特定提交,请先创建指向该提交的标记,然后固定到该标记。

注意

ref如果未指定 ,则管道将默认使用 refs/heads/main

还可以使用 @self 来引用找到主管道的存储库。 如果要重新引用扩展管道存储库中的内容,这在 extends 模板中使用起来很方便。 例如:

# Repo: Contoso/Central
# File: template.yml
jobs:
- job: PreBuild
  steps: []

  # Template reference to the repo where this template was
  # included from - consumers of the template are expected
  # to provide a "BuildJobs.yml"
- template: BuildJobs.yml@self

- job: PostBuild
  steps: []
# Repo: Contoso/MyProduct
# File: azure-pipelines.yml
resources:
  repositories:
    - repository: templates
      type: git
      name: Contoso/Central

extends:
  template: template.yml@templates
# Repo: Contoso/MyProduct
# File: BuildJobs.yml
jobs:
- job: Build
  steps: []

模板表达式

使用模板 表达式 指定如何在管道初始化期间动态解析值。 将模板表达式包装在此语法中: ${{ }}

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

注意

表达式仅针对 stagesjobssteps、 和 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 包含传入的参数值的上下文。 此外,还可以访问 variables 包含 YAML 文件中指定的所有变量的上下文,以及该主题) 的每个变量上 (记录的许多 预定义变量 。 重要的是,它没有运行时变量,例如管道中存储的变量,也没有在启动运行时给定的变量。 模板扩展 发生在运行初期,因此这些变量不可用。

必需的参数

可以在模板开头添加验证步骤,以检查所需的参数。

以下示例使用 Bash (检查 solution 参数,使它能够在任何平台上) 工作:

# File: steps/msbuild.yml

parameters:
- name: 'solution'
  default: ''
  type: string

steps:
- bash: |
    if [ -z "$SOLUTION" ]; then
      echo "##vso[task.logissue type=error;]Missing template parameter \"solution\""
      echo "##vso[task.complete result=Failed;]"
    fi
  env:
    SOLUTION: ${{ parameters.solution }}
  displayName: Check for required parameters
- task: msbuild@1
  inputs:
    solution: ${{ parameters.solution }}
- task: vstest@2
  inputs:
    solution: ${{ parameters.solution }}

若要显示模板在缺少所需参数时失败:

# File: azure-pipelines.yml

# This will fail since it doesn't set the "solution" parameter to anything,
# so the template will use its default of an empty string
steps:
- template: steps/msbuild.yml

模板表达式函数

可以在模板中使用 常规函数 。 还可以使用几个模板表达式函数。

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
  env:
    ${{ 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并且仅在变量等于 testfoo打印。

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

迭代插入

指令 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:
      - A
      steps:
      - script: echo This job depends on both Job A and on SomeSpecialTool.

转义值

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

施加的限制

模板和模板表达式可能会导致管道的大小和复杂性的爆炸性增长。 为了帮助防止增长失控,Azure Pipelines 施加了以下限制:

  • 不能直接或间接地 (包含超过 100 个单独的 YAML 文件)
  • 不超过 20 个级别的模板嵌套 (模板,包括其他模板)
  • 实际上,分析 YAML (时消耗的内存不超过 10 MB,这通常介于 600 KB - 2 MB 的磁盘 YAML 之间,具体取决于使用的特定功能)

模板参数

可以将参数传递给模板。 部分 parameters 定义模板中可用的参数及其默认值。 模板在管道运行前进行扩展,以便将 周围 ${{ }} 的值替换为它从封闭管道接收的参数。 因此,参数中只能使用 预定义的变量

若要跨多个管道使用参数,请参阅如何创建 变量组

带有参数的作业、阶段和步骤模板

# File: templates/npm-with-params.yml

parameters:
  name: ''  # defaults for any parameters that aren't specified
  vmImage: ''

jobs:
- job: ${{ parameters.name }}
  pool: 
    vmImage: ${{ parameters.vmImage }}
  steps:
  - script: npm install
  - script: npm test

在管道中使用模板时,请指定模板参数的值。

# File: azure-pipelines.yml

jobs:
- template: templates/npm-with-params.yml  # Template reference
  parameters:
    name: Linux
    vmImage: 'ubuntu-latest'

- template: templates/npm-with-params.yml  # Template reference
  parameters:
    name: macOS
    vmImage: 'macOS-10.13'

- template: templates/npm-with-params.yml  # Template reference
  parameters:
    name: Windows
    vmImage: 'windows-latest'

还可以将参数与步骤或阶段模板一起使用。 例如,包含参数的步骤:

# File: templates/steps-with-params.yml

parameters:
  runExtendedTests: 'false'  # defaults for any parameters that aren't specified

steps:
- script: npm test
- ${{ if eq(parameters.runExtendedTests, 'true') }}:
  - script: npm test --extended

在管道中使用模板时,请指定模板参数的值。

# File: azure-pipelines.yml

steps:
- script: npm install

- template: templates/steps-with-params.yml  # Template reference
  parameters:
    runExtendedTests: 'true'

注意

标量参数始终被视为字符串。 例如, eq(parameters['myparam'], true) 几乎总是返回 true,即使 myparam 参数是单词 false。 非空字符串在布尔上下文中强制转换为 true 。 可以重写该 表达式 以显式比较字符串: eq(parameters['myparam'], 'true')

参数不限于标量字符串。 只要参数展开的位置需要映射,参数就可以是映射。 同样,可以在需要序列的位置传递序列。 例如:

# azure-pipelines.yml
jobs:
- template: process.yml
  parameters:
    pool:   # this parameter is called `pool`
      vmImage: ubuntu-latest  # and it's a mapping rather than a string


# process.yml
parameters:
  pool: {}

jobs:
- job: build
  pool: ${{ parameters.pool }}

使用其他存储库

可以将模板保留在其他存储库中。 例如,假设你有一个核心管道,你希望所有应用管道都使用该管道。 可以将模板放在核心存储库中,然后从每个应用存储库中引用它:

# Repo: Contoso/BuildTemplates
# File: common.yml
parameters:
  vmImage: 'ubuntu 16.04'

jobs:
- job: Build
  pool:
    vmImage: ${{ parameters.vmImage }}
  steps:
  - script: npm install
  - script: npm test

现在可以在多个管道中重复使用此模板。 resources使用规范提供核心存储库的位置。 引用核心存储库时,请使用 @ 并在 中 resources提供它的名称。

# Repo: Contoso/LinuxProduct
# File: azure-pipelines.yml
resources:
  repositories:
    - repository: templates
      type: github
      name: Contoso/BuildTemplates

jobs:
- template: common.yml@templates  # Template reference
# Repo: Contoso/WindowsProduct
# File: azure-pipelines.yml
resources:
  repositories:
    - repository: templates
      type: github
      name: Contoso/BuildTemplates
      ref: refs/tags/v1.0 # optional ref to pin to

jobs:
- template: common.yml@templates  # Template reference
  parameters:
    vmImage: 'windows-latest'

对于 type: githubname<identity>/<repo> 上例所示。 对于type: git (Azure Repos) ,name<project>/<repo>。 项目必须位于同一组织中;不支持跨组织引用。

当管道启动时,存储库仅解析一次。 之后,在管道期间使用相同的资源。 仅使用模板文件。 完全扩展模板后,最终管道就如同完全在源存储库中定义一样运行。 这意味着不能在管道中使用模板存储库中的脚本。

如果要使用模板的特定固定版本,请确保固定到引用。ref 是分支 (refs/heads/<name>) 或标记 (refs/tags/<name>) 。 如果要固定特定提交,请先创建一个指向该提交的标记,然后固定到该标记。

表达式

使用模板 表达式 指定如何在管道初始化期间动态解析值。 将模板表达式包装在此语法中: ${{ }}

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

例如,定义模板:

# File: steps/msbuild.yml

parameters:
  solution: '**/*.sln'

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 上下文,其中包含传入的参数的值。 此外,还可以访问 variables 上下文,其中包含 YAML 文件中指定的所有变量以及 系统变量。 重要的是,它没有运行时变量(例如管道中存储的变量),也没有在启动运行时给定的运行时变量。 模板扩展 发生在运行早期,因此这些变量不可用。

必需的参数

可以在模板的开头添加验证步骤,以检查所需的参数。

以下示例使用 Bash (检查 solution 参数,使参数能够在任何平台) 工作:

# File: steps/msbuild.yml

parameters:
  solution: ''

steps:
- bash: |
    if [ -z "$SOLUTION" ]; then
      echo "##vso[task.logissue type=error;]Missing template parameter \"solution\""
      echo "##vso[task.complete result=Failed;]"
    fi
  env:
    SOLUTION: ${{ parameters.solution }}
  displayName: Check for required parameters
- task: msbuild@1
  inputs:
    solution: ${{ parameters.solution }}
- task: vstest@2
  inputs:
    solution: ${{ parameters.solution }}

若要显示模板在缺少所需的参数时失败,请执行以下操作:

# File: azure-pipelines.yml

# This will fail since it doesn't set the "solution" parameter to anything,
# so the template will use its default of an empty string
steps:
- template: steps/msbuild.yml

模板表达式函数

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

format

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

coalesce

  • 计算结果为第一个非空、非 null 字符串参数
  • 最小参数:2。 最大参数:N
  • 示例:
parameters:
  restoreProjects: ''
  buildProjects: ''

steps:
- script: echo ${{ coalesce(parameters.foo, parameters.bar, 'Nothing to see') }}

插入

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

# File: jobs/build.yml

parameters:
  preBuild: []
  preTest: []
  preSign: []

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:
  additionalVariables: {}

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

条件插入

如果要有条件地插入序列或映射,请使用插入和表达式计算。

例如,在序列中插入:

# File: steps/build.yml

parameters:
  toolset: msbuild

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:
  debug: false

steps:
- script: tool
  env:
    ${{ if eq(parameters.debug, 'true') }}:
      TOOL_DEBUG: true
      TOOL_DEBUG_DIR: _dbg
steps:
- template: steps/build.yml
  parameters:
    debug: true

迭代插入

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

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

# job.yml
parameters:
  jobs: []

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:
  jobs: []

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:
      - A
      steps:
      - script: echo This job depends on both Job A and on SomeSpecialTool.

转义

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

限制

模板和模板表达式可能会导致管道的大小和复杂性的爆炸性增长。 为了帮助防止失控增长,Azure Pipelines 施加了以下限制:

  • 不能直接或间接包含超过 50 个单独的 YAML 文件 ()
  • 实际上,分析 YAML (时消耗的内存不超过 10 MB,这通常介于 600 KB - 2 MB 的磁盘 YAML 之间,具体取决于使用的特定功能)
  • 每个模板表达式不允许超过 2000 个字符