Azure pipeline yaml 작성

이동건·2022년 11월 15일

애저 파이프라인은 리포지토리의 yaml파일을 이용해 정의된다.
일반적으로 리포지토리의 루트에 azure-pipelines.yml로 저장된다.
예시는 다음과 같다.

trigger:
 - main

 pool:
   vmImage: 'ubuntu-latest'

 steps:
 - task: Maven@4
   inputs:
     mavenPomFile: 'pom.xml'
     mavenOptions: '-Xmx3072m'
     javaHomeOption: 'JDKVersion'
     jdkVersionOption: '1.11'
     jdkArchitectureOption: 'x64'
     publishJUnitResults: false
     testResultsFiles: '**/surefire-reports/TEST-*.xml'
     goals: 'package'

이 파이프라인은 main branch에 변경 사항을 push하거나 pull request를 생성할 때 실행된다.
Microsoft에서 호스팅하는 Linux 시스템에서 실행되며, 파이프라인 프로세스는 Maven 작업을 실행하는 단일 step으로 이루어져 있다.

pool:
vmImage: "ubuntu-latest"

현재 파이프라인은 Linux 에이전트에서 실행됨을 나타낸다.
다른 플랫폼을 선택하고 싶다면 vmImage 값을 변경하면 된다.
예시는 다음과 같다.

pool:
  vmImage: "windows-latest"
pool:
  vmImage: "macos-latest"

파이프라인에 steps로 scripts나 tasks를 추가할 수 있다.
task는 미리 패키지된 스크립트이다.
앱을 빌드, 테스트, 게시 또는 배포하는 작업에 사용할 수 있다.
자바의 경우 위와 같이 Maven task가 testing 및 publishing을 처리하지만 task를 이용해 code coverage results도 publish할 수 있다.
예시는 다음과 같다.

- task: PublishCodeCoverageResults@1
  inputs:
    codeCoverageTool: "JaCoCo"
    summaryFileLocation: "$(System.DefaultWorkingDirectory)/**/site/jacoco/jacoco.xml"
    reportDirectory: "$(System.DefaultWorkingDirectory)/**/site/jacoco"
    failIfCoverageEmpty: true

위는 코드 커버리지 툴을 사용해 검사하는 task이다.

여러 플랫폼에 build하는 방법
한 프로젝트를 멀티 플랫폼에 빌드 및 테스트가 가능하다.
starategy의 matrix를 사용하면 된다.
예시는 다음과 같다.

strategy:
  matrix:
    linux:
      imageName: "ubuntu-latest"
    mac:
      imageName: "macOS-latest"
    windows:
      imageName: "windows-latest"
  maxParallel: 3

pool:
  vmImage: $(imageName)

다양한 버전으로 build 하기
프로젝트를 다양한 버전으로 빌드하기 위해선 matrix를 사용하면 된다.
예시는 다음과 같다.

strategy:
  matrix:
    jdk10:
      jdkVersion: "1.10"
    jdk11:
      jdkVersion: "1.11"
  maxParallel: 2

그후 메이븐에서 옵션을 다음과 같이 바꿔준다.

jdkVersionOption: $(jdkVersion)

다양한 플랫폼에서 다양한 버전으로 빌드하고 싶다면 다음과 같이 바꾸면 된다.

trigger:
- main

strategy:
  matrix:
    jdk10_linux:
      imageName: "ubuntu-latest"
      jdkVersion: "1.10"
    jdk11_windows:
      imageName: "windows-latest"
      jdkVersion: "1.11"
  maxParallel: 2

pool:
  vmImage: $(imageName)

steps:
- task: Maven@4
  inputs:
    mavenPomFile: "pom.xml"
    mavenOptions: "-Xmx3072m"
    javaHomeOption: "JDKVersion"
    jdkVersionOption: $(jdkVersion)
    jdkArchitectureOption: "x64"
    publishJUnitResults: true
    testResultsFiles: "**/TEST-*.xml"
    goals: "package"

CI 트리거 변경하기

trigger: 에 업데이트를 푸시할 때마다 파이프라인이 실행되도록 한다. yaml파이프라인은 default branch로 (보통은 main branch 임) CI 트리거가 구성된다. 특정 분기 또는 pull request에 대해 트리거 설정을 할 수 있다. pull request의 경우 trigger:를 pr:로 바꿔주면 된다. pr:은 각 Pull request에 대해 실행된다.
예시는 다음과 같다.

trigger:
  - main
  - releases/*

pr:
  - main
  - releases/*

로 변경해준다.

실패시 작업 항목 생성
yaml 파이프라인에서 실패시 작업 항목을 만들기 위해서는 파이프라인의 원하는 지점에 작업 항목을 만들어주어야 한다.

아래의 예시에는 두 가지 작업이 있다. 첫 번째 작업은 파이프라인의 작업을 나타내는데, 실패하면 두 번째 작업이 실행되고 파이프라인과 동일한 프로젝트에 버그가 생성된다.

# When manually running the pipeline, you can select whether it
# succeeds or fails.
parameters:
- name: succeed
  displayName: Succeed or fail
  type: boolean
  default: false

trigger:
- main

pool:
  vmImage: ubuntu-latest

jobs:
- job: Work
  steps:
  - script: echo Hello, world!
    displayName: 'Run a one-line script'

  # This malformed command causes the job to fail
  # Only run this command if the succeed variable is set to false
  - script: git clone malformed input
    condition: eq(${{ parameters.succeed }}, false)

# This job creates a work item, and only runs if the previous job failed
- job: ErrorHandler
  dependsOn: Work
  condition: failed()
  steps: 
  - bash: |
      az boards work-item create \
        --title "Build $(build.buildNumber) failed" \
        --type bug \
        --org $(System.TeamFoundationCollectionUri) \
        --project $(System.TeamProject)
    env: 
      AZURE_DEVOPS_EXT_PAT: $(System.AccessToken)
    displayName: 'Create work item on failure'

조금 더 기초적인 부분부터 보자.
task는 파이프라인에서 자동화를 정의하기 위한 구성요소이다.
task는 입력 집합으로 추상화된 패키지된 스크립트이다.

파이프라인에 작업을 추가할 때 파이프라인에 일련의 요구사항을 추가할 수 있다.
요구사항은 작업을 실행하기 위해 에이전트에 설치해야하는 필수 구성요소를 정의한다.
빌드 또는 배포를 실행하면 이 요구사항을 충족하는 에이전트가 선택된다.

job을 실행하면 모든 task들이 순차적으로 하나씩 실행된다.
다중 에이전트에서 task의 집합을 병렬로 실행하거나 에이전트를 사용하지 않고 일부 task들을 실행하려고 하면 job을 참고해야한다.

기본적으로는 모든 작업은 호스트에 있든 작업 건테이너에 있든 동일한 context에서 실행된다. 필요에 따라 step targets를 사용하여 개별 작업에 대한 컨텍스트를 제어할 수 있다.

Custom tasks
YAML pipelines에서는 이름으로 task를 참조한다.만약 이름이 기본 제공 task와 custom task 모두 일치할 경우에 기본 제공 작업이 우선적으로 제공된다. 이런 경우를 방지하기 위해 custom task에 대해 작업 GUID 또는 정규화된 이름을 custom task에 사용할 수 없다.

Task versions
작업의 버전이 지정되면 파이프라인에 사용되는 작업의 주 버전을 지정해야한다.
새 부 버전 (1.2~1.3 등)이 릴리즈되면 빌드 또는 리리스에서 새 버전을 자동으로 사용한다.
하지만 새 주 버전 (2.0, 3.0 등)이 릴리즈 되면 파이프라인을 편집하고 새 주 버전으로 수동 변경할 때 까지 빌드 또는 릴리스에서 지정한 주 버전을 계속 사용한다.

Task Control options

- task: string  # reference to a task and version, e.g. "VSBuild@1"
  condition: expression     # see below
  continueOnError: boolean  # 'true' if future steps should run even if this step fails; defaults to 'false'
  enabled: boolean          # whether or not to run this step; defaults to 'true'
  retryCountOnTaskFailure: number # Max number of retries; default is zero
  timeoutInMinutes: number  # how long to wait before timing out the task
  target: string            # 'host' or the name of a container resource to target

Step target
Tasks는 에이전트 호스트 또는 컨테이너인 실행 컨텍스트에서 실행된다. 하나의 step은 target을 특정하여 컨텍스트에 의해 override될 수 있다.
가능한 옵션들은 host를 통해 타겟 에이전트 호스트를 대상으로 한다. 이는 파이프라인에 정의된 컨테이너이다.
다음의 예시와 같다.

resources:
  containers:
  - container: pycontainer
    image: python:3.8

steps:
- task: SampleTask@1
  target: host
- task: AnotherTask@1
  target: pycontainer

여기서 host에서 SampleTask가 실행되고 컨테이너에서 AnotherTask가 실행된다.

작업이 실패한 경우 재시도 횟수
retryCountOnTaskFailure 에 의해 알 수 있다.

- task: <name of task>
   retryCountOnTaskFailure: <max number of retries>
   ...

환경 변수

각 task에는 env 라는 property가 있다. 이는 작업 프로세스에 매핑된 환경 변수를 나타내는 문자열 쌍 목록인 속성이다.

task: AzureCLI@2
displayName: Azure CLI
inputs: # Specific to each task
env:
  ENV_VARIABLE_NAME: value
  ENV_VARIABLE_NAME2: value
  ...

이와 같이 작성한다.

아래의 예제는 Azure DevOps CLI를 사용하여 인증하는 데 사용되는 환경변수에 값을 AZURE_DEVOPS_EXT_PAT을 이용해 할당한다.

# Using the script shortcut syntax
- script: az pipelines variable-group list --output table
  env:
    AZURE_DEVOPS_EXT_PAT: $(System.AccessToken)
  displayName: 'List variable groups using the script step'

# Using the task syntax
- task: CmdLine@2
  inputs:
    script: az pipelines variable-group list --output table
  env:
    AZURE_DEVOPS_EXT_PAT: $(System.AccessToken)
  displayName: 'List variable groups using the command line task'

매개 변수

템플릿에서 매개 변수 및 해당 데이터 형식을 지정하고 해당 매개 변수를 파이프라인에 전달할 수 있다.

매개 변수 전달

매개 변수에는 이름 및 데이터 형식이 포함되어야 한다.
azure-pipelines.yml에 매개변수 yesNo가 부울 값으로 설정되면 빌드가 성공한다. yesNo가 String 값으로 설정 되면 build가 fail된다.

# 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

템플릿을 설정하고 yesNo에 값을 넣는다. 이 때 불린 값이 아니면 build를 fail한다.

런타임에 템플릿을 선택하는 매개 변수
조건에 따라 파이프라인 YAML에서 다른 템플릿을 호출할 수 있다.
이 예제에서는 매개변수 experimentalTemplate 가 true이면 experimental.yml이 실행된다.

#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

Parameter data types

Data type / Notes
string : string
number : may be restricted to values:, otherwise any number-like string is accepted
boolean : true or false
object : any YAML structure
step : a single step
stepList : sequence of steps
job : a single job
jobList : sequence of jobs
deployment : a single deployment job
deploymentList : sequence of deployment jobs
stage : a single stage
stageList : sequence of stages

stepList, job, jobList, deployment, deploymentList, stage 및 stageList 데이터 형식은 모두 표준 YAML 스키마 형식을 사용합니다. 이 예제에는 문자열, 숫자, 부울, 개체, 단계 및 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 }}

템플릿의 확장

보안을 강화하기 위해 파이프라인이 특정 템플릿에서 확장되도록 적용할 수 있습니다. 파일 start.yml 은 매개 변수 buildSteps를 정의한 다음, 파이프라인 azure-pipelines.yml에서 사용됩니다.
start.yml 에서 buildStep이 script step 단계를 사용하여 전달되면 거부되고 파이프라인 빌드가 실패합니다. 템플릿에서 확장하는 경우 필요한 템플릿 승인을 추가하여 보안을 강화할 수 있습니다.

# 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를 이용해서 템플릿에서 확장할 수 있다.

# 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를 소용해 템플릿에서 매개변수로 사용되는 stages, steps, jobs에 추가 속성을 전달할 수 있다.
특히 jobList, deploymentList, stageList 내에서 templateContext으로 특정할 수 있다.

templateContext을 이용해 각 job을 처리할 때 환경을 더 쉽게 설정할 수 있다.
작업 및 해당 환경 속성 개체를 함께 job에 묶는 걸 통해서, templateContext가 YAML을 보다 유지관리하기 쉽고 쉽게 이해할 수 있도록 도와준다.

이 예제에서의 매개변수 testing-template.yml의 testSet는 jobList의 데이터 타입을 갖고있다.
testing-template.yml 템플릿은 각 키워드를 사용해 새 변수 testJob을 만든다.
그 후 템플릿은 azure-pipeline.yml에 설정된 testJob.templateContext.expectedHTTPResponseCode을 참조한다.

response code가 200이면 템플릿에서 REST request를 만들고 response가 500이면 템플릿이 디버깅을 위해 모든 환경 변수를 출력한다.

#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

step 재사용

템플릿을 삽입하여 여러 jobs에서 하나 이상의 steps를 다시 사용할 수 있다.
템플릿의 Steps 외에도 각 job은 더 많은 steps를 정의할 수 있다.

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

Job 재사용
Steps와 마찬가지로 job도 템플릿과 함께 재사용 될 수 있다.

# 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

multiple jobs를 돌릴 때 충돌을 방지하기 위해서 템플릿 파일에서 작업 이름을 제거해야 한다.

# 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

Stage 재사용
스테이지도 템플릿과 함께 재사용 할 수 있다.

# 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

Job, Stage, Step : 매개변수가 있는 템플릿

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

step 또는 stage 템플릿과 함께 매개변수를 사용할 수 있다.
다음의 예시를 보자

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

매개 변수는 스칼라 문자열로 제한되지 않는다. 예를 들어 object type을 사용하는 경우는 다음과 같다.

# 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에서 정의하고 다른 템플릿에 포함될 수 있다. 이 기능은 모든 변수를 하나의 파일에 저장하려는 경우에 유용하다.
템플릿을 사용해 파이프라인에 변수를 포함하는 경우 포함된 템플릿은 변수를 정의하는 데만 사용할 수 있다.
type을 제한하려는 경우 parameter를 변수 대신 사용한다.

이 예제에서 변수 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 }}.

매개변수가 있는 변수 템플릿 : Variable templates with parameter

템플릿을 사용하여 변수에 매개 변수를 전달할 수 있다.
이 예제는 DIRECTORY 매개 변수(parameter)를 RELEASE_COMMAND 변수(variable)에 전달한다.

# 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.yml과 fileC.yml을 다음과 같은 형식으로 참조할 수 있다.

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

만약 fileC.yml이 시작 포인트이고 fileA.yml과 fileB.yml을 참조하려면 다음과 같이 작성한다.

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

fileB.yml이 시작점인 경우 fileA.yml과 fileC.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를 코어 레포지토리 위치에 제공한다.

# 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: github의 경우 name이 <identity>/<repo>가 된다. (azure의 경우) type: git 의 경우는 <project>/<repo>가 된다. 해당 프로젝트가 별도의 Azure DevOps 조직에 있는 경우 프로젝트에 엑세스 하기 위해서 service connection of type Azure Repos/Team Foundation Server에 대한 설정이 필요하다.

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

리포지토리는 파이프라인이 시작될 때 한 번만 확인된다.
그 다음 파이프라인 기간 동안 동일한 리소스가 사용된다. 오직 템플릿 파일만 사용된다.
템플릿이 완전히 확장되면 최종 파이프라인은 원본 리포지토리에 정의된 것 처럼 실행된다.
즉, 파이프라인의 템플릿 리포지토리에서 스크립트를 사용할 수 있다.

특정한 버전을 사용하고 싶으면 ref에 고정을 해야한다. ref는 각기 다른 브랜치 (refs/heads/<name>)이나 태그(refs/tags/<name>)이다. 특정 커밋을 고정하려면 먼저 해당 커밋을 가리키는 태그를 만들고, 해당 태그에 고정한다.

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

템플릿 표현법 : Template expressions

템플릿 expressions를 사용해 파이프라인 초기화 중에 값을 동적으로 할당하는 방법을 지정한다.
템플릿 식을 ${{ }} 구문 안에 래핑한다.
템플릿 expressions는 템플릿 parameters와 변수들을 확장할 수 있다.
parameters object는 expressions에서 variables object (변수 객체)처럼 작동한다.
template expressions에서는 미리 정의된 변수만 사용 가능하다.

다음의 예시처럼 템플릿을 정의한다.

# 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

그런 다음 템플릿을 참조하고 optional solution parameter를 전달한다.

# File: azure-pipelines.yml

steps:
- template: steps/msbuild.yml
  parameters:
    solution: my.sln

Required parameters
템플릿의 시장 부분에 유효성 검사 단계를 추가하여 필요한 매개 변수를 확인할 수 있다.
다음은 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

Template expression functions
템플릿에서 general function을 사용할 수 있다.
또한 몇 가지 템플릿 expression function도 사용 가능하다.

format

  • 간단한 문자열로 토큰 바꾸기
  • 최소 매개변수: 2, 최대 매개변수: N
  • 예시: ${{ format('{0} Build', parameters.os) }} → 'Windows Build'

coalesce

  • non-empty, non-null인 첫 번째 string argument를 본다.
  • 최소 매개변수: 2, 최대 매개변수 : N
  • 예 :
parameters:
- name: 'restoreProjects'
  default: ''
  type: string
- name: 'buildProjects'
  default: ''
  type: string

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

Insertion

템플릿 expressions를 사용하여 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

배열이 배열에 삽임되면 중첩된 배열이 flattened 된다.
매핑에 삽입하려면 특수 속성인 ${{ 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

조건부 삽입

템플릿에서 시퀀스 또는 매핑에 조건부로 삽입하려면 삽입 및 expression evaluation을 사용한다.
또한 템플릿 syntax를 사용하는 한 템플릿 외부에서 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는 항상 출력되고 변수 foo가 test와 같을 때만 this is a 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

반복 삽입 : Iterative insertion

each 는 YAML squence (array) 또는 매핑 (key-value pairs)의 경우 iterative insertion을 허용한다.
예를 들어 각 작업의 단계를 pre- and post-steps로 래핑할 수 있다.

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

값 이스케이프

${{가 포함된 이스케이프 값이 필요한 경우 해당 값을 expression string으로 감싼다.
예를 들어 ${{ 'my${{value' }} or ${{ 'my${{value with a '' single quote too' }}
다음과 같이 작성한다.

제한사항
템플릿 및 템플릿 expressions는 파이프라인의 크기와 복잡성을 폭발적으로 증가시킬 수 있다.
이런 증가를 막기 위해 Azure Pipelines는 다음과 같은 제한 사항을 적용한다.

  • 100개 이하의 개별 YAML 파일이 포함될 수 있음(직접 또는 간접적으로)
  • 20개 이하의 템플릿 중첩(다른 템플릿을 포함한 템플릿)
  • YAML을 구문 분석하는 동안 10MB 이하의 메모리가 소비(실제로 사용되는 특정 기능에 따라 일반적으로 600KB ~ 2MB의 디스크 YAML 사이임).
profile
코드를 통한 세계의 창조

0개의 댓글