애저 파이프라인은 리포지토리의 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
coalesce
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는 다음과 같은 제한 사항을 적용한다.