Skip to content

LLVM Trunk Failure Analyzer #57

LLVM Trunk Failure Analyzer

LLVM Trunk Failure Analyzer #57

# Copyright 2024-2026, Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
# Analyzes failures in the LLVM trunk nightly workflow using Claude Code.
name: LLVM Trunk Failure Analyzer
on:
# zizmor: ignore[dangerous-triggers] - workflow_run is intentionally used to analyze nightly failures
workflow_run:
workflows: ["Nightly Linux tests / LLVM trunk"]
types:
- completed
workflow_dispatch:
inputs:
run_id:
description: 'Workflow run ID to analyze (leave empty for latest failed run)'
required: false
type: string
permissions: {}
jobs:
analyze-failure:
# Disabling this workflow for non ispc/ispc repo, since number of build submissions is limited.
# Only run if the nightly workflow failed, or if manually triggered
if: github.repository == 'ispc/ispc' && (github.event.workflow_run.conclusion == 'failure' || github.event_name == 'workflow_dispatch')
runs-on: ubuntu-latest
permissions:
contents: read
actions: read
issues: write
outputs:
issue_number: ${{ steps.create-issue.outputs.issue_number }}
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: '20'
- name: Determine run ID to analyze
id: get-run-id
env:
GH_TOKEN: ${{ github.token }}
INPUT_RUN_ID: ${{ inputs.run_id }}
WORKFLOW_RUN_ID: ${{ github.event.workflow_run.id }}
run: |
if [ -n "$INPUT_RUN_ID" ]; then
RUN_ID="$INPUT_RUN_ID"
elif [ -n "$WORKFLOW_RUN_ID" ]; then
RUN_ID="$WORKFLOW_RUN_ID"
else
# Find the latest failed run of the nightly workflow
RUN_ID=$(gh run list --workflow="linux-nightly-trunk.yml" --status=failure --limit=1 --json databaseId --jq '.[0].databaseId')
fi
echo "run_id=$RUN_ID" >> "$GITHUB_OUTPUT"
echo "Analyzing run ID: $RUN_ID"
- name: Download LLVM SHA artifact from failed run
id: download-sha
env:
GH_TOKEN: ${{ github.token }}
run: |
RUN_ID="${{ steps.get-run-id.outputs.run_id }}"
echo "Downloading LLVM SHA artifact from run $RUN_ID"
# Download the artifact
gh run download "$RUN_ID" --name llvm_commit_sha --dir ./artifacts || {
echo "Failed to download LLVM SHA artifact"
echo "current_sha=unknown" >> "$GITHUB_OUTPUT"
exit 0
}
if [ -f "./artifacts/llvm-commit-sha.txt" ]; then
CURRENT_SHA=$(cat ./artifacts/llvm-commit-sha.txt)
echo "Current LLVM SHA: $CURRENT_SHA"
echo "current_sha=$CURRENT_SHA" >> "$GITHUB_OUTPUT"
else
echo "LLVM SHA file not found"
echo "current_sha=unknown" >> "$GITHUB_OUTPUT"
fi
- name: Get previous successful run's LLVM SHA
id: get-previous-sha
env:
GH_TOKEN: ${{ github.token }}
run: |
# Find the latest successful run before the failed one
FAILED_RUN_ID="${{ steps.get-run-id.outputs.run_id }}"
FAILED_RUN_DATE=$(gh run view "$FAILED_RUN_ID" --json createdAt --jq '.createdAt')
echo "Looking for successful runs before $FAILED_RUN_DATE"
# Get successful runs and find one before the failed run
PREV_RUN_ID=$(gh run list --workflow="linux-nightly-trunk.yml" --status=success --limit=5 --json databaseId,createdAt \
--jq ".[] | select(.createdAt < \"$FAILED_RUN_DATE\") | .databaseId" | head -1)
if [ -z "$PREV_RUN_ID" ]; then
echo "No previous successful run found"
echo "previous_sha=unknown" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "Previous successful run ID: $PREV_RUN_ID"
# Download artifact from previous run
gh run download "$PREV_RUN_ID" --name llvm_commit_sha --dir ./prev_artifacts || {
echo "Failed to download previous LLVM SHA artifact"
echo "previous_sha=unknown" >> "$GITHUB_OUTPUT"
exit 0
}
if [ -f "./prev_artifacts/llvm-commit-sha.txt" ]; then
PREV_SHA=$(cat ./prev_artifacts/llvm-commit-sha.txt)
echo "Previous LLVM SHA: $PREV_SHA"
echo "previous_sha=$PREV_SHA" >> "$GITHUB_OUTPUT"
else
echo "Previous LLVM SHA file not found"
echo "previous_sha=unknown" >> "$GITHUB_OUTPUT"
fi
- name: Get recent ISPC commits
id: get-ispc-commits
env:
GH_TOKEN: ${{ github.token }}
run: |
# Get ISPC commits from last 24 hours
SINCE=$(date -u -d '24 hours ago' '+%Y-%m-%dT%H:%M:%SZ')
echo "Getting ISPC commits since $SINCE"
COMMITS=$(git log --since="$SINCE" --oneline HEAD 2>/dev/null || echo "")
if [ -z "$COMMITS" ]; then
# Fallback: get last 5 commits
COMMITS=$(git log --oneline -5 HEAD)
fi
echo "Recent ISPC commits:"
echo "$COMMITS"
# Save to file for the agent
echo "$COMMITS" > ispc-recent-commits.txt
- name: Run Claude Code analyzer
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GH_TOKEN: ${{ github.token }}
run: |
RUN_ID="${{ steps.get-run-id.outputs.run_id }}"
CURRENT_SHA="${{ steps.download-sha.outputs.current_sha }}"
PREVIOUS_SHA="${{ steps.get-previous-sha.outputs.previous_sha }}"
echo "=== LLVM Trunk Failure Analysis ==="
echo "Failed run ID: $RUN_ID"
echo "Current LLVM SHA: $CURRENT_SHA"
echo "Previous LLVM SHA: $PREVIOUS_SHA"
echo "=================================="
# Run Claude Code with the analyzer skill and capture output
if ! npx @anthropic-ai/claude-code --print \
"/analyze-llvm-trunk --run-id $RUN_ID --current-sha $CURRENT_SHA --previous-sha $PREVIOUS_SHA" \
> analysis_output.txt 2>&1; then
echo "::error::Claude Code analysis failed"
echo "=== Analysis Output ==="
cat analysis_output.txt
exit 1
fi
cat analysis_output.txt
- name: Create GitHub issue with analysis
id: create-issue
env:
GH_TOKEN: ${{ github.token }}
run: |
RUN_ID="${{ steps.get-run-id.outputs.run_id }}"
CURRENT_SHA="${{ steps.download-sha.outputs.current_sha }}"
RUN_URL="https://github.com/${{ github.repository }}/actions/runs/$RUN_ID"
# Check if an open issue already exists for LLVM trunk failure
EXISTING_ISSUE=$(gh issue list --label "llvm-trunk" --state open --limit 1 --json number --jq '.[0].number')
if [ -n "$EXISTING_ISSUE" ]; then
echo "Updating existing issue #$EXISTING_ISSUE"
{
echo "## New Failure Analysis ($(date -u '+%Y-%m-%d %H:%M UTC'))"
echo ""
echo "**Failed run:** $RUN_URL"
echo "**LLVM SHA:** \`$CURRENT_SHA\`"
echo ""
echo "<details>"
echo "<summary>Analysis Output</summary>"
echo ""
cat analysis_output.txt
echo ""
echo "</details>"
echo ""
echo "---"
echo "Generated with [Claude Code](https://claude.com/claude-code)"
} > issue_body.md
gh issue comment "$EXISTING_ISSUE" --body-file issue_body.md
echo "issue_number=$EXISTING_ISSUE" >> "$GITHUB_OUTPUT"
else
echo "Creating new issue"
{
echo "## LLVM Trunk Build Failure"
echo ""
echo "**Failed run:** $RUN_URL"
echo "**LLVM SHA:** \`$CURRENT_SHA\`"
echo ""
echo "## Analysis"
echo ""
cat analysis_output.txt
echo ""
echo "---"
echo "Generated with [Claude Code](https://claude.com/claude-code)"
} > issue_body.md
ISSUE_NUMBER=$(gh issue create \
--title "LLVM trunk nightly build failure" \
--label "llvm-trunk" \
--body-file issue_body.md | grep -oE '[0-9]+$')
echo "Created issue #$ISSUE_NUMBER"
echo "issue_number=$ISSUE_NUMBER" >> "$GITHUB_OUTPUT"
fi
request-fix:
# Request Claude to fix LLVM trunk failures via reusable workflow
needs: analyze-failure
if: success() && needs.analyze-failure.outputs.issue_number != ''
permissions:
contents: write
pull-requests: write
issues: write
actions: read
uses: ./.github/workflows/claude.yml
with:
prompt: "Fix issue #${{ needs.analyze-failure.outputs.issue_number }} and create a PR"
secrets: inherit