ci-failure-retrieval

Par nvidia · skills

Récupère et diagnostique les échecs de tests CI des pull requests TensorRT-LLM via l'API GitHub et l'API Jenkins testReport. À utiliser lorsque l'utilisateur demande des informations sur les échecs CI d'une PR, souhaite consulter les détails des tests échoués, ou a besoin du stdout/stderr d'une exécution CI.

npx skills add https://github.com/nvidia/skills --skill ci-failure-retrieval

Récupération des Défaillances CI

Entrée : un numéro de PR ou une requête pour vérifier les défaillances CI. Exigence d'authentification : nécessite l'accès au réseau d'entreprise pour résoudre l'URL de base Jenkins. Sortie : un résumé des tests échoués avec les détails d'erreur, et optionnellement les stdout/stderr complets pour des défaillances spécifiques.

Important : SSL et Authentification

Jenkins nécessite SSL avec vérification de certificat désactivée. Utilisez toujours le contournement de contexte ssl en Python ou les flags -sk dans curl :

import ssl
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

L'approche curl -s retourne souvent des pages HTML de connexion ; préférez l'approche Python urllib avec contournement SSL.

Phase 0 — Obtenir les Informations de la Dernière Exécution CI

Déterminez d'abord le commit de la dernière exécution CI, le numéro de build et les comptages de passage/défaillance de haut niveau :

source ~/utils/github/set_github_token.sh

PR_NUM=<pr_number>

# Récupère le dernier commentaire du bot CI (contient le numéro de build et le commit)
gh api "repos/NVIDIA/TensorRT-LLM/issues/${PR_NUM}/comments" --paginate --jq \
  '[.[] | select(.user.login == "tensorrt-cicd") | select(.body | test("L0_MergeRequest_PR"))] | last | .body'

# Récupère le commit HEAD de la PR et son statut blossom-ci (comptages de passage/défaillance)
HEAD_SHA=$(gh api "repos/NVIDIA/TensorRT-LLM/pulls/${PR_NUM}" --jq '.head.sha')
gh api "repos/NVIDIA/TensorRT-LLM/commits/${HEAD_SHA}/statuses" --jq \
  '[.[] | select(.context == "blossom-ci")] | first | {state, description}'

Le champ description affiche les comptages agrégés comme "23969 passed, 1 failed, 8962 skipped".

Phase 1 — Obtenir le Numéro de Build Jenkins

Extrayez le numéro de build L0_MergeRequest_PR du commentaire du bot CI :

BUILD_NUM=$(gh api "repos/NVIDIA/TensorRT-LLM/issues/${PR_NUM}/comments" --paginate --jq \
  '[.[] | select(.user.login == "tensorrt-cicd") | select(.body | test("L0_MergeRequest_PR"))] | last | .body' \
  | grep -oP 'L0_MergeRequest_PR/\K\d+')

Phase 1.5 — Vérifier les Défaillances de Stage du Pipeline (avant d'explorer les détails des tests)

De nombreuses défaillances CI sont au niveau infrastructure (problèmes de nœud Slurm, arrêts de pipeline, épuisement des ressources) où aucun code de test n'est exécuté du tout. Vérifiez toujours d'abord les stages du pipeline :

import json, ssl, urllib.request

ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

JENKINS_BASE = "https://prod.blsm.nvidia.com/sw-tensorrt-top-1/job/LLM/job/main/job/L0_MergeRequest_PR"
BUILD_NUM = <build_number>

# Obtient l'aperçu des stages du pipeline
url = f"{JENKINS_BASE}/{BUILD_NUM}/wfapi/describe"
resp = urllib.request.urlopen(urllib.request.Request(url), context=ctx, timeout=30)
data = json.loads(resp.read())

print(f"Pipeline status: {data.get('status')}")
for stage in data.get('stages', []):
    status = stage.get('status', '')
    if status not in ('SUCCESS', 'SKIPPED', 'NOT_EXECUTED'):
        name = stage.get('name', '')
        print(f"  [{status}] {name}")
        if 'error' in stage:
            print(f"    Error: {stage['error']}")

Phase 1.6 — Analyse du Journal de Console (Très Précieuse pour les Défaillances Infrastructure)

Le journal de console Jenkins contient un résumé d'analyse des défaillances CI avec des sections comme ## Recommended Actions et ## Infrastructure Notes. C'est la source la plus précieuse pour comprendre les défaillances infrastructure :

url = f"{JENKINS_BASE}/{BUILD_NUM}/consoleText"
resp = urllib.request.urlopen(urllib.request.Request(url), context=ctx, timeout=30)
text = resp.read().decode('utf-8', errors='replace')

# Extrait les lignes liées aux défaillances de la fin du journal
for line in text[-8000:].split('\n'):
    lo = line.lower()
    if any(kw in lo for kw in ['fail', 'error', 'abort', 'likely cause',
                                'recommended action', 'infrastructure',
                                'no test code', 'stage result']):
        print(line.strip()[:300])

Sections clés à rechercher dans le journal de console :

  • Failing job / Failed stage : quel sous-job et stage Jenkins a échoué
  • Likely cause : analyse automatisée des causes racines (problèmes Slurm, timeouts de pipeline, etc.)
  • No test code was executed : confirme une défaillance infrastructure uniquement (aucun correctif de code nécessaire)
  • Recommended Actions : si re-déclencher CI ou investiguer les changements de code

Phase 2 — Interroger l'API testReport Jenkins pour les Défaillances de Tests

Ne procédez ici que si les phases 1.5/1.6 indiquent des défaillances de tests réelles (pas des problèmes infrastructure) :

url = f"{JENKINS_BASE}/{BUILD_NUM}/testReport/api/json"
resp = urllib.request.urlopen(urllib.request.Request(url), context=ctx, timeout=30)
data = json.loads(resp.read())

print(f'Summary: {data["passCount"]} passed, {data["failCount"]} failed, {data["skipCount"]} skipped')

failed = []
for suite in data.get('suites', []):
    for case in suite.get('cases', []):
        if case.get('status') in ('FAILED', 'REGRESSION'):
            failed.append(case)

if not failed:
    print('No test failures in testReport!')
else:
    print(f'Failed tests ({len(failed)}):')
    for f in failed:
        print(f'  - {f["className"]}.{f["name"]}')
        err = (f.get('errorDetails') or '')[:200]
        if err:
            print(f'    Error: {err}')

Phase 3 — Obtenir stdout/stderr Complets pour une Défaillance de Test Spécifique

Le errorStackTrace peut être incomplet quand les erreurs proviennent de sous-processus. Récupérez stdout et stderr pour le cas de test spécifique afin de trouver la vraie erreur :

for suite in data.get('suites', []):
    for case in suite.get('cases', []):
        if case.get('status') in ('FAILED', 'REGRESSION'):
            name = f'{case["className"]}.{case["name"]}'
            if '<search_term>' in name:
                print(f'=== {name} ===')
                print('--- Error ---')
                print(case.get('errorDetails', ''))
                print('--- Stack Trace ---')
                print(case.get('errorStackTrace', ''))
                print('--- Stdout (last 3000 chars) ---')
                print((case.get('stdout') or '')[-3000:])
                print('--- Stderr (last 3000 chars) ---')
                print((case.get('stderr') or '')[-3000:])
                break

Champs Disponibles par Cas de Test Échoué (API testReport Jenkins)

  • className, name : identifiant du test
  • status : FAILED ou REGRESSION
  • errorDetails : message d'erreur
  • errorStackTrace : trace de pile complète (peut être incomplète pour les erreurs de sous-processus)
  • stdout, stderr : sortie complète du test (peut être volumineux, vérifiez-les quand la trace de pile est insuffisante)

Motifs de Défaillance Courants

Motif Diagnostic Action
No test code was executed + erreurs Slurm Infrastructure : épuisement des ressources du nœud Slurm Re-déclencher CI
Stage ABORTED + Downstream job did not succeed Défaillance en cascade due à la politique fail-fast Corriger le stage cause racine, re-déclencher
newosproc / errno=11 / fork/exec Épuisement de la table des processus kernel sur le nœud de connexion Attendre et re-déclencher
testReport: 0 failed mais blossom-ci: N failed Défaillances au niveau stage, pas au niveau tests Vérifier Phase 1.5/1.6
testReport: N failed avec des noms de tests réels Défaillances du code de test réelles Investiguer les erreurs de test en Phase 3

Anti-Motifs

  • Ne devinez pas les URL Jenkins ; utilisez toujours la base connue https://prod.blsm.nvidia.com/sw-tensorrt-top-1/job/LLM/job/main/job/L0_MergeRequest_PR.
  • N'utilisez pas curl -s pour l'API Jenkins ; cela retourne des pages HTML de connexion. Utilisez Python urllib avec contournement SSL.
  • Ne passez pas directement à testReport (Phase 2) sans vérifier d'abord les stages du pipeline (Phase 1.5) — de nombreuses défaillances sont infrastructure uniquement avec zéro défaillances de tests.
  • N'arrêtez pas à errorStackTrace s'il mentionne des défaillances de wrapper génériques comme Process exited with status 1 ; vérifiez stdout et stderr pour la vraie erreur.
  • Ne récupérez pas tous les cas de test quand vous recherchez une défaillance spécifique ; utilisez le filtre <search_term> en Phase 3.

Skills similaires