Указание заданий в конвейере

Azure DevOps Services | Azure DevOps Server 2022 — Azure DevOps Server 2019

Конвейер можно упорядочить в задания. Каждый конвейер имеет хотя бы одно задание. Задание — это ряд шагов, которые выполняются последовательно как единица. Другими словами, задание — это наименьшая единица работы, которую можно запланировать для выполнения.

Дополнительные сведения о ключевых понятиях и компонентах, составляющих конвейер, см. в разделе "Основные понятия" для новых пользователей Azure Pipelines.

Azure Pipelines не поддерживает приоритет задания для конвейеров YAML. Чтобы управлять выполнением заданий, можно указать условия и зависимости.

Определение одного задания

В самом простом случае конвейер имеет одно задание. В этом случае вам не нужно явно использовать job ключевое слово, если вы не используете шаблон. Вы можете напрямую указать шаги в файле YAML.

Этот ФАЙЛ YAML имеет задание, которое выполняется в размещенном корпорацией Майкрософт агенте и выходных 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.

Задания пула агентов

Это наиболее распространенный тип заданий, и они выполняются на агенте в пуле агентов.

  • При использовании размещенных корпорацией Майкрософт агентов каждое задание в конвейере получает новый агент.
  • Используйте запросы с локальными агентами , чтобы указать, какие возможности должен иметь агент для выполнения задания. Вы можете получить тот же агент для последовательных заданий, в зависимости от того, существует ли несколько агентов в пуле агентов, которые соответствуют требованиям конвейера. Если в пуле есть только один агент, соответствующий требованиям конвейера, конвейер ожидает, пока этот агент не будет доступен.

Примечание.

Требования и возможности предназначены для использования с локальными агентами, чтобы задания могли соответствовать агенту, который соответствует требованиям задания. При использовании агентов, размещенных Корпорацией Майкрософт, вы выбираете образ агента, который соответствует требованиям задания, поэтому, хотя это возможно, чтобы добавить возможности в размещенный корпорацией Майкрософт агент, вам не нужно использовать возможности с размещенными корпорацией Майкрософт агентами.

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

Зависимости

При определении нескольких заданий на одном этапе можно указать зависимости между ними. Конвейеры должны содержать по крайней мере одно задание без зависимостей. По умолчанию задания конвейера YAML Azure DevOps выполняются параллельно, если dependsOn значение не задано.

Примечание.

Каждый агент может одновременно выполнять только одно задание. Для параллельного выполнения нескольких заданий необходимо настроить несколько агентов. Кроме того, вам потребуется достаточно параллельных заданий.

Синтаксис определения нескольких заданий и их зависимостей:

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

Время ожидания

Чтобы избежать расходования ресурсов при отсутствии ответа задания или слишком длительном ожидании, рекомендуем задать предельное значение для времени выполнения задания. Используйте параметр времени ожидания задания, чтобы указать предельное значение для времени выполнения задания (в минутах). Задание значения равно нулю означает, что задание может выполняться:

  • Навсегда для локальных агентов
  • В течение 360 минут (6 часов) в размещенных майкрософт агентах с общедоступным проектом и общедоступный репозиторий
  • В течение 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

Время ожидания имеет следующий уровень приоритета.

  1. В размещенных корпорацией Майкрософт агентах задания ограничены в том, сколько времени они могут выполняться на основе типа проекта и выполняются ли они с помощью платного параллельного задания. При истечении интервала времени ожидания задания, размещенного корпорацией Майкрософт, задание завершается. В размещенных майкрософт агентах задания не могут выполняться дольше этого интервала, независимо от времени ожидания на уровне задания, указанного в задании.
  2. Время ожидания, настроенное на уровне задания, указывает максимальную длительность выполнения задания. Когда интервал времени ожидания задания истекает, задание завершается. Если задание выполняется в агенте, размещенном корпорацией Майкрософт, задание времени ожидания уровня задания больше, чем встроенное время ожидания на уровне задания, размещенного корпорацией Майкрософт, не влияет и используется время ожидания задания, размещенного корпорацией Майкрософт.
  3. Вы также можете задать время ожидания для каждой задачи по отдельности. См . параметры управления задачами. Если интервал времени ожидания задания истекает до завершения задачи, выполнение задания завершается, даже если задача настроена с длительным интервалом времени ожидания.

Настройка нескольких заданий

Из одного задания, который вы создаете, можно выполнять несколько заданий на нескольких агентах параллельно. Некоторыми примерами могут служить:

  • Сборки с несколькими конфигурациями: можно параллельно создавать несколько конфигураций. Например, можно создать приложение Visual C++ для обеих debug платформ и releasex64 конфигурацийx86. Дополнительные сведения см. в статье "Сборка 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

Фрагментирование

Задание агента можно использовать для параллельного выполнения набора тестов. Например, можно запустить большой набор тестов 1000 на одном агенте. Кроме того, можно использовать два агента и выполнять 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 — где задачи отправляют результаты теста.

$(Common.TestResultsDirectory) Они $(Build.ArtifactStagingDirectory) всегда удаляются и повторно создаются до каждой сборки.

При запуске конвейера в локальном агенте по умолчанию ни один из подкаталогов, отличных $(Build.ArtifactStagingDirectory)$(Common.TestResultsDirectory) от двух последовательных запусков. В результате можно выполнять добавочные сборки и развертывания, при условии, что задачи реализуются для использования этого. Это поведение можно переопределить с помощью workspace параметра задания.

Внимание

Параметры очистки рабочей области применимы только для локальных агентов. Задания всегда выполняются на новом агенте с агентами, размещенными корпорацией Майкрософт.

- 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

Примечание.

В зависимости от возможностей агента и требований конвейера каждое задание может быть перенаправлено на другой агент в локальном пуле. В результате вы можете получить новый агент для последующих запусков конвейера (или этапов или заданий в одном конвейере), поэтому очистка не гарантирует, что последующие запуски, задания или этапы смогут получать доступ к выходным данным из предыдущих запусков, заданий или этапов. Вы можете настроить возможности агента и требования конвейера, чтобы указать, какие агенты используются для выполнения задания конвейера, но если в пуле нет только одного агента, соответствующего требованиям, нет никакой гарантии, что последующие задания будут использовать тот же агент, что и предыдущие задания. Дополнительные сведения см. в разделе "Указание требований".

Помимо очистки рабочей области, можно также настроить очистку, настроив параметр "Очистка " в пользовательском интерфейсе параметров конвейера. Если параметр Clean имеет значение true, то значение по умолчанию эквивалентно указанию clean: true каждого шага проверка out в конвейере. При указании clean: trueвы будете запускаться git clean -ffdx перед получением git reset --hard HEAD git. Чтобы настроить параметр Clean , выполните следующие действия.

  1. Измените конвейер, выберите ...и выберите "Триггеры".

    Изменение триггеров.

  2. Выберите YAML, Get sources и настройте нужный параметр "Очистить ". Значение по умолчанию: 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()

Сведения об использовании зависимости и условия см. в разделе "Указание условий".

Доступ к маркеру OAuth

Скрипты, выполняемые в задании, можно разрешить доступ к текущему маркеру безопасности Azure Pipelines или TFS OAuth. Маркер можно использовать для проверки подлинности в REST API Azure Pipelines.

Маркер 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)

Дальнейшие действия