diff --git a/.agents/skills/rustfs-release-publish/SKILL.md b/.agents/skills/rustfs-release-publish/SKILL.md index ac520cee3..1c64897c8 100644 --- a/.agents/skills/rustfs-release-publish/SKILL.md +++ b/.agents/skills/rustfs-release-publish/SKILL.md @@ -1,25 +1,29 @@ --- name: rustfs-release-publish -description: "End-to-end RustFS release pipeline: cut a preview tag first, verify the CI build and release artifacts, run the downloaded binary locally and exercise the console, validate the server with the latest rc client, then bump to the final version via rustfs-release-version-bump and publish the final tag from the validated preview hash — never from latest main. Use whenever the user wants to release/publish a RustFS version (发版/发布)." +description: "End-to-end RustFS release pipeline: bump version files on main directly to the final target version, cut a preview tag on that commit, verify the CI build and release artifacts, run the downloaded binary locally and exercise the console, validate the server with the latest rc client, then publish the final tag on the SAME validated commit — never a new bump commit, never latest main. Use whenever the user wants to release/publish a RustFS version (发版/发布)." --- # RustFS Release Publish (preview-validated pipeline) This skill orchestrates a full release. It wraps `rustfs-release-version-bump` (which only edits version files and opens the PR) with a mandatory preview-tag validation loop before the final tag is published. +Core design: **version files never carry a `-preview.N` suffix**. The preview suffix exists only in tag names. This works because the binary self-reports the git tag it was built from (`build::TAG` via shadow_rs, see `rustfs/src/config/cli.rs` `SHORT_VERSION`), and `build.yml` derives artifact names and prerelease classification from the tag name — Cargo.toml's version is only a no-tag fallback. Therefore the preview tag and the final tag can (and MUST) point at the exact same commit: what you validated is byte-for-byte the source that ships. + Pipeline shape: ``` -bump to -preview.N -> merge -> tag preview -> CI green +bump version files to (final version, ONE commit) -> merge + -> tag at that commit -> CI green -> verify release artifacts -> run binary locally + console checks -> validate with latest rc client - -> bump to ON TOP OF the validated preview hash -> CI green - -> tag final version at that commit (NOT main HEAD) + -> tag at the SAME commit (zero delta) -> re-verify CI/release ``` +On validation failure: fix lands on main via normal PR (version files are already at ``, no new bump PR), then tag `` at the new main commit and restart from Phase 2. + ## Required inputs - Final target version, for example `1.0.0-beta.10`. -- Preview iteration `N` (default: next unused `-preview.N` for that target; check with `git tag -l '-preview.*'` after `git fetch --tags`). +- Preview iteration `N` (default: next unused preview tag for that target; check with `git tag -l '-preview.*'` — and for stable targets `git tag -l '-rc.*'` — after `git fetch --tags`). If the target version is missing or ambiguous, stop and ask before doing anything (see the semver gate below). @@ -31,7 +35,7 @@ Versions follow [SemVer 2.0.0](https://semver.org/). Precedence reminder: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0 < 1.0.1 < 1.1.0 < 2.0.0 ``` -Numeric prerelease identifiers compare numerically (`beta.9 < beta.10`), not lexically — see [semver.org spec item 11](https://semver.org/#spec-item-11). Preview tags (`-preview.N`) are internal validation tags layered on top of the target's prerelease channel — they are never themselves a deliverable version. +Numeric prerelease identifiers compare numerically (`beta.9 < beta.10`), not lexically — see [semver.org spec item 11](https://semver.org/#spec-item-11). Preview tags are internal validation tags layered on top of the target's prerelease channel — they are never themselves a deliverable version and never appear in version files. Rules: @@ -39,12 +43,18 @@ Rules: - After a stable `X.Y.Z` exists, the next version must state which component bumps: patch `X.Y.(Z+1)` for fixes only, minor `X.(Y+1).0` for backward-compatible features, major `(X+1).0.0` for breaking changes. If the user names a bump type but not a number, compute it from the latest stable tag and echo the exact resulting version back for confirmation. - Echo the final confirmed version string verbatim in your first status report; every later phase must use exactly that string. If at any point the user's wording and the confirmed version diverge, stop and re-confirm. +## Preview tag naming + +- Prerelease target (contains `alpha`/`beta`/`rc`): preview tag is `-preview.N`, e.g. `1.0.0-beta.10-preview.3`. It contains `beta`, so `build.yml`'s substring-based classification marks it prerelease — safe. +- **Stable** target (e.g. `1.1.0`): NEVER tag `1.1.0-preview.N` — `build.yml` marks a tag prerelease only if its name contains `alpha`, `beta`, or `rc`, so `1.1.0-preview.N` would be treated as a stable release and overwrite `latest.json` as stable. Use `1.1.0-rc.N` as the preview tag instead. + ## Hard rules -- **Prerelease classification is substring-based.** `build.yml` marks a tag as prerelease only if its name contains `alpha`, `beta`, or `rc`. A preview of a prerelease target (`1.0.0-beta.10-preview.3`) contains `beta` and is safe. For a **stable** target (e.g. `1.1.0`), NEVER tag `1.1.0-preview.N` — it would be treated as a stable release and overwrite `latest.json` as stable. Use `1.1.0-rc.N` as the preview tag instead. +- Version files (Cargo.toml, Cargo.lock, README, flake.nix, Chart.yaml, rustfs.spec) are bumped ONCE, directly to ``. Never write a `-preview.N` suffix into any version file. If `rustfs-release-version-bump` is ever asked for a `-preview` version, that is a pipeline bug — stop. - Tags have no `v` prefix. Always annotated: `git tag -a -m "Release "`. -- The final tag MUST point at a commit whose ancestry is exactly `validated preview hash + final version-bump commit(s)`. Never tag current `main` HEAD: commits merged after the preview was validated are unvalidated. -- Phases run in order; a failure in any phase blocks everything after it. After the fix lands on main, restart from Phase 1 with `N+1` — do not resume mid-pipeline against a stale hash. +- The final tag MUST point at exactly `PREVIEW_HASH` — the commit the validated preview tag points at. Never tag current `main` HEAD (commits merged after validation are unvalidated), and never create an extra version-bump commit between preview and final. +- Phases run in order; a failure in any phase blocks everything after it. After the fix lands on main, restart from Phase 2 with the next preview iteration against the new `origin/main` hash — do not resume mid-pipeline against a stale hash. +- If the release is abandoned after Phase 1 merged, main's version files claim a version that was never tagged. Either revert the bump PR or leave it to be overwritten by the next release — but tell the user explicitly and record the decision. - User-facing status updates in Chinese; commits, PR titles/bodies, and tag messages in English. No hard-wrapping in commit messages, PR bodies, or documentation prose — one logical line per sentence/paragraph, let soft wrap handle display. ## Phase 0 — Preflight @@ -53,9 +63,10 @@ Rules: - `gh auth status` works; confirm you can view `gh release list -L 3`. - Confirm the exact final target version with the user if not explicit. -## Phase 1 — Preview version bump +## Phase 1 — Version bump to the final target (once) -- Invoke the `rustfs-release-version-bump` skill with version `-preview.N`, full GitHub flow (commit/push/PR). +- If main's version files already read `` (e.g. this is a restart after a failed preview), verify with `rg -n "" Cargo.toml rustfs.spec helm/rustfs/Chart.yaml` and skip to Phase 2. +- Otherwise invoke the `rustfs-release-version-bump` skill with the final `` (NOT a preview version), full GitHub flow (commit/push/PR). - Get the PR merged into main. Record the resulting main commit: ```bash @@ -63,21 +74,23 @@ git fetch origin main PREVIEW_HASH=$(git rev-parse origin/main) # must contain the bump PR ``` -`PREVIEW_HASH` is the single source of truth for the rest of the pipeline — report it to the user and reuse it verbatim in Phases 2 and 6. +`PREVIEW_HASH` is the single source of truth for the rest of the pipeline — report it to the user and reuse it verbatim in Phases 2 and 6. Both the preview tag and the final tag will point at it. ## Phase 2 — Publish the preview tag ```bash -git tag -a "-preview.N" -m "Release -preview.N" "$PREVIEW_HASH" -git push origin "-preview.N" +git tag -a "" -m "Release " "$PREVIEW_HASH" +git push origin "" ``` Pushing the tag triggers `.github/workflows/build.yml` ("Build and Release"); `docker.yml` chains off it via `workflow_run`. +On a restart (N+1), refresh `PREVIEW_HASH=$(git rev-parse origin/main)` first — it must contain the fix — and re-report it. + ## Phase 3 — CI and artifact verification - Watch the tag build: `gh run list --workflow build.yml --limit 5` then `gh run watch `. Every matrix target must succeed (linux x86_64/aarch64 × musl/gnu, macos-aarch64, windows-x86_64) plus the release and latest.json jobs. -- Verify the GitHub release: `gh release view "-preview.N" --json isPrerelease,assets` +- Verify the GitHub release: `gh release view "" --json isPrerelease,assets` - `isPrerelease` must be `true`. - Assets must include all 6 platform zips in both versioned (`rustfs--v.zip`) and `-latest` forms, plus `SHA256SUMS`, `SHA512SUMS`, `rustfs-.sbom.cdx.json`, `rustfs-.provenance.json`. - Verify the chained Docker run succeeded: `gh run list --workflow docker.yml --limit 3`. @@ -88,9 +101,9 @@ Pushing the tag triggers `.github/workflows/build.yml` ("Build and Release"); `d Work inside the session scratchpad directory; never leave stray data dirs. ```bash -gh release download "-preview.N" -p "rustfs-macos-aarch64-v.zip" -D "$SCRATCH" +gh release download "" -p "rustfs-macos-aarch64-v.zip" -D "$SCRATCH" cd "$SCRATCH" && unzip -o rustfs-*.zip -./rustfs --version # must report the preview version and expected short SHA +./rustfs --version # must report the PREVIEW TAG (build::TAG), not the Cargo.toml version, plus expected short SHA mkdir -p data RUSTFS_ACCESS_KEY=rustfsadmin RUSTFS_SECRET_KEY=rustfsadmin ./rustfs ./data ``` @@ -99,6 +112,7 @@ Defaults: S3 endpoint `:9000`, embedded console `:9001`. Checks (all must pass): +- `./rustfs --version` reports the preview tag name and the short SHA of `PREVIEW_HASH`. Reporting `` without the `-preview.N` suffix means the build did not embed the tag — treat as FAIL and investigate before proceeding. - `curl -fsS http://localhost:9000/health/ready` returns ready. - Startup log shows the embedded console being served (this was the regression that `fix(release): require embedded console assets` guards). - Open `http://localhost:9001` in the browser: login with `rustfsadmin`/`rustfsadmin`; dashboard renders without JS console errors; create a bucket, upload a file, download it back (byte-identical), delete the object and bucket. Keep the server running for Phase 5. @@ -131,31 +145,25 @@ rc alias remove preview - Any FAIL blocks the release. Afterwards stop the server and delete the scratch data directory. -## Phase 6 — Final version bump from the validated hash +## Phase 6 — Publish the final tag on the validated commit + +No second version bump, no release branch. The final tag goes on the exact commit the preview validated: ```bash -git checkout -b release/ "$PREVIEW_HASH" # NOT origin/main -``` - -- Invoke `rustfs-release-version-bump` with the final `` on this branch (commit/push/PR). Its verification gate (`make pre-commit` etc.) must pass; the PR's CI must be green before proceeding. -- Do not rebase this branch onto main and do not merge main into it — that would reintroduce unvalidated commits under the final tag. - -## Phase 7 — Publish the final tag - -```bash -FINAL_HASH=$(git rev-parse release/) # PREVIEW_HASH + bump commit(s) only -git merge-base --is-ancestor "$PREVIEW_HASH" "$FINAL_HASH" # must succeed -git tag -a "" -m "Release " "$FINAL_HASH" +git fetch origin --tags +git rev-parse "^{commit}" # must equal PREVIEW_HASH — abort if not +git tag -a "" -m "Release " "$PREVIEW_HASH" git push origin "" ``` -- Re-run the Phase 3 verification against the final tag (for a stable target, `isPrerelease` must now be `false`). -- Merge the bump PR into main afterwards so main records the version. With squash-merge, main's copy of the bump differs from the tagged commit — that is expected and fine. +- CI rebuilds from the same source; the only changed input is the tag name, so the binary now self-reports ``. +- Re-run the Phase 3 verification against the final tag: all matrix jobs green; `gh release view ""` shows the full asset set; for a prerelease target `isPrerelease` is `true`, for a stable target it must be `false` and `latest.json` must be updated. +- Optionally spot-check `./rustfs --version` from a final-tag artifact — it must report ``. ## Output contract Always report: -- Target version, preview tag(s) used, `PREVIEW_HASH`, `FINAL_HASH`. +- Target version, preview tag(s) used, `PREVIEW_HASH` (which both tags point at). - Per-phase result (PASS/FAIL/BLOCKED) with key evidence: CI run URLs, release URLs, console check results, the rc command matrix. - Any deviation from this pipeline and why the user approved it. diff --git a/.agents/skills/rustfs-release-version-bump/SKILL.md b/.agents/skills/rustfs-release-version-bump/SKILL.md index ab00d6f06..0e39ce737 100644 --- a/.agents/skills/rustfs-release-version-bump/SKILL.md +++ b/.agents/skills/rustfs-release-version-bump/SKILL.md @@ -18,6 +18,8 @@ Validated baseline: release pattern used in PR `#2957`. If target version is missing or ambiguous, stop and ask before editing. +Reject any target version containing a `-preview.` suffix: preview identifiers are tag-only (see `rustfs-release-publish`) and must never be written into version files. If asked for one, stop and point to the release pipeline instead of editing. + ## Read before editing - `AGENTS.md` (root and nearest path-specific files).