Document

SUBSCRIBE TO GET FULL ACCESS TO THE E-BOOKS FOR FREE 🎁SUBSCRIBE NOW

Professional Dropdown with Icon

SUBSCRIBE NOW TO GET FREE ACCESS TO EBOOKS

Les pipelines Azure DevOps se décrivent aujourd’hui en YAML, dans un fichier azure-pipelines.yml versionné avec le code. L’éditeur graphique « classique » existe encore, mais toutes les nouveautés (modèles, environnements, vérifications) ne sont disponibles qu’en YAML. Ce tutoriel construit un pipeline complet pour une application Node.js : construction, tests avec publication des résultats, création d’un artefact, puis déploiement vers deux environnements dont un protégé par une approbation manuelle. Chaque bloc est expliqué, et la dernière partie montre comment factoriser le pipeline avec des modèles.

Prérequis : une organisation et un projet Azure DevOps (voir l’introduction à Azure DevOps), un dépôt Git contenant une application Node.js avec npm test, et le parallélisme gratuit accordé (ou un agent auto-hébergé).

Structure d’un pipeline YAML

NiveauRôleExécution
trigger / pr / schedulesQuand le pipeline démarre
variablesValeurs réutilisées ; peuvent venir d’un groupe de variables
stagesGrandes phases (Build, Test, Déploiement)Séquentielles par défaut
jobsUnité de travail exécutée sur un agentParallèles au sein d’une étape
stepsTâches (task), scripts (script, bash, pwsh) et mots-clés (checkout, publish, download)Séquentiels

Le pipeline complet

# azure-pipelines.yml
name: $(Date:yyyyMMdd)$(Rev:.r)          # numéro de build lisible : 20260910.3

trigger:
  branches:
    include: [main, release/*]
  paths:
    exclude: [docs/*, README.md]         # pas de build pour la documentation seule

pr:
  branches:
    include: [main]                      # validation des pull requests

schedules:
  - cron: "0 3 * * 1"                    # tous les lundis 03:00 UTC
    displayName: Build hebdomadaire
    branches:
      include: [main]
    always: false                        # seulement s'il y a des changements

variables:
  - group: app-commun                    # groupe de variables (Library) : registre, URLs…
  - name: nodeVersion
    value: '22.x'
  - name: artifactName
    value: webapp

pool:
  vmImage: ubuntu-latest                 # agent hébergé par Microsoft

stages:
  # ---------------------------------------------------------------- BUILD
  - stage: Build
    displayName: Construction et tests
    jobs:
      - job: BuildTest
        displayName: npm ci, lint, test
        steps:
          - checkout: self
            fetchDepth: 1                # clone superficiel : plus rapide

          - task: NodeTool@0
            displayName: Installer Node.js $(nodeVersion)
            inputs:
              versionSpec: $(nodeVersion)

          - task: Cache@2
            displayName: Cache npm
            inputs:
              key: 'npm | "$(Agent.OS)" | package-lock.json'
              path: $(Pipeline.Workspace)/.npm

          - script: |
              npm ci --cache $(Pipeline.Workspace)/.npm --prefer-offline
              npm run lint
            displayName: Installer et analyser

          - script: npm test -- --ci --reporters=default --reporters=jest-junit
            displayName: Tests unitaires
            env:
              JEST_JUNIT_OUTPUT_DIR: $(Common.TestResultsDirectory)

          - task: PublishTestResults@2
            displayName: Publier les résultats de tests
            condition: succeededOrFailed()          # même si les tests échouent
            inputs:
              testResultsFormat: JUnit
              testResultsFiles: '$(Common.TestResultsDirectory)/*.xml'

          - script: npm run build
            displayName: Construire l'application

          - task: ArchiveFiles@2
            displayName: Archiver dist/
            inputs:
              rootFolderOrFile: dist
              includeRootFolder: false
              archiveFile: $(Build.ArtifactStagingDirectory)/$(artifactName).zip

          - publish: $(Build.ArtifactStagingDirectory)/$(artifactName).zip
            artifact: $(artifactName)
            displayName: Publier l'artefact

  # ---------------------------------------------------------------- DEV
  - stage: Dev
    displayName: Déploiement dev
    dependsOn: Build
    condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
    jobs:
      - template: templates/deploy.yml
        parameters:
          environmentName: dev
          webAppName: $(webAppBaseName)-dev       # vient du groupe de variables

  # ---------------------------------------------------------------- PROD
  - stage: Prod
    displayName: Déploiement production
    dependsOn: Dev
    condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
    jobs:
      - template: templates/deploy.yml
        parameters:
          environmentName: production           # approbation configurée sur l'environnement
          webAppName: $(webAppBaseName)-prod

Le modèle de déploiement réutilisable

Un modèle (template) est un fichier YAML paramétré inclus par les étapes. Dev et Prod exécutent exactement les mêmes pas ; seule la cible change, ce qui élimine les divergences entre environnements.

# templates/deploy.yml
parameters:
  - name: environmentName
    type: string
    values: [dev, staging, production]
  - name: webAppName
    type: string

jobs:
  - deployment: Deploy
    displayName: Déployer vers ${{ parameters.environmentName }}
    environment: ${{ parameters.environmentName }}     # déclenche approbations et vérifications
    strategy:
      runOnce:
        deploy:
          steps:
            - download: current
              artifact: webapp

            - task: AzureWebApp@1
              displayName: Déployer sur App Service
              inputs:
                azureSubscription: sc-azure-labo        # connexion de service (fédération d'identité)
                appType: webAppLinux
                appName: ${{ parameters.webAppName }}
                package: $(Pipeline.Workspace)/webapp/webapp.zip
                runtimeStack: NODE|22-lts

            - bash: |
                for i in $(seq 1 12); do
                  code=$(curl -s -o /dev/null -w '%{http_code}' "https://${{ parameters.webAppName }}.azurewebsites.net/healthz")
                  [ "$code" = "200" ] && echo "OK" && exit 0
                  echo "tentative $i : HTTP $code" ; sleep 10
                done
                echo "Le service ne répond pas" ; exit 1
              displayName: Test de fumée

Configurer l’approbation sur l’environnement production

  1. Menu Pipelines → Environments ; l’environnement production a été créé automatiquement au premier passage (ou créez-le manuellement).
  2. Ouvrez-le, cliquez sur ⋮ → Approvals and checks → Approvals, ajoutez le groupe des responsables de mise en production, cochez Requester should not approve.
  3. Ajoutez éventuellement Branch control (seule refs/heads/main peut déployer) et Business hours.

À la prochaine exécution, l’étape Prod s’arrête avec le statut En attente d’approbation ; les approbateurs reçoivent un courriel et valident depuis le résumé de l’exécution. Le fonctionnement détaillé (portes automatiques, permutation d’emplacements) est dans notre tutoriel sur les approbations et portes.

Variables, secrets et expressions

steps:
  # Variables prédéfinies utiles
  - script: |
      echo "Dépôt      : $(Build.Repository.Name)"
      echo "Branche    : $(Build.SourceBranchName)"
      echo "Commit     : $(Build.SourceVersion)"
      echo "Raison     : $(Build.Reason)"        # IndividualCI, PullRequest, Schedule, Manual
      echo "Agent      : $(Agent.Name) / $(Agent.OS)"
    displayName: Variables prédéfinies

  # Secret : jamais interpolé directement dans le script, passé par env
  - script: ./deploy.sh
    env:
      API_TOKEN: $(apiToken)                     # variable secrète du groupe de variables

  # Définir une variable pour les pas suivants
  - bash: echo "##vso[task.setvariable variable=version;isOutput=true]1.4.$(Build.BuildId)"
    name: ver
  - script: echo "Version calculée : $(ver.version)"

Trois syntaxes coexistent : ${{ }} est évalué à la compilation du pipeline (paramètres, conditions de modèles), $[ ] à l’exécution (dépendances entre jobs), et $( ) est la substitution classique de variables dans les pas. Les secrets ne sont jamais affichés dans les journaux et ne sont pas transmis automatiquement aux scripts : il faut les mapper avec env:.

Exécuter le pipeline

  1. Pipelines → New pipeline → Azure Repos Git (ou GitHub) → votre dépôt → Existing Azure Pipelines YAML file/azure-pipelines.yml.
  2. Cliquez Run. Au premier passage, autorisez l’accès au groupe de variables et à la connexion de service (Permit).
  3. Suivez les étapes en direct ; l’onglet Tests affiche les résultats JUnit, l’onglet Artifacts le fichier webapp.zip.
# Depuis la ligne de commande avec l'extension Azure DevOps de l'Azure CLI
az extension add --name azure-devops
az devops configure --defaults organization=https://dev.azure.com/<votre-organisation> project=devops-lab
az pipelines run --name "webapp" --branch main
az pipelines runs list --top 5 -o table

Erreurs fréquentes

  • « No hosted parallelism has been purchased or granted » – demandez le parallélisme gratuit via le formulaire Microsoft ou utilisez un agent auto-hébergé.
  • « Variable group was not found or is not authorized » – ouvrez le groupe dans Library et autorisez le pipeline (Pipeline permissions).
  • Erreur d’indentation YAML – utilisez l’éditeur intégré d’Azure DevOps ou l’extension VS Code « Azure Pipelines » qui valide le schéma ; les tabulations sont interdites.
  • L’étape Prod est ignorée – la condition sur Build.SourceBranch n’est vraie que pour main ; les exécutions de pull request ont une branche refs/pull/….
  • L’approbation n’apparaît pas – le job est un job ordinaire et non un deployment, ou l’environnement n’a pas de vérification configurée.

À retenir

  • Un pipeline YAML = déclencheurs + variables + étapes → jobs → pas ; il vit dans Git avec le code.
  • Publiez toujours les résultats de tests et un artefact ; déployez cet artefact, jamais un nouveau build.
  • Les jobs deployment liés à un environnement apportent approbations, vérifications et historique.
  • Factorisez avec des modèles ; passez les secrets par env: ; préférez la fédération d’identité aux clés.

Pour continuer : agents auto-hébergés sur Linux et infrastructure avec ARM et Bicep. Documentation officielle : Schéma YAML Azure Pipelines.

Retour parcours Azure DevOps — hub de la série et leçons sœurs.

Share your love

Leave a Reply

Your email address will not be published. Required fields are marked *