Version : 1.1 · Date : 2026-10-22 · Domaine 3 de l'examen : Design and implement build and release pipelines (50 à 55 %)
En une phrase : un pipeline sérieux produit un binaire versionné une seule fois, le teste à plusieurs niveaux, le publie dans un feed (Azure Artifacts) ou un registre (GitHub Packages), puis ne le promeut que si des gates de qualité, de sécurité et de gouvernance sont au vert.

Ce que l'examen demande#
Texte officiel du guide d'étude AZ-400 (compétences au 27/07/2026), blocs Design and implement a package management strategy et Design and implement a testing strategy for pipelines :
| # | Compétence mesurée (guide officiel, en anglais) | Section |
|---|---|---|
| 1 | Recommend package management tools including GitHub Packages and Azure Artifacts | 2 |
| 2 | Design and implement package feeds and views for local and upstream packages | 3 |
| 3 | Design and implement a dependency versioning strategy for code assets and packages, including semantic versioning (SemVer) and date-based (CalVer) | 4 |
| 4 | Design and implement a versioning strategy for pipeline artifacts | 5 |
| 5 | Design and implement quality and release gates, including security and governance | 6 |
| 6 | Design a comprehensive testing strategy, including local tests, unit tests, integration tests, and load tests | 7 |
| 7 | Implement tests in a pipeline, including configuring test tasks, configuring test agents, and integration of test results | 8 |
| 8 | Implement code coverage analysis | 9 |
Les pipelines eux-mêmes (YAML, triggers, agents, templates, environments) sont au chapitre 04, la rétention et les tests instables (flaky tests) au chapitre 06, l'analyse de sécurité du code et des dépendances au chapitre 07.
1. Les bases à maîtriser#
1.1 Le vocabulaire#
| Terme | Ce que c'est |
|---|---|
| Package | Une unité réutilisable et versionnée (NuGet, npm, Maven, Python, Cargo, Universal Package, image de conteneur) consommée par d'autres projets |
| Feed | Le conteneur de packages d'Azure Artifacts. Un feed peut héberger plusieurs types de packages |
| View | Un sous-ensemble filtré des versions d'un feed (@local, @prerelease, @release) qu'on partage avec un public donné |
| Upstream source | Une source que le feed interroge quand il ne contient pas le package (registre public, autre feed) |
| Pipeline artifact | Le résultat d'un run (binaires, scripts, fichiers IaC) passé d'un job ou d'un stage à l'autre, ou d'un pipeline à l'autre |
| Quality gate / release gate | Une condition automatique ou humaine qui autorise ou bloque la suite du pipeline |
1.2 Deux familles d'artifacts à ne pas confondre#
- Pipeline artifacts (
publish,PublishPipelineArtifact@1) : liés à un run, pour déployer ce que ce run a construit. Ils ne comptent pas dans le stockage facturé d'Azure Artifacts. - Packages dans un feed : réutilisables entre projets, avec une version immuable, des views et des upstreams. Tous les packages comptent dans le stockage, y compris ceux sauvegardés depuis un upstream et ceux de la corbeille (Recycle Bin).
2. Choisir GitHub Packages ou Azure Artifacts#

2.1 GitHub Packages#
- Registres : npm, RubyGems, Apache Maven, Gradle, NuGet, et le Container registry (
ghcr.io) pour les images Docker et OCI. - Visibilité : un package publié dans un dépôt public est public ; dans un dépôt privé, il est partagé avec les collaborateurs ou l'organisation.
- Permissions : héritées du dépôt, ou granulaires (par utilisateur ou organisation) selon le registre.
- Authentification : dans GitHub Actions, le
GITHUB_TOKENpublie les packages du dépôt du workflow (avecpermissions: packages: write). Hors Actions, GitHub Packages n'accepte qu'un personal access token (classic) (pas de fine-grained PAT), avec les scopesread:packages(installer),write:packages(publier) etdelete:packages(supprimer, avecread:packages). Visibilité d'un package : public ou private, réglée par un admin du package. - Facturation : les packages publics sont gratuits ; les privés ont un quota gratuit de stockage et de transfert selon le plan.
2.2 Azure Artifacts#
- Types : NuGet, npm, Maven, Gradle, Python, Cargo et Universal Packages (n'importe quels fichiers, jusqu'à 4 TiB).
- Upstream sources vers les registres publics et d'autres feeds, views pour la diffusion, retention policies.
- Facturation au stockage : 2 GiB gratuits par organisation. Au-delà, on ne peut plus publier tant qu'on n'a pas configuré la facturation (Organization settings > Billing > Usage limit > No limit, pay for what you use).
2.3 La règle de choix#
| Situation | Choix |
|---|---|
| Code et CI dans GitHub, packages consommés surtout par GitHub Actions | GitHub Packages |
| Images de conteneur produites dans GitHub | GitHub Container registry (ghcr.io), ou Azure Container Registry pour les déployer dans Azure |
| CI dans Azure DevOps, besoin de cacher les registres publics (résilience, contrôle) | Azure Artifacts avec upstream sources |
| Canaux de diffusion (préversion, validé) pour d'autres équipes | Azure Artifacts avec views |
| Fichiers arbitraires versionnés (outils, jeux de données, binaires) | Universal Packages (Azure Artifacts) |
Piège : GitHub Packages n'a pas d'équivalent des upstream sources ni des views d'Azure Artifacts. Une question qui parle de « proxy des registres publics » ou de « promouvoir un package validé » vise Azure Artifacts.
3. Feeds, upstream sources et views#

3.1 Créer un feed#
Artifacts > Create Feed : nom, Visibility (qui voit les packages), Scope (projet ou organisation) et la case Include packages from common public sources qui active les upstream sources publics. Microsoft recommande le scope projet.
| Scope | URL de la source | Accès |
|---|---|---|
| Project-scoped | contient le projet (…/{org}/{project}/_packaging/{feed}/…) |
il faut aussi l'accès au projet |
| Organization-scoped | sans le projet | toute l'organisation selon les rôles |
Les public feeds dépendent des public projects. À partir de 2027, les projets publics existants deviennent privés ; leurs feeds publics ne seront plus accessibles publiquement.
3.2 Les upstream sources#
Le feed cherche toujours dans le même ordre : (1) les packages publiés dans le feed, (2) ceux déjà sauvegardés depuis un
upstream, (3) chaque upstream, dans l'ordre configuré. C'est ce qui rend la restauration déterministe : NuGet, par exemple,
interroge en parallèle toutes les sources d'un nuget.config et prend la première réponse, d'où des résultats imprévisibles.
Bonnes pratiques Microsoft :
- un seul feed dans chaque fichier de configuration client (
nuget.config,.npmrc,pip.conf), avec ses upstreams ; - ordonner les upstreams volontairement, surtout si l'organisation republie en interne des packages open source modifiés ;
- pour un feed d'une autre organisation du même tenant Microsoft Entra : le locator
azure-feed://organisation/projet/feed@view, et le propriétaire doit partager la view avec All feeds and people in organizations associated with my Microsoft Entra tenant.
Points chiffrés et comportements :
- 20 upstreams au maximum par type de package et par feed ;
- quand un package vient d'un upstream, Azure Artifacts en garde une copie : les builds continuent si le registre public tombe ;
- le premier enregistrement depuis un upstream exige au moins Feed and Upstream Reader (Collaborator). Un simple Feed Reader ne peut consommer que ce qui est déjà sauvegardé ;
- les snapshots Maven ne sont pas pris en charge dans les upstreams.
3.3 Les views#
- Trois views par défaut :
@local(vue par défaut : tout ce qui est publié et tout ce qui est sauvegardé depuis un upstream),@prereleaseet@release, ces deux dernières pouvant être renommées ou supprimées. - On publie toujours dans le feed (donc dans
@local), jamais directement dans une autre view, même si on change la view par défaut. On promeut ensuite : Package > Promote ou l'API REST (PATCH JSON Patch). - Pas de rétrogradation : une version promue ne revient pas à
@local. - Les views sont en lecture seule et servent de canaux :
@prereleasepour les premiers utilisateurs,@releasepour tous. - Une view peut être partagée plus largement que le feed (Visibility de la view) : quelqu'un qui a accès à une view télécharge ses packages même sans droit sur le feed. Pour verrouiller, il faut restreindre le feed et ses views.
- Promouvoir exige Feed Publisher (Contributor) ou Feed Owner.
# Consommer seulement les versions validées : la source pointe sur la view @release
# https://pkgs.dev.azure.com/{organisation}/{projet}/_packaging/{feed}@release/nuget/v3/index.json
3.4 Rétention, suppression et immuabilité#
- Immuabilité : une version publiée est réservée pour toujours. Impossible de republier
1.2.3, même après suppression. - Retention policies (Feed settings > Feed details > Enable package retention) avec deux réglages : Maximum number of versions per package et Days to keep recently downloaded packages. Une version n'est supprimée que si les deux conditions sont réunies (nombre de versions atteint et pas de téléchargement dans le délai).
- Les versions promues dans une view sont exemptées de la rétention : promouvoir, c'est aussi protéger.
- Le nettoyage tourne une fois par jour. Les versions supprimées vont dans la Recycle Bin, gardées 30 jours (et toujours facturées) ; seul un Feed Owner peut restaurer ou supprimer définitivement.
- Selon l'écosystème : Deprecate (npm, avertissement), Unlist (NuGet, masqué des recherches), Yank (Cargo), Delete
(corbeille).
nuget.exe deletevers Azure Artifacts fait un unlist, pas une suppression.
Limites : 5 000 versions par package, 500 MiB par fichier (4 TiB pour les Universal Packages), 375 KB pour un
package.json.
3.5 Les rôles du feed et l'accès des pipelines#

- Project Collection Administrators et Azure Artifacts Administrators sont automatiquement Feed Owner de tous les feeds.
- Le Build Service du projet (
{Projet} Build Service ({Organisation})) et le Project Collection Build Service reçoivent par défaut Feed and Upstream Reader (Collaborator) : ils restaurent et sauvegardent depuis les upstreams, mais ne publient pas. Pour publier depuis un pipeline, passez le Build Service en Feed Publisher (Contributor). - Feed d'un autre projet : ajoutez le Build Service aux Readers du projet qui héberge le feed, et donnez-lui un rôle sur le feed.
- Un run déclenché depuis un fork externe n'a pas accès aux secrets : l'authentification au feed échoue après coup.
Authentification dans Azure Pipelines :
steps:
- task: NuGetAuthenticate@1 # configure nuget.exe, dotnet et MSBuild pour toute la durée du job
- script: dotnet restore
- script: dotnet pack -c Release -o $(Build.ArtifactStagingDirectory) /p:Version=$(packageVersion)
- script: dotnet nuget push $(Build.ArtifactStagingDirectory)/*.nupkg --source "MonFeed" --api-key AzureArtifacts
NuGetAuthenticate@1est la méthode recommandée : elle installe l'Azure Artifacts Credential Provider et vaut pour tout le job, y compris dans vos propres scripts. Pour un feed d'une autre organisation ou un dépôt tiers, déclarez une NuGet service connection dansnuGetServiceConnections.- Équivalents pour les autres écosystèmes :
npmAuthenticate@0,PipAuthenticate@1, ou le fluxUniversalPackages@0. - Hors pipeline : le Credential Provider en interactif, ou un service principal avec certificat par la variable
ARTIFACTS_CREDENTIALPROVIDER_FEED_ENDPOINTS.
Dans GitHub Actions (publication npm vers GitHub Packages) :
permissions:
contents: read
packages: write # sans cette ligne, le GITHUB_TOKEN ne peut pas publier
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
registry-url: https://npm.pkg.github.com
- run: npm ci && npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Un package privé n'est téléchargeable par les workflows d'autres dépôts que si ceux-ci ont reçu la lecture dans Package settings > Manage Actions access.
4. Versionner le code et les packages : SemVer et CalVer#

4.1 Semantic Versioning (SemVer)#
Format MAJOR.MINOR.PATCH :
| Partie | On l'incrémente quand… | Exemple |
|---|---|---|
| MAJOR | un changement casse la compatibilité (MINOR et PATCH repartent à 0) | 2.6.5 → 3.0.0 |
| MINOR | on ajoute une fonction compatible (PATCH repart à 0) | 1.4.17 → 1.5.0 |
| PATCH | on corrige un bug compatible | 1.0.0 → 1.0.1 |
- Préversion : suffixe
-alpha,-beta.1,-rc.2. Une préversion est inférieure à la version finale (2.0.0-rc.1 < 2.0.0). En SemVer 2.0,rc.10passe aprèsrc.2(comparaison numérique des segments séparés par des points). - Métadonnées de build : suffixe
+sha.abc123, ignoré pour l'ordre des versions. - NuGet ajoute un 4ᵉ segment (Revision) et compare les étiquettes de préversion sans tenir compte de la casse. Par défaut, il
n'installe pas les préversions (
-prerelease, Include prerelease). - Exemple dans l'écosystème Azure : les modules Azure Verified Modules imposent SemVer et démarrent en
0.1.0jusqu'à leur première version stable1.0.0.
4.2 Calendar Versioning (CalVer)#
La version vient de la date de livraison (par exemple 2026.10.3 ou 2026.10.21.2). Adapté aux applications et outils
livrés à un rythme régulier, où la date parle plus que la compatibilité. Microsoft Learn ne décrit pas CalVer en détail : la
convention de référence est calver.org (format libre, YYYY.MM.MICRO par exemple), comme
semver.org pour SemVer.
| SemVer | CalVer | |
|---|---|---|
| Dit si c'est compatible | Oui (MAJOR) | Non |
| Dit quand c'est sorti | Non | Oui |
| Usage type | Bibliothèques, packages, API consommées par d'autres | Applications, images, outils internes, systèmes d'exploitation |
Réponse d'examen : pour une bibliothèque partagée qui doit signaler les ruptures de compatibilité → SemVer. Pour un produit livré à date fixe dont les consommateurs ne dépendent pas d'une API → CalVer possible.
4.3 La stratégie de dépendances#
- Fixer la plage acceptée dans chaque projet consommateur, et verrouiller les versions résolues dans un fichier de verrouillage versionné dans Git pour des builds reproductibles.
- Ne jamais dépendre directement d'un registre public dans un pipeline d'entreprise : passer par le feed + upstream, qui garde une copie et devient le point de contrôle (voir aussi Dependabot au chapitre 07).
- Monter de version MAJOR = décision explicite (revue, tests), pas une mise à jour automatique.
5. Versionner les pipeline artifacts#
5.1 Le run number dans Azure Pipelines#
- Valeur par défaut :
$(Date:yyyyMMdd).$(Rev:r)(par exemple20261021.3).$(Rev:r)n'existe que dans le run number et repart à 1 dès qu'une autre partie du numéro change (la date, ou le préfixe de version). - Se règle avec
name:au niveau du pipeline YAML (pas dans un template ni un stage) ;$(Build.BuildNumber)le relit dans les scripts. Fuseau : UTC. 255 caractères maximum, sans",/,\,:,<,>,',|,?,@,*. $(Rev:rr)ajoute un zéro en tête, mais NuGet et d'autres outils le retirent : à éviter dans un numéro de version.
name: $(majeur).$(mineur).$(Rev:r) # 1.4.1, 1.4.2… repart à 1 si mineur change
variables:
majeur: 1
mineur: 4
# Alternative : un compteur explicite, indépendant du run number
patch: $[counter(format('{0}.{1}', variables.majeur, variables.mineur), 0)]
packageVersion: $(majeur).$(mineur).$(patch)
counter(prefix, seed): incrémente à chaque run, un compteur par valeur de préfixe ; si on revient à un ancien préfixe, il reprend où il en était. Utilisable seulement dans la définition d'une variable, jamais dans une condition. Les compteurs sont propres à un pipeline.- Pour les Universal Packages,
versionOption: major | minor | patch | customincrémente à partir de la dernière version du feed.
5.2 Build once, deploy many#
- On versionne et on construit une seule fois, puis on promeut le même binaire de stage en stage (dev → test → prod) : ce qui a été testé est exactement ce qui part en production.
- Passage entre stages :
publish(raccourci dePublishPipelineArtifact@1) puisdownload: current. Dans un deployment job, les artifacts sont téléchargés automatiquement dans$(Pipeline.Workspace)(hookdeploy) ;download: nonel'empêche. - Entre pipelines : déclarer un pipeline resource, puis
download: <ressource>. PublishPipelineArtifact@1n'existe que sur Azure DevOps Services ; sur Azure DevOps Server, on utilise Publish Build Artifacts.
- stage: Build
jobs:
- job: build
steps:
- script: dotnet publish -c Release -o $(Build.ArtifactStagingDirectory)/app
- publish: $(Build.ArtifactStagingDirectory)/app
artifact: app-$(Build.BuildNumber) # le nom porte la version
- stage: Deploy
dependsOn: Build
jobs:
- deployment: deploy
environment: prod
strategy:
runOnce:
deploy:
steps:
- script: ls $(Pipeline.Workspace) # l'artifact y est déjà téléchargé
Côté GitHub Actions : actions/upload-artifact@v4 (artifacts immuables en v4) avec retention-days, qui ne peut pas dépasser
la limite fixée au niveau du dépôt, de l'organisation ou de l'entreprise. La stratégie de rétention complète est au
chapitre 06.
6. Quality gates et release gates#

6.1 Les types de gates#
| Où | Mécanisme | Exemples |
|---|---|---|
| Pull request | Branch policies / branch protection rules (chapitre 02) | build validation, tests obligatoires, reviewers, statut de couverture |
| Dans le pipeline | Une tâche qui échoue | tests rouges, seuil de couverture, analyse de sécurité, failureCriteria de charge |
| Avant un stage (YAML) | Approvals and checks sur une ressource | approbation, heures ouvrées, alertes Azure Monitor, template obligatoire |
| Avant / après un stage (Classic) | Deployment gates | Query work items, Azure Policy compliance |
| GitHub Actions | Environment protection rules | required reviewers, wait timer, branches autorisées |
6.2 Approvals and checks (Azure Pipelines YAML)#
L'essentiel pour la stratégie de gates (le détail complet, l'ordre et les exemples YAML sont au chapitre 04, § 10.2) :
- posés hors du YAML par le propriétaire de la ressource protégée (environment, service connection, repository, variable group, secure file, agent pool) : l'auteur du pipeline ne peut pas les contourner ;
- cinq catégories dans l'ordre : static checks (Branch control, Required template, Evaluate artifact) → pre-check approvals → dynamic checks (Approval, Invoke Azure Function, Invoke REST API, Business Hours, Query Azure Monitor alerts) → post-check approvals → exclusive lock ;
- gouvernance : Required template impose d'étendre un template approuvé, Branch control réserve la production à
main; bypass en hotfix seulement pour un administrateur de la ressource, et tracé.
6.3 Deployment gates (Classic release)#
- En pre-deployment et post-deployment conditions d'un stage de release classique.
- Gates intégrés : Invoke Azure Function, Query Azure Monitor alerts, Invoke REST API, Query work items (nombre de work items dans un seuil, par exemple zéro bug P0), Check Azure Policy compliance.
- Réglages : Delay before evaluation (laisser le système se stabiliser), timeout (6 minutes minimum) et sampling interval (5 minutes minimum). Les gates sont réévalués jusqu'à ce qu'ils réussissent tous dans le même intervalle.
6.4 GitHub Actions : environment protection rules#
Côté GitHub, la gate avant déploiement est l'environment et ses protection rules : required reviewers (6 au maximum, une approbation suffit), wait timer (jusqu'à 30 jours), deployment branches and tags, custom deployment protection rules (GitHub Apps, preview). Sur un dépôt privé, reviewers et wait timer demandent GitHub Enterprise. Tableau complet et disponibilité par plan : chapitre 04, § 10.5.
6.5 Les gates de sécurité et de gouvernance#
- Sécurité : faire échouer le build sur une vulnérabilité critique (GitHub Advanced Security, Dependabot, Microsoft Defender for Cloud DevOps security, voir chapitre 07), analyser les images de conteneur avant publication.
- Gouvernance : Required template, Branch control, Check Azure Policy compliance, approbations des propriétaires de l'environnement de production.
- Qualité : pourcentage de tests réussis, couverture minimale, critères de charge, pas d'alerte Azure Monitor active après déploiement (post-deployment).
7. Concevoir la stratégie de test#

7.1 La taxonomie de Microsoft (L0 à L4)#
| Niveau | Nature | Dépendances | Où le lancer |
|---|---|---|---|
| L0 / L1 | Tests unitaires | seulement le code testé (L0 : en mémoire) | poste, chaque PR |
| L2 | Tests fonctionnels | l'assembly + SQL, fichiers… | PR ou CI |
| L3 | Fonctionnels contre un service déployé | déploiement de test, stubs pour les dépendances clés | stage de test |
| L4 | Intégration en production | déploiement complet | production |
Repères chiffrés de Microsoft pour les tests unitaires : moins de 60 ms en moyenne par test L0, moins de 400 ms par test L1, aucun test au-delà de 2 secondes. Une équipe Microsoft lance plus de 60 000 tests unitaires en parallèle en moins de six minutes.
7.2 Les principes#
- Shift left : faire le maximum de tests avant le merge dans la branche principale ; shift right : garder en production ce qui n'a de sens qu'avec le vrai trafic (smoke tests, surveillance, injection de pannes).
- Écrire chaque test au niveau le plus bas possible ; privilégier les tests sans dépendance externe.
- Viser la fiabilité : un test instable coûte cher ; Microsoft décourage les tests UI, souvent instables.
- Tests fonctionnels isolés : état connu au départ, exécutables dans n'importe quel ordre, uniquement par l'API publique.
- Le code de test est du code produit : même revue, à côté du code, sous la responsabilité de son propriétaire.
- Tests locaux : le développeur lance au moins L0/L1 (et souvent L2) avant le commit ; la PR échoue si les tests échouent.
7.3 Les tests de charge avec Azure Load Testing#
- Service managé qui exécute des scripts Apache JMeter ou Locust, déclenchable depuis Azure Pipelines, GitHub Actions ou l'Azure CLI.
failureCriteriadans le fichier YAML de configuration (versionné avec le script) : le test échoue, et le pipeline avec, si un seuil client est dépassé.autoStoparrête le test si le taux d'erreur s'emballe (évite de payer un test cassé).- Les critères sur des métriques serveur (CPU d'une App Service…) se configurent dans le portail, pas depuis le pipeline ; la managed identity de la ressource Load Testing doit alors avoir Monitoring Reader sur le composant surveillé.
# loadtest.yaml : versionné à côté de script.jmx
version: v0.1
testId: api-commandes
displayName: Charge sur l'API commandes
testPlan: script.jmx
engineInstances: 1
failureCriteria:
- avg(response_time_ms) > 300 # moyenne au-delà de 300 ms : échec
- percentage(error) > 5 # plus de 5 % d'erreurs : échec
- GetCommande: avg(latency) > 200 # critère sur une requête précise (nom du sampler JMeter)
autoStop:
errorPercentage: 80
timeWindow: 120
8. Exécuter les tests dans le pipeline#

8.1 Les tâches de test#
| Tâche | Usage |
|---|---|
DotNetCoreCLI@2 (command: test) |
tests .NET ; publie seul ses résultats ; prend en charge Microsoft.Testing.Platform |
VSTest@3 |
runner Visual Studio Test (MSTest, xUnit, NUnit, tests Selenium…) ; distribution sur plusieurs agents, rerun, Test Impact Analysis. Ne prend pas en charge Microsoft.Testing.Platform |
PublishTestResults@2 |
publie des résultats produits par n'importe quel runner : formats JUnit (défaut), NUnit, VSTest (TRX), XUnit, CTest |
| Maven, Gradle, Ant… | options intégrées de publication des résultats |
- script: npm test -- --reporter mocha-junit-reporter --reporter-options mochaFile=./test-results.xml
- task: PublishTestResults@2
condition: succeededOrFailed() # publier même si des tests ont échoué
inputs:
testResultsFormat: JUnit
testResultsFiles: '**/test-results.xml'
failTaskOnFailedTests: true # le job échoue sur un test rouge
testResultsFormat: VSTestdésigne le format TRX, quel que soit le runner qui l'a produit.
8.2 Les agents de test#
- Microsoft-hosted : outils standards préinstallés, machine neuve à chaque job, rien à maintenir.
- Self-hosted : nécessaire pour un réseau privé, des outils spécifiques ou des tests UI sur navigateur physique, qui exigent un agent en mode interactif avec autologon (pas en service). Un navigateur headless n'en a pas besoin.
VSTest@3exige la capacitévstest: Visual Studio installé sur l'agent, ou la tâche Visual Studio Test Platform Installer en amont.- L'ancien couple Visual Studio Test Agent Deployment / Run functional tests est déprécié : on utilise
VSTest@3.
8.3 Accélérer et fiabiliser#
- Parallélisme : un job multi-agents (
strategy: parallel) etVSTest@3répartit les tests en lots, selondistributionBatchType:basedOnTestCases(nombre de tests et d'agents),basedOnExecutionTime(durées passées, lots d'égale durée),basedOnAssembly.dontDistribute: trueréplique les tests sur chaque agent au lieu de les répartir. - Rerun :
rerunFailedTestsrelance les tests échoués, avec un seuil (rerunType) au-delà duquel on ne relance pas. - Test Impact Analysis : ne lance que les tests touchés par le changement.
- Garde-fou :
failOnMinTestsNotRunfait échouer la tâche si trop peu de tests ont tourné (adaptateur cassé, filtre erroné). - Les tests data-driven (xUnit, NUnit, MSTest) ont des limites : pas de distribution ni de TIA, et le rerun seulement avec des paramètres statiques.
jobs:
- job: tests
strategy:
parallel: 3 # 3 agents se partagent les lots
pool:
vmImage: windows-latest
steps:
- task: VSTest@3
inputs:
testAssemblyVer2: '**\*Tests.dll'
distributionBatchType: basedOnExecutionTime
rerunFailedTests: true
8.4 Où lire les résultats#
L'onglet Tests du run (et les analytics de tests) agrège les résultats, regroupe les tentatives d'un rerun et l'historique d'un test, ce qui aide à repérer les tests instables (traités au chapitre 06).
Côté GitHub Actions, le runner produit ses fichiers de résultats ; on les conserve avec actions/upload-artifact@v4 et on fait
échouer le job sur un code de sortie non nul du runner de tests.
9. La couverture de code#
PublishCodeCoverageResults@2publie des résumés Cobertura, JaCoCo, Clover, gcov, pcov et.coverage; plusieurs fichiers de résumé (motif minimatch) sont fusionnés en un seul rapport. La v1, limitée à Cobertura et JaCoCo, sera dépréciée.pathToSourcesest nécessaire quand le rapport ne contient pas de chemins absolus (cas de JaCoCo),failIfCoverageEmptyfait échouer la tâche s'il n'y a rien à publier.- En .NET : le package
coverlet.collectoret--collect "XPlat Code Coverage"produisent un rapport Cobertura ;VSTestetdotnet testsavent aussi produire des fichiers.coverage. - Onglet Code Coverage : vue par dossier et par fichier, et rapport HTML selon le format.
- Statut de couverture en pull request : fichier
azurepipelines-coverage.ymlà la racine du dépôt, qui fixe un seuil sur la couverture des lignes modifiées (diff coverage). Seul le format.coveragede Visual Studio est accepté pour valider la couverture d'une PR, et elle n'est pas fusionnée entre plusieurs pipelines.
- task: DotNetCoreCLI@2
inputs:
command: test
arguments: '--collect "XPlat Code Coverage"'
- task: PublishCodeCoverageResults@2
inputs:
summaryFileLocation: '$(Agent.TempDirectory)/**/coverage.cobertura.xml'
failIfCoverageEmpty: true
# azurepipelines-coverage.yml (racine du dépôt) : statut de PR sur la couverture des lignes modifiées
coverage:
status:
comments: on
diff:
target: 70%
Un pourcentage de couverture n'est pas une preuve de qualité : utilisez-le comme garde-fou sur le code modifié plutôt que comme objectif global.
10. Labs conseillés#
À faire dans une organisation Azure DevOps de test (les 2 GiB gratuits d'Azure Artifacts suffisent) et un dépôt GitHub personnel.
Lab 1 · Feed, upstream et views (30 min, gratuit)
- Créez un feed scopé projet avec Include packages from common public sources.
- Pointez un projet .NET ou Node sur ce seul feed et restaurez : les packages publics apparaissent dans le feed (Source : nuget.org).
- Publiez votre propre package
1.0.0, puis promouvez-le vers@prerelease. - Essayez de republier
1.0.0: refusé (immuabilité). - Résultat attendu :
@localcontient tout,@prereleaseseulement la version promue.
Lab 2 · Publier depuis un pipeline avec le bon rôle (30 min)
- Pipeline YAML :
NuGetAuthenticate@1,dotnet pack,dotnet nuget push. - Premier run : 403 sur le push, car le Build Service n'est que Collaborator.
- Passez le Build Service en Feed Publisher (Contributor), relancez : la publication réussit.
- Ajoutez une variable
counterpour le PATCH et vérifiez qu'il augmente à chaque run.
Lab 3 · Tests, résultats et couverture (30 min)
- Ajoutez un test qui échoue volontairement.
dotnet testavec--collect "XPlat Code Coverage", puisPublishCodeCoverageResults@2.- Vérifiez l'onglet Tests (échec visible) et l'onglet Code Coverage.
- Corrigez le test et ajoutez
azurepipelines-coverage.ymlavectarget: 70%; ouvrez une PR et observez le statut.
Lab 4 · Approvals and checks (20 min)
- Créez un environment
productionavec un check Approval et un check Business Hours. - Ajoutez un stage
deploymentqui le cible : le run s'arrête avant le stage en attendant. - Ajoutez un Exclusive lock et lancez deux runs : avec
runLatest, seul le dernier passe.
Lab 5 · Charge avec Azure Load Testing (40 min, payant à l'usage)
- Créez une ressource Azure Load Testing et un test à partir d'une URL.
- Ajoutez un
loadtest.yamlavecfailureCriteriaet lancez-le depuis le pipeline (tâche Azure Load Testing). - Mettez un seuil impossible (
avg(response_time_ms) > 1) : le pipeline échoue. - Nettoyage : supprimez le groupe de ressources.
11. Pièges d'examen#
| Situation dans la question | Réponse attendue | Pourquoi |
|---|---|---|
| Restaurer des packages publics de façon fiable même si nuget.org tombe | Upstream sources sur un feed Azure Artifacts | Le feed garde une copie de chaque package consommé |
Plusieurs sources dans nuget.config, résultats imprévisibles |
Un seul feed avec upstreams | NuGet interroge les sources en parallèle |
Publier directement dans @release |
Impossible : publier dans le feed puis promouvoir | Seule @local accepte la publication |
Remettre une version promue dans @local |
Impossible | Pas de rétrogradation |
Republier 1.2.3 après l'avoir supprimée |
Impossible : publier 1.2.4 |
Les versions sont immuables, même supprimées |
| Garder certaines versions malgré la retention policy | Les promouvoir dans une view | Les versions promues sont exemptées |
| Le pipeline restaure mais ne publie pas (403) | Build Service en Feed Publisher (Contributor) | Il n'est que Collaborator par défaut |
| Un Reader n'arrive pas à installer un package public jamais utilisé | Il faut un Collaborator pour le premier enregistrement | Les Readers ne voient que ce qui est déjà sauvegardé |
| Pipeline d'un projet A, feed du projet B | Build Service dans les Readers du projet B + rôle sur le feed | Feed scopé projet : double accès |
| Partager les packages validés avec toute l'organisation sans ouvrir le feed | View @release avec visibilité People in my organization |
Les views se partagent indépendamment |
| Feed d'une autre organisation du même tenant | Locator azure-feed://…@view + view partagée au tenant |
Seul le propriétaire peut ouvrir la view |
| Publier un package npm vers GitHub Packages depuis Actions | permissions: packages: write + GITHUB_TOKEN |
Sans permission, le jeton ne publie pas |
| Bibliothèque qui doit signaler ses ruptures | SemVer, incrément du MAJOR | CalVer ne dit rien de la compatibilité |
| Numéro qui repart à zéro quand la version mineure change | counter(prefix, seed) ou $(Rev:r) dans le run number |
Le compteur dépend du préfixe |
Utiliser counter() dans une condition de step |
Impossible | Seulement dans la définition d'une variable |
| Le pipeline doit ignorer un check en urgence | Bypass par un administrateur de la ressource | Possible pour Approval, Business Hours, Azure Function, REST API |
| Empêcher un auteur de pipeline de retirer l'approbation de production | Mettre le check sur l'environment, pas dans le YAML | Les checks ne vivent pas dans le fichier |
| Imposer un modèle de pipeline sécurisé pour une service connection de prod | Check Required template | Check statique de gouvernance |
| Un seul déploiement à la fois sur un environnement | Check Exclusive lock (runLatest ou sequential) |
Évite les déploiements concurrents |
| Bloquer une release tant qu'il reste un bug P0 (Classic) | Gate Query work items avec un seuil maximum à 0 | Gate intégré de release |
| Le rapport de tests manque quand un test échoue | condition: succeededOrFailed() sur PublishTestResults@2 |
Sinon l'étape est sautée |
| Tests UI Selenium sur un vrai navigateur | Agent self-hosted en mode interactif avec autologon | Un service n'a pas de session graphique |
| Réduire la durée d'une grosse suite VSTest | Job multi-agents + distributionBatchType: basedOnExecutionTime |
Lots d'égale durée |
| Ne lancer que les tests concernés par le changement | Test Impact Analysis | Sélection automatique |
Publier une couverture au format Clover, gcov ou .coverage |
PublishCodeCoverageResults@2 |
La v1 ne connaît que Cobertura et JaCoCo |
| Statut de couverture en PR qui ne marche pas avec Cobertura | Utiliser le format .coverage |
Seul format accepté pour la validation de PR |
| Faire échouer le pipeline si la latence dépasse 300 ms sous charge | failureCriteria d'Azure Load Testing |
Le statut du test devient celui du pipeline |
| Critère sur le CPU du serveur depuis le pipeline | Impossible : à configurer dans le portail | Les critères serveur ne passent pas par le CI/CD |
12. Scénarios corrigés#
1. Une équipe .NET dépend de nuget.org. Lors d'une panne du registre, tous les builds ont échoué. La sécurité veut aussi contrôler ce qui entre. Que proposez-vous ?
Un feed Azure Artifacts scopé projet avec l'upstream nuget.org, et un
nuget.configqui ne référence que ce feed. Chaque package consommé est sauvegardé dans le feed : les builds continuent pendant une panne, et le feed devient le point de contrôle (rôles, analyse des dépendances).
2. Une bibliothèque interne doit être testée par deux équipes pilotes avant d'être proposée à toute l'entreprise. Comment la diffuser ?
Publier dans le feed (
@local), promouvoir vers@prereleasepour les pilotes (source…/feed@prerelease), puis vers@releaseune fois validée. Donner aux consommateurs l'accès à la view@releaseseulement.
3. Le pipeline de publication échoue avec une erreur 403 au dotnet nuget push, alors que le restore fonctionne. Cause et
correction ?
Le Build Service a par défaut Feed and Upstream Reader (Collaborator) : il restaure mais ne publie pas. Lui donner Feed Publisher (Contributor) sur le feed (et l'accès Readers au projet si le feed est dans un autre projet).
4. Le stockage Azure Artifacts dépasse 2 GiB à cause de milliers de versions CI. On veut garder les versions livrées. Que faire ?
Activer une retention policy (nombre maximum de versions + jours sans téléchargement) et promouvoir les versions livrées dans une view, ce qui les exempte. Penser que la Recycle Bin garde 30 jours et compte encore dans le stockage.
5. Une API publique change le format de ses réponses. Quelle version publier après 2.3.7 ?
3.0.0: c'est une rupture de compatibilité, donc incrément du MAJOR (et remise à zéro de MINOR et PATCH).
6. Le pipeline doit produire 1.4.0, 1.4.1, 1.4.2… puis repartir à 1.5.0 quand on passe la variable mineure à 5. Comment
faire ?
patch: $[counter(format('{0}.{1}', variables.majeur, variables.mineur), 0)]et une version$(majeur).$(mineur).$(patch). Le compteur est propre à chaque préfixemajeur.mineur(ouname: $(majeur).$(mineur).$(Rev:r), qui repart à 1).
7. La production doit exiger l'approbation du responsable d'exploitation, interdire les déploiements le week-end et vérifier qu'aucune alerte n'est active. L'équipe applicative ne doit pas pouvoir le retirer. Que configurez-vous ?
Sur l'environment
production: un check Approval, un check Business Hours et un check Query Azure Monitor alerts. Les checks ne sont pas dans le YAML et seul le propriétaire de l'environment les modifie.
8. Deux merges rapides lancent deux déploiements en production en même temps et se marchent dessus. Correction ?
Un check Exclusive lock sur l'environment, avec
lockBehavior: runLatest(seul le dernier run déploie) ousequentialsi chaque version doit passer.
9. Une suite de 40 000 tests .NET dure 50 minutes. Comment la réduire sans perdre de couverture ?
Job multi-agents (
strategy: parallel) avecVSTest@3etdistributionBatchType: basedOnExecutionTime, plus Test Impact Analysis sur les PR ; à plus long terme, déplacer des tests fonctionnels lents vers des tests unitaires L0/L1 (shift left).
10. L'équipe veut bloquer une PR si le nouveau code est couvert à moins de 80 %. Que mettre en place ?
Un fichier
azurepipelines-coverage.ymlavecdiff: target: 80%, un pipeline de build validation qui produit la couverture au format.coverage(VSTest oudotnet test), et la branch policy qui exige ce statut.
13. Pour aller plus loin#
- Azure Container Registry pour les images déployées sur Azure (AKS, Container Apps), avec analyse par Defender for Containers : voir le parcours AKS et le cours SC-500.
- Package graphs d'Azure Artifacts : comment un feed construit les dépendances transitives à partir de ses upstreams.
- Symbol server d'Azure Artifacts pour déboguer les binaires natifs publiés.
- Azure Test Plans : tests manuels et exploratoires, et lancement de tests automatisés depuis un plan de test.
- Azure Chaos Studio avec Azure Load Testing pour la validation continue (approche mission-critical du Well-Architected Framework).
14. Fiche à retenir#
- GitHub Packages = registres npm, NuGet, Maven, Gradle, RubyGems, conteneurs ; pas d'upstreams ni de views.
- Azure Artifacts = NuGet, npm, Maven, Gradle, Python, Cargo, Universal Packages ; upstreams, views, retention ; 2 GiB gratuits.
- Feed scopé projet recommandé ; un seul feed par fichier de configuration client.
- Ordre de recherche : publiés → déjà sauvegardés → upstreams dans l'ordre ; 20 upstreams max par type.
- Premier enregistrement depuis un upstream : Collaborator minimum.
- Publier dans
@local, promouvoir ensuite, jamais rétrograder ; une view partagée donne accès sans droit sur le feed. - Versions immuables, même après suppression ; retention = nombre max et jours sans téléchargement ; versions promues exemptées ; Recycle Bin 30 jours.
- Rôles : Reader < Collaborator < Contributor (publie, promeut) < Owner (supprime, retention, upstreams).
- Build Service = Collaborator par défaut → Contributor pour publier ; feed d'un autre projet = Readers du projet + rôle.
-
NuGetAuthenticate@1(recommandé) ;permissions: packages: write+GITHUB_TOKENcôté GitHub. - SemVer : MAJOR rupture, MINOR fonction, PATCH correctif ; préversion < version finale ; CalVer = date, pas de compatibilité.
- Run number par défaut
$(Date:yyyyMMdd).$(Rev:r);counter(prefix, seed)seulement dans une variable. - Build once, deploy many ; artifacts téléchargés automatiquement dans un deployment job.
- Checks dans l'ordre : static → pre-approval → dynamic → post-approval → exclusive lock ; pas dans le YAML ; bypass par l'admin de la ressource.
- Gates Classic : Azure Function, Azure Monitor alerts, REST API, Query work items, Azure Policy ; timeout ≥ 6 min, échantillonnage ≥ 5 min.
- GitHub environments : 6 reviewers, wait timer jusqu'à 43 200 min, branches autorisées.
- Taxonomie L0 à L4, shift left / shift right ; tests unitaires < 60 ms (L0) et < 400 ms (L1).
- Azure Load Testing :
failureCriteriaetautoStopdans le YAML ; critères serveur seulement dans le portail. -
PublishTestResults@2(JUnit, NUnit, VSTest/TRX, XUnit, CTest) avecsucceededOrFailed();VSTest@3multi-agents, rerun, TIA ; UI sur navigateur réel = agent interactif. -
PublishCodeCoverageResults@2(Cobertura, JaCoCo, Clover,.coverage… ; fusion des fichiers) ; statut de PR viaazurepipelines-coverage.yml, format.coverageseulement.
Références#
Lues le 21/10/2026 :
- Study guide for Exam AZ-400
- Azure Artifacts key concepts
- Azure Artifacts best practices
- What are Azure Artifacts feeds?
- Feed scopes: project vs organization feeds
- Set up upstream sources
- What are feed views?
- Promote packages and manage feed views
- Manage permissions (feeds)
- Delete and recover packages
- Package sizes and count limits
- Monitor Artifacts storage consumption
- NuGetAuthenticate@1
- Publish and download Universal Packages with Azure Pipelines
- SNFR17 - Semantic Versioning (Azure Verified Modules)
- Package versioning (NuGet)
- Run and build numbers
- Expressions : counter
- Publish and download pipeline artifacts
- Define approvals and checks
- Deployment gates concepts
- Use gates and approvals to control your deployment
- Shift testing left with unit tests
- Shift right to test in production
- Define fail criteria for load tests (Azure Load Testing)
- PublishTestResults@2
- VSTest@3
- Run automated tests from test plans
- PublishCodeCoverageResults@2
- Review and configure code coverage results
- Introduction to GitHub Packages
- Publishing and installing a package with GitHub Actions
- Deployments and environments (GitHub Actions)
- Store and share data with workflow artifacts