Condiciones de canalización

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

En este artículo se describen las condiciones en las que se ejecuta una fase, un trabajo o un paso de Azure Pipelines y cómo especificar condiciones diferentes. Para obtener más contexto sobre las fases, los trabajos y los pasos, consulte Conceptos clave de Azure Pipelines.

  • De manera predeterminada, se ejecuta un trabajo o una fase si no depende de ningún otro trabajo o fase, o si todas sus dependencias han finalizado correctamente. Este requisito se aplica no solo a las dependencias directas, sino a sus dependencias indirectas, calculadas de forma recursiva.

  • De manera predeterminada, se ejecuta un paso si aún no se ha producido ningún error en su trabajo y el paso inmediatamente anterior a él ha finalizado.

Puede invalidar o personalizar este comportamiento forzando una fase, un trabajo o un paso para ejecutarse aunque se produzca un error en una dependencia anterior o especificando una condición personalizada.

Nota:

En este artículo se describen las funcionalidades de canalización YAML. Para las canalizaciones clásicas, puede especificar las condiciones en las que se va a ejecutar la tarea o el trabajo en las Opciones de control de cada tarea y, en las Opciones adicionales de un trabajo de una canalización de versión.

Condiciones en las que se ejecuta una fase, un trabajo o un paso

En la definición de canalización YAML, puede especificar las siguientes condiciones en las que se ejecuta una fase, un trabajo o un paso:

  • Solo cuando todas las dependencias directas e indirectas anteriores que tienen el mismo grupo de agentes se hayan realizado correctamente. Si tiene grupos de agentes diferentes, esas fases o trabajos se ejecutarán simultáneamente. Esta es la condición predeterminada si no hay ninguna condición establecida en YAML.

  • Incluso si se ha producido un error en una dependencia anterior, a menos que se haya cancelado la ejecución. Use succeededOrFailed() en YAML para esta condición.

  • Incluso si se ha producido un error en una dependencia anterior, incluso si se ha cancelado la ejecución. Use always() en YAML para esta condición.

  • Solo cuando se ha producido un error en una dependencia anterior. Use failed() en YAML para esta condición.

  • Condiciones personalizadas.

De manera predeterminada, las fases, los trabajos y los pasos se ejecutan si todas las dependencias directas e indirectas se han completado correctamente. Este estado equivale a especificar condition: succeeded(). Para obtener más información, consulte Función de estado correcto.

Al especificar una propiedad condition para una fase, trabajo o paso, debe sobrescribir el valor predeterminado condition: succeeded(). Especificar sus propias condiciones puede hacer que la fase, el trabajo o el paso se ejecuten incluso si se cancela la compilación. No olvide tener en cuenta el estado de la fase o trabajo primario al escribir sus propias condiciones.

En el siguiente ejemplo de YAML se muestran las condiciones always() y failed(). El paso del primer trabajo se ejecuta aunque se produzca un error en las dependencias o se cancele la compilación. El segundo trabajo solo se ejecuta si se produce un error en el primer trabajo.

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

También puede establecer y usar variables en las condiciones. En el ejemplo siguiente se establece y se usa una variable 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

Las condiciones se evalúan para determinar si se debe iniciar una fase, un trabajo o un paso. Por lo tanto, nada calculado en tiempo de ejecución dentro de esa unidad de trabajo estará disponible. Por ejemplo, si tiene un trabajo que establece una variable con una expresión en tiempo de ejecución mediante la sintaxis $[ ], no podrá usar esa variable en una condición personalizada de ese trabajo.

Condiciones personalizadas

Si las condiciones integradas no satisfacen sus necesidades, puede especificar condiciones personalizadas. Las condiciones se escriben como expresiones en las definiciones de canalización YAML.

El agente evalúa la expresión comenzando con la función más interna y continuando hacia fuera. El resultado final es un valor booleano que determina si se debe ejecutar o no la tarea, el trabajo o la fase. Para obtener una guía completa sobre la sintaxis, consulte Expresiones.

Si alguna de las condiciones permite que la tarea se ejecute incluso después de cancelar la compilación, especifique un valor razonable para el tiempo de espera de cancelación para que estas tareas tengan tiempo suficiente para completarse después de que el usuario cancele una ejecución.

Resultados de condición cuando se cancela una compilación

Cuando se cancela una compilación, no significa que todas sus fases, trabajos o pasos dejen de ejecutarse. Las fases, trabajos o pasos que dejan de ejecutarse dependen de las condiciones que haya especificado y del momento de la ejecución de la canalización en que canceló la compilación. Si se omite un elemento principal de la fase, el trabajo o el paso, la tarea no se ejecuta, independientemente de sus condiciones.

Una fase, trabajo o paso se ejecuta cada vez que sus condiciones se evalúan como true. Si la condición no tiene en cuenta el estado del elemento principal de la tarea, esta podría ejecutarse incluso si se cancela su elemento principal. Para controlar si se ejecutan fases, trabajos o pasos con condiciones cuando se cancela una compilación, asegúrese de incluir una función de comprobación de estado del trabajo en las condiciones.

En los ejemplos siguientes se muestran los resultados de varias condiciones establecidas en fases, trabajos o pasos cuando se cancela la compilación.

Ejemplo de fase 1

En la canalización siguiente, de forma predeterminada stage2 dependería de stage1, pero stage2 tiene establecida una condition que se ejecutará siempre que la rama de origen sea main, independientemente del estado de stage1.

Si pone en cola una compilación en la rama main y la cancela mientras se ejecuta stage1, stage2 seguirá ejecutándose, ya que eq(variables['Build.SourceBranch'], 'refs/heads/main') se evalúa como 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

Ejemplo de fase 2

En la canalización siguiente, stage2 depende de stage1 de forma predeterminada. El trabajo B de stage2 tiene establecida una condition. Si pone en cola una compilación en la rama main y la cancela mientras se ejecuta stage1, stage2 no se ejecutará, aunque contenga un trabajo cuya condición se evalúe como true.

El motivo es que stage2 tiene el valor predeterminado condition: succeeded(), que se evalúa como false cuando se cancela stage1. Por lo tanto, se omite stage2 y no se ejecuta ninguna de sus trabajos.

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

Ejemplo de fase 3

En la canalización siguiente, de forma predeterminada stage2 depende de stage1, y el paso dentro del trabajo B tiene establecida una condition.

Si pone en cola una compilación en la rama main y la cancela mientras se ejecuta stage1, stage2 no se ejecutará, aunque contenga un paso en el trabajo B cuya condición se evalúe como true. El motivo es que se omite stage2 en respuesta a la cancelación 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')

Ejemplo de trabajo 1

En la siguiente canalización YAML, el trabajo B depende del trabajo A de forma predeterminada, pero el trabajo B tiene establecida una condition para ejecutarse siempre que la rama de origen sea main. Si pone en cola una compilación en la rama main y la cancela mientras se ejecuta el trabajo A, el trabajo B seguirá ejecutándose, ya que eq(variables['Build.SourceBranch'], 'refs/heads/main') se evalúa como 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

Si quiere que el trabajo B solo se ejecute cuando el trabajo A se realice correctamente y el origen de compilación sea la rama main, su condition debería ser and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')).

Ejemplo de trabajo 2

En la canalización siguiente, el trabajo B depende del trabajo A de forma predeterminada. Si pone en cola una compilación en la rama main y la cancela mientras el trabajo A se está ejecutando, B el trabajo no se ejecutará, aunque su paso tenga una condition que se evalúe como true.

El motivo es que el trabajo B tiene el valor predeterminado condition: succeeded(), que se evalúa como false cuando se cancela el trabajo A. Por lo tanto, se omite el trabajo B y no se ejecuta ninguno de sus pasos.

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

Ejemplo de paso

También puede tener condiciones en los pasos.

En la canalización siguiente, el paso 2.3 tiene establecida una condition para ejecutarse cada vez que la rama de origen sea main. Si pone en cola una compilación en la rama main y la cancela mientras se ejecutan los pasos 2.1 o 2.2, el paso 2.3 se sigue ejecutando, ya que eq(variables['Build.SourceBranch'], 'refs/heads/main') se evalúa como 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')

Configuración de la condición

En la tabla siguiente se muestra la configuración de ejemplo de condition para generar varios resultados.

Nota:

Release.Artifacts.{artifact-alias}.SourceBranch equivale a Build.SourceBranch.

Resultado deseado Configuración de condición de ejemplo
Ejecutar si la rama de origen es principal, incluso si la fase, el trabajo o el paso principal o anterior no se pudieron realizar o se cancelaron. eq(variables['Build.SourceBranch'], 'refs/heads/main')
Ejecutar si la rama de origen es principal y la fase, el trabajo o el paso principal o anterior se realizaron correctamente. and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
Ejecutar si la rama de origen no es principal y la fase, el trabajo o el paso principal o anterior se realizaron correctamente. and(succeeded(), ne(variables['Build.SourceBranch'], 'refs/heads/main'))
Ejecutar para ramas de temas de usuario, si la fase, el trabajo o el paso principal o anterior se realizaron correctamente. and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/heads/users/'))
Ejecutar para compilaciones de integración continua (CI), si la fase, el trabajo o el paso principal o anterior se realizaron correctamente. and(succeeded(), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI'))
Ejecutar si una directiva de rama desencadenó la compilación para una solicitud de incorporación de cambios y se produjo un error en la fase, el trabajo o el paso principal o anterior. and(failed(), eq(variables['Build.Reason'], 'PullRequest'))
Ejecutar para una compilación programada, incluso si se produjo un error en la fase, el trabajo o el paso principal o anterior o se cancelaron. eq(variables['Build.Reason'], 'Schedule')
Ejecutar si una variable se establece en true, incluso si la fase, el trabajo o el paso principal o anterior no se realizaron correctamente o se cancelaron. eq(variables['System.debug'], true)

Nota:

Puede establecer una condición para que se ejecute si una variable es null (cadena vacía). Dado que todas las variables se tratan como cadenas en Azure Pipelines, una cadena vacía es equivalente a null en la siguiente canalización:

variables:
- name: testEmpty
  value: ''

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

Parámetros en condiciones

La expansión de parámetros se produce antes de que se consideren las condiciones. Por lo tanto, al declarar un parámetro en la misma canalización que una condición, puede insertar el parámetro dentro de la condición. El script del siguiente código YAML se ejecuta porque parameters.doThing es true.

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

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

La condition de la canalización anterior combina dos funciones: succeeded() y ${{ eq(parameters.doThing, true) }}. La función succeeded() comprueba si el paso anterior se realizó correctamente. La función succeeded() devuelve true porque no había ningún paso anterior.

La función ${{ eq(parameters.doThing, true) }} comprueba si el parámetro doThing es igual a true. Dado que el valor predeterminado para doThing es true, la condición devuelve true de forma predeterminada, a menos que la canalización establezca un valor diferente.

Parámetros de plantilla en condiciones

Al pasar un parámetro a una plantilla, debe establecer el valor del parámetro en la plantilla o usar templateContext para pasar el parámetro a la plantilla.

Por ejemplo, el siguiente archivo parameters.yml declara el parámetro doThing y el valor predeterminado:

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

El código de canalización hace referencia a la plantilla de parameters.yml. La salida de la canalización es I did a thing porque el parámetro doThing es true.

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

trigger:
- none

extends:
  template: parameters.yml

Para obtener más ejemplos de parámetros de plantilla, consulte Referencia de uso de plantillas.

Variables de salida de trabajo usadas en condiciones de trabajo posteriores

Puede hacer que una variable esté disponible para trabajos futuros y especificarla en una condición. Las variables disponibles para trabajos futuros deben marcarse como variables de salida de varios trabajos mediante isOutput=true, como en el código siguiente:

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

Variables creadas en un paso utilizadas en condiciones de paso posteriores

Puede crear una variable que esté disponible para pasos futuros para especificarla en una condición. Las variables creadas a partir de pasos están disponibles para pasos futuros de forma predeterminada y no es necesario marcarlas como variables de salida de varios trabajos.

Hay algunos aspectos importantes que se deben tener en cuenta sobre las variables de ámbito que se crean a partir de los pasos.

  • Las variables creadas en un paso de un trabajo se limitarán a los pasos del mismo trabajo.
  • Las variables creadas en un paso solo estarán disponibles en pasos posteriores solo como variables de entorno.
  • Las variables creadas en un paso no se pueden usar en el paso que las define.

En el ejemplo siguiente se muestra cómo crear una variable de canalización en un paso y el uso de la variable en la condición y el script de un paso posterior.

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

Preguntas más frecuentes

¿Cómo puedo desencadenar un trabajo si un trabajo anterior se realizó correctamente con incidencias?

Puede usar el resultado del trabajo anterior en una condición. Por ejemplo, en el siguiente YAML, la condición eq(dependencies.A.result,'SucceededWithIssues') permite que se ejecute el trabajo B, ya que el trabajo A se realizó correctamente con 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

Cancelé mi compilación, pero todavía se está ejecutando. ¿Por qué?

Puede experimentar este problema si una condición configurada en una fase no incluye ninguna función de comprobación de estado del trabajo. Para resolver el problema, agregue una función de comprobación de estado del trabajo a la condición.

Si cancela un trabajo mientras está en la fase de cola, pero no en ejecución, se cancelará todo el trabajo, incluidas las demás fases. Para obtener más información, consulte Salidas de condición cuando se cancela una compilación anteriormente en este artículo.