Skip to content

Commit 4e73d92

Browse files
authored
Merge pull request #694 from code-payments/feat/triage-specific-issue
feat(triage): support triaging a specific Bugsnag issue by URL or ID
2 parents 5010798 + eec2bcb commit 4e73d92

2 files changed

Lines changed: 71 additions & 27 deletions

File tree

.claude/skills/triage/SKILL.md

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
---
22
name: triage
33
description: >
4-
Fetch the top open Bugsnag production issue, investigate with evidence from
5-
stack traces / logs / breadcrumbs, propose a fix direction, route through
6-
domain experts, and write a lean review brief.
4+
Triage a Bugsnag production issue — either the top open issue or a specific
5+
issue by URL/ID. Investigate with evidence from stack traces / logs /
6+
breadcrumbs, propose a fix direction, route through domain experts, and write
7+
a lean review brief.
78
allowed-tools:
89
- Bash
910
- Read
@@ -21,9 +22,19 @@ allowed-tools:
2122
You are a senior Android engineer performing daily Bugsnag triage for the
2223
Flipcash Android app. Follow the steps below exactly.
2324

24-
## Step 1 — Fetch the top open issue
25+
## Step 1 — Fetch the issue
2526

26-
Run the helper script:
27+
If the user provided a Bugsnag URL or error ID, pass it to the helper script:
28+
29+
```bash
30+
# Specific issue by URL
31+
bash .claude/skills/triage/scripts/bugsnag-top.sh --url "https://app.bugsnag.com/org/project/errors/abc123"
32+
33+
# Specific issue by error ID
34+
bash .claude/skills/triage/scripts/bugsnag-top.sh --error-id abc123
35+
```
36+
37+
Otherwise, fetch the top open issue automatically:
2738

2839
```bash
2940
bash .claude/skills/triage/scripts/bugsnag-top.sh

.claude/skills/triage/scripts/bugsnag-top.sh

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
# ./bugsnag-top.sh --all # top open error, production, all versions
1010
# ./bugsnag-top.sh --since 2026-05-01T00:00:00Z # custom since filter
1111
# ./bugsnag-top.sh --severity error # filter by severity
12+
# ./bugsnag-top.sh --error-id <id> # fetch a specific error by ID
13+
# ./bugsnag-top.sh --url <bugsnag_url> # fetch a specific error by Bugsnag URL
1214

1315
set -euo pipefail
1416

@@ -63,13 +65,25 @@ RELEASE_STAGE="production"
6365
SEVERITY=""
6466
SINCE=""
6567
ALL_VERSIONS=false
68+
EXPLICIT_ERROR_ID=""
6669

6770
while [[ $# -gt 0 ]]; do
6871
case "$1" in
6972
--internal) RELEASE_STAGE="production"; SINCE=""; ALL_VERSIONS=true; shift ;;
7073
--severity) SEVERITY="$2"; shift 2 ;;
7174
--all) ALL_VERSIONS=true; shift ;;
7275
--since) SINCE="$2"; shift 2 ;;
76+
--error-id) EXPLICIT_ERROR_ID="$2"; shift 2 ;;
77+
--url)
78+
# Extract error ID from a Bugsnag dashboard URL
79+
# e.g. https://app.bugsnag.com/org/project/errors/abc123def456
80+
EXPLICIT_ERROR_ID=$(echo "$2" | grep -oE '/errors/([a-f0-9]+)' | sed 's|/errors/||')
81+
if [[ -z "$EXPLICIT_ERROR_ID" ]]; then
82+
echo "ERROR: Could not extract error ID from URL: $2" >&2
83+
exit 1
84+
fi
85+
shift 2
86+
;;
7387
*) echo "Unknown option: $1" >&2; exit 1 ;;
7488
esac
7589
done
@@ -112,30 +126,49 @@ api() {
112126
return 1
113127
}
114128

115-
# ── Fetch top open error ──────────────────────────────────────────────
116-
FILTERS="filters[error.status][]=open&filters[app.release_stage][]=${RELEASE_STAGE}"
117-
if [[ -n "$SEVERITY" ]]; then
118-
FILTERS="${FILTERS}&filters[event.severity][]=${SEVERITY}"
119-
fi
120-
if [[ -n "$SINCE" ]]; then
121-
FILTERS="${FILTERS}&filters[event.since][]=${SINCE}"
122-
fi
123-
124-
ERRORS_URL="${API_BASE}/projects/${PROJECT_ID}/errors?${FILTERS}&sort=events&direction=desc&per_page=1"
125-
ERRORS_JSON=$(api "$ERRORS_URL")
126-
127-
if [[ -z "$ERRORS_JSON" ]] || ! echo "$ERRORS_JSON" | jq -e '.[0]' >/dev/null 2>&1; then
128-
echo "No open errors found for release_stage=${RELEASE_STAGE}" >&2
129-
exit 1
129+
# ── Fetch error ───────────────────────────────────────────────────────
130+
if [[ -n "$EXPLICIT_ERROR_ID" ]]; then
131+
# Fetch a specific error by ID
132+
ERROR_URL="${API_BASE}/projects/${PROJECT_ID}/errors/${EXPLICIT_ERROR_ID}"
133+
ERROR_JSON=$(api "$ERROR_URL")
134+
135+
if [[ -z "$ERROR_JSON" ]] || ! echo "$ERROR_JSON" | jq -e '.id' >/dev/null 2>&1; then
136+
echo "ERROR: Could not fetch error ${EXPLICIT_ERROR_ID}" >&2
137+
exit 1
138+
fi
139+
140+
ERROR_ID="$EXPLICIT_ERROR_ID"
141+
TITLE=$(echo "$ERROR_JSON" | jq -r '(.error_class // "") + ": " + (.message // "")')
142+
SEVERITY_VAL=$(echo "$ERROR_JSON" | jq -r '.severity')
143+
EVENTS=$(echo "$ERROR_JSON" | jq -r '.events')
144+
USERS=$(echo "$ERROR_JSON" | jq -r '.users')
145+
FIRST_SEEN=$(echo "$ERROR_JSON" | jq -r '.first_seen')
146+
else
147+
# Fetch top open error
148+
FILTERS="filters[error.status][]=open&filters[app.release_stage][]=${RELEASE_STAGE}"
149+
if [[ -n "$SEVERITY" ]]; then
150+
FILTERS="${FILTERS}&filters[event.severity][]=${SEVERITY}"
151+
fi
152+
if [[ -n "$SINCE" ]]; then
153+
FILTERS="${FILTERS}&filters[event.since][]=${SINCE}"
154+
fi
155+
156+
ERRORS_URL="${API_BASE}/projects/${PROJECT_ID}/errors?${FILTERS}&sort=events&direction=desc&per_page=1"
157+
ERRORS_JSON=$(api "$ERRORS_URL")
158+
159+
if [[ -z "$ERRORS_JSON" ]] || ! echo "$ERRORS_JSON" | jq -e '.[0]' >/dev/null 2>&1; then
160+
echo "No open errors found for release_stage=${RELEASE_STAGE}" >&2
161+
exit 1
162+
fi
163+
164+
ERROR_ID=$(echo "$ERRORS_JSON" | jq -r '.[0].id')
165+
TITLE=$(echo "$ERRORS_JSON" | jq -r '.[0] | (.error_class // "") + ": " + (.message // "")')
166+
SEVERITY_VAL=$(echo "$ERRORS_JSON" | jq -r '.[0].severity')
167+
EVENTS=$(echo "$ERRORS_JSON" | jq -r '.[0].events')
168+
USERS=$(echo "$ERRORS_JSON" | jq -r '.[0].users')
169+
FIRST_SEEN=$(echo "$ERRORS_JSON" | jq -r '.[0].first_seen')
130170
fi
131171

132-
ERROR_ID=$(echo "$ERRORS_JSON" | jq -r '.[0].id')
133-
TITLE=$(echo "$ERRORS_JSON" | jq -r '.[0] | (.error_class // "") + ": " + (.message // "")')
134-
SEVERITY_VAL=$(echo "$ERRORS_JSON" | jq -r '.[0].severity')
135-
EVENTS=$(echo "$ERRORS_JSON" | jq -r '.[0].events')
136-
USERS=$(echo "$ERRORS_JSON" | jq -r '.[0].users')
137-
FIRST_SEEN=$(echo "$ERRORS_JSON" | jq -r '.[0].first_seen')
138-
139172
# ── Fetch latest event for this error ─────────────────────────────────
140173
EVENTS_URL="${API_BASE}/projects/${PROJECT_ID}/errors/${ERROR_ID}/events?sort=timestamp&direction=desc&per_page=1"
141174
EVENTS_JSON=$(api "$EVENTS_URL")

0 commit comments

Comments
 (0)