Condições do pipeline

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

Este artigo descreve as condições sob as quais um estágio, trabalho ou etapa do Azure Pipelines acontece e como especificar condições diferentes. Para ter acesso a mais contexto sobre estágios, trabalhos e etapas, consulte Principais conceitos do Azure Pipelines.

  • Por padrão, um trabalho ou estágio acontecerá se ele não depender de nenhum outro trabalho ou estágio ou se todas as dependências forem concluídas sem erros. Esse requisito se aplica não apenas às dependências diretas, mas também às dependências indiretas, calculadas recursivamente.

  • Por padrão, uma etapa acontece se nenhum erro ocorrer no trabalho e a etapa imediatamente anterior for concluída.

Você pode substituir ou personalizar esse comportamento ao especificar uma condição personalizada ou ao forçar a execução de um estágio, trabalho ou etapa, mesmo que uma dependência anterior falhe.

Observação

Este artigo discute os recursos de pipeline YAML. Para pipelines clássicos, você pode especificar algumas condições sob as quais tarefas ou trabalhos acontecem em Opções de Controle de cada tarefa e em Opções adicionais de um trabalho em um pipeline de lançamento.

Condições sob as quais um estágio, trabalho ou etapa é executado

No YAML de definição de pipeline, você pode especificar as seguintes condições sob as quais um estágio, trabalho ou etapa é executado:

  • Somente quando todas as dependências diretas e indiretas anteriores com o mesmo pool de agentes tiverem sido bem-sucedidas. Se houver pools de agentes diferentes, esses fases ou trabalhos serão executados simultaneamente. Esta condição é o padrão se nenhuma condição for definida no YAML.

  • Mesmo que uma dependência anterior tenha falhado, a menos que a execução tenha sido cancelada. Use succeededOrFailed() no YAML para essa condição.

  • Mesmo que uma dependência anterior tenha falhado, mesmo que a execução tenha sido cancelada. Use always() no YAML para essa condição.

  • Somente quando uma dependência anterior tiver falhado. Use failed() no YAML para essa condição.

  • Condições personalizadas.

Por padrão, estágios, trabalhos e etapas serão executados se todas as dependências diretas e indiretas tiverem êxito. Esse status é o mesmo que especificar condition: succeeded(). Para obter mais informações, consulte Função de status com êxito.

Ao especificar uma propriedade condition para um estágio, trabalho ou etapa, você substitui o padrão condition: succeeded(). Especificar suas próprias condições pode fazer com que seu estágio, trabalho ou etapa seja executado mesmo que a compilação seja cancelada. Certifique-se de que as condições gravadas levem em conta o estado do estágio ou trabalho pai.

O exemplo de YAML a seguir mostra as condições always() e failed(). A etapa no primeiro trabalho é executada mesmo se as dependências falharem ou se a compilação for cancelada. O segundo trabalho será executado somente se o primeiro falhar.

jobs:
- job: Foo

  steps:
  - script: echo Hello!
    condition: always() # this step runs, even if the build is canceled

- job: Bar
  dependsOn: Foo
  condition: failed() # this job runs only if Foo fails

Você também pode definir e usar variáveis em condições. O exemplo a seguir define e usa uma variável isMain para designar main como 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)

Importante

As condições são avaliadas para determinar se um estágio, trabalho ou etapa será iniciado. Portanto, nada calculado no runtime dentro dessa unidade de trabalho estará disponível. Por exemplo, se você tiver um trabalho que define uma variável usando uma expressão de runtime com a sintaxe $[ ], não será possível usar essa variável em uma condição personalizada nesse trabalho.

Condições personalizadas

Se as condições internas não atenderem às suas necessidades, é possível especificar condições personalizadas. Grave condições como expressões em definições do pipeline YAML.

O agente avalia a expressão começando com a função mais interna e prosseguindo para o exterior. O resultado final é um valor booleano que determina se a tarefa, o trabalho ou o estágio deve ou não ser executado. Para ter acesso a um guia completo sobre sintaxe, consulte Expressões.

Se qualquer uma de suas condições possibilitar que a tarefa seja executada mesmo após o cancelamento da compilação, especifique um valor razoável de tempo-limite de cancelamento para que essas tarefas tenham tempo suficiente para serem concluídas depois que o usuário cancelar uma execução.

Resultados da condição quando uma compilação é cancelada

Cancelar uma compilação não significa que todos os estágios, trabalhos ou etapas vão parar de ser executados. Os estágios, trabalhos ou etapas que não serão mais executados dependerão das condições especificadas e em que ponto da execução do pipeline você cancelou a compilação. Se o pai de um estágio, trabalho ou etapa for ignorado, a tarefa não será executada, independentemente das condições.

Um estágio, trabalho ou etapa é executado sempre que as condições são avaliadas quanto ao true. Se sua condição não levar em conta o estado do pai da tarefa, a tarefa poderá ser executada mesmo que o pai seja cancelado. Para controlar se estágios, trabalhos ou etapas com condições serão executados quando uma compilação for cancelada, certifique-se de incluir uma função de verificação de status do trabalho em suas condições.

Os exemplos a seguir mostram os resultados de várias condições definidas em estágios, trabalhos ou etapas quando a compilação é cancelada.

Exemplo de estágio 1

No pipeline a seguir, por padrão, stage2 dependeria de stage1, mas stage2 tem um conjunto condition para ser executado sempre que a ramificação de origem for main, independentemente do status stage1.

Se você enfileirar uma compilação na ramificação main e cancelá-la enquanto stage1 estiver em execução, stage2 ainda será executado, pois eq(variables['Build.SourceBranch'], 'refs/heads/main') fará uma avaliação quanto a 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

Exemplo de estágio 2

No pipeline a seguir, stage2 depende de stage1 por padrão. O trabalho B em stage2 tem um conjunto condition. Se você enfileirar uma compilação na ramificação main e cancelá-la enquanto stage1 estiver em execução, stage2 não será executado, mesmo que ele contenha um trabalho cuja condição seja avaliada quanto a true.

O motivo é que stage2 tem o padrão condition: succeeded(), que é avaliado como false quando stage1 é cancelado. Portanto, stage2 é ignorado e nenhum de seus trabalhos é executado.

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

Exemplo de estágio 3

No pipeline a seguir, por padrão, stage2 depende de stage1, e a etapa dentro do trabalho B tem um conjunto condition.

Se você enfileirar uma compilação na ramificação main e cancelá-la enquanto stage1 estiver em execução, stage2 não será executado, mesmo que contenha uma etapa no trabalho B cuja condição seja avaliada quanto a true. O motivo é que stage2 é ignorado em resposta ao cancelamento de 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')

Exemplo de trabalho 1

No pipeline YAML a seguir, o trabalho B depende do trabalho A por padrão, mas o trabalho B tem um conjunto condition que será executado sempre que a ramificação de origem for main. Se você enfileirar uma compilação na ramificação main e cancelá-la enquanto o trabalho A estiver em execução, o trabalho B ainda será executado, pois eq(variables['Build.SourceBranch'], 'refs/heads/main') será avaliado quanto a true.

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

Se você quiser que o trabalho B seja executado somente quando o trabalho A tiver êxito e a origem da compilação for a ramificação main, condition deverá ser and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')).

Exemplo de trabalho 2

No pipeline a seguir, o trabalho B depende do trabalho A por padrão. Se você enfileirar uma compilação na ramificação main e cancelá-la enquanto o trabalho A estiver em execução, o trabalho B não será executado, mesmo que sua etapa tenha um condition que seja avaliado como true.

O motivo é que o trabalho B tem o padrão condition: succeeded(), que é avaliado como false quando o trabalho A é cancelado. Portanto, o trabalho B é ignorado e nenhuma de suas etapas é executada.

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

Exemplo de etapa

Você também pode ter condições nas etapas.

No pipeline a seguir, a etapa 2.3 tem um conjunto condition que será executado sempre que a ramificação de origem for main. Se você enfileirar uma compilação na ramificação main e cancelá-la enquanto as etapas 2.1 ou 2.2 estiverem em execução, a etapa 2.3 ainda será executada, porque eq(variables['Build.SourceBranch'], 'refs/heads/main') é avaliado quanto a 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')

Configurações da condição

A tabela a seguir mostra configurações de exemplo de condition para produzir vários resultados.

Observação

Release.Artifacts.{artifact-alias}.SourceBranch é equivalente a Build.SourceBranch.

Resultado desejado Exemplo de configuração de condição
Execute se a ramificação de origem for principal, mesmo que o estágio, trabalho ou etapa pai ou anterior tenha falhado ou tenha sido cancelado. eq(variables['Build.SourceBranch'], 'refs/heads/main')
Execute se a ramificação de origem for principal e o estágio, trabalho ou etapa pai ou anterior tiver sido bem-sucedido. and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
Execute se a ramificação de origem não for principal, e o estágio, trabalho ou etapa pai ou anterior tiver sido bem-sucedido. and(succeeded(), ne(variables['Build.SourceBranch'], 'refs/heads/main'))
Execute para ramificações de tópico do usuário, se o estágio, trabalho ou etapa pai ou anterior tiver sido bem-sucedido. and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/heads/users/'))
Execute para compilações de CI (integração contínua), se o estágio, trabalho ou etapa pai ou anterior tiver sido bem-sucedido. and(succeeded(), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI'))
Execute se a compilação tiver sido disparada por uma política de ramificação para uma solicitação de pull, e o estágio, trabalho ou etapa pai ou anterior tiver falhado. and(failed(), eq(variables['Build.Reason'], 'PullRequest'))
Execute para uma compilação agendada, mesmo que o estágio, trabalho ou etapa pai ou anterior tenha falhado ou tenha sido cancelado. eq(variables['Build.Reason'], 'Schedule')
Execute se uma variável estiver configurada como true, mesmo que o estágio, trabalho ou etapa pai ou anterior tenha falhado ou tenha sido cancelado. eq(variables['System.debug'], true)

Observação

Você pode definir uma condição para ser executada se uma variável for nula (cadeia de caracteres vazia). Como todas as variáveis são tratadas como cadeias de caracteres no Azure Pipelines, uma cadeia de caracteres vazia é equivalente a null no pipeline a seguir:

variables:
- name: testEmpty
  value: ''

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

Parâmetros em condições

A expansão de parâmetros ocorre antes que as condições sejam consideradas. Portanto, ao declarar um parâmetro no mesmo pipeline como uma condição, você pode incorporar o parâmetro na condição. O script no YAML a seguir é executado porque parameters.doThing é true.

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

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

O condition no pipeline anterior combina duas funções: succeeded() e ${{ eq(parameters.doThing, true) }}. A função succeeded() verifica se a etapa anterior foi bem-sucedida. A função succeeded() retorna true porque não havia nenhuma etapa anterior.

A função ${{ eq(parameters.doThing, true) }} verifica se o parâmetro doThing é igual a true. Como o valor padrão de doThing é true, a condição retorna true por padrão, a menos que o pipeline defina um valor diferente.

Parâmetros de modelo em condições

Ao passar um parâmetro para um modelo, você precisa definir o valor do parâmetro em seu modelo ou usar templateContext para passar o parâmetro para o modelo.

Por exemplo, o seguinte arquivo parameters.yml declara o parâmetro doThing e o valor padrão:

# 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) }}

O código do pipeline faz referência ao modelo parameters.yml. A saída do pipeline é I did a thing porque o parâmetro doThing é true.

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

trigger:
- none

extends:
  template: parameters.yml

Para mais exemplos de parâmetro de modelo, confira Referência de uso do modelo.

Variáveis de saída de trabalho usadas em condições de trabalho subsequentes

Você pode disponibilizar uma variável para trabalhos futuros e especificá-la em uma condição. As variáveis disponíveis para trabalhos futuros devem ser marcadas como variáveis de saída de vários trabalhos usando isOutput=true, como no código a seguir:

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."

Variáveis criadas em uma etapa usada em condições de etapa subsequentes

Você pode criar uma variável disponível para etapas futuras para especificá-la em uma condição. As variáveis criadas com base nas etapas estão disponíveis para etapas futuras por padrão e não precisam ser marcadas como variáveis de saída de vários trabalhos.

Há algumas coisas importantes a serem observadas sobre variáveis de escopo criadas com base em etapas.

  • As variáveis criadas em uma etapa em um trabalho terão como escopo as etapas no mesmo trabalho.
  • As variáveis criadas em uma etapa serão disponibilizadas nas etapas subsequentes apenas como variáveis de ambiente.
  • As variáveis criadas em uma etapa não podem ser usadas na etapa que as define.

O exemplo a seguir mostra a criação de uma variável de pipeline em uma etapa e o uso da variável na condição e no script de uma etapa subsequente.

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'))

Perguntas frequentes

Como posso disparar um trabalho se um trabalho anterior concluir com problemas?

Você pode usar o resultado do trabalho anterior em uma condição. Por exemplo, no YAML a seguir, a condição eq(dependencies.A.result,'SucceededWithIssues') permite que o trabalho B seja executado porque o trabalho A teve êxito com problemas.

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

Cancelei minha compilação, mas ela ainda está em execução. Por quê?

Você pode ter esse problema se uma condição configurada em um estágio não incluir uma função de verificação de status do trabalho. Para resolver o problema, adicione uma função de verificação de status do trabalho à condição.

Se você cancelar um trabalho enquanto ele estiver no estágio da fila, mas não estiver em execução, todo o trabalho será cancelado, incluindo todos os outros estágios. Para obter mais informações, consulte Resultados da condição quando uma compilação é cancelada acima neste artigo.