你可以将管道整理到作业中。 每个管道至少有一个作业。 作业是作为一个单元按顺序运行的一系列步骤。
换句话说,作业是可以计划运行的最小工作单位。
若要了解构成管道的关键概念和组件,请参阅
新 Azure Pipelines 用户的关键概念
。
Azure Pipelines 不支持 YAML 管道的作业优先级。 若要控制作业运行时,可以指定
条件
和
依赖项
。
定义单个作业
在最简单的情况下,管道有一个作业。 在这种情况下,除非使用
模板
,否则不必显式使用
job
关键字。 可以直接在 YAML 文件中指定步骤。
此 YAML 文件具有在
Microsoft 托管代理
上运行并输出
Hello world
的作业。
pool:
vmImage: 'ubuntu-latest'
steps:
- bash: echo "Hello world"
你可能想要在该作业上指定其他属性。 在这种情况下,可以使用 job
关键字。
jobs:
- job: myJob
timeoutInMinutes: 10
pool:
vmImage: 'ubuntu-latest'
steps:
- bash: echo "Hello world"
管道可以有多个作业。 在这种情况下,可以使用 jobs
关键字。
jobs:
- job: A
steps:
- bash: echo "A"
- job: B
steps:
- bash: echo "B"
管道可能有多个阶段,每个阶段具有多个作业。 在这种情况下,可以使用 stages
关键字。
stages:
- stage: A
jobs:
- job: A1
- job: A2
- stage: B
jobs:
- job: B1
- job: B2
用于指定作业的完整语法为:
- job: string # name of the job, A-Z, a-z, 0-9, and underscore
displayName: string # friendly name to display in the UI
dependsOn: string | [ string ]
condition: string
strategy:
parallel: # parallel strategy
matrix: # matrix strategy
maxParallel: number # maximum number simultaneous matrix legs to run
# note: `parallel` and `matrix` are mutually exclusive
# you may specify one or the other; including both is an error
# `maxParallel` is only valid with `matrix`
continueOnError: boolean # 'true' if future jobs should run even if this job fails; defaults to 'false'
pool: pool # agent pool
workspace:
clean: outputs | resources | all # what to clean up before the job runs
container: containerReference # container to run this job inside
timeoutInMinutes: number # how long to run the job before automatically cancelling
cancelTimeoutInMinutes: number # how much time to give 'run always even if cancelled tasks' before killing them
variables: { string: string } | [ variable | variableReference ]
steps: [ script | bash | pwsh | powershell | checkout | task | templateReference ]
services: { string: string | container } # container resources to run as a service container
用于指定作业的完整语法为:
- job: string # name of the job, A-Z, a-z, 0-9, and underscore
displayName: string # friendly name to display in the UI
dependsOn: string | [ string ]
condition: string
strategy:
parallel: # parallel strategy
matrix: # matrix strategy
maxParallel: number # maximum number simultaneous matrix legs to run
# note: `parallel` and `matrix` are mutually exclusive
# you may specify one or the other; including both is an error
# `maxParallel` is only valid with `matrix`
continueOnError: boolean # 'true' if future jobs should run even if this job fails; defaults to 'false'
pool: pool # agent pool
workspace:
clean: outputs | resources | all # what to clean up before the job runs
container: containerReference # container to run this job inside
timeoutInMinutes: number # how long to run the job before automatically cancelling
cancelTimeoutInMinutes: number # how much time to give 'run always even if cancelled tasks' before killing them
variables: { string: string } | [ variable | variableReference ]
steps: [ script | bash | pwsh | powershell | checkout | task | templateReference ]
services: { string: string | container } # container resources to run as a service container
uses: # Any resources (repos or pools) required by this job that are not already referenced
repositories: [ string ] # Repository references to Azure Git repositories
pools: [ string ] # Pool names, typically when using a matrix strategy for the job
如果作业的主要目的是部署应用(而不是生成或测试应用),则可以使用称为部署作业的特殊作业类型。
部署作业的语法为:
- deployment: string # instead of job keyword, use deployment keyword
pool:
name: string
demands: string | [ string ]
environment: string
strategy:
runOnce:
deploy:
steps:
- script: echo Hi!
尽管可以在 job
中添加部署任务的步骤,但我们建议改用部署作业。 部署作业有一些好处。 例如,可以部署到环境,其中包括能够查看已部署内容历史记录等好处。
使用 Microsoft 托管代理时,管道中的每个作业都会获得一个新的代理。
将需求与自托管代理一起使用,以指定代理运行作业必须具备的功能。 你可能会为连续作业获取相同的代理,具体取决于代理池中是否存在多个与管道需求匹配的代理。 如果池中只有一个与管道需求匹配的代理,则管道将等待,直到此代理可用。
需求和功能设计用于自托管代理,以便作业可与满足作业要求的代理匹配。 使用 Microsoft 托管代理时,为代理选择符合作业要求的映像,这样的话,虽然可以向 Microsoft 托管代理添加功能,但无需将功能与 Microsoft 托管代理一起使用。
pool:
name: myPrivateAgents # your job runs on an agent in this pool
demands: agent.os -equals Windows_NT # the agent must have this capability to run the job
steps:
- script: echo hello world
或多个需求:
pool:
name: myPrivateAgents
demands:
- agent.os -equals Darwin
- anotherCapability -equals somethingElse
steps:
- script: echo hello world
详细了解代理功能。
服务器作业
服务器作业中的任务由服务器(Azure Pipelines 或 TFS)进行协调和执行。 服务器作业不需要代理或任何目标计算机。 服务器作业目前仅支持少数任务。 服务器作业的最大时间为 30 天。
无代理作业支持的任务
目前,无代理作业仅支持以下现成任务:
调用 Azure 函数任务
调用 REST API 任务
手动验证任务
发布到 Azure 服务总线任务
查询 Azure Monitor 警报任务
查询工作项任务
由于任务是可扩展的,因此可以使用扩展添加更多无代理任务。 无代理作业的默认超时时间为 60 分钟。
matrix: { string: { string: string } }
pool: server # note: the value 'server' is a reserved keyword which indicates this is an agentless job
还可以使用简化的语法:
jobs:
- job: string
pool: server # note: the value 'server' is a reserved keyword which indicates this is an agentless job
在单个阶段中定义多个作业时,可以指定这些作业之间的依赖关系。 管道必须包含至少一个没有依赖关系的作业。 默认情况下,除非设置了值 dependsOn
,否则 Azure DevOps YAML 管道作业将并行运行。
每个代理一次只能运行一个作业。 要并行运行多个作业,必须配置多个代理。 还需要足够的并行作业。
若要添加新作业,请在管道的任务选项卡中选择管道通道上的“...”。 在编辑器中选择作业时,会显示作业的条件和执行顺序。
在生成管道中指定多个作业时,这些作业默认情况下会并行运行。 可以通过在作业之间配置依赖关系来指定作业执行必须遵循的顺序。 发布管道不支持作业依赖关系。 发布管道中的多个作业按顺序运行。
例如,下面所示的管道使用两个代理作业和一个服务器作业将整体发布执行划分为单独的执行作业。
在上面的示例中:
发布的第一个作业中的任务在代理上运行,完成此作业后,将发布代理。
服务器作业包含一个在 Azure Pipelines 或 TFS 上运行的手动干预任务。
作业不在代理或任何目标服务器上执行,也不需要代理或任何目标服务器。
手动干预任务显示其消息,并等待用户的“继续”或“拒绝”响应。 在此示例中,如果达到配置的超时值,则任务将自动拒绝部署(如果不希望生成自动响应,请将控制选项部分中的超时设置为零)。
如果发布继续,则第三个作业中的任务可能在不同的代理上运行。 如果发布被拒绝,则此作业不会运行,并且发布被标记为失败。
务必要了解分阶段执行的一些后果:
每个作业可能使用不同的代理。 不要假定早期作业的状态在后续作业期间可用。
每个作业中任务的“出错时继续”和“始终运行”选项对后续作业中的任务没有任何影响。 例如,在第一个作业结束时对任务设置“始终运行”并不能保证后续作业中的任务将运行。
- job: B
dependsOn: A
condition: and(succeeded(), eq(variables['build.sourceBranch'], 'refs/heads/main'))
steps:
- script: echo this only runs for master
可以指定作业根据上一作业中设置的输出变量的值运行。 在这种情况下,只能使用直接依赖作业中设置的变量:
jobs:
- job: A
steps:
- script: "echo '##vso[task.setvariable variable=skipsubsequent;isOutput=true]false'"
name: printvar
- job: B
condition: and(succeeded(), ne(dependencies.A.outputs['printvar.skipsubsequent'], 'true'))
dependsOn: A
steps:
- script: echo hello from B
为了避免在作业无响应或等待时间过长时占用资源,最好对允许作业运行的时间设置限制。 使用作业超时设置来指定作业运行限制(以分钟为单位)。 将值设置为零表示作业可以:
在自托管代理上永久运行
在具有公共项目和公共存储库的 Microsoft 托管代理上运行 360 分钟(6 小时)
在具有专用项目或专用存储库的 Microsoft 托管代理上运行 60 分钟(除非支付了额外的容量)
超时期限从作业开始运行时开始。 不包括工作排队或等待代理的时间。
timeoutInMinutes
允许为作业执行时间设置限制。 如果未指定,则默认值为 60 分钟。 指定 0
时,将使用最大限制(上述)。
当部署任务设置为在上一个任务失败时继续运行,cancelTimeoutInMinutes
允许为作业取消时间设置限制。 如果未指定,默认值为 5 分钟。 该值的范围应介于 1 到 35790 分钟之间。
jobs:
- job: Test
timeoutInMinutes: 10 # how long to run the job before automatically cancelling
cancelTimeoutInMinutes: 2 # how much time to give 'run always even if cancelled tasks' before stopping them
超时的优先级如下。
在 Microsoft 托管的代理上,根据项目类型以及是否使用付费并行作业运行来限制作业可以运行多长时间。 当 Microsoft 托管的作业超时间隔过时,作业将终止。 在 Microsoft 托管的代理上,作业的运行时间不能超过此间隔,不管作业中指定的任何作业级别超时。
在作业级别配置的超时指定要运行的作业的最大持续时间。 作业级别超时间隔过后,作业将终止。 如果作业在 Microsoft 托管的代理上运行,则将作业级别超时设置为大于内置的 Microsoft 托管作业级别超时的间隔没有效果,而是使用 Microsoft 托管的作业超时。
还可以单独为每个任务设置超时 - 请参阅任务控制选项。 如果作业级别超时间隔在任务完成之前已过,则运行作业将终止,即使任务配置了更长的超时间隔。
多作业配置
在创作的单个作业中,可以在多个代理上并行运行多个作业。 示例包括:
多配置生成:可以并行生成多个配置。 例如,可以在 x86
和 x64
平台上为 debug
和 release
配置生成 Visual C++ 应用。 有关详细信息,请参阅 Visual Studio 生成 - 多个平台的多个配置。
多配置部署:例如,可以在不同的地理区域并行运行多个部署。
多配置测试:可以并行运行测试多个配置。
即使多配置变量为空,多配置也始终生成至少一个作业。
matrix
策略允许使用不同的变量集多次调度作业。 maxParallel
标记限制并行度。 以下作业将调度三次,并将“位置”和“浏览器”设置为指定值。 但是,只有两个作业将同时运行。
jobs:
- job: Test
strategy:
maxParallel: 2
matrix:
US_IE:
Location: US
Browser: IE
US_Chrome:
Location: US
Browser: Chrome
Europe_Chrome:
Location: Europe
Browser: Chrome
矩阵配置名称(如上面的 US_IE
)只能包含基本拉丁字母(A-Z 和 a-z)、数字以及下划线 (_
)。
它们必须以字母开头。
此外,名称长度不能超过 100 个字符。
还可以使用输出变量生成矩阵。
如果需要使用脚本生成矩阵,此操作可能很方便。
matrix
将接受包含字符串化 JSON 对象的运行时表达式。
展开时,该 JSON 对象必须与矩阵语法匹配。
在下面的示例中,我们对 JSON 字符串进行了硬编码,但其可由脚本语言或命令行程序生成。
jobs:
- job: generator
steps:
- bash: echo "##vso[task.setVariable variable=legs;isOutput=true]{'a':{'myvar':'A'}, 'b':{'myvar':'B'}}"
name: mtrx
# This expands to the matrix
# a:
# myvar: A
# b:
# myvar: B
- job: runner
dependsOn: generator
strategy:
matrix: $[ dependencies.generator.outputs['mtrx.legs'] ]
steps:
- script: echo $(myvar) # echos A or B depending on which leg is running
若要使用多配置选项运行多个作业,请标识名为乘数的变量,并为该乘数指定值列表。 为列表中的每个值运行单独的作业。 若要在生成或部署中使用乘数,则必须:
在管道的变量选项卡上或变量组中定义一个或多个变量。
每个变量(在此上下文中是乘数变量)都必须定义为要单独传递给代理的值的逗号分隔列表。
输入乘数变量的名称(不带 $ 和括号)作为乘数参数的值。 不支持将机密变量用作乘数变量。
如果要为多个乘数变量执行作业,请以逗号分隔的列表形式输入变量名称 - 省略每个变量的 $ 和括号。
如果要将部署期间使用的代理数限制为小于为订阅配置的代理数,请输入该值作为“最大代理数”参数。
例如,可以定义名为 Location 和 Browser 的两个变量,如下所示:
位置 = US,Europe
浏览器 = IE,Chrome,Edge,Firefox
以下配置将使用最多 4 个代理同时执行 8 次部署:
乘数 = Location,Browser
最大代理数 = 4
使用多配置,可以运行多个作业,每个作业的一个或多个变量(乘数)具有不同的值。 如果要在多个代理上运行相同的作业,则可以使用并行的多代理选项。 上述测试切片示例可以通过多代理选项完成。
代理作业可用于并行运行一套测试。 例如,你可以在一个代理上运行一大套测试(1000 个)。 也可以使用两个代理,在每个代理上并行运行 500 个测试。
若要应用切片,作业中的任务应当足够智能,了解自己所属的切片。
Visual Studio 测试任务是支持测试切片的此类任务之一。 如果已安装多个代理,则可以指定 Visual Studio 测试任务在这些代理上并行运行的方式。
parallel
策略使作业可以重复多次。
变量 System.JobPositionInPhase
和 System.TotalJobsInPhase
将添加到每个作业。 然后,可以在脚本中使用变量在作业之间划分工作。
请参阅使用代理作业进行并行和多次执行。
以下作业将被调度五次,并相应地设置 System.JobPositionInPhase
和 System.TotalJobsInPhase
的值。
jobs:
- job: Test
strategy:
parallel: 5
在代理作业上指定“多代理”选项以应用切片。
作业的调度次数与指定的代理数相同,并且 System.JobPositionInPhase
和 System.TotalJobsInPhase
变量在每个作业中自动设置。
如果使用 YAML,则可以在作业上指定变量。 可以使用宏语法 $ (variableName) 将变量传递给任务输入,或使用阶段变量在脚本中访问变量。
mySimpleVar: simple var value
"my.dotted.var": dotted var value
"my var with spaces": var with spaces value
steps:
- script: echo Input macro = $(mySimpleVar). Env var = %MYSIMPLEVAR%
condition: eq(variables['agent.os'], 'Windows_NT')
- script: echo Input macro = $(mySimpleVar). Env var = $MYSIMPLEVAR
condition: in(variables['agent.os'], 'Darwin', 'Linux')
- bash: echo Input macro = $(my.dotted.var). Env var = $MY_DOTTED_VAR
- powershell: Write-Host "Input macro = $(my var with spaces). Env var = $env:MY_VAR_WITH_SPACES"
运行代理池作业时,它会在代理上创建工作区。 工作区是一个目录,它在其中下载源、运行步骤并生成输出。 可以在作业中使用 Pipeline.Workspace
变量引用工作区目录。 在该目录下,将创建各种子目录:
Build.SourcesDirectory
是任务下载应用程序源代码的位置。
Build.ArtifactStagingDirectory
是任务下载管道所需的生成工件或在发布生成工件之前上传生成工件的位置。
Build.BinariesDirectory
是任务写入其输出的位置。
Common.TestResultsDirectory
是任务上传其测试结果的位置。
$(Build.ArtifactStagingDirectory)
和 $(Common.TestResultsDirectory)
始终在每次生成之前删除并重新创建。
在自托管代理上运行管道时,默认情况下,不会在两个连续运行之间清理除 $(Build.ArtifactStagingDirectory)
和 $(Common.TestResultsDirectory)
之外的任何子目录。 因此,可以执行增量生成和部署,前提是实现了相应的任务。 可以使用作业上的 workspace
设置替代此行为。
工作区清理选项仅适用于自托管代理。 使用 Microsoft 托管代理时,作业始终在新代理上运行。
- job: myJob
workspace:
clean: outputs | resources | all # what to clean up before the job runs
指定其中 clean
一个选项时,其解释如下:
outputs
:在运行新作业之前删除 Build.BinariesDirectory
。
resources
:在运行新作业之前删除 Build.SourcesDirectory
。
all
:在运行新作业之前删除整个 Pipeline.Workspace
目录。
jobs:
- deployment: MyDeploy
pool:
vmImage: 'ubuntu-latest'
workspace:
clean: all
environment: staging
根据代理功能和管道需求,每个作业可能会路由到自托管池中的不同代理。 因此,你可能会在后续管道运行(或同一管道中的阶段或作业)中获得新代理,因此不清理并不能保证后续运行、作业或阶段将能够访问以前运行、作业或阶段的输出。 可以配置代理功能和管道需求来指定用于运行管道作业的代理,但除非池中只有一个满足需求的代理,否则不保证后续作业将与以前的作业使用相同的代理。 有关详细信息,请参阅指定需求。
除了工作区清理之外,还可以通过在管道设置 UI 中配置清理设置来配置清理。 当清理设置为 true 时(这也是其默认值),就等效于为管道中的每个签出步骤指定 clean: true
。 指定 clean: true
时,你将运行 git clean -ffdx
,然后运行 git reset --hard HEAD
,而后提取 git。 配置“清理”设置:
编辑管道,选择 ...,然后选择触发器。
选择 YAML、获取源,并配置所需的清理设置。 默认值为 true。
在自托管代理上运行管道时,默认情况下,不会在两个连续运行之间清理任何子目录。 因此,可以执行增量生成和部署,前提是实现了相应的任务。 但是,可以使用 Get sources
任务下的 Clean build
选项替代此行为。 这些选项因使用的存储库类型而异。
GitHub
Azure Repos Git
artifactName: WebSite
# download the artifact and deploy it only if the build job succeeded
- job: Deploy
pool:
vmImage: 'ubuntu-latest'
steps:
- checkout: none #skip checking out the default repository resource
- task: DownloadBuildArtifacts@0
displayName: 'Download Build Artifacts'
inputs:
artifactName: WebSite
downloadPath: $(Pipeline.Workspace)
dependsOn: Build
condition: succeeded()
有关使用 dependsOn 和条件的信息,请参阅指定条件。
访问 OAuth 令牌
可以允许作业中运行的脚本访问当前的 Azure Pipelines 或 TFS OAuth 安全令牌。
此令牌可用于向 Azure Pipelines REST API 进行身份验证。
steps:
- powershell: |
$url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/build/definitions/$($env:SYSTEM_DEFINITIONID)?api-version=4.1-preview"
Write-Host "URL: $url"
$pipeline = Invoke-RestMethod -Uri $url -Headers @{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"
SYSTEM_ACCESSTOKEN: $(system.accesstoken)