---
name: azure-pipelines
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.
version: 1.0.0
license: CC-BY-4.0
updated: 2026-08-16
---

# 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

```yaml
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:

```yaml
  - 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:

```yaml
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:

```yaml
  - 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.
