LLVM Trunk Failure Analyzer #47
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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 |