33# Reads SENTRY_AUTH_TOKEN from .env in the repo root.
44# Run via cron: 0 9 * * * /path/to/repo/scripts/sentry-autofix.sh
55
6- set -euo pipefail
6+ set -uo pipefail
77
88REPO_DIR=" $( cd " $( dirname " $0 " ) /.." && pwd) "
99LOG_FILE=" ${REPO_DIR} /.sentry-autofix.log"
1010SEEN_FILE=" ${REPO_DIR} /.sentry-seen-issues.json"
1111SENTRY_ORG=" gamarr"
1212
13- cd " $REPO_DIR "
14- git pull --rebase origin main 2> /dev/null || true
13+ log () { echo " $( date) : $1 " >> " $LOG_FILE " ; }
14+
15+ cd " $REPO_DIR " || { log " ERROR: Cannot cd to $REPO_DIR " ; exit 1; }
16+
17+ log " === Starting Sentry check ==="
18+
19+ # Pull latest
20+ if ! git pull --rebase origin main >> " $LOG_FILE " 2>&1 ; then
21+ log " WARNING: git pull failed, continuing with local state"
22+ fi
1523
1624# Load credentials
25+ if [ ! -f " $REPO_DIR /.env" ]; then
26+ log " ERROR: .env file not found at $REPO_DIR /.env"
27+ exit 1
28+ fi
1729set -a
1830source " $REPO_DIR /.env"
1931set +a
2032
21- : " ${SENTRY_AUTH_TOKEN:? Set SENTRY_AUTH_TOKEN in .env} "
33+ if [ -z " ${SENTRY_AUTH_TOKEN:- } " ]; then
34+ log " ERROR: SENTRY_AUTH_TOKEN not set in .env"
35+ exit 1
36+ fi
2237
23- log () { echo " $( date) : $1 " >> " $LOG_FILE " ; }
24- log " Checking Sentry for new issues..."
38+ log " Fetching unresolved issues from Sentry..."
2539
2640# Fetch unresolved issues
27- ISSUES=$( curl -sf -H " Authorization: Bearer ${SENTRY_AUTH_TOKEN} " \
28- " https://sentry.io/api/0/organizations/${SENTRY_ORG} /issues/?query=is:unresolved&sort=date&limit=10" )
41+ HTTP_CODE=$( curl -s -o /tmp/sentry-issues.json -w " %{http_code}" \
42+ -H " Authorization: Bearer ${SENTRY_AUTH_TOKEN} " \
43+ " https://sentry.io/api/0/organizations/${SENTRY_ORG} /issues/?query=is:unresolved&sort=date&limit=10" )
44+
45+ if [ " $HTTP_CODE " != " 200" ]; then
46+ log " ERROR: Sentry API returned HTTP $HTTP_CODE "
47+ [ -f /tmp/sentry-issues.json ] && cat /tmp/sentry-issues.json >> " $LOG_FILE "
48+ exit 1
49+ fi
50+
51+ ISSUES=$( cat /tmp/sentry-issues.json)
52+ ISSUE_COUNT=$( echo " $ISSUES " | python3 -c " import json,sys; print(len(json.load(sys.stdin)))" 2>&1 )
53+ log " Fetched $ISSUE_COUNT unresolved issues"
2954
3055# Load seen IDs
3156if [ -f " $SEEN_FILE " ]; then
32- SEEN=$( cat " $SEEN_FILE " )
57+ SEEN=$( cat " $SEEN_FILE " )
58+ SEEN_COUNT=$( echo " $SEEN " | python3 -c " import json,sys; print(len(json.load(sys.stdin)))" 2>&1 )
59+ log " Loaded $SEEN_COUNT seen issue IDs"
3360else
34- SEEN=" []"
61+ SEEN=" []"
62+ log " No seen issues file, starting fresh"
3563fi
3664
3765# Find new error-level issues not in seen list
@@ -43,12 +71,17 @@ seen_ids = set(str(s) for s in seen)
4371new = [i for i in issues if str(i['id']) not in seen_ids and i['level'] == 'error']
4472if not new:
4573 sys.exit(1)
74+ for i in new:
75+ print(f\" - [{i['id']}] {i['title']} (count: {i['count']})\" , file=sys.stderr)
4676print(json.dumps([{'id': i['id'], 'title': i['title'], 'count': i['count'], 'firstSeen': i['firstSeen']} for i in new]))
47- " 2> /dev/null ) || {
48- log " No new issues."
77+ " 2>> " $LOG_FILE " ) || {
78+ log " No new issues. Done. "
4979 exit 0
5080}
5181
82+ NEW_COUNT=$( echo " $NEW_ISSUES " | python3 -c " import json,sys; print(len(json.load(sys.stdin)))" )
83+ log " Found $NEW_COUNT new issue(s), fetching stack traces..."
84+
5285# Fetch stack traces for each new issue
5386DETAILS=$( echo " $NEW_ISSUES " | python3 -c "
5487import json, sys, subprocess
@@ -61,13 +94,20 @@ for issue in issues:
6194 capture_output=True, text=True)
6295 if result.returncode == 0:
6396 issue['event'] = json.loads(result.stdout)
97+ print(f'Fetched event for issue {iid}', file=sys.stderr)
98+ else:
99+ print(f'WARNING: Failed to fetch event for issue {iid} (exit {result.returncode})', file=sys.stderr)
64100print(json.dumps(issues, indent=2))
65- " )
101+ " 2>> " $LOG_FILE " )
66102
67- log " New issues found, invoking Claude..."
68- echo " $DETAILS " >> " $LOG_FILE "
103+ if [ -z " $DETAILS " ]; then
104+ log " ERROR: Failed to fetch issue details"
105+ exit 1
106+ fi
107+
108+ log " Invoking Claude to analyze and fix..."
69109
70- claude -p --model opus " New Sentry issues found. Here are the details:
110+ CLAUDE_OUTPUT= $( claude -p --model opus " New Sentry issues found. Here are the details:
71111
72112$DETAILS
73113
@@ -78,6 +118,11 @@ For each issue:
78118
79119After processing, update .sentry-seen-issues.json — append all new issue IDs (both fixed and skipped).
80120Commit all changes and push to main.
81- Keep fixes minimal. Do not refactor surrounding code." >> " $LOG_FILE " 2>&1
121+ Keep fixes minimal. Do not refactor surrounding code." 2>&1 ) || {
122+ log " ERROR: Claude exited with code $? "
123+ echo " $CLAUDE_OUTPUT " >> " $LOG_FILE "
124+ exit 1
125+ }
82126
83- log " Done."
127+ echo " $CLAUDE_OUTPUT " >> " $LOG_FILE "
128+ log " === Done ==="
0 commit comments