Поделиться через


Условия трубопровода

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

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

  • По умолчанию задание или этап выполняется, если оно не зависит от другого задания или этапа, или если все его зависимости завершены и выполнены успешно. Это требование применяется не только к прямым зависимостям, но и к их косвенным зависимостям, вычисляемых рекурсивно.

  • По умолчанию шаг выполняется, если ничего в его задании еще не провалилось и шаг, непосредственно предшествующий, завершен.

Это поведение можно переопределить или настроить путем принудительного выполнения этапа, задания или шага, даже если предыдущая зависимость завершается сбоем или путем указания настраиваемого условия.

Примечание.

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

Условия выполнения этапа, задания или шага

В определении конвейера YAML можно указать следующие условия, в которых выполняется этап, задание или шаг:

  • Только в случае успешного выполнения всех предыдущих прямых и косвенных зависимостей с тем же пулом агентов. Если у вас есть разные пулы агентов, эти этапы или задания выполняются одновременно. Это условие по умолчанию, если условие не задано в YAML.

  • Даже если предыдущая зависимость завершается ошибкой, если выполнение не отменено. Используйте succeededOrFailed() в YAML для этого условия.

  • Даже если предыдущая зависимость завершается ошибкой, и даже если запуск отменен. Используйте always() в YAML для этого условия.

  • Только в случае, если предыдущая зависимость завершается сбоем. Используйте failed() в YAML для этого условия.

  • Пользовательские условия.

По умолчанию этапы, работы и шаги запускаются, если все прямые и косвенные зависимости выполняются успешно. Это состояние совпадает с указанием condition: succeeded(). Дополнительные сведения см. в разделе функция состояния "Успех".

При указании condition свойства для этапа, задания или шага вы перезаписываете значение по умолчанию condition: succeeded(). Указание собственных условий может привести к тому, что этап, задание или шаг будут выполнены, даже если сборка отменена. Убедитесь, что условия, которые вы записываете, принимают во внимание состояние родительского этапа или задачи.

В следующем примере YAML показаны условия always() и failed(). Шаг в первом задании выполняется, даже если зависимости дают сбой или сборка отменяется. Во второй задаче скрипта exit 1 вызывает сбой задания Foo. Второе задание выполняется только в том случае, если первое задание завершается ошибкой.

jobs:
- job: Foo
  steps:
  - script: echo Hello!
    condition: always() # this step runs, even if the build is canceled
  - script: |
      echo "This task will fail."
      exit 1 
- job: Bar
  dependsOn: Foo
  condition: failed() # this job runs only if Foo fails

Можно также задать и использовать переменные в условиях. В следующем примере задаётся и используется isMain переменная для обозначения main в качестве Build.SourceBranch.

variables:
  isMain: $[eq(variables['Build.SourceBranch'], 'refs/heads/main')]

stages:
- stage: A
  jobs:
  - job: A1
    steps:
      - script: echo Hello Stage A!

- stage: B
  condition: and(succeeded(), eq(variables.isMain, true))
  jobs:
  - job: B1
    steps:
      - script: echo Hello Stage B!
      - script: echo $(isMain)

Внимание

Условия оцениваются, чтобы определить, следует ли начинать этап, задание или шаг. Поэтому ничего вычисляемого во время выполнения в этой единице работы доступно. Например, если у вас есть задание, которое задает переменную с помощью выражения среды выполнения с $[ ] синтаксисом, эту переменную нельзя использовать в пользовательском условии в этом задании.

Настраиваемые условия

Если встроенные условия не соответствуют вашим потребностям, можно указать пользовательские условия. Условия записываются в виде выражений в определениях конвейера YAML.

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

Если какое-либо из ваших условий позволяет выполнять задачу даже после отмены сборки, укажите разумное значение тайм-аута на отмену, чтобы эти задачи имели достаточно времени для завершения после отмены выполнения пользователем.

Результаты обработки условий при отмене сборки

Отмена сборки не означает, что все его этапы, задания или шаги перестают выполняться. Какие этапы, задания или шаги перестают выполняться, зависят от указанных условий и в какой точке выполнения конвейера вы отменили сборку. Если этап, задание или родитель шага пропущены, задача не выполняется независимо от ее условий.

Этап, задание или шаг выполняются всякий раз, когда их условия равны true. Если условие не учитывает состояние родительского элемента задачи, задача может выполняться даже если ее родительский элемент отменен. Чтобы контролировать выполнение этапов, заданий или шагов с условиями в случае отмены сборки, обязательно включите функцию проверки статуса задания в ваши условия.

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

Пример этапа 1

В следующем конвейере по умолчанию stage2 будет зависеть от stage1, но stage2 имеет condition, настроенный на выполнение всякий раз, когда исходная ветка — main, независимо от статуса stage1.

Если вы поставите сборку в очередь на ветке main и отмените её, пока выполняется stage1, то stage2 всё равно выполняется, потому что eq(variables['Build.SourceBranch'], 'refs/heads/main') оценивается как true.

stages:
- stage: stage1
  jobs:
  - job: A
    steps:
      - script: echo 1; sleep 30
- stage: stage2
  condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')
  jobs:
  - job: B
    steps:
      - script: echo 2

Пример этапа 2

В следующем конвейере stage2 зависит от stage1 по умолчанию. Задание B в stage2 имеет набор condition. Если вы вызовете сборку в main ветви и отмените её во время stage1 выполнения, stage2 не будет выполнен, даже если он содержит задание, условие которого оценивается как true.

stages:
- stage: stage1
  jobs:
  - job: A
    steps:
      - script: echo 1; sleep 30
- stage: stage2
  jobs:
  - job: B
    condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')
    steps:
      - script: echo 2

Пример этапа 3

В следующем конвейере по умолчанию stage2 зависит от stage1, и шаг в задании B имеет набор condition.

Если вы поставите в очередь сборку в main ветке и отмените ее во время stage1 выполнения, stage2 не будет выполнен, даже если он содержит шаг в задании B, условие которого оценивается как true. Причина заключается в том, что stage2 пропускается в ответ на отмену stage1.

stages:
- stage: stage1
  jobs:
  - job: A
    steps:
      - script: echo 1; sleep 30
- stage: stage2
  jobs:
  - job: B
    steps:
      - script: echo 2
        condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')

Пример задания 1

В следующем конвейере YAML задание B зависит от задания A по умолчанию, но задание B имеет условие condition, чтобы выполняться каждый раз, когда исходная ветка — main. Если вы запустите сборку в ветке main и отмените ее во время выполнения задания A, задание B по-прежнему выполняется, так как оценка равна eq(variables['Build.SourceBranch'], 'refs/heads/main').

jobs:
- job: A
  steps:
  - script: sleep 30
- job: B
  dependsOn: A 
  condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')
  steps:
    - script: echo step 2.1

Если вы хотите, чтобы задание B выполнялось только в случае успешного выполнения задания A и если источник сборки — ветка main, значение condition должно быть and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')).

Пример задания 2

В следующем конвейере задание B зависит от задания A по умолчанию. Если вы поставите сборку в очередь на main ветки и отмените ее во время выполнения задания A, задание B не выполняется, даже если его шаг condition оценивается как true.

Причина заключается в том, что задание B оценивается как false, когда задание A отменяется. Таким образом, задание B пропускается, и ни один из его шагов не выполняется.

jobs:
- job: A
  steps:
  - script: sleep 30
- job: B
  dependsOn: A 
  steps:
    - script: echo step 2.1
  condition: and(eq(variables['Build.SourceBranch'], 'refs/heads/main'), succeeded())

Пример шага

Вы также можете устанавливать условия для шагов.

В следующем конвейере шаг 2.3 настроен для выполнения каждый раз, когда исходная ветка является condition. Если вы запустите сборку в ветке main и отмените ее во время выполнения шагов 2.1 или 2.2, шаг 2.3 по-прежнему выполняется, так как eq(variables['Build.SourceBranch'], 'refs/heads/main') оценивается как true.

steps:
  - script: echo step 2.1
  - script: echo step 2.2; sleep 30
  - script: echo step 2.3
    condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')

Настройки условий

В следующей таблице показаны примеры condition параметров для получения различных результатов.

Примечание.

Release.Artifacts.{artifact-alias}.SourceBranch эквивалентна Build.SourceBranch.

Требуемый результат Пример настройки условия
Запустите, если исходная ветвь является основной, даже если родительский или предыдущий этап, задание или шаг завершился сбоем или был отменен. eq(variables['Build.SourceBranch'], 'refs/heads/main')
Запустите, если исходная ветвь является главной и родительский или предыдущий этап, задание или шаг выполнен успешно. and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
Запустите, если исходная ветвь не является основной, и если родительский или предыдущий этап, задание или шаг завершились успешно. and(succeeded(), ne(variables['Build.SourceBranch'], 'refs/heads/main'))
Запустите ветки пользовательских тем, если родительский или предыдущий этап, задание или шаг были выполнены успешно. and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/heads/users/'))
Запускайте сборки непрерывной интеграции (CI), если родительский или предыдущий этап, задание или шаг завершились успешно. and(succeeded(), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI'))
Запустите, если сборка была инициирована политикой ветки для pull-запроса, и предыдущий этап, задание или шаг был завершен с ошибкой. and(failed(), eq(variables['Build.Reason'], 'PullRequest'))
Выполните запуск запланированной сборки, даже если родительская или предыдущая стадия, задание или этап завершились сбоем или были отменены. eq(variables['Build.Reason'], 'Schedule')
Запустите, если переменная установлена в true, даже если вышестоящий или предыдущий этап, задание или шаг завершился сбоем или был отменен. eq(variables['System.debug'], true)

Примечание.

Можно задать условие для запуска, если переменная имеет значение NULL (пустая строка). Так как все переменные в Azure Pipelines рассматриваются как строки, пустая строка эквивалентна null в следующем конвейере:

variables:
- name: testEmpty
  value: ''

jobs:
  - job: A
    steps:
    - script: echo testEmpty is blank
    condition: eq(variables.testEmpty, '')

Параметры в условиях

Расширение параметров происходит до рассмотрения условий. Поэтому при объявлении параметра в том же конвейере, что и условие, можно внедрить параметр в условие. Скрипт в следующем YAML выполняется, так как parameters.doThing истинно.

parameters:
- name: doThing
  default: true
  type: boolean

steps:
- script: echo I did a thing
  condition: and(succeeded(), ${{ eq(parameters.doThing, true) }})

В предыдущем конвейере condition объединяются две функции: succeeded() и ${{ eq(parameters.doThing, true) }}. Функция succeeded() проверяет, выполнен ли предыдущий шаг успешно. succeeded() функция возвращает true из-за отсутствия предыдущего шага.

Функция ${{ eq(parameters.doThing, true) }} проверяет, равен ли параметр doThingtrue. Так как значение doThing по умолчанию равно true, условие возвращается true по умолчанию, если конвейер не задает другое значение.

Параметры шаблона в условиях

При передаче параметра в шаблон необходимо задать значение параметра в шаблоне или использовать templateContext для передачи параметра шаблону.

Например, следующий файл parameters.yml объявляет doThing параметр и значение по умолчанию:

# parameters.yml
parameters:
- name: doThing
  default: true # value passed to the condition
  type: boolean

jobs:
  - job: B
    steps:
    - script: echo I did a thing
    condition: ${{ eq(parameters.doThing, true) }}

Код конвейера ссылается на шаблон parameters.yml . Выходные данные конвейера равны I did a thing, так как параметр doThing равен true.

# azure-pipeline.yml
parameters:
- name: doThing
  default: true 
  type: boolean

trigger:
- none

extends:
  template: parameters.yml

Дополнительные примеры параметров шаблона см. в справочнике по использованию шаблона.

Выходные переменные задания, используемые в последующих условиях задания

Вы можете сделать переменную доступной для будущих заданий и указать ее в условии. Переменные, доступные для будущих заданий, должны быть помечены как выходные переменные с несколькими заданиями с помощью isOutput=trueследующего кода:

jobs:
- job: Foo
  steps:
  - bash: |
      echo "This is job Foo."
      echo "##vso[task.setvariable variable=doThing;isOutput=true]Yes" #set variable doThing to Yes
    name: DetermineResult
- job: Bar
  dependsOn: Foo
  condition: eq(dependencies.Foo.outputs['DetermineResult.doThing'], 'Yes') #map doThing and check the value
  steps:
  - script: echo "Job Foo ran and doThing is Yes."

Переменные, созданные в шаге, используемые в условиях последующих шагов

Вы можете создать переменную, которая будет доступна для последующих шагов при указании в условии. Переменные, созданные на основе шагов, доступны для будущих шагов по умолчанию и не должны быть помечены как переменные выходных данных с несколькими заданиями.

Есть несколько важных моментов, которые следует отметить о переменных области видимости, созданных из шагов.

  • Переменные, созданные на этапе задания, доступны для использования в шагах того же задания.
  • Переменные, созданные на шаге, доступны только в качестве переменных среды.
  • Переменные, созданные на шаге, нельзя использовать на шаге, который определяет их.

В следующем примере показано создание переменной конвейера на шаге и использование переменной в условии и скрипте последующего шага.

steps:

# This step creates a new pipeline variable: doThing. This variable is available to subsequent steps.
- bash: |
    echo "##vso[task.setvariable variable=doThing]Yes"
  displayName: Step 1

# This step is able to use doThing, so it uses doThing in its condition
- script: |
    # Access the variable from Step 1 as an environment variable.
    echo "Value of doThing (as DOTHING env var): $DOTHING."
  displayName: Step 2
  condition: and(succeeded(), eq(variables['doThing'], 'Yes')) # or and(succeeded(), eq(variables.doThing, 'Yes'))

Вопросы и ответы

Как я могу активировать задание, если предыдущее задание было выполнено с проблемами?

Вы можете использовать результат предыдущего задания в условии. Например, в следующем YAML условие eq(dependencies.A.result,'SucceededWithIssues') позволяет выполнять задание B после успешного выполнения задания A с проблемами.

jobs:
- job: A
  displayName: Job A
  continueOnError: true # next job starts even if this one fails
  steps:
  - script: echo Job A ran
  - script: exit 1

- job: B
  dependsOn: A
  condition: eq(dependencies.A.result,'SucceededWithIssues') # targets the result of the previous job 
  displayName: Job B
  steps:
  - script: echo Job B ran

Я отменил процесс сборки, но он все еще выполняется. Почему?

Эта проблема возникает, если условие, настроенное на этапе, не включает функцию проверки состояния задания. Чтобы устранить проблему, добавьте функцию проверки состояния задания в условие.

Если вы отменяете задание, пока оно находится на этапе очереди, но не выполняется, все задание отменяется, включая все остальные этапы. Дополнительные сведения см. в разделе Результаты условий при отмене сборки, указанном ранее в этой статье.