diff --git a/.claude/skills/greptimedb-release-note/SKILL.md b/.claude/skills/greptimedb-release-note/SKILL.md new file mode 100644 index 0000000000..336192e9cc --- /dev/null +++ b/.claude/skills/greptimedb-release-note/SKILL.md @@ -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 +`` 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 /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 `/main`): +``` +GITHUB_TOKEN=$(gh auth token) git cliff .. --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/)` 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 .. --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 ..`: 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 --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 `). +- 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 fetch origin main + git -C 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 + git -C 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/ -X PATCH -F body=@body.md`. diff --git a/.claude/skills/greptimedb-release/SKILL.md b/.claude/skills/greptimedb-release/SKILL.md new file mode 100644 index 0000000000..215493519e --- /dev/null +++ b/.claude/skills/greptimedb-release/SKILL.md @@ -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 `` 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.`. + - `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 :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 '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 +release/vX.Y` only *opportunistically* updates the remote-tracking ref +`/release/vX.Y` (and only when the remote has a matching configured refspec), so it +may be missing or stale (e.g. a custom ``, or a branch just created in §0). Reading +`FETCH_HEAD` always reflects the tip just fetched: +``` +git fetch release/vX.Y +git show FETCH_HEAD:Cargo.toml | grep -A30 '\[workspace.package\]' | grep -m1 version +``` +(For a fresh minor cut from main, `/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 :refs/tags/vX.Y.Z # remove the tag +``` + +## Conventions / gotchas + +- Remotes: `` 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---*`). diff --git a/.gitignore b/.gitignore index 0789f3ec10..1c3dfd626a 100644 --- a/.gitignore +++ b/.gitignore @@ -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.*