Skip to content
jesusprodriguez.com

azure-pipelines

Azure Pipelines: CI/CD en YAML

YAML pipelines that do not block the team: one artefact for every environment, versioned templates, secrets kept out of the repo.

stack:
Azure DevOps
version:
v1.0.0
updated:
size:
4.1 KB
read:
2 min
license:
CC-BY-4.0

When it fires

When creating or changing azure-pipelines.yml, or when a build fails only on the agent.

description: Escribe y depura pipelines YAML de Azure DevOps - etapas, plantillas reutilizables, caché, variable groups y despliegues con aprobación. Úsala al crear o modificar azure-pipelines.yml, al montar CI para un repo nuevo o cuando una build falle solo en el agente.

  • Stages and environments
  • Templates and caching
  • Secrets and approvals
  • Debugging the agent

How you ask for it

> Review azure-pipelines.yml: the build passes locally and fails only on the agent.

Say this to the agent as it is: the skill loads itself from its description, you do not have to name it.

How to install one

/plugin marketplace add https://jesusprodriguez.com/skills/marketplace.json
/plugin install azure-devops@jprodriguez-toolkit

The native route, and the only one that updates itself: add the marketplace once and `/plugin marketplace update` brings in new versions. Skills get their own namespace (`azure-devops:azure-pr-review`).

The whole file

This is exactly what you download: no summaries, nothing trimmed.

Heads-up: the skill file itself is written in Spanish. Agents read it fine and answer in your language, but the prose below is not translated.

Azure Pipelines: CI/CD en YAML

Un pipeline es código de producción: se lee más veces de las que se escribe y cuando falla bloquea a todo el equipo.

Esqueleto

trigger:
  branches: { include: [main, release/*] }
  paths:    { exclude: [docs/*, README.md] }

pr:
  branches: { include: [main] }

variables:
  - group: comun-produccion          # variable group de Library
  - name: buildConfiguration
    value: Release

stages:
  - stage: Build
    jobs:
      - job: Compilar
        pool: { vmImage: ubuntu-latest }
        steps:
          - task: UseDotNet@2
            inputs: { version: '8.0.x' }
          - script: dotnet restore
          - script: dotnet build -c $(buildConfiguration) --no-restore
          - script: dotnet test -c $(buildConfiguration) --no-build --collect:"XPlat Code Coverage"
          - task: PublishTestResults@2
            condition: succeededOrFailed()      # los tests rojos también se publican

condition: succeededOrFailed() en la publicación de resultados: si solo publicas cuando todo va bien, el día que falla no tienes el informe que explica por qué.

Reglas que evitan la mayoría de los sustos

Fija las versiones. vmImage: ubuntu-latest cambia bajo tus pies; los SDK también. Fija la versión del SDK explícitamente y anota por qué si te quedas atrás.

Un artefacto, varios entornos. Se compila una vez y ese mismo artefacto se despliega a dev, pre y producción. Recompilar por entorno significa que lo que validaste no es lo que desplegaste.

Secretos, nunca en el YAML. Variable groups enlazados a Key Vault, o variables marcadas como secretas. Un secreto no se expone como variable de entorno a un script que no lo necesita, y no se imprime nunca (Azure enmascara ***, pero solo si lo reconoce literalmente: en base64 o troceado no lo enmascara).

Entornos con aprobación. Producción es un environment con approvals and checks, no un stage más:

  - stage: Produccion
    dependsOn: Preproduccion
    condition: succeeded()
    jobs:
      - deployment: Desplegar
        environment: produccion       # aquí cuelgan las aprobaciones
        strategy:
          runOnce:
            deploy:
              steps: [ ... ]

Plantillas contra el copiar-pegar. Cinco repos con el mismo YAML duplicado son cinco sitios donde arreglar el mismo fallo:

resources:
  repositories:
    - repository: plantillas
      type: git
      name: Plataforma/pipelines-comunes
      ref: refs/tags/v3            # etiqueta, no rama: una rama cambia sola

extends:
  template: dotnet-api.yml@plantillas
  parameters:
    proyecto: src/Api/Api.csproj

Caché de dependencias con clave que incluya el lockfile, o el caché servirá paquetes obsoletos:

  - task: Cache@2
    inputs:
      key: 'nuget | "$(Agent.OS)" | **/packages.lock.json'
      path: $(NUGET_PACKAGES)

Depurar una build que falla solo en el agente

Por probabilidad, de mayor a menor:

  1. Diferencia de entorno: versión de SDK, de Node, de imagen del agente.
  2. Rutas y mayúsculas: el agente Linux distingue mayúsculas; tu Windows no. Models/User.cs vs models/user.cs compila en local y falla ahí.
  3. Ficheros no versionados: funciona en local porque tienes un appsettings.Development.json que está en .gitignore.
  4. Orden y paralelismo: los tests pasan en tu máquina por el orden de ejecución y fallan al paralelizar. El bug es del test, no del agente.
  5. Restore parcial: fuentes de NuGet privadas sin autenticar en el agente.

Activa system.debug: true en las variables de la ejecución antes de empezar a adivinar. Y reproduce en un agente, no en tu portátil: cada iteración a ciegas cuesta una cola de build al equipo entero.