9. Déboguer les exécutions
Sections
Réglages de lecture
Voix naturelle enregistrée pour ce cours, la même dans tous les navigateurs.
Aucune voix pour cette langue dans ce navigateur.
Plus de voix
Code et termes techniques en anglais
Désactivé : la voix de la page lit tout, sans pause entre deux voix.
Aucune voix pour cette langue dans ce navigateur.
Plus de voix
D’autres voix : Microsoft Edge propose des voix naturelles en ligne, et Windows (Paramètres › Heure et langue › Voix), macOS et Android en installent d’autres.
Un workflow qui échoue exprès
Section intitulée « Un workflow qui échoue exprès ».github/workflows/gha-09-debug.yml a quatre jobs, chacun une situation que tu rencontreras :
# GitHub Actions course, lesson 9: reading a failing run, debug logging, re-runs, timeoutsname: "GHA 09: debugging"
on: workflow_dispatch: inputs: fail: description: Make the test step fail type: boolean default: true push: branches: [main] paths: ['.github/workflows/gha-09-debug.yml']
permissions: contents: read
jobs: noisy: runs-on: ubuntu-latest steps: - name: Groups, debug and notice messages run: | echo "::group::Environment of the step" echo "RUNNER_OS=$RUNNER_OS RUNNER_ARCH=$RUNNER_ARCH" echo "RUNNER_DEBUG='${RUNNER_DEBUG:-}'" echo "::endgroup::" echo "::debug::only visible when step debug logging is on" echo "::notice title=Lesson 9::a notice annotation" - name: Trace the commands with set -x run: | set -x version=$(date -u +%Y.%m.%d) test -n "$version" - name: Tests (fail on demand, attempt ${{ github.run_attempt }}) run: | if [ "${{ inputs.fail }}" = "true" ] && [ "${{ github.run_attempt }}" = "1" ]; then echo "::error title=Flaky test::failed on attempt ${{ github.run_attempt }}" exit 1 fi echo "tests passed on attempt ${{ github.run_attempt }}"
independent: runs-on: ubuntu-latest steps: - run: echo "this job doesn't depend on noisy"
allowed-to-fail: runs-on: ubuntu-latest continue-on-error: true steps: - run: exit 3
timeout: runs-on: ubuntu-latest timeout-minutes: 1 steps: - run: sleep 90Le step de tests n’échoue qu’à la première tentative : un test instable (flaky), la raison la plus courante de relancer.
Étape 1 : le résumé, depuis le terminal
Section intitulée « Étape 1 : le résumé, depuis le terminal »gh workflow run gha-09-debug.yml --field fail=truegh run view 34850662582La fin de la sortie liste les annotations — chaque ::error, ::warning et ::notice, plus les erreurs ajoutées par le runner :
ANNOTATIONSX The job has exceeded the maximum execution time of 1m0stimeout: .github#1
X The operation was canceled.timeout: .github#5
X Process completed with exit code 1.noisy: .github#10
X failed on attempt 1noisy: .github#9
- a notice annotationnoisy: .github#14
X Process completed with exit code 3.allowed-to-fail: .github#5Lis-les avant tout log : ici, elles disent déjà quels jobs ont échoué et pourquoi — un timeout, un test, un échec attendu. Le title= d’une annotation apparaît dans la page web, pas dans cette liste.
Étape 2 : seulement les logs en échec
Section intitulée « Étape 2 : seulement les logs en échec »gh run view 34850662582 --log-failedLe log complet de cette tentative fait 169 lignes ; --log-failed en a renvoyé 15, uniquement les steps en échec de noisy et allowed-to-fail :
noisy Tests (fail on demand, attempt 1) ##[error]failed on attempt 1noisy Tests (fail on demand, attempt 1) ##[error]Process completed with exit code 1.allowed-to-fail Run exit 3 ##[error]Process completed with exit code 3.Le job timeout n’y est pas : son step a été annulé, pas mis en échec. Quand un job semble disparaître de --log-failed, regarde sa conclusion.
Les commandes de workflow qui structurent un log
Section intitulée « Les commandes de workflow qui structurent un log »Dans le log normal du premier step :
##[group]Environment of the stepRUNNER_OS=Linux RUNNER_ARCH=X64RUNNER_DEBUG=''##[endgroup]##[notice]a notice annotation::group::title…::endgroup::regroupent des lignes dans une section repliable du log web.::notice,::warning,::errorcréent des annotations (avectitle=,file=,line=— leçon 4).::debug::n’a rien affiché : les messages de débogage sont masqués tant que les logs de débogage ne sont pas activés.
Pour les scripts shell, set -x affiche chaque commande après expansion, l’équivalent d’une exécution pas à pas :
++ date -u +%Y.%m.%d+ version=2026.09.14+ test -n 2026.09.14Les logs de débogage
Section intitulée « Les logs de débogage »Deux interrupteurs, en secrets ou en variables du dépôt, ou pour une seule relance avec --debug :
| Paramètre | Ajoute |
|---|---|
ACTIONS_STEP_DEBUG = true |
des lignes ##[debug] : évaluation des conditions, inputs, fichier de script exécuté, messages ::debug:: |
ACTIONS_RUNNER_DEBUG = true |
les logs de diagnostic du runner dans l’archive des logs |
La troisième tentative de l’exécution a été lancée avec :
gh run rerun 34850662582 --debugLe même step, maintenant :
##[debug]Evaluating condition for step: 'Groups, debug and notice messages'##[debug]Evaluating: success()##[debug]Evaluating success:##[debug]=> true##[debug]Result: true##[debug]Starting: Groups, debug and notice messages...##[debug]/usr/bin/bash -e /home/runner/work/_temp/e3c00f12-b91a-4ef4-830d-2340170b7bc7.sh::group::Environment of the step##[group]Environment of the stepRUNNER_OS=Linux RUNNER_ARCH=X64RUNNER_DEBUG='1'::endgroup::##[endgroup]##[debug]only visible when step debug logging is on##[notice]a notice annotation- Chaque
if:montre comment il a été évalué — le moyen le plus rapide de comprendre un step qui a été ignoré. RUNNER_DEBUGvaut1: un script peut afficher davantage quand cette variable est définie.- Le job
noisyest passé de 70 à 190 lignes de log.
L’archive des logs de cette tentative, téléchargée avec gh api repos/spareilleux/learn/actions/runs/34850662582/attempts/3/logs > attempt3.zip, contient un dossier par job avec un fichier par step, et un dossier runner-diagnostic-logs :
runner-diagnostic-logs/103998873521-noisy.zip 13448 Runner_20260914-134407-utc.log 73191 Worker_20260914-134409-utc.logLe log Runner est celui de l’agent qui prend en charge les jobs ; le log Worker est celui du processus qui exécute les steps. Tu en as rarement besoin, sauf quand un job échoue avant son premier step.
Relancer
Section intitulée « Relancer »La documentation : « Les relances utilisent les privilèges de l’acteur qui a initialement déclenché le workflow … Le workflow utilisera aussi le même GITHUB_SHA (SHA du commit) et le même GITHUB_REF ». Une relance teste le même commit : elle peut révéler un test instable, pas valider un correctif que tu viens de pousser.
La tentative 2 a été lancée avec gh run rerun 34850662582 --failed :
noisy success attempt=2 13:42:13 → 13:42:16timeout cancelled attempt=2 13:42:13 → 13:43:42allowed-to-fail failure attempt=2 13:42:13 → 13:42:16independent success attempt=2 13:40:15 → 13:40:18noisya réussi :github.run_attemptvalait2, et même le nom du step a changé (Tests (fail on demand, attempt 2)).- Les trois jobs qui n’avaient pas réussi ont tourné à nouveau — celui qui avait été annulé compris ;
independentn’a pas été relancé : ses horaires sont ceux de la tentative 1, repris tels quels. - Chaque tentative garde ses propres logs (
attempts/1/logs,attempts/2/logs…).
Timeouts et conclusions
Section intitulée « Timeouts et conclusions »timeout-minutes vaut par défaut 360 minutes par job. Le job timeout était limité à 1 minute et exécutait sleep 90 :
2026-09-14T13:44:10.0526092Z ##[group]Run sleep 902026-09-14T13:45:37.2574842Z ##[error]The operation was canceled.2026-09-14T13:45:37.3009029Z Terminate orphan process: pid (2052) (sleep)Annulé au bout de 87 secondes, pas 60 — à chaque tentative, et dans l’exercice avec sleep 300. Considère la limite comme « annulé un certain temps après la limite », et fixe-la bien en dessous de la durée que tu es prêt à payer.
Les conclusions des exécutions, qui décident de l’icône rouge ou grise :
| Exécution | Jobs | Conclusion de l’exécution |
|---|---|---|
| push | noisy ✓, independent ✓, allowed-to-fail ✗ (continue-on-error), timeout annulé |
cancelled |
| dispatch, tentative 1 | noisy ✗, timeout annulé, les autres comme ci-dessus |
failure |
| dispatch, tentatives 2 et 3 | noisy ✓, timeout annulé |
cancelled |
Un timeout rend l’exécution cancelled, pas failed — et une règle de notification ou un check obligatoire qui ne surveille que les échecs passe à côté.
À retenir
Section intitulée « À retenir »- Commence par
gh run view <id>(annotations), puisgh run view <id> --log-failed; les jobs annulés ne figurent pas dans les logs en échec. ::group::,::notice::etset -xrendent les logs lisibles ;::debug::a besoin des logs de débogage.gh run rerun --debugmontre comment chaqueif:a été évalué, et ajoute les logs de diagnostic du runner.gh run rerun --failedrelance chaque job qui n’a pas réussi, sur le même commit.- Un timeout de job annule le job (ici 87 s pour une limite d’1 minute) et rend l’exécution cancelled.
Exercices
Section intitulée « Exercices »- Déplace le timeout du job vers le step :
timeout-minutes: 1sur un stepsleep 300, suivi d’un step avecif: always(). Quelle est la conclusion du step, et le step suivant s’exécute-t-il ?
Solution
Vérifié avec gha-09-exercises.yml :
step-timeout | Run date -u +%T | 13:46:49step-timeout | Run date -u +%T | ##[error]The action 'Run date -u +%T' has timed out after 1 minutes.step-timeout | Run date -u +%T | 13:48:01Le step a échoué (il n’a pas été annulé) au bout de 72 secondes, le step always() s’est exécuté, et la conclusion du job était failure. Le timeout au niveau du job, dans la même exécution, a annulé son job au bout de 87 secondes (13:46:49 → 13:48:16), avec sleep 300 : le délai ne dépend pas du script.
- Le seul job en échec d’une exécution a
continue-on-error: true, et un autre job le référence dansneeds. Quelle est la conclusion de l’exécution, et que contientneeds.allowed-to-fail.result?
Solution
allowed-to-fail failureafter successrun conclusion successneeds.allowed-to-fail.result=successLe job est affiché en échec, mais l’exécution réussit — « Mets true pour permettre à une exécution de workflow de réussir quand ce job échoue » — et pour le job dépendant, le résultat est success : after s’est exécuté sans aucun if:. Un job dépendant ne peut pas savoir que l’échec a été toléré.
- Un job s’est exécuté alors que tu t’attendais à ce que son
if:le fasse ignorer. Où peux-tu voir comment GitHub a évalué la condition, sans les logs de débogage ?
Solution
Dans le log system du job, qui fait partie de l’archive des logs (gh api repos/<owner>/<repo>/actions/runs/<run-id>/attempts/<n>/logs), fichier <job>/system.txt. Pour noisy, à la tentative 1, sans débogage :
Requested labels: ubuntu-latestJob defined at: spareilleux/learn/.github/workflows/gha-09-debug.yml@refs/heads/mainWaiting for a runner to pick up this job...Evaluating noisy.ifEvaluating: success()Result: trueUn job sans if: est évalué comme success(). Pour le if: des steps, relance avec --debug : les lignes ##[debug]Evaluating condition for step apparaissent dans le log du step.