# Post Release Status

> Post or update a release status message in Slack tracking cherry-picked PRs and their current status. Use when the user asks to post, update, or check cherry-pick status for a release.

- Skill: `warpdotdev/post-release-status` (Agent Skill)
- Install (CLI): `npx skillmds@latest add warpdotdev/post-release-status`
- Raw SKILL.md: https://api.skillmd.com/api/skills/warpdotdev/post-release-status/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: warpdotdev (https://skillmd.com/u/warpdotdev)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/warpdotdev/post-release-status

---


# post-release-status

Post or update a top-level Slack message that tracks the status of all cherry-picked PRs for a release branch.

## Configuration

This skill reads environment-specific values from environment variables (see the repo `README.md`):

- `SLACK_BOT_TOKEN` — Slack bot token with `channels:history`, `channels:read`, `chat:write`, and `chat:update` OAuth scopes.
- `INTERNAL_REPO` — `owner/repo` that holds your release branches and cherry-pick PRs.
- `REPO_DIR` — absolute path to your local checkout of `INTERNAL_REPO`.
- `RELEASE_SLACK_CHANNEL` — Slack channel name (or ID) to post the status in.
- `RELEASE_CHANNELS` — space-separated release channels used to derive the channel label from a branch (default `preview stable`).
- `STATUS_EMOJI_IN_REVIEW` / `STATUS_EMOJI_MERGED` / `STATUS_EMOJI_VERIFIED` — Slack emoji for each PR status (defaults `:large_yellow_square:` / `:merged:` / `:verified:`).

**All git/gh operations run inside `INTERNAL_REPO`.** Run `cd "$REPO_DIR"` before executing any git or `gh` commands.

## Step 1: Clarify inputs

Before proceeding, ensure you have:

- **Release branch**: The full release branch name (e.g. `stable_release/v0.YYYY.MM.DD.HH.MM.stable_NN`). This can be provided in one of three ways:
  1. The user gives it directly.
  2. The user gives a cherry-pick PR URL — deduce the branch from the PR's base branch:
     ```bash
     gh pr view <PR_NUMBER> --repo "$INTERNAL_REPO" --json baseRefName --jq '.baseRefName'
     ```
  3. If neither is provided, ask the user for the release branch or a PR URL.
- **Slack channel ID**: The Slack channel to post in (defaults to `$RELEASE_SLACK_CHANNEL`; a channel ID looks like `C0123456789`). If you only have a channel name, resolve it:
  ```bash
  curl -s -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
    "https://slack.com/api/conversations.list?types=public_channel,private_channel&limit=200" | \
    jq -r --arg name "$RELEASE_SLACK_CHANNEL" '.channels[] | select(.name == $name) | .id'
  ```

Derive the **channel** (one of `$RELEASE_CHANNELS`) and **version string** from the branch name for display.

If `$SLACK_BOT_TOKEN` is not set, ask the user for it before proceeding.

## Step 2: Find cherry-pick PRs

List all PRs targeting the release branch:

```bash
gh pr list --repo "$INTERNAL_REPO" --base $BRANCH_NAME --state all --json number,title,url,state --limit 100
```

Each PR will have:
- `state`: `OPEN` or `MERGED`
- `number`, `title`, `url`: for display

## Step 3: Look for an existing status message

Search the Slack channel for the most recent message matching this release:

```bash
curl -s -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
  "https://slack.com/api/conversations.history?channel=<SLACK_CHANNEL_ID>&limit=50" | \
  jq '[.messages[] | select(.text | test("<VERSION_OR_BRANCH_PATTERN>"))] | first | {ts, text}'
```

Use a pattern that matches the release version or branch name in the message text (e.g. the version string from Step 1).

**If a matching message is found:**
- Save its `ts` for updating later.
- Parse the message to find previously tracked PRs and their statuses. Look for these emoji patterns:
  - `$STATUS_EMOJI_IN_REVIEW` (default `:large_yellow_square:`) → in review
  - `$STATUS_EMOJI_MERGED` (default `:merged:`) → merged
  - `$STATUS_EMOJI_VERIFIED` (default `:verified:`) → verified
- **Preserve `$STATUS_EMOJI_VERIFIED` status** — do not downgrade a verified PR back to merged.

**If no matching message is found:** proceed with current GitHub state only.

## Step 4: Determine final PR statuses

For each cherry-pick PR, determine the display status:

1. If the PR was `$STATUS_EMOJI_VERIFIED` in the previous message → keep as `$STATUS_EMOJI_VERIFIED`
2. Else if the PR state is `MERGED` on GitHub → `$STATUS_EMOJI_MERGED`
3. Else if the PR state is `OPEN` on GitHub → `$STATUS_EMOJI_IN_REVIEW`

## Step 5: Format the message

Use Slack Block Kit so the release name renders as a true header (larger text). Build a `blocks` JSON array and a plain-text `text` fallback (used for notifications and for searching in Step 3):

```json
[
  {
    "type": "header",
    "text": {
      "type": "plain_text",
      "text": "<version> <channel> release"
    }
  },
  {
    "type": "section",
    "text": {
      "type": "mrkdwn",
      "text": "• :large_yellow_square: <https://github.com/OWNER/REPO/pull/123|PR #123> — <title>\n• :merged: <https://github.com/OWNER/REPO/pull/456|PR #456> — <title>\n• :verified: <https://github.com/OWNER/REPO/pull/789|PR #789> — <title>"
    }
  }
]
```

Also set `TEXT_FALLBACK` to the plain version of the title (e.g. `"v0.YYYY.MM.DD stable release"`) — this is used for notifications and for the search pattern in Step 3.

Use Slack mrkdwn hyperlink format in the section block: `<URL|display text>`.

## Step 6: Post or update the message

**If updating an existing message** (message `ts` found in Step 3):

```bash
curl -s -X POST \
  -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
  -H "Content-Type: application/json" \
  --data "$(jq -n \
    --arg channel "<SLACK_CHANNEL_ID>" \
    --arg ts "<EXISTING_MESSAGE_TS>" \
    --arg text "$TEXT_FALLBACK" \
    --argjson blocks "$BLOCKS_JSON" \
    '{channel: $channel, ts: $ts, text: $text, blocks: $blocks}')" \
  "https://slack.com/api/chat.update" | jq '{ok, ts, error}'
```

**If posting a new message:**

```bash
curl -s -X POST \
  -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
  -H "Content-Type: application/json" \
  --data "$(jq -n \
    --arg channel "<SLACK_CHANNEL_ID>" \
    --arg text "$TEXT_FALLBACK" \
    --argjson blocks "$BLOCKS_JSON" \
    '{channel: $channel, text: $text, blocks: $blocks}')" \
  "https://slack.com/api/chat.postMessage" | jq '{ok, ts, error}'
```

## Step 7: Confirm

Share the permalink with the user:

```bash
curl -s -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
  "https://slack.com/api/chat.getPermalink?channel=<SLACK_CHANNEL_ID>&message_ts=<MESSAGE_TS>" | \
  jq -r '.permalink'
```

## Notes

- The message is always a **top-level** message, not a thread reply.
- When updating, PR statuses are refreshed from GitHub, but **`$STATUS_EMOJI_VERIFIED` statuses are preserved** from the previous message.
- If the API returns `ok: false`, check the `error` field. Common errors: `not_in_channel`, `missing_scope`, `message_not_found`.
- To manually mark a PR as verified, the user can ask to update a specific PR's status.

