chore: add release runbook skills for maintainers (#8296)

* chore: add release runbook skills for maintainers

Signed-off-by: evenyag <realevenyag@gmail.com>

* chore: address release-note skill review comments

Signed-off-by: evenyag <realevenyag@gmail.com>

* chore: fetch release ref before checking Cargo.toml

Signed-off-by: evenyag <realevenyag@gmail.com>

* chore: read FETCH_HEAD for release version check

Signed-off-by: evenyag <realevenyag@gmail.com>

---------

Signed-off-by: evenyag <realevenyag@gmail.com>
This commit is contained in:
Yingwen
2026-06-16 14:13:30 +08:00
committed by GitHub
parent 4373c77d35
commit 1adee3cf47
3 changed files with 267 additions and 1 deletions

View File

@@ -0,0 +1,144 @@
---
name: greptimedb-release-note
description: Generate a GreptimeDB release changelog with git cliff (correct range, subtract already-released patch PRs, rebuild contributors, add human-curated highlights), output to a file, and prepare the docs-repo blog PR. Use when asked to write/generate a GreptimeDB release note or changelog.
---
# GreptimeDB Release Note / Changelog
Generate the changelog for a GreptimeDB release. Tooling: **`git cliff`** (config:
`cliff.toml` in the greptimedb repo) and **`gh`**. Run inside the greptimedb checkout.
**Prerequisites:** `git cliff`, `gh` (check `gh auth status`), and **Python** (the
subtract-PRs / rebuild-contributors step in §3§4 is scripted). This skill writes
`<remote>` for the git remote pointing at `GreptimeTeam/greptimedb` (often `upstream`,
sometimes `origin`); resolve it with
`git remote -v | grep -i 'GreptimeTeam/greptimedb' | awk '{print $1}' | head -1`.
## 1. GitHub token (never print it)
`git cliff` enriches commits with PR titles/authors via the GitHub API; for hundreds of
commits you need a token or you hit rate limits. Pass it inline and **never read or echo the
token**:
```
GITHUB_TOKEN=$(gh auth token) git cliff ...
```
Alternatively the user sources an env file that exports `GITHUB_TOKEN` (don't read it). Without
a token it still runs, but may be rate-limited / incomplete.
## 2. Determine the previous version (skip nightlies)
From `gh release list --repo GreptimeTeam/greptimedb`, ignore `*-nightly-*`, `-rc.*`, `-beta.*`,
and build-suffixed tags; focus on formal `vX.Y.Z`.
- Patch `vX.Y.Z` (Z>0): previous = `vX.Y.(Z-1)`.
- New minor `vX.Y.0`: previous = the latest `vX.(Y-1).*` (for `v1.0.0`, the biggest `0.x`).
Double-check with the user.
## 3. Pick the range and generate
Key topology fact: a **minor tag** (e.g. `v1.0.0`) is an ancestor of `main`; **patch tags**
(`v1.0.1`, `v1.0.2`) live on the `release/v1.0` branch and are **NOT** ancestors of `main`
(they are cherry-picks with different SHAs). Verify with
`git merge-base --is-ancestor <tag> <remote>/main`.
### New minor (`X.Y.0`, cut from main)
Note the two different tags here: the `git cliff` **base is the previous minor `.0` tag**
(e.g. `v1.0.0`, an ancestor of `main`) — **not** the "previous version" from §2 (the latest
patch, e.g. `v1.0.2`), which is only used below to decide which patch PRs to subtract.
Base = the **previous minor tag** (e.g. `v1.0.0`); tip = the release commit (= `release/vX.Y`
tip, usually `<remote>/main`):
```
GITHUB_TOKEN=$(gh auth token) git cliff <prev-minor-tag>..<release-commit> --tag vX.Y.0 \
-o /path/CHANGELOG-vX.Y.0.md
```
`cliff.toml`'s `ignore_tags` folds in-range nightly tags into the single section.
**Then subtract PRs already shipped in the intermediate patch releases** (`vX.(Y-1).1`,
`.2`, …) — their main-branch commits are inside the range and would duplicate, and the
audience cares about what's new vs the latest patch. Collect the PR set from the patch release
bodies and remove matching lines:
```
gh release view vX.(Y-1).Z --repo GreptimeTeam/greptimedb | grep -oE 'pull/[0-9]+'
```
Remove every changelog bullet whose `#NNNN` is in that combined set (a small Python script is
the reliable way — match `pull/<n>)` on lines starting with `*`).
### Patch (`X.Y.Z`, Z>0, cherry-picks on the release branch)
The previous patch tag is an ancestor of the release branch, so a plain range works:
```
GITHUB_TOKEN=$(gh auth token) git cliff <prev-patch-tag>..<release-branch-tip> --tag vX.Y.Z -o ...
```
No extra subtraction (the branch only contains the new cherry-picks). If the branch history is
messy, instead identify the newly cherry-picked PRs since the previous patch and keep only
those.
## 4. Rebuild contributor sections after subtracting
`cliff` computes `New Contributors` / `All Contributors` over the full range, so after removing
lines, recompute from the **remaining** commit bullets:
- **All Contributors** = sorted set of `@user` from remaining `* ... by [@user] ... in [#NN]`
lines (drop bots like `dependabot[bot]`).
- **New Contributors** = drop any entry whose first-contribution PR was removed (their only
in-range PR shipped in a patch).
Do this in the same script that subtracts the PRs.
## 5. Verify
Cross-check the result against `git log <base>..<tip>`: no subtracted PR remains, and no
genuine new PR was dropped. Optionally drop the mechanical `chore: bump version to vX.Y.Z`
line (ask the user; some prefer to keep it).
## 6. Human-curated sections (insert after the `Release date:` line)
Mirror past release bodies (`gh release view v1.0.0 --repo GreptimeTeam/greptimedb`):
- **Short intro**, terse, engineer-written tone (no marketing adjectives).
- **`### 👍 Highlights`** — *few, deep* highlights, each with a **working example**
(SQL / TOML config). To get examples right, **read the highlight PR and the related docs
PR/page** in the docs repo (`GreptimeTeam/docs`, often checked out locally) — verify syntax
in `docs/reference/sql/*.md`, `config/*.example.toml`, `config/config.md`. Do **not** mention
implementation details, tiny features, or unfinished/experimental-but-not-ready features.
Always have the user review and edit the highlights; iterate.
- **Dashboard** subsection — don't just bump the version. Read the dashboard PRs in the bundled
release (`gh release view <ver> --repo GreptimeTeam/dashboard`; then the linked PRs) and
describe the user-facing change.
## 7. Output
Write to `CHANGELOG-vX.Y.Z.md` (title `# vX.Y.Z`, which `--tag` produces) and **do not commit
it**. The release runbook deletes it after the release + docs PR are done.
## 8. Docs-repo blog variant + draft PR
The release note is also published as a blog post in **`GreptimeTeam/docs`**.
- **Ask the user for their local `GreptimeTeam/docs` checkout path**; if they have none, offer
to clone (`git clone git@github.com:GreptimeTeam/docs.git <path>`).
- File: `blog/release-X-Y-Z.md` (version with dashes; see `blog/release-1-0-0.md`).
- Content = the GitHub release body **minus the `# vX.Y.Z` H1** (start at `Release date:`),
**plus docs frontmatter**:
```
---
keywords: [release, GreptimeDB, changelog, vX.Y.Z]
description: GreptimeDB vX.Y.Z Changelog
date: YYYY-MM-DD
---
```
- The docs working tree may have unrelated WIP — **don't disturb it**: use a `git worktree` off
`origin/main`:
```
git -C <docs> fetch origin main
git -C <docs> worktree add -b chore/X.Y.Z-release-note /tmp/docs-release-note origin/main
```
- **The PR body must follow the docs repo's template** (`.github/pull_request_template.md` —
"What's Changed in this PR" + a Checklist). Fill in the description; leave checklist boxes
for the reviewer.
- Commit with sign-off, push, open a **draft** PR, then remove the worktree:
```
git -C /tmp/docs-release-note add blog/release-X-Y-Z.md
git -C /tmp/docs-release-note commit -s -m "docs: add X.Y.Z release note"
git -C /tmp/docs-release-note push -u origin chore/X.Y.Z-release-note
gh pr create --draft --repo GreptimeTeam/docs --base main --head chore/X.Y.Z-release-note \
--title "docs: add X.Y.Z release note" --body-file <template-filled body>
git -C <docs> worktree remove /tmp/docs-release-note
```
- Gotcha: `gh pr edit/create` may fail with an org-scope error if the token lacks `read:org`.
Edit the body via REST instead: `gh api repos/GreptimeTeam/docs/pulls/<n> -X PATCH -F body=@body.md`.

View File

@@ -0,0 +1,119 @@
---
name: greptimedb-release
description: Runbook for publishing a new GreptimeDB version (tag + GitHub release + docs release-note PR) on the upstream GreptimeTeam/greptimedb repo. Use when asked to "release" / "publish" a GreptimeDB version (e.g. v1.1.0, v1.0.3).
---
# GreptimeDB Release Runbook
Publish a formal GreptimeDB release on **`GreptimeTeam/greptimedb`**. Always operate against
that repo (for `gh`, pass `--repo GreptimeTeam/greptimedb`). Changelog generation is a
separate, involved task — use the **`greptimedb-release-note`** skill for it.
This whole flow touches public infrastructure. Confirm with the user before the
outward-facing step (creating the release, which creates the tag and triggers CI).
## Prerequisites & remote
- Tools: `gh` (check with `gh auth status`) and `git`. Changelog generation additionally
needs `git cliff` and Python — see the `greptimedb-release-note` skill.
- **Resolve the remote first.** This runbook writes `<remote>` for the git remote pointing
at `GreptimeTeam/greptimedb`; substitute your actual name (often `upstream`, sometimes
`origin` on a direct clone):
```
git remote -v | grep -i 'GreptimeTeam/greptimedb' | awk '{print $1}' | head -1
```
## 0. Inputs: version and branch
- Ask the user for the **version** to release (e.g. `1.1.0`, `1.0.3`) and, if needed, the
**branch**.
- **Branch is inferred from version**: `MAJOR.MINOR` → `release/v<MAJOR>.<MINOR>`.
- `v1.0.0 / v1.0.1 / v1.0.2` live on `release/v1.0`; `v1.1.0` lives on `release/v1.1`.
- Infer it, then double-check with the user.
- **New minor/major (`X.Y.0`)** is cut from `main`. If `release/vX.Y` does not exist on
the remote, offer to create it from the intended `main` commit (with the user's consent):
`git push <remote> <commit>:refs/heads/release/vX.Y`.
- **Patch (`X.Y.Z`, Z>0)** must use the existing `release/vX.Y` branch (it carries
cherry-picked commits).
- Check what exists on the remote: `git ls-remote --heads <remote> 'release/*'`.
## 1. Verify the Cargo version
The workspace version on the release branch **must** equal the version being released, or
stop. **Fetch the branch first**, then read `FETCH_HEAD` directly — `git fetch <remote>
release/vX.Y` only *opportunistically* updates the remote-tracking ref
`<remote>/release/vX.Y` (and only when the remote has a matching configured refspec), so it
may be missing or stale (e.g. a custom `<remote>`, or a branch just created in §0). Reading
`FETCH_HEAD` always reflects the tip just fetched:
```
git fetch <remote> release/vX.Y
git show FETCH_HEAD:Cargo.toml | grep -A30 '\[workspace.package\]' | grep -m1 version
```
(For a fresh minor cut from main, `<remote>/main` and `release/vX.Y` are usually the same
commit.)
## 2. Generate and curate the changelog
Use the **`greptimedb-release-note`** skill. It produces `CHANGELOG-vX.Y.Z.md` (uncommitted)
and the docs-blog variant. **Review the highlights with the user and iterate** before
publishing.
## 3. Create the GitHub release (creates the tag + triggers CI)
**Do NOT pre-create the tag.** Creating the release creates the tag and fires the
tag-push CI (`.github/workflows/release.yml`) that builds all binaries (**~hours**).
Confirm with the user, then:
```
gh release create vX.Y.Z \
--repo GreptimeTeam/greptimedb \
--target release/vX.Y \
--title "Release vX.Y.Z" \
--notes-file CHANGELOG-vX.Y.Z.md \
--prerelease
```
- Title convention: `Release vX.Y.Z`.
- Always create as **`--prerelease`**: prerelease here is just a "build in progress" marker.
The CI clears it on success (see §5). (The user creating it on the web works too.)
- Verify: `gh release view vX.Y.Z --repo GreptimeTeam/greptimedb --json name,tagName,isPrerelease,draft,targetCommitish`.
## 4. Open the docs release-note PR (do not wait for CI)
Right after triggering the release, open the docs draft PR (see the docs section of the
`greptimedb-release-note` skill). It only needs the finalized changelog.
Then **delete the local `CHANGELOG-vX.Y.Z.md`** (its content now lives in the release body
and the docs blog post).
## 5. After the CI build finishes (~hours)
CI's `publish-github-release` action, for a tag matching `^vX.Y.Z$`, runs
`ncipollo/release-action` with `allowUpdates: true`, **`prerelease=false`,
`makeLatest=true`, `omitBody=true`** (so it keeps our changelog body but finalizes the
flags). These flags are described from the current `.github/workflows/release.yml` —
**verify against the workflow** if behavior differs. Verify success:
```
gh release view vX.Y.Z --repo GreptimeTeam/greptimedb --json isPrerelease,assets
```
**Latest handling is conditional on whether this is the newest version:**
- **Releasing the latest version** (e.g. v1.1.0 when nothing newer exists) → CI's finalized
state (non-prerelease, latest) is correct; **do nothing**.
- **Releasing a non-latest line** (e.g. a patch `v1.0.3` while `v1.1.0` is already latest) →
set it back to non-latest after CI finishes:
`gh release edit vX.Y.Z --repo GreptimeTeam/greptimedb --latest=false`.
## 6. Rollback (only on failure, with double confirmation)
Show the user exactly what will be removed first; never delete blindly.
```
gh release delete vX.Y.Z --repo GreptimeTeam/greptimedb # remove the release
git push <remote> :refs/tags/vX.Y.Z # remove the tag
```
## Conventions / gotchas
- Remotes: `<remote>` is whatever points at `GreptimeTeam/greptimedb` (see Prerequisites).
`gh` defaults can be unreliable in a repo with many remotes — always pass
`--repo GreptimeTeam/greptimedb`.
- Release title is always `Release vX.Y.Z`.
- When reasoning about "previous version", skip nightly / build-suffixed tags
(`*-nightly-*`, `vX.Y.Z-rc.N-<sha>-<date>-*`).

5
.gitignore vendored
View File

@@ -75,4 +75,7 @@ AGENTS.md
# local design docs
docs/specs/
.vs/
.vs/
# Claude Code personal/local overrides (keep shared .claude/ content tracked)
.claude/*.local.*