Skip to main content

post-daily-new-issues

Post the daily digest of new Sentry issues for the current stable release to an on-call Slack channel. Use when the user asks to run or post the daily stable Sentry digest for on-call.

소스 정보

저장소
warpdotdev/client-release-agent-oss
최근 소스 활동
2026년 7월 8일 15:54
감지된 SKILL.md 언어
영어
스타
3
포크
1

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
2 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
post-daily-new-issues
description
Post the daily digest of new Sentry issues for the current stable release to an on-call Slack channel. Use when the user asks to run or post the daily stable Sentry digest for on-call.
# post-daily-new-issues Post a daily digest of *new* Sentry issues for the current release on **`$DIGEST_CHANNEL`** (default `stable`) to an on-call Slack channel, tagging the on-call usergroup. The digest is **scoped to a single calendar date** so a scheduled agent can run this once per weekday without re-reporting issues that were already shared on a previous day. ## Configuration This skill reads environment-specific values from environment variables (see the repo `README.md`): - `SLACK_BOT_TOKEN` — Slack bot token with `channels:read`, `chat:write`, `usergroups:read` scopes. - `SENTRY_AUTH_TOKEN` — Sentry auth token with `event:read` and `project:read` scopes. Used to call the Sentry REST API directly. - `SENTRY_ORG` — Sentry org slug. - `SENTRY_PROJECT` — Sentry project slug (e.g. your release client project). - `SENTRY_PROJECT_ID` — numeric Sentry project ID (used to build release URLs). - `RELEASE_SLACK_CHANNEL` — Slack channel name (or ID) to post the digest in. - `ONCALL_SLACK_GROUP` — Slack usergroup handle for the on-call (e.g. `oncall-primary`). - `RELEASE_VERSIONS_URL` — optional public URL returning a JSON document with the current release version. Omit if you pass a version explicitly. - `DIGEST_CHANNEL` — channel whose release the digest reports on (default `stable`); also selects the version key read from `RELEASE_VERSIONS_URL`. ## Step 0: Decide whether to run today (weekend skip) This skill is intentionally a no-op on Saturday and Sunday. Compute the day of week in UTC: ```bash DOW=$(date -u +%u) # 1=Mon ... 7=Sun ``` - If `DOW` is `6` (Sat) or `7` (Sun): print a short note (e.g. `"Skipping: weekend"`) and exit without posting to Slack. - Otherwise continue. If the caller passed an explicit target date (see Step 2), skip this step entirely and use what they provided. ## Step 1: Find the current release version If `RELEASE_VERSIONS_URL` is set, read the current version for `$DIGEST_CHANNEL` from it. The exact JSON path depends on your release metadata format; the channel key is selected by `$DIGEST_CHANNEL`, for example: ```bash RELEASE_VERSION=$(curl -fsS "$RELEASE_VERSIONS_URL" | jq -r --arg ch "$DIGEST_CHANNEL" '.[$ch].version') ``` `RELEASE_VERSION` looks like `v0.YYYY.MM.DD.HH.MM.stable_NN` (a documented example template — adjust to match the version scheme your release pipeline emits). If `RELEASE_VERSIONS_URL` is unset, ask the user for the current release version. If the field is missing or `curl` fails, stop and surface the error — do not post a partial digest. ## Step 2: Compute the target date window The window is a half-open UTC interval `[START_DATE, END_DATE)` (i.e. `firstSeen >= START_DATE AND firstSeen < END_DATE`). Both are `YYYY-MM-DD` strings. The default behavior depends on which weekday the agent is running: - **Tue–Fri** (`DOW` 2–5): report yesterday only. - `START_DATE` = yesterday (UTC), `END_DATE` = today (UTC). - **Mon** (`DOW` 1): report Saturday + Sunday + the previous Monday's overnight, because the agent did not run on the weekend. - `START_DATE` = 3 days ago (UTC, that Saturday), `END_DATE` = today (UTC, that Monday). On macOS (BSD `date`): ```bash TODAY=$(date -u +%Y-%m-%d) if [ "$DOW" = "1" ]; then START_DATE=$(date -u -v-3d +%Y-%m-%d) # Saturday else START_DATE=$(date -u -v-1d +%Y-%m-%d) # Yesterday fi END_DATE=$TODAY ``` On Linux (GNU `date`, e.g. inside a remote environment): ```bash TODAY=$(date -u +%Y-%m-%d) if [ "$DOW" = "1" ]; then START_DATE=$(date -u -d '3 days ago' +%Y-%m-%d) else START_DATE=$(date -u -d 'yesterday' +%Y-%m-%d) fi END_DATE=$TODAY ``` **Override**: if the user explicitly asks for a different window (e.g. "post the digest for 2026-04-25"), use their dates instead and skip the weekend check. ## Step 3: Fetch new issues from Sentry Call the Sentry REST API directly with `$SENTRY_AUTH_TOKEN`. The query string must include both: 1. `firstRelease:<RELEASE_VERSION>` — restricts to issues whose first-seen release matches the live release build (this matches Sentry's "New Issues" tab on the release page). 2. `firstSeen:>=START_DATE firstSeen:<END_DATE` — narrows to the target window so already-reported issues from previous days are excluded. This is the **noise-control** mechanism; do not omit it. Sort by frequency (`sort=freq`) and request `limit=100` so the true total and the top 3 are both stable even if there's a long tail of one-event issues. ```bash QUERY="firstRelease:${RELEASE_VERSION} firstSeen:>=${START_DATE} firstSeen:<${END_DATE}" ISSUES_JSON=$(curl -fsS -G "https://sentry.io/api/0/projects/${SENTRY_ORG}/${SENTRY_PROJECT}/issues/" \ -H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \ --data-urlencode "query=$QUERY" \ --data-urlencode "sort=freq" \ --data-urlencode "limit=100") ``` The response is a JSON array. Each element has at least: `shortId`, `title`, `count` (event count, as a string), `userCount`, `firstSeen`, `lastSeen`, `permalink`. Parse it with `jq`. **If the array is empty, exit silently — do NOT post anything to Slack.** Print a short note like `"No new issues in window; skipping post"` so the run log makes the no-op visible, then stop. The on-call channel should only get a message when there's something to act on; an empty digest just adds noise. ## Step 4: Compute the total and pick the top 3 The message has two distinct numbers, and they must come from different slices of the response: - **`TOTAL_NEW_ISSUES`** — the full count of new issues in the window (used in the "N new issues since …" summary line). Compute this from the entire array, **before** any truncation. - **Top 3 issues** — the first 3 entries by event count, used to populate the bullet list. The list is intentionally short to keep the digest scannable; the on-call clicks through to Sentry for the long tail. For each of the top 3, capture: - Short ID from `.shortId` - Title from `.title` — truncate to ~140 chars on a single line - Event count from `.count` (cast to int) - User count from `.userCount` - Issue URL: prefer `.permalink` if present, else build it as `https://${SENTRY_ORG}.sentry.io/issues/<SHORT_ID>` If fewer than 3 issues exist, include all of them. Example `jq` to compute both numbers in one pass: ```bash TOTAL_NEW_ISSUES=$(printf '%s' "$ISSUES_JSON" | jq 'length') BULLETS=$(printf '%s' "$ISSUES_JSON" | jq -r --arg org "$SENTRY_ORG" ' [.[] | { short: .shortId, title: (.title | gsub("\n"; " ") | .[0:140]), events: (.count | tonumber), users: .userCount, url: (.permalink // ("https://" + $org + ".sentry.io/issues/" + .shortId)) }] | sort_by(-.events) | .[0:3] | map("• <\(.url)|\(.short)> — \(.events) events, \(.users) users — \(.title)") | join("\n") ') ``` ## Step 5: Resolve Slack IDs Resolve once per run. If the channel ID and subteam ID are stable in your environment you may cache them, but always validate they still match. ```bash # Channel ID for $RELEASE_SLACK_CHANNEL CHANNEL_ID=$(curl -s -H "Authorization: Bearer $SLACK_BOT_TOKEN" \ "https://slack.com/api/conversations.list?types=public_channel,private_channel&limit=1000" | \ jq -r --arg name "$RELEASE_SLACK_CHANNEL" '.channels[] | select(.name==$name) | .id') # Subteam ID for the on-call usergroup SUBTEAM_ID=$(curl -s -H "Authorization: Bearer $SLACK_BOT_TOKEN" \ "https://slack.com/api/usergroups.list" | \ jq -r --arg handle "$ONCALL_SLACK_GROUP" '.usergroups[] | select(.handle==$handle) | .id') ``` If either lookup is empty, surface the error and stop — do not guess IDs. ## Step 6: Format and post the message Use Slack Block Kit. The mention must be `<!subteam^${SUBTEAM_ID}>` so it actually pings the on-call group. Build a `text` fallback for notifications and search. Build the Sentry release link first — every message must include it so the on-call can jump straight into the filtered "new issues" view: ```bash RELEASE_URL="https://${SENTRY_ORG}.sentry.io/explore/releases/${RELEASE_VERSION}/?issuesType=new&project=${SENTRY_PROJECT_ID}" ``` The `issuesType=new` query param is what pre-selects the **New Issues** tab; do not omit it. `project=${SENTRY_PROJECT_ID}` is the numeric ID for your Sentry project. Message structure: 1. **Header**: `<RELEASE_VERSION>: new Sentry issues for <date or range>` 2. **Section** with the subteam mention and a one-line summary that uses the **true total**, not the bullet count. Example: `<!subteam^S012345> — ${TOTAL_NEW_ISSUES} new issues since <START_DATE> · <RELEASE_URL|View in Sentry>` On a Monday run, phrase the window as `since Saturday` instead of a bare date. 3. **Section** listing only the **top 3** issues by event count, one per line, in this format: ``` • <ISSUE_URL|SHORT_ID> — <events> events, <users> users — <title> ``` 4. **Section** with a triage reminder, e.g.: `_Please <${RELEASE_URL}|review the full New Issues tab in Sentry> and triage._` This is what tells the on-call the bullets are only a sample and that they need to click through. Use Slack mrkdwn link syntax (`<URL|text>`) inside `mrkdwn` blocks. Keep titles on a single line; truncate with `…` if needed. If `TOTAL_NEW_ISSUES` is zero, do not reach this step — the skill exits in Step 3 without posting. There is no "all clear" message; silence is the all-clear signal. Date display: - Tue–Fri: show `START_DATE` (e.g. `2026-04-28 (UTC)`). - Mon: show the range, e.g. `Sat 2026-04-25 – Mon 2026-04-27 (UTC)`. Post as a **top-level** message (no `thread_ts`). Suppress link previews so the message stays compact — with several Sentry links per post, unfurls would dominate the channel: ```bash curl -s -X POST \ -H "Authorization: Bearer $SLACK_BOT_TOKEN" \ -H "Content-Type: application/json" \ --data "$(jq -n \ --arg channel "$CHANNEL_ID" \ --arg text "$TEXT_FALLBACK" \ --argjson blocks "$BLOCKS_JSON" \ '{channel: $channel, text: $text, blocks: $blocks, unfurl_links: false, unfurl_media: false}')" \ "https://slack.com/api/chat.postMessage" | jq '{ok, ts, error}' ``` `unfurl_links: false` blocks regular URL previews; `unfurl_media: false` blocks image/video previews. Both are required — omitting either lets Slack render whichever class of preview it didn't see suppressed. If `ok` is false, log the `error` field and stop. Common failures: `not_in_channel` (invite the bot), `missing_scope`, `channel_not_found`. ## Step 7: Confirm Fetch and print the permalink so a human (or downstream agent) can click into the post: ```bash curl -s -H "Authorization: Bearer $SLACK_BOT_TOKEN" \ "https://slack.com/api/chat.getPermalink?channel=$CHANNEL_ID&message_ts=<MESSAGE_TS>" | \ jq -r '.permalink' ``` ## Notes - **Why scope by `firstSeen` and not just `firstRelease`?** Without the date filter, every daily run would re-post the same long-lived issues from earlier in the release's lifetime. Filtering by `firstSeen` on the target date is what makes the digest actionable and not noisy. - **Why bundle the weekend on Monday instead of running on Sat/Sun?** If the on-call rotation is staffed Mon–Fri, weekend posts would go unread. Bundling on Monday surfaces anything that broke over the weekend in a single message. - **Manual reruns**: if the user provides explicit `START_DATE` / `END_DATE` (e.g. for a backfill or to retry a missed day), use those and skip the weekday/weekend logic. - A reusable helper that fetches and normalizes issues is provided at `scripts/fetch_new_issues.sh`.
GitHub에서 보기