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

模板用于 YAML 管道中可重用的内容、逻辑和参数。 需要了解 Azure Pipelines 关键概念 (如阶段、步骤和工作等)的基础知识才能有效地利用好模板。

模板可帮助你加快开发速度。 例如,可以在模板中包含一系列相同的任务,然后在 YAML 管道的不同阶段多次包含模板。

模板还可以帮助你确保管道的安全。 当模板控制管道中允许的内容时,该模板则定义另一个文件必须遵循的逻辑。 例如,你可能想要限制允许运行哪些任务。 此类情况下,可以使用模板阻止某人成功运行违反组织安全策略的任务。

有两种类型的模板:包含和扩展。

  • 包含模板 支持在模板中插入可重用的内容。 如果使用模板来包含内容,它的作用类似于许多编程语言中的 include 指令。 一个文件中的内容会插入到另一个文件中。
  • 扩展模板 可以控制管道中允许的内容。 当扩展模板控制管道中允许的内容时,该模板则定义另一个文件必须遵循的逻辑。
  • 还应使用 模板表达式 模板参数 来充分利用模板。

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

    从模板扩展

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

    # 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"
    

    可以从一个 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 reference
    - template: templates/stages2.yml # Template reference
    

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

    # 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'
    

    没有指定类型的标量参数被视为字符串。 例如,如果 myparam 未显式设置为 booleaneq(true, parameters['myparam']) 将返回 true,即使 myparam 参数是单词 false。 非空字符串在布尔上下文中强制转换为 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
    

    或者,fileB.yml 可以引用 fileA.yml 和使用 fileC.yml 这样的绝对路径。

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

    使用其他存储库

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

    # Repo: Contoso/BuildTemplates
    # File: common.yml
    parameters:
    - name: 'vmImage'
      default: 'ubuntu-22.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
    

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

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

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

    还可以使用存储库资源的 SHA 值固定到 Git 中的特定提交。 SHA 值是一个 40 个字符的校验和,用于唯一标识提交。

    resources:
      repositories:
        - repository: templates
          type: git
          name: Contoso/BuildTemplates
          ref: 1234567890abcdef1234567890abcdef12345678
    

    还可以使用 @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: []
    

    如何在模板中使用变量?

    有时,根据变量将参数设置为值可能会很有用。 参数在处理管道运行时会提前扩展,因此并非所有变量都可用。 若要查看模板中有哪些预定义变量可用,请参阅使用预定义变量

    在此示例中,预定义变量 Build.SourceBranchBuild.Reason 用于 template.yml 中的条件。

    # File: azure-pipelines.yml
    trigger:
    - main
    extends:
      template: template.yml
    
    # File: template.yml
    steps:
    - script: echo Build.SourceBranch = $(Build.SourceBranch) # outputs refs/heads/main
    - script: echo Build.Reason = $(Build.Reason) # outputs IndividualCI
    - ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/main') }}: 
      - script: echo I run only if Build.SourceBranch = refs/heads/main 
    - ${{ if eq(variables['Build.Reason'], 'IndividualCI') }}: 
      - script: echo I run only if Build.Reason = IndividualCI 
    - script: echo I run after the conditions