Skip to content

Commit a72a7ea

Browse files
randleeclaude
andcommitted
build: Add CI failure summary script and automation config
- Add .claude/scripts/ci-failure-summary.sh for quick CI failure diagnosis - Add .claude/ci-automation.yaml for CI automation configuration Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent e3ed27d commit a72a7ea

File tree

2 files changed

+183
-0
lines changed

2 files changed

+183
-0
lines changed

.claude/ci-automation.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# CI Automation Configuration for roslyn-diff
2+
# .NET 10 project with xUnit tests
3+
4+
upstream_branch: main
5+
build_command: dotnet build --configuration Release
6+
test_command: dotnet test --configuration Release --no-build
7+
warn_patterns:
8+
- "warning CS"
9+
- "warning NU"
10+
allow_warnings: false
11+
auto_fix_enabled: true
12+
repo_root: .
13+
14+
# Stack detection
15+
stack: dotnet
16+
solution_file: roslyn-diff.sln
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
#!/bin/bash
2+
# CI Failure Summary Script
3+
# Extracts concise failure information from GitHub Actions logs
4+
# Usage: ./ci-failure-summary.sh <PR_NUMBER|RUN_ID> [--verbose]
5+
6+
set -e
7+
8+
# Colors for output
9+
RED='\033[0;31m'
10+
YELLOW='\033[1;33m'
11+
GREEN='\033[0;32m'
12+
CYAN='\033[0;36m'
13+
BOLD='\033[1m'
14+
NC='\033[0m' # No Color
15+
16+
VERBOSE=false
17+
INPUT="$1"
18+
19+
if [[ "$2" == "--verbose" ]]; then
20+
VERBOSE=true
21+
fi
22+
23+
if [[ -z "$INPUT" ]]; then
24+
echo -e "${RED}Usage: $0 <PR_NUMBER|RUN_ID> [--verbose]${NC}"
25+
echo " PR_NUMBER: e.g., 29"
26+
echo " RUN_ID: e.g., 12345678"
27+
exit 1
28+
fi
29+
30+
# Determine if input is PR number or run ID
31+
if [[ "$INPUT" =~ ^[0-9]+$ ]] && [[ ${#INPUT} -lt 6 ]]; then
32+
# Likely a PR number (< 6 digits)
33+
PR_NUM="$INPUT"
34+
echo -e "${CYAN}=== CI Failure Summary for PR #${PR_NUM} ===${NC}\n"
35+
36+
# Get PR info
37+
PR_INFO=$(gh pr view "$PR_NUM" --json title,headRefName,baseRefName,state 2>/dev/null || echo "{}")
38+
if [[ "$PR_INFO" != "{}" ]]; then
39+
TITLE=$(echo "$PR_INFO" | jq -r '.title')
40+
HEAD=$(echo "$PR_INFO" | jq -r '.headRefName')
41+
BASE=$(echo "$PR_INFO" | jq -r '.baseRefName')
42+
echo -e "${BOLD}PR:${NC} $TITLE"
43+
echo -e "${BOLD}Branch:${NC} $HEAD$BASE\n"
44+
fi
45+
46+
# Get check status
47+
echo -e "${BOLD}Check Status:${NC}"
48+
gh pr checks "$PR_NUM" 2>/dev/null | while read -r line; do
49+
if echo "$line" | grep -q "fail\|X"; then
50+
echo -e " ${RED}${NC} $line"
51+
elif echo "$line" | grep -q "pass\|✓"; then
52+
echo -e " ${GREEN}${NC} $line"
53+
else
54+
echo " $line"
55+
fi
56+
done
57+
echo ""
58+
59+
# Get the failed run ID
60+
RUN_ID=$(gh run list --branch "$(echo "$PR_INFO" | jq -r '.headRefName')" --limit 1 --json databaseId,conclusion --jq '.[0].databaseId' 2>/dev/null)
61+
else
62+
# Assume it's a run ID
63+
RUN_ID="$INPUT"
64+
echo -e "${CYAN}=== CI Failure Summary for Run #${RUN_ID} ===${NC}\n"
65+
fi
66+
67+
if [[ -z "$RUN_ID" ]]; then
68+
echo -e "${YELLOW}No recent runs found${NC}"
69+
exit 0
70+
fi
71+
72+
# Get run status
73+
RUN_INFO=$(gh run view "$RUN_ID" --json conclusion,status,jobs 2>/dev/null || echo "{}")
74+
CONCLUSION=$(echo "$RUN_INFO" | jq -r '.conclusion // "in_progress"')
75+
STATUS=$(echo "$RUN_INFO" | jq -r '.status')
76+
77+
echo -e "${BOLD}Run #${RUN_ID}:${NC} $STATUS ($CONCLUSION)\n"
78+
79+
# List failed jobs
80+
echo -e "${BOLD}Failed Jobs:${NC}"
81+
FAILED_JOBS=$(echo "$RUN_INFO" | jq -r '.jobs[] | select(.conclusion == "failure") | .name' 2>/dev/null)
82+
if [[ -z "$FAILED_JOBS" ]]; then
83+
echo -e " ${GREEN}No failed jobs${NC}\n"
84+
else
85+
echo "$FAILED_JOBS" | while read -r job; do
86+
echo -e " ${RED}${NC} $job"
87+
done
88+
echo ""
89+
fi
90+
91+
# Get failed logs and parse them
92+
echo -e "${BOLD}Failure Details:${NC}"
93+
FAILED_LOG=$(gh run view "$RUN_ID" --log-failed 2>/dev/null || echo "")
94+
95+
if [[ -z "$FAILED_LOG" ]]; then
96+
echo -e " ${GREEN}No failure logs available${NC}"
97+
exit 0
98+
fi
99+
100+
# Save raw log for verbose mode
101+
if [[ "$VERBOSE" == true ]]; then
102+
echo "$FAILED_LOG" > /tmp/ci-failure-raw.log
103+
echo -e " ${CYAN}Raw log saved to /tmp/ci-failure-raw.log${NC}\n"
104+
fi
105+
106+
# Extract .NET test failures
107+
echo -e "\n${YELLOW}── Test Failures ──${NC}"
108+
TEST_FAILURES=$(echo "$FAILED_LOG" | grep -E "Failed\s+\w+|✗.*\[FAIL\]|\[xUnit.*\].*Failed" | head -20 || true)
109+
if [[ -n "$TEST_FAILURES" ]]; then
110+
echo "$TEST_FAILURES" | while read -r line; do
111+
# Clean up the line - remove timestamps and job prefixes
112+
CLEAN=$(echo "$line" | sed 's/^.*\t//' | sed 's/^[0-9T:.-]*Z //')
113+
echo -e " ${RED}${NC} $CLEAN"
114+
done
115+
else
116+
echo -e " ${GREEN}No test failures found${NC}"
117+
fi
118+
119+
# Extract assertion errors (expected vs actual)
120+
echo -e "\n${YELLOW}── Assertion Details ──${NC}"
121+
ASSERTIONS=$(echo "$FAILED_LOG" | grep -iE "Expected.*to be|Expected.*but found|Actual:|expected.*got|should be.*but|difference of" | grep -v "Passed" | head -15 || true)
122+
if [[ -n "$ASSERTIONS" ]]; then
123+
echo "$ASSERTIONS" | while read -r line; do
124+
CLEAN=$(echo "$line" | sed 's/^.*\t//' | sed 's/^[0-9T:.-]*Z //')
125+
echo " $CLEAN"
126+
done
127+
else
128+
echo -e " ${GREEN}No assertion details found${NC}"
129+
fi
130+
131+
# Extract build errors
132+
echo -e "\n${YELLOW}── Build Errors ──${NC}"
133+
BUILD_ERRORS=$(echo "$FAILED_LOG" | grep -E "error CS[0-9]+:|error NU[0-9]+:|error MSB[0-9]+:" | head -10 || true)
134+
if [[ -n "$BUILD_ERRORS" ]]; then
135+
echo "$BUILD_ERRORS" | while read -r line; do
136+
CLEAN=$(echo "$line" | sed 's/^.*\t//' | sed 's/^[0-9T:.-]*Z //')
137+
echo -e " ${RED}$CLEAN${NC}"
138+
done
139+
else
140+
echo -e " ${GREEN}No build errors found${NC}"
141+
fi
142+
143+
# Extract timeout/performance issues
144+
echo -e "\n${YELLOW}── Timeouts/Performance ──${NC}"
145+
TIMEOUTS=$(echo "$FAILED_LOG" | grep -iE "timeout|timed out|exceeded|too slow|milliseconds|elapsed" | grep -iE "fail|error|exceed" | grep -v "Passed" | head -10 || true)
146+
if [[ -n "$TIMEOUTS" ]]; then
147+
echo "$TIMEOUTS" | while read -r line; do
148+
CLEAN=$(echo "$line" | sed 's/^.*\t//' | sed 's/^[0-9T:.-]*Z //')
149+
echo -e " ${YELLOW}$CLEAN${NC}"
150+
done
151+
else
152+
echo -e " ${GREEN}No timeout issues found${NC}"
153+
fi
154+
155+
# Extract exception stack traces (just the exception line, not full stack)
156+
echo -e "\n${YELLOW}── Exceptions ──${NC}"
157+
EXCEPTIONS=$(echo "$FAILED_LOG" | grep -E "Exception:|Error:|System\.\w+Exception" | grep -v "^[[:space:]]*at " | head -10 || true)
158+
if [[ -n "$EXCEPTIONS" ]]; then
159+
echo "$EXCEPTIONS" | while read -r line; do
160+
CLEAN=$(echo "$line" | sed 's/^.*\t//' | sed 's/^[0-9T:.-]*Z //')
161+
echo -e " ${RED}$CLEAN${NC}"
162+
done
163+
else
164+
echo -e " ${GREEN}No exceptions found${NC}"
165+
fi
166+
167+
echo -e "\n${CYAN}=== End Summary ===${NC}"

0 commit comments

Comments
 (0)