パイプラインにジョブを指定する

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

パイプラインをジョブに整理することができます。 すべてのパイプラインには、少なくとも 1 つのジョブがあります。 "ジョブ" とは、1 つの単位として順番に実行される一連のステップです。 つまり、ジョブは、実行をスケジュールできる最小の作業単位です。

パイプラインを構成する主要な概念とコンポーネントについては、新しい Azure Pipelines ユーザーの主要な概念に関するページを参照してください。

Azure Pipelines では、YAML パイプラインのジョブ優先度はサポートされていません。 ジョブの実行タイミングを制御するには、条件依存関係を指定します。

1 つのジョブを定義する

最もシンプルなケースでは、パイプラインに 1 つのジョブがあります。 この場合、テンプレートを使っている場合を除き、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 で実行されます。
  • コンテナー ジョブ は、エージェント プール内のエージェント上のコンテナーで実行されます。 コンテナーの選択の詳細については、「コンテナー ジョブを定義する」を参照してください。
  • エージェント プール ジョブはエージェント プール内のエージェント上で実行されます。
  • サーバー ジョブは、Azure DevOps Server で実行されます。

エージェント プール ジョブ

これらは最も一般的な種類のジョブであり、エージェント プール内のエージェント上で実行されます。

  • Microsoft ホステッド エージェントを使う場合、パイプラインの各ジョブは新しいエージェントを取得します。
  • セルフホステッド エージェントには要求を使い、ジョブを実行するためにエージェントに必要な機能を指定します。 パイプラインの要求と一致するエージェントがエージェント プールに複数あるかどうかに応じて、連続するジョブに同じエージェントを取得することができます。 パイプラインの要求に一致するエージェントがプール内に 1 つしかない場合、このエージェントが使用可能になるまでパイプラインは待機します。

Note

要求と機能はセルフホステッド エージェントで使うように設計されているので、ジョブをジョブの要件を満たすエージェントと対応付けることができます。 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 日です。

エージェントレス ジョブでサポートされるタスク

現在、既定のエージェントレス ジョブでは、次のタスクのみがサポートされています。

タスクは拡張機能可能であるため、拡張機能を使ってエージェントレス タスクをさらに追加できます。 エージェントレス ジョブの既定のタイムアウトは 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

依存関係

1 つのステージで複数のジョブを定義する場合、それらの間の依存関係を指定できます。 パイプラインには、依存関係のないジョブを少なくとも 1 つ含める必要があります。 既定では、dependsOn 値が設定されている場合を除き、Azure DevOps YAML パイプライン ジョブは並列で実行されます。

Note

各エージェントは、一度に 1 つのジョブのみを実行できます。 複数のジョブを並列で実行するには、複数のエージェントを構成する必要があります。 また、十分な数の並列ジョブも必要です。

複数のジョブとその依存関係を定義するための構文は次のとおりです。

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

Timeouts

ジョブが応答しないときや待機時間が長すぎるときにリソースを占有しないようにするには、ジョブの実行時間に制限を設定することをお勧めします。 ジョブのタイムアウト設定を使って、ジョブの実行に関する制限を分単位で指定します。 値をゼロに設定した場合、ジョブを実行できる期間は次のとおりです。

  • セルフホステッド エージェントの場合は永続的
  • パブリック プロジェクトとパブリック リポジトリを使う Microsoft ホステッド エージェントの場合は 360 分 (6 時間)
  • プライベート プロジェクトまたはプライベート リポジトリを使う Microsoft ホステッド エージェントの場合は 60 分 (追加容量を購入していない場合)

タイムアウト期間は、ジョブの実行が開始されたときに開始されます。 これには、ジョブがキューに入っている時間やエージェントを待機している時間は含まれません。

timeoutInMinutes を使うと、ジョブの実行時間に制限を設定できます。 指定しない場合、既定値は 60 分です。 0 を指定した場合、(前述した) 上限が使われます。

配置タスクで前のタスクが失敗した場合に実行を継続するように設定している場合、cancelTimeoutInMinutes を使うと、ジョブのキャンセル時間に制限を設定できます。 指定しない場合、既定値は 5 分です。 この値の範囲は 1 分から 35,790 分です。

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 でホストされているジョブ レベルのタイムアウトより大きい間隔に設定しても効果はなく、Microsoft がホストするジョブのタイムアウトが使用されます。
  3. 各タスクのタイムアウトを個別に設定することもできます。「タスク制御オプション」をご覧ください。 タスクが完了する前にジョブ レベルのタイムアウト間隔が経過すると、タスクのタイムアウト間隔が長く構成されている場合でも、実行中のジョブは終了します。

複数ジョブの構成

作成した 1 つのジョブから、複数のエージェントで複数のジョブを並列で実行することができます。 次に例をいくつか示します。

  • 複数構成のビルド: 複数の構成を並列でビルドできます。 たとえば、x86x64 の両方のプラットフォーム上で debugrelease の両方の構成向けに Visual C++ アプリをビルドできます。 詳細については、「 Visual Studio Build - 複数のプラットフォームの複数の構成を参照してください。

  • 複数構成の配置: 複数の配置を、たとえば異なる地域に対して並列で実行できます。

  • 複数構成のテスト: テスト用の複数の構成を並列で実行できます。

  • 複数構成の場合、複数構成変数が空であっても、少なくとも 1 つのジョブが常に生成されます。

matrix 戦略を使うと、異なる変数セットを使ってジョブを複数回ディスパッチできます。 maxParallel タグを使うと、並列処理の量を制限できます。 Location と Browser に設定した値のとおり、次のジョブは 3 回ディスパッチされます。 ただし、同時に実行されるのは 2 つのジョブのみです。

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

Note

(上記の 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 つのエージェントで 1,000 件という大規模な一連のテストを実行できます。 また、2 つのエージェントを使って、それぞれに対して 500 個のテストを並列して実行できます。

スライスを適用するには、ジョブ内のタスクに、その属するスライスを理解できる高い機能が必要です。

Visual Studio Test タスクは、そのようなテスト スライスをサポートするタスクの 1 つです。 複数のエージェントをインストールした場合、これらのエージェント上で Visual Studio Test タスクを並列で実行する方法を指定できます。

parallel 戦略を使うと、ジョブを何度も複製できます。 変数 System.JobPositionInPhaseSystem.TotalJobsInPhase が各ジョブに追加されます。 この変数をスクリプト内で使うことで、作業を複数のジョブに分割できます。 エージェント ジョブを使った並列および複数の実行に関する記事を参照してください。

次のジョブは 5 回ディスパッチされます。その際に System.JobPositionInPhaseSystem.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"

condition の使用については、「条件の指定」を参照してください。

ワークスペース

エージェント プール ジョブを実行すると、エージェント上にワークスペースが作成されます。 ワークスペースとは、ソースをダウンロードし、ステップを実行し、出力を生成するディレクトリです。 ワークスペース ディレクトリは、ジョブ内で Pipeline.Workspace 変数を使って参照できます。 この下に、さまざまなサブディレクトリが作成されます。

  • Build.SourcesDirectory は、タスクがアプリケーションのソース コードをダウンロードする場所です。
  • Build.ArtifactStagingDirectory は、タスクがパイプラインに必要な成果物をダウンロードしたり、発行前の成果物をアップロードしたりする場所です。
  • Build.BinariesDirectory は、タスクが出力を書き込む場所です。
  • Common.TestResultsDirectory は、タスクがテスト結果をアップロードする場所です。

$(Build.ArtifactStagingDirectory)$(Common.TestResultsDirectory) は、毎回のビルド前に常に削除され、再作成されます。

セルフホステッド エージェント上でパイプラインを実行する場合、既定で、$(Build.ArtifactStagingDirectory)$(Common.TestResultsDirectory) 以外のサブディレクトリは、2 つの連続した実行の間にクリーンされません。 その結果、それを使うタスクが実装されていれば、増分ビルドと配置を行うことができます。 この動作は、ジョブの 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

注意

エージェントの機能とパイプラインの要求によっては、各ジョブはセルフホステッド プール内の異なるエージェントにルーティングされる可能性があります。 その結果、後続のパイプラインの実行 (または同じパイプラインのステージやジョブ) には新しいエージェントが使われる可能性があります。そのため、クリーンしなくても、後続の実行、ジョブ、ステージが以前の実行、ジョブ、ステージの出力にアクセスできることは保証されません。 エージェントの機能とパイプラインの要求を構成して、パイプライン ジョブの実行に使うエージェントを指定できます。ただし、要求を満たすエージェントがプール内に 1 つしかない場合を除き、後続のジョブが以前のジョブと同じエージェントを使う保証はありません。 詳細については、「要求の指定」を参照してください。

ワークスペースのクリーンに加えて、パイプライン設定 UI で [クリーン] 設定を構成することでクリーンを構成することもできます。 [クリーン] 設定が true (既定値) の場合、パイプラインのチェックアウト ステップごとに clean: true を指定することと同じです。 clean: true を指定した場合は、git フェッチの前に git clean -ffdxgit 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: PublishBuildArtifacts@1
    inputs:
      pathtoPublish: '$(System.DefaultWorkingDirectory)'
      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()

dependsOncondition の使用については、「条件の指定」を参照してください。

OAuth トークンにアクセスする

ジョブ内で実行されるスクリプトが、現在の Azure Pipelines または TFS 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)

次の内容