Triage de l'échec CI en problème GitHub
Investiguer un job GitHub Actions qui échoue, extraire la cause racine et créer
un problème de bug bien structuré contre NVIDIA/Megatron-LM.
Workflow
1. Parser l'URL
L'argument est une URL GitHub Actions. Ce sera l'un des éléments suivants :
- Job URL:
https://github.com/<owner>/<repo>/actions/runs/<run_id>/job/<job_id> - Run URL:
https://github.com/<owner>/<repo>/actions/runs/<run_id>
Extraire run_id et, s'il est présent, job_id.
2. Identifier les jobs échoués
-
Si un
job_ida été fourni, utiliser ce job directement. -
Si seul un
run_ida été fourni, lister tous les jobs échoués de la run :gh run view <run_id> --repo NVIDIA/Megatron-LM --json jobs \ --jq '[.jobs[] | select(.conclusion == "failure") | {id: .databaseId, name: .name, url: .url}]'Si plusieurs jobs ont échoué, demander à l'utilisateur lequel trier, ou les trier tous s'il le dit.
3. Récupérer les logs d'échec
Pour chaque job échoué, récupérer les logs et les réduire à l'échec :
# Extraire le log brut et garder uniquement les lignes porteuses d'erreur
gh api repos/NVIDIA/Megatron-LM/actions/jobs/<job_id>/logs 2>&1 \
| grep -E "(FAILED|ERROR|\bError\b|assert|Traceback|Exception|##\[error\])" \
| head -200
Capturer aussi le nom complet du job :
gh run view --job <job_id> --repo NVIDIA/Megatron-LM --json name --jq .name
Si la sortie grep est clairsemée, télécharger les logs complets et chercher la
section FAILURES de pytest ou le dernier signal de sortie non-zéro.
4. Résoudre la PR déclencheur et l'auteur du test
PR déclencheur : la branche head de la run suit le pattern pull-request/<number>.
L'extraire et résoudre la PR :
gh run view <run_id> --repo NVIDIA/Megatron-LM --json headBranch --jq .headBranch
# → p. ex. "pull-request/4332"
# Extraire le numéro de PR et récupérer les métadonnées :
gh pr view <pr_number> --repo NVIDIA/Megatron-LM --json number,title,url \
--jq '{number: .number, title: .title, url: .url}'
Auteur du fichier de test : trouver le login GitHub de celui qui a dernièrement modifié
le fichier de test qui échoue. Le fichier peut ne pas exister sur main — d'abord
déterminer la branche de base de la PR, puis chercher à partir de là :
# 1. Obtenir la branche de base de la PR (p. ex. "main", "dev", "release/X.Y")
gh pr view <pr_number> --repo NVIDIA/Megatron-LM --json baseRefName --jq .baseRefName
# 2. Chercher les commits sur cette branche de base
gh api "repos/NVIDIA/Megatron-LM/commits?path=<test-file-path>&sha=<base-branch>&per_page=1" \
--jq '.[0] | {login: .author.login, name: .commit.author.name, sha: .sha}'
Si le résultat est vide (le fichier a été introduit par la PR elle-même), interroger les commits de la PR à la place :
gh api "repos/NVIDIA/Megatron-LM/pulls/<pr_number>/commits" \
--jq '[.[] | select(.files? // [] | any(.filename == "<test-file-path>"))] | .[0].author.login'
En dernier recours, lister les commits de la PR et choisir l'auteur du commit dont le message est le plus proche du fichier de test qui échoue.
5. Extraire la cause racine
À partir des logs, identifier :
- Test(s) échoué(s) : les lignes correspondant à
FAILED tests/...::...donnent les IDs de nœud pytest exacts. - Message d'erreur : l'échec d'assertion, le type d'exception ou le premier cadre de traceback significatif — le garder sous ~30 lignes.
- Nom du job : le nom du job GitHub Actions (p. ex.
tests/unit_tests/transformer/moe/**/*.py - latest). - Run / job URLs et PR URL : pour les liens dans le problème.
6. Vérifier les problèmes en doublon
Chercher les problèmes ouverts qui couvrent déjà le même test :
gh issue list --repo NVIDIA/Megatron-LM \
--state open \
--search "<failed-test-filename>" \
--json number,title,url \
--limit 10
- Si un problème ouvert correspondant existe, ne pas créer un nouveau. Signaler le problème existant à l'utilisateur et arrêter.
- Si aucune correspondance n'est trouvée, procéder à la création d'un nouveau problème.
7. Créer le problème
Passer --assignee <test-author-login> pour assigner le problème à l'auteur du fichier de test.
Inclure l'URL de la PR déclencheur dans le corps du problème.
gh issue create \
--repo NVIDIA/Megatron-LM \
--title "🐛 CI failure: <failed-test-node-id>" \
--label "bug" \
--assignee "<test-author-login>" \
--body "..."
Utiliser la structure de modèle de rapport de bug pour le corps :
**Describe the bug**
CI test `<failed-test-node-id>` failed in job [`<job-name>`](<job-url>).
Tag @NVIDIA/mcore-oncall to get oncall's attention to this issue.
**Failing run**
| Field | Value |
|-------|-------|
| PR | [#<pr_number>: <pr_title>](<pr_url>) |
| Run | [<run_id>](<run_url>) |
| Job | [<job_name>](<job_url>) |
**Error**
<core error message / traceback — 30 lines max>
**Steps/Code to reproduce bug**
Re-run the failing CI job linked above, or locally inside the dev container:
```bash
pytest <failed-test-node-id>
Additional context
Triaged automatically via /triage-issue.
Si plusieurs tests ont échoué dans le même job, lister chacun en tant que point
séparé sous "Describe the bug" et inclure les extraits d'erreur combinés. Assigner
le problème à l'auteur du fichier de test qui apparaît en premier dans la liste des échecs.
### 8. Rendre compte à l'utilisateur
Afficher l'URL du problème nouvellement créé (ou du doublon, s'il a été trouvé) pour que
l'utilisateur puisse le vérifier ou le partager.
## Directives importantes
- Ne jamais créer un problème si un doublon existe déjà — lier le problème existant à la place.
- Toujours inclure le lien vers la PR déclencheur dans le corps du problème.
- Toujours assigner le problème à l'auteur le plus récent du fichier de test. Si la recherche d'auteur échoue
(p. ex. le commit a été fait par un bot ou le login n'est pas disponible),
ignorer `--assignee` et le noter dans la section "Additional context".
- Garder l'extrait d'erreur concis (≤30 lignes). Tronquer les longs tracebacks et noter que le log complet
est disponible via l'URL du job.
- Ne pas deviner la cause racine — citer la sortie du log réelle textuellement.
- Si le job est encore en cours ou les logs ne sont pas disponibles, le dire et demander à l'utilisateur de réessayer une fois que la run est complète.