Derivado de DevOps y de su uso para contenedores me he metido mucho al uso de archivos YAML, su significado viene de Yet Another Markup Language (Otro Lenguaje Mas de Marcado). Y ha sido muy promocionado con la idea de que es menor en el consumo de recursos que JSON y mucho más eficiente.
Para el caso de DevOps, sin importar mucho si quieres usar Github, Azure DevOps, Jenkins o cualquier otro producto seguro caerás en este formato de archivo en donde el único dolor de cabeza radica en la indentación que permite que al igual que otros lenguajes como Python todo fluya sin problemas. En cuanto a esto solo te puedo decir que con el tiempo te vas acostumbrando a ver estas fallas muy rápido.
Uno de los retos más importantes en la implementación de CI/CD es establecer condiciones para muchos casos diversos vamos a ver algunos de ellos y de esta manera, adquirir un poco de experiencia con la sintaxis. Comencemos con algunos buenos ejercicicios para ello. Comienza por crear un nuevo pipeline con algo como esto.
jobs: - job: Script_One displayName: 'First task' steps: - script: echo Mensaje siempre activado - job: Script_Two displayName: 'Second task' steps: - script: echo Segundo mensaje |
Ahora, lo más fácil. Hacer que la segunda tarea dependa de la primera. Y que la primera siempre se ejecute.
trigger: - master pool: vmImage: 'ubuntu-latest' jobs: - job: Script_One displayName: 'First task' steps: - script: echo Mensaje siempre activado condition: always() - job: Script_Two displayName: 'Second task' dependsOn: Script_One steps: - script: echo Segundo mensaje |
Sigamos con una que es bien común. Hacer que ciertos procesos del pipeline se ejecuten únicamente con cierta rama, en este caso master (o main si es un repo más actual).
variables: isMain: $[eq(variables['Build.SourceBranch'], 'refs/heads/master')] pool: vmImage: 'ubuntu-latest' jobs: - job: Script_One condition: and(succeeded(), eq(variables.isMain, true)) displayName: 'First task' steps: - script: echo Mensaje siempre activado - job: Script_Two condition: and(succeeded(), ne(variables.isMain, true)) displayName: 'Second task' steps: - script: echo Segundo mensaje |
Hay varios cambios aquí. Puedes ver que eliminé el trigger del inicio y puse una variable. Puedes incluir la variable si quieres o puedes poner dentro de la condición el dato, cuando lo aprendí lo hice como lo muestro y la verdad se me hace mucho más fácil así, escoge la forma que más te acomode y notarás que el resultado es el mismo. Podrás también ver que dependeremos ahora de la rama para ejecutar una tarea o la otra.

O si cambiamos de rama.

Esta función de condiciones es una herramienta muy útil pero no es algo de lo que debamos abusar, no por tener esta posibilidad es una buena idea meter todos los procesos en un solo mega archivo. Lo mejor es seguir trabjando con pipelines separadas por procesos o utilizar stages en lugar de jobs o mejor aún con templates de las que tengo un artículo pendiente.
Considera con estos ejemplos los operadores lógicos que estoy usando y a los que puedes recurrir sin problema. Puedes, por ejemplo desencadenar un job solo si la compilación o proceso de Integración continua fue exitoso.
and(succeeded(), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI')) |
Puedes probar con ciertos valores de variables. A continuación, en un siguiente paso, lo que hice fue crear una variable y asignarle un nombre. Esta variable en una tercera tarea es comparada y si cierto valor es el adecuado entonces puede continuar o de lo contrario, detener la tarea. Solo para verificar cual es el valor recibido, pasé en el script el valor de esta variable.
variables: - name: isMain value: $[eq(variables['Build.SourceBranch'], 'refs/heads/master')] - name: nombreBranch value: 'Amin' jobs: - job: Script_One condition: and(succeeded(), eq(variables.isMain, true)) displayName: 'First task' steps: - script: echo Mensaje siempre activado - job: Script_Two condition: and(succeeded(), ne('variables.isMain', true)) displayName: 'Second task' steps: - script: echo Segundo mensaje - job: Script_Three condition: and(succeeded(), eq('${{ variables.nombreBranch }}', 'Amin')) displayName: 'Third task' steps: - script: echo Tercer mensaje con la variable nombreBranch y su valor '${{ variables.nombreBranch }}' |
Así como en el caso anterior, también podrías trabajar con parámetros en el caso de que estés pensando en hacer una plantilla. Por último, podríamos también usar el valor de una variable recién modificada en una tarea anterior y en la subsecuente evaluar el nuevo valor, aquí, lo más importante es que asignes el parámetro isOutput=true.
- job: Script_Four displayName: 'Fourth task' steps: - bash: | echo 'Vamos a cambiar la variable de valor' echo "##vso[task.setvariable variable=nombreBranch;isOutput=true]Miranda" name: resultadoCuatro - job: Script_Five displayName: 'Fifth task' dependsOn: Script_Four condition: eq(dependencies.Script_Four.outputs['resultadoCuatro.nombreBranch'], 'Miranda') steps: - script: echo 'Si, el resultado de la tarea anterior resultó bien' |
Con todas estas posibilidades es que puedes jugar con los diferentes escenarios en donde estés creando un entorno enorme de entradas y salidas que puedan definir el curso final de tus pipelines. El script completo de este artículo luce así.
variables: - name: isMain value: $[eq(variables['Build.SourceBranch'], 'refs/heads/master')] - name: nombreBranch value: 'Amin' jobs: - job: Script_One condition: and(succeeded(), eq(variables.isMain, true)) displayName: 'First task' steps: - script: echo Mensaje siempre activado - job: Script_Two condition: and(succeeded(), ne('variables.isMain', true)) displayName: 'Second task' steps: - script: echo Segundo mensaje - job: Script_Three condition: and(succeeded(), eq('${{ variables.nombreBranch }}', 'Amin')) displayName: 'Third task' steps: - script: echo Tercer mensaje con la variable nombreBranch y su valor '${{ variables.nombreBranch }}' - job: Script_Four displayName: 'Fourth task' steps: - bash: | echo 'Vamos a cambiar la variable de valor' echo "##vso[task.setvariable variable=nombreBranch;isOutput=true]Miranda" name: resultadoCuatro - job: Script_Five displayName: 'Fifth task' dependsOn: Script_Four condition: eq(dependencies.Script_Four.outputs['resultadoCuatro.nombreBranch'], 'Miranda') steps: - script: echo 'Si, el resultado de la tarea anterior resultó bien' |