Triage CI Failure dans une GitHub Issue
Enquêter sur un job GitHub Actions défaillant, extraire la cause racine et déposer
une issue de bug bien structurée contre NVIDIA/Megatron-LM.
Workflow
1. Parser l'URL
L'argument est une URL GitHub Actions. Elle sera l'une des suivantes :
- 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, si présent, job_id.
2. Identifier les jobs défaillants
-
Si un
job_ida été fourni, utiliser ce job directement. -
Si seul un
run_ida été fourni, lister tous les jobs défaillants 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 tous les trier s'il le dit.
3. Récupérer les logs de défaillance
Pour chaque job défaillant, récupérer les logs et les affiner jusqu'à la défaillance :
# Récupérer le log brut et conserver 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 de grep est clairsemée, télécharger les logs complets et chercher la section pytest
FAILURES ou le dernier signal de sortie non-zéro.
4. Résoudre la PR de déclenchement et l'auteur du test
PR de déclenchement : la branche head de la run suit le motif pull-request/<number>.
L'extraire et résoudre la PR :
gh run view <run_id> --repo NVIDIA/Megatron-LM --json headBranch --jq .headBranch
# → ex. "pull-request/4332"
# Extraire le numéro 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 la personne qui a touché en dernier le fichier de test défaillant. 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 (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), requêter 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 se rapproche le plus du fichier de test défaillant.
5. Extraire la cause racine
À partir des logs, identifier :
- Test(s) défaillant(s) : les lignes correspondant à
FAILED tests/...::...donnent les ID de nœud pytest exacts. - Message d'erreur : l'échec d'assertion, le type d'exception, ou le premier frame de traceback significatif — le conserver sous ~30 lignes.
- Nom du job : le nom du job GitHub Actions (ex.
tests/unit_tests/transformer/moe/**/*.py - latest). - Run / job URLs et URL PR : pour lier dans l'issue.
6. Vérifier les issues dupliquées
Chercher les issues ouvertes 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 une issue ouverte correspondante existe, ne pas en créer une nouvelle. Signaler l'issue existante à l'utilisateur et arrêter.
- Si aucune correspondance n'est trouvée, procéder à la création d'une nouvelle issue.
7. Créer l'issue
Passer --assignee <test-author-login> pour assigner l'issue à l'auteur du fichier de test. Inclure l'URL de la PR de déclenchement dans le corps de l'issue.
gh issue create \
--repo NVIDIA/Megatron-LM \
--title "🐛 CI failure: <failed-test-node-id>" \
--label "bug" \
--assignee "<test-author-login>" \
--body "..."
Utiliser la structure du 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 the [@mcore-oncall](https://github.com/orgs/NVIDIA/teams/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, en lister chacun comme une puce séparée sous "Describe the bug" et inclure les extraits d'erreur combinés. Assigner l'issue à l'auteur du fichier de test qui apparaît en premier dans la liste de défaillance.
### 8. Rapporter à l'utilisateur
Afficher l'URL de l'issue nouvellement créée (ou du doublon, si trouvé) pour que l'utilisateur puisse l'examiner ou la partager.
## Recommandations importantes
- Ne jamais créer une issue si un doublon existe déjà — lier l'existante à la place.
- Toujours inclure le lien de la PR de déclenchement dans le corps de l'issue.
- Toujours assigner l'issue à l'auteur le plus récent du fichier de test. Si la recherche d'auteur échoue (ex. le commit a été fait par un bot ou le login est indisponible), 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 verbatim.
- Si le job est encore en cours ou les logs sont indisponibles, le dire et demander à l'utilisateur de réessayer une fois la run complétée.