在您的流程中指定作業

Azure DevOps 服務 |Azure DevOps Server |Azure DevOps Server 2022

您可以將管線組織成不同的工作。 每個管線至少有一個工作。 作業是一系列以單位順序執行的步驟。 換句話說,作業是可被排程執行的最小工作單位。

若要了解組成管線的重要概念和元件,請參閱 新 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新增部署工作的步驟,但建議您改用 部署作業。 部署作業有幾個優點。 例如,您可以部署到一個環境,這樣做的好處包括能夠查看您所部署專案的歷程記錄。

作業類型

作業可以是不同類型的作業,視作業的執行位置而定。

  • 代理程式集區作業執行於代理程式集區中的代理程式上。
  • 伺服器作業執行於 Azure DevOps Server 上。
  • 容器作業 執行於代理程式集區中某個代理程式的容器內。 如需選擇容器的詳細資訊,請參閱 定義容器作業。

代理集區工作

代理池任務是最常見的任務。 這些作業會在代理程式集區中的代理程式上執行。 您可以指定要執行工作的集區,也可以設定要求,以指定代理程式需要具備的能力來執行您的工作。 代理程式可以由 Microsoft 裝載或自行裝載。 如需詳細資訊,請參閱 Azure Pipelines 代理程式。

  • 當您使用 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

深入瞭解 代理程式功能。

伺服器作業

伺服器會在伺服器作業中協調和執行工作。 伺服器作業不需要代理程式或任何目標計算機。 現在伺服器作業只支援幾個任務。 伺服器作業的最長時間為 30 天。

無需代理程式的作業中支援的任務

目前針對無代理作業,只支援下列工作:

由於工作是可延伸的,因此您可以使用擴充功能來新增更多無代理程式工作。 無代理程式作業的預設逾時為 60 分鐘。

指定伺服器作業的完整語法為:

jobs:
- job: string
  timeoutInMinutes: number
  cancelTimeoutInMinutes: number
  strategy:
    maxParallel: number
    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 管線作業會以平行方式執行。

注意

每個代理程式一次只能執行一個作業。 若要平行執行多個作業,您必須設定多個代理程式。 您也需要足夠的 平行作業。

定義多個作業及其相依性的語法如下:

jobs:
- job: string
  dependsOn: string
  condition: string

循序建置的範例作業:

jobs:
- job: Debug
  steps:
  - script: echo hello from the Debug build
- job: Release
  dependsOn: Debug
  steps:
  - script: echo hello from the Release build

平行建置的範例作業(無相依性):

jobs:
- job: Windows
  pool:
    vmImage: 'windows-latest'
  steps:
  - script: echo hello from Windows
- job: macOS
  pool:
    vmImage: 'macOS-latest'
  steps:
  - script: echo hello from macOS
- job: Linux
  pool:
    vmImage: 'ubuntu-latest'
  steps:
  - script: echo hello from Linux

扇出範例:

jobs:
- job: InitialJob
  steps:
  - script: echo hello from initial job
- job: SubsequentA
  dependsOn: InitialJob
  steps:
  - script: echo hello from subsequent A
- job: SubsequentB
  dependsOn: InitialJob
  steps:
  - script: echo hello from subsequent B

風扇的範例:

jobs:
- job: InitialA
  steps:
  - script: echo hello from initial A
- job: InitialB
  steps:
  - script: echo hello from initial B
- job: Subsequent
  dependsOn:
  - InitialA
  - InitialB
  steps:
  - script: echo hello from subsequent

條件

您可以指定每個作業據以執行的條件。 根據預設,如果作業不依賴於任何其他作業,或是所有它依賴的作業成功完成,則會執行作業。 您可以透過強制運行作業來自訂此行為,即使前一個作業失敗,或者指定自定義條件。

根據執行上一個作業的狀態執行作業的範例:

jobs:
- job: A
  steps:
  - script: exit 1

- job: B
  dependsOn: A
  condition: failed()
  steps:
  - script: echo this will run when A fails

- job: C
  dependsOn:
  - A
  - B
  condition: succeeded('B')
  steps:
  - script: echo this will run when B runs and succeeds

使用 自訂條件的範例:

jobs:
- job: A
  steps:
  - script: echo hello

- 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 分鐘之間。

注意

設定 timeoutInMinutes 或 cancelTimeoutInMinutes 超過Microsoft託管代理最大工作長度,對託管代理管線沒有影響,因為這些工作會根據託管代理的限制逾時。 更多資訊請參閱前述的 暫停 章節。

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

逾時具有下列層級的優先順序。

  1. 在 Microsoft 託管的代理程式上,作業會根據專案類型以及是否使用付費平行作業來執行而受時間長度的限制。 當 Microsoft 託管的作業逾時時間隔結束時,作業就會終止。 在 Microsoft 裝載的代理程式上,無論作業中指定的任何作業層級逾時設定,作業都不能超過此間隔。
  2. 在作業層級設定的逾時會指定要執行之作業的最大持續時間。 當作業層級的超時時間經過時,作業就會被終止。 當作業在由 Microsoft 託管的代理程式上執行時,設定的作業層級逾時若超過 Microsoft 託管內建作業層級逾時 ,將不會產生效果。
  3. 您也可以個別設定每個工作的逾時 - 請參閱 工作控制選項。 如果工作層級逾時間隔在工作完成之前經過,即使工作設定了較長的逾時間隔,執行中的作業也會終止。

多作業組態

從您撰寫的單一作業中,您可以平行地在多個代理程式上執行多個作業。 這些範例包含:

  • 多重組態組建: 您可以平行建置多個組態。 例如,您可以為 debug 和 release 組態,以及 x86 和 x64 平台建置 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

切片

代理程式作業可用來平行執行一組測試。 例如,您可以在單一代理程式上執行包含 1,000 個測試的大型套件。 或者,您可以使用兩個代理程式,並平行執行每一個代理程式 500 個測試。

若要套用分片,作業中的工作應具備足夠的智慧,以了解其所屬的分片。

Visual Studio 測試工作是支持測試切割的這類工作之一。 如果您安裝了多個代理程式,您可以指定 Visual Studio 測試工作在這些代理程式上平行執行的方式。

此 parallel 策略可讓作業重複多次。 變數 System.JobPositionInPhase 和 System.TotalJobsInPhase 會新增至每個作業。 然後,您可以在腳本內使用變數,將工作分割在作業之間。 請參閱 透過代理程式作業進行平行及多重執行。

下列作業會被派遣五次,並適當地設定 System.JobPositionInPhase 和 System.TotalJobsInPhase 的值。

jobs:
- job: Test
  strategy:
    parallel: 5

作業變數

如果您使用 YAML,可以在作業上指定變數。 變數可以使用巨集語法 $(variableName) 傳遞至工作輸入,或使用階段變數在腳本中存取。

以下是在作業中定義變數並在工作中使用這些變數的範例。

variables:
  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 中透過配置 Clean 設定來進行清理。 當 清理 設定為 true 時,也就是其預設值,相當於在管線中的每個 clean: true 步驟中指定 。 當您指定 clean: true時,您會在 git 擷取之前先執行 git clean -ffdx,然後執行 git reset --hard HEAD。 若要設定 清除 設定值:

  1. 編輯您的管線,選擇 ...,然後選取 [ 觸發程式]。

    編輯觸發程式。

  2. 選取 [YAML]、 [取得來源],然後設定您想要的 [清除 ] 設定。 預設值為 True。

    清除設定。

工件下載

此範例 YAML 檔案會發佈成品 Website ,然後將成品下載至 $(Pipeline.Workspace)。 只有在建置作業成功時,部署作業才會執行。

# test and upload my code as an artifact named Website
jobs:
- job: Build
  pool:
    vmImage: 'ubuntu-latest'
  steps:
  - script: npm test
  - task: PublishPipelineArtifact@1
    inputs:
      artifactName: Website
      targetPath: '$(System.DefaultWorkingDirectory)'

# 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: DownloadPipelineArtifact@2
    displayName: 'Download Pipeline Artifact'
    inputs:
      artifactName: Website
      targetPath: '$(Pipeline.Workspace)'
  dependsOn: Build
  condition: succeeded()

如需使用 dependsOn 和條件的相關信息,請參閱指定條件。

存取 OAuth 令牌

您可以允許在作業中執行的腳本存取目前的 Azure Pipelines OAuth 安全性令牌。 令牌可用來向 Azure Pipelines REST API 進行驗證。

OAuth 令牌一律可供 YAML 管線使用。 它必須使用 env 明確映射到工作或步驟。 以下是範例:

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)"
  env:
    SYSTEM_ACCESSTOKEN: $(system.accesstoken)

下一步是什麼