diff --git a/.agents/skills/rustfs-release-publish/SKILL.md b/.agents/skills/rustfs-release-publish/SKILL.md index d3e101b83..6bab73e80 100644 --- a/.agents/skills/rustfs-release-publish/SKILL.md +++ b/.agents/skills/rustfs-release-publish/SKILL.md @@ -1,6 +1,6 @@ --- name: rustfs-release-publish -description: "Run the end-to-end RustFS console gate, version bump, preview validation, human confirmation, and final-tag publication pipeline. Use only when the user explicitly asks to release or publish a RustFS version (发版/发布)." +description: "Run the RustFS console gate, source version bump, preview validation, human confirmation, final-tag publication, and post-release installation and website updates. Use only when the user explicitly asks to release or publish a RustFS version (发版/发布)." --- # RustFS Release Publish (preview-validated pipeline) @@ -18,16 +18,18 @@ Pipeline shape: ``` check console main against its latest Release -> if ahead: publish console -> wait for Release asset + latest API - -> bump RustFS version files to (final version, ONE commit) -> merge + -> bump Cargo.toml and Cargo.lock to -> merge -> tag at that commit -> CI green -> verify preview Release assets -> run binary locally + console checks -> validate with latest rc client -> report preview acceptance results -> STOP for explicit human confirmation -> tag at the SAME commit (zero delta) -> re-verify CI/release -> CI deletes the -preview.N Releases (tags kept) + -> verify published images -> publish Helm chart from the validated source + -> update installation references on main -> update rustfs.com announcement ``` -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. +On preview validation failure: fix lands on main via normal PR (Cargo versions are already at ``, no new source bump PR), then tag `` at the new main commit and restart from Phase 2. Installation references remain on the previous published deliverable throughout preview validation. ## Required inputs @@ -56,19 +58,21 @@ Rules: - Use `-preview.N` for every target, e.g. `1.0.0-beta.10-preview.3` or `1.1.0-preview.1`. - The canonical suffix is exactly `-preview.`. `build.yml` recognizes it before alpha/beta/rc classification and routes it to the preview-only path; any other tag containing `-preview` fails closed instead of being treated as a release. -- A preview Release MUST be published with `isPrerelease=true` and `isLatest=false`. Any `*-latest` preview asset or preview-triggered `latest.json`, R2, Docker, or Helm publication is a pipeline failure. +- A preview Release MUST be published with `isPrerelease=true` and `isLatest=false`. Any `*-latest` preview asset or preview-triggered `latest.json`, R2, Helm, or moving Docker channel tag is a pipeline failure. Docker images may use the exact preview version tag, including its existing variant suffixes. - Preview Releases are cleaned up by the `cleanup-preview-releases` job after `publish-release` succeeds for the deliverable tag. It deletes every Release whose tag is exactly `-preview.` and never passes `--cleanup-tag`, so the tags survive. ## Hard rules -- 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. +- Before preview, bump only Cargo.toml (workspace package and internal dependency versions) and the corresponding workspace members in Cargo.lock, directly to ``. Keep README installation examples, flake.nix, Chart.yaml, and rustfs.spec on the previous published deliverable until Phase 7. Never write a `-preview.N` suffix into these files; preview identifiers belong to validation tags and artifacts. +- Publishing a tag alone does not make an installation target available. Verify the exact image manifest, Release assets, and source archive before advancing references that consume them. Helm packaging derives its versions from the final tag and waits for that image; it does not require an early Chart.yaml bump on main. - Preview Release assets are versioned and intentionally visible on the Releases page for the duration of validation. Do not label them Latest or use them to update any latest distribution channel. - Never delete a preview Release by hand before Phase 6 finishes — Phase 4 downloads its assets and the final Release notes are generated while it still exists. Cleanup is CI's job; only step in manually (`gh release delete "" --yes`, never `--cleanup-tag`) if `cleanup-preview-releases` failed. - Tags have no `v` prefix. Always annotated: `git tag -a -m "Release "`. -- 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. +- 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. Phase 7 updates installation references on main after publication; neither tag moves to that follow-up commit. - When a previous deliverable exists, GitHub Release notes for the preview and final tags MUST use it as their shared comparison baseline: the most recently published non-preview Release before the target. Internal `-preview.N` Releases are explicitly excluded from that selection, even when they point at the same commit as the final tag — cleanup runs after the notes are generated, so the preview Release is still present and would otherwise be picked as the baseline. If no previous deliverable exists, omit `previous_tag_name` and record that GitHub's default baseline fallback was used. - Generated Release notes carry a workflow-management marker so retries can repair them. Before manually curating a generated body, remove that marker; unmarked non-placeholder notes are preserved by later workflow runs. -- 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. +- Phases run in order; a failure blocks dependent steps. For a preview/source acceptance failure before the final tag exists, land the fix, verify Cargo still matches the confirmed target, and restart from Phase 2 with the next preview at the fixed commit. If main has advanced to another target, resolve that source/version mismatch before another preview. +- Once the final tag exists, preserve its commit. Retry failed publication jobs for that exact tag; do not recreate the tag or restart preview on newer main. If a source change is required after final-tag publication, report the failure and obtain a new target version. Phase 7 failures resume only the failed follow-up after rechecking artifact availability and whether a newer release has superseded it. - Completing preview acceptance does not authorize the final tag. After Phases 3–5 pass, report the acceptance evidence and stop until the user explicitly confirms continuation. The original release request, an earlier confirmation, silence, or an automated follow-up does not satisfy this gate. - Confirmation is scoped to the reported ``, ``, and `PREVIEW_HASH`. A failed or repeated acceptance cycle, including any new preview iteration, invalidates prior confirmation and requires a new one. - 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. @@ -84,10 +88,10 @@ Rules: Read and complete [the Console gate](references/console-gate.md) before Phase 1. Verify the latest published Console asset and exact commit; if Console main is ahead, complete its release and asset verification first. A successful build alone does not satisfy this gate. -## Phase 1 — Version bump to the final target (once) +## Phase 1 — Source version bump to the final target (once) -- 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). +- If Cargo.toml and all workspace members in Cargo.lock already read `` (e.g. this is a restart after a failed preview), verify both and skip the source bump. Installation versions intentionally differ during preview; do not treat them as leftovers. If a previous preparation advanced installation references to an unavailable target, restore those references to the verified published baseline before selecting the next preview commit. +- Otherwise invoke the `rustfs-release-version-bump` skill with stage `prepare`, the final `` (NOT a preview version), and full GitHub flow (commit/push/PR). - Get the PR merged into main. Record the resulting main commit: ```bash @@ -106,7 +110,7 @@ git push origin "" Pushing the tag triggers `.github/workflows/build.yml` ("Build and Release"); `docker.yml` chains off it via `workflow_run`. -The preview run builds versioned artifacts and publishes them in a GitHub prerelease. Its latest-channel, R2, Docker, and Helm jobs must be skipped. Those publication paths run only after the final tag is pushed. +The preview run builds versioned artifacts and publishes them in a GitHub prerelease. Docker may publish exact preview image tags. Latest-channel, R2, and Helm publication must be skipped; installation references and the website announcement stay unchanged. On a restart (N+1), refresh `PREVIEW_HASH=$(git rev-parse origin/main)` first — it must contain the fix — and re-report it. @@ -116,7 +120,7 @@ On a restart (N+1), refresh `PREVIEW_HASH=$(git rev-parse origin/main)` first - Confirm the Release publication jobs (`create-release`, `upload-release-assets`, and `publish-release`) succeed while `update-latest-version` is skipped. - Verify `gh release view "" --json isPrerelease,assets,url`: `isPrerelease` must be `true`, and the Release must contain all 6 versioned platform zips, checksums, SBOM, and provenance with no `-latest` assets. Confirm `gh api repos/{owner}/{repo}/releases/latest --jq .tag_name` does not return ``. - Record `PREVIOUS_DELIVERABLE`, selected from published Releases by `publishedAt` after excluding the current tag and every `-preview.N` tag. Verify `gh release view "" --json body --jq .body` contains `## What's Changed` and, when `PREVIOUS_DELIVERABLE` exists, `**Full Changelog**: https://github.com/rustfs/rustfs/compare/...`. For a repository with no previous deliverable, verify a Full Changelog link exists and record the GitHub baseline fallback. -- Confirm preview-triggered Docker and Helm jobs are skipped. Preview validation covers the built RustFS binaries, embedded console, and rc compatibility; Docker image construction and Helm publication are deferred to the final tag because the Dockerfiles consume GitHub Release assets. +- Confirm Helm is skipped. If preview Docker images are published, confirm they use only exact preview tags (and variant suffixes), with no `latest`, `alpha`, `beta`, or `rc` channel updates. Preview validation covers the built RustFS binaries, embedded console, and rc compatibility; it does not authorize advancing any installation default. ## Phases 4–5 — Local artifact, Console, and rc acceptance @@ -130,7 +134,7 @@ Continue to Phase 6 only after a new user reply explicitly confirms the reported ## 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: +No second source version bump. The final tag goes on the exact commit the preview validated: ```bash git fetch origin --tags @@ -145,6 +149,10 @@ git push origin "" - Verify the preview cleanup: `cleanup-preview-releases` must succeed, `gh release view ""` must then report `release not found` for every preview iteration of this target, and `git rev-parse "^{commit}"` must still resolve to `PREVIEW_HASH` (the tag is kept). If the job failed, delete the leftover Releases manually with `gh release delete "" --yes` and report it. - Optionally spot-check `./rustfs --version` from a final-tag artifact — it must report ``. +## Phase 7 — Installation references and website announcement + +Only after Phase 6 succeeds, complete [post-release updates](references/post-release-updates.md): align installation references on main, then update the existing top banner in `rustfs/rustfs.com`. A failed or incomplete publication leaves both on the previous available version. These follow-up commits never change `PREVIEW_HASH` or either release tag. Track their PR, merge, and deployment states separately from artifact publication; an open PR is not a live website update. + ## Output contract Always report: @@ -153,4 +161,5 @@ Always report: - Target version, preview tag(s) used, `PREVIEW_HASH` (which both tags point at). - Manual confirmation gate status (`WAITING_FOR_CONFIRMATION` or `CONFIRMED`) and its exact target, preview tag, and `PREVIEW_HASH`. - Per-phase result (PASS/FAIL/BLOCKED) with key evidence: preview and final Release URLs, preview `isPrerelease`/`isLatest` state, final latest-channel state, console check results, the rc command matrix, and the preview-Release cleanup result (deleted Releases plus surviving tags). +- Post-release installation PR and verification results; website banner target, text, link, PR, and observed deployment state. Report any remaining merge authorization or failed deployment explicitly rather than claiming the banner is live. - Any deviation from this pipeline and why the user approved it. diff --git a/.agents/skills/rustfs-release-publish/references/post-release-updates.md b/.agents/skills/rustfs-release-publish/references/post-release-updates.md new file mode 100644 index 000000000..5797afb4a --- /dev/null +++ b/.agents/skills/rustfs-release-publish/references/post-release-updates.md @@ -0,0 +1,32 @@ +# Post-release Installation and Website Updates + +Read only after the final non-preview tag has passed Phase 6. Tag creation or a green binary build alone is insufficient: the release assets, source archive, container images, Helm package, and applicable latest channels must be available. Preview tags never enter this phase. + +## Installation references + +1. Re-read the published deliverable state before edits or a retry. If a newer release has superseded this target, do not downgrade installation references or the website announcement. Report the superseding release and leave those defaults intact. +2. Invoke `rustfs-release-version-bump` with stage `post-release`, the exact target, and the authorized delivery scope. Prepare the follow-up on current main; do not edit or move either validated release tag. Cargo versions may already be preparing the next target and must remain untouched. +3. Verify the exact Docker image manifest, Release download links, RPM source archive, and Helm repository entry before publishing the installation PR. The chart workflow overrides chart/app versions from the final tag, pins the source checkout to that release, and waits for its default Docker image before packaging. +4. Report the installation PR and its merge state separately from the completed release. Reuse existing merge authorization and repository checks; do not infer new merge authority from this reference. + +## rustfs.com top banner + +Use the existing announcement configuration from [website PR #112](https://github.com/rustfs/rustfs.com/pull/112). Do not add a second banner or redesign the header. + +1. In an isolated checkout of `rustfs/rustfs.com`, read its current `AGENTS.md`, PR template if present, `data/announcement.ts`, and the consuming header component. Search for an existing announcement PR for this target before creating another. +2. Update `homeAnnouncement` in `data/announcement.ts` after the release and installation availability checks pass. Keep `enabled: true`, `badge: 'New'`, and the existing component. For a stable release, use: + + ```ts + export const homeAnnouncement = { + enabled: true, + badge: 'New', + message: 'RustFS is now available! Please', + linkText: 'upgrade and try', + href: '/download', + } as const + ``` + + Replace `` with the exact published version. Reserve GA wording for the actual first stable release. For a final alpha/beta/rc tag, explicitly call it a prerelease; use its GitHub Release URL if `/download` does not expose that target. Never announce a `-preview.N` build here. +3. Use the site's current package manager and required checks. For this config-only change, type-check and lint the changed file, build the site, and inspect the generated homepage for the version, visible link text, and destination. Confirm `/download` actually offers the announced version before using that link. +4. Commit, push, and create or update the website PR when included in the authorized release scope. Include the published RustFS Release URL and checks run. Keep merge and production-deployment authority separate; reuse permission already given, but this reference grants none by itself. +5. After an authorized merge/deployment, verify the live `https://rustfs.com/` banner and its destination. If only the PR is ready, report that state and URL; do not report the banner as deployed. A website failure does not invalidate or move the published release tag: retry this phase after resolving the failure. diff --git a/.agents/skills/rustfs-release-version-bump/SKILL.md b/.agents/skills/rustfs-release-version-bump/SKILL.md index 2f77ee27a..104a6b647 100644 --- a/.agents/skills/rustfs-release-version-bump/SKILL.md +++ b/.agents/skills/rustfs-release-version-bump/SKILL.md @@ -1,16 +1,15 @@ --- name: rustfs-release-version-bump -description: "Prepare the version-file and release-asset bump for an exact RustFS alpha/beta/stable target, with verification and optional commit/push/PR delivery. Use for an explicit version bump or when invoked by the release-publish workflow." +description: "Prepare Cargo versions for an exact RustFS target, or align installation references after its artifacts are published, with verification and optional commit/push/PR delivery. Use for an explicit version bump or when invoked by the release-publish workflow." --- # RustFS Release Version Bump Use this skill to prepare and verify release version files. Commit, push, and PR steps apply only when included in the user's delivery scope; publishing release tags belongs to `rustfs-release-publish`. -Validated baseline: release pattern used in PR `#2957`. - ## Required inputs - Exact target version, for example `1.0.0-beta.4`. +- Stage: `prepare` (default) or `post-release`. Infer `post-release` only when the user or parent release workflow explicitly requests installation updates after publication; a normal version bump means `prepare`. - Delivery scope: local (`edit/verify`), git (`commit/push`), or GitHub (`commit/push/PR`). Derive it from the conversation; when unspecified, prepare and verify locally without blocking on a delivery question. @@ -25,25 +24,32 @@ Reject any target version containing `-preview`: preview identifiers are tag-onl - `.github/pull_request_template.md` only when preparing a PR. - Current branch status and diff against `origin/main`. -## Default release file scope +## Stage boundaries -Treat the following file list as the default checklist for each release bump: +`prepare` updates only: - `Cargo.toml` - `Cargo.lock` + +`post-release` updates installation and packaging references only: + - `README.md` - `README_ZH.md` - `flake.nix` - `helm/rustfs/Chart.yaml` - `rustfs.spec` -Only drop a file when the current repository release process clearly no longer requires it. +During preview, installation references intentionally retain the previous published deliverable. Do not sweep them into a source bump to make every version string match. `flake.nix` builds local source, but its package label is aligned with the other packaging references after publication. + +Before `post-release` edits, verify that the exact non-preview target has a published GitHub Release, downloadable assets and source archive, and a pullable `rustfs/rustfs:` image manifest. If any prerequisite is missing, report `BLOCKED` and leave installation references unchanged. If a newer deliverable has already superseded this target, do not downgrade installation defaults during a retry. + +Helm CI derives chart versions from the triggering tag, so the final tag can retain the previous Chart.yaml values. Update the repository copy only after the target image and published chart are available. Neither post-release changes nor their merge commit may replace the preview-validated final tag. ## Hard release policy - Docker doc tags use `` (for example `rustfs/rustfs:1.0.0-beta.4`), not `v`. -- Helm chart version mapping follows `beta.N -> 0.N.0`. -- `rustfs.spec` `Release` uses prerelease suffix only (for example `beta.4`). +- Derive Helm chart and app versions with `scripts/helm_chart_version.sh `; the existing mapping is `beta.N -> 0.N.0`, with other target versions retained. +- `rustfs.spec` `Release` uses the prerelease suffix (for example `beta.4`), or `1` for a stable release. - Do not change these rules without explicit confirmation. ## Step-by-step workflow @@ -52,22 +58,18 @@ Only drop a file when the current repository release process clearly no longer r - Use the exact target and delivery scope already supplied; ask only for a missing or ambiguous target or a material release-policy choice. - Inspect current branch and ensure only release-related files are touched for this task. -2. Update workspace versions +2. Update workspace versions (`prepare` only) - Bump `[workspace.package].version` in `Cargo.toml`. - Bump internal workspace crate dependency versions in `Cargo.toml`. - Update `Cargo.lock` so workspace package versions match target version. -- Re-scan for partial leftovers. +- Re-scan Cargo.toml and workspace members in Cargo.lock for partial leftovers; leave external dependency versions unchanged. -3. Update release assets +3. Update installation references (`post-release` only) - `README.md` and `README_ZH.md`: update versioned Docker examples to target version. - `flake.nix`: update package version to target version. -- `helm/rustfs/Chart.yaml`: -- `appVersion` = target version. -- `version` follows chart mapping rule, for example: -- `1.0.0-beta.3` -> `0.3.0` -- `1.0.0-beta.4` -> `0.4.0` +- `helm/rustfs/Chart.yaml`: use the app and chart versions returned by `scripts/helm_chart_version.sh `. - `rustfs.spec`: -- Set `Release` to prerelease suffix (example `beta.4`). +- Set `Version` to the numeric version and `Release` to the prerelease suffix (example `beta.4`), or `1` for a stable release. Verify that `Source0` and the unpacked source directory resolve to the exact published target, including its prerelease suffix when present. - Add/update top changelog entry with exact format: - `* Thu May 20 2026 houseme ` - `- Update RPM package to RustFS 1.0.0-beta.4` @@ -78,15 +80,14 @@ Only drop a file when the current repository release process clearly no longer r - Changelog version text must match target release version exactly. 4. Verify before shipping -- Run: -- `make pre-commit` -- If `make pre-commit` fails, fix task-attributable failures and rerun affected checks. Report unresolved required checks as `BLOCKED`; do not silently widen scope to fix unrelated issues. +- Follow the root verification tiers for the final diff instead of running a full-workspace gate for version strings. +- For `prepare`, validate Cargo metadata with the updated lockfile and confirm workspace package/internal dependency versions agree. Do not accept a lockfile containing unrelated dependency updates. +- For `post-release`, render the Helm chart and confirm its default image is the verified target; run `scripts/test_helm_chart_version.sh` when chart versions change. Check the README image tags, Nix package version, and expanded RPM source URL against that same target. +- Run `git diff --check` for either stage. Report unresolved required checks as `BLOCKED`; do not silently widen scope to fix unrelated issues. 5. Commit strategy (only when committing is authorized) -- Preferred split when both parts changed: -- `chore(release): prepare ` for `Cargo.toml` and `Cargo.lock`. -- `chore(release): align release assets for ` for docs and packaging files. -- If user asks for one commit, use one commit. +- Use `chore(release): prepare ` for `prepare` and `chore(release): align installation references for ` for `post-release`. +- These stages happen on opposite sides of publication; do not combine them in a preview-preparation commit or PR. - Stage only intended release files; do not include unrelated working tree changes. 6. Push and PR (only for the authorized delivery scope) @@ -104,13 +105,12 @@ Only drop a file when the current repository release process clearly no longer r - `git diff --name-only origin/main...HEAD` - `git diff --stat origin/main...HEAD` - `rg -n "|" Cargo.toml Cargo.lock README.md README_ZH.md flake.nix helm/rustfs/Chart.yaml rustfs.spec` -- `make pre-commit` ## Output contract When using this skill, always report: -- Target version. +- Target version and stage. - Files changed. - Any assumptions or uncertainties requiring confirmation. - Verification result (`PASSED` or `BLOCKED`) with key evidence. diff --git a/.github/workflows/helm-package.yml b/.github/workflows/helm-package.yml index 8538f04fd..cab28487a 100644 --- a/.github/workflows/helm-package.yml +++ b/.github/workflows/helm-package.yml @@ -48,9 +48,10 @@ jobs: chart_version: ${{ steps.version.outputs.chart_version }} steps: - - name: Checkout helm chart repo + - name: Checkout release source uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v7 with: + ref: ${{ github.event.workflow_run.head_sha || (startsWith(inputs.version, 'refs/tags/') && inputs.version || format('refs/tags/{0}', inputs.version)) }} persist-credentials: false # Both inputs reach the shell through env rather than `${{ }}` @@ -83,6 +84,40 @@ jobs: ./scripts/helm_chart_version.sh "$RAW_TAG" + # Docker and Helm share the binary-build trigger. Do not publish a chart + # until the image selected by its default appVersion is pullable. + - name: Wait for release image + timeout-minutes: 20 + env: + APP_VERSION: ${{ steps.version.outputs.app_version }} + run: | + set -euo pipefail + if [[ ! "$APP_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]] || + [[ "$APP_VERSION" == *-preview* ]]; then + echo "Invalid deliverable image version: $APP_VERSION" >&2 + exit 1 + fi + + for attempt in {1..60}; do + if token=$(curl --fail --silent --show-error --connect-timeout 10 --max-time 20 \ + 'https://auth.docker.io/token?service=registry.docker.io&scope=repository:rustfs/rustfs:pull' \ + | jq -er '.token // empty') && + curl --fail --silent --show-error --head --connect-timeout 10 --max-time 20 \ + --header "Authorization: Bearer $token" \ + --header 'Accept: application/vnd.oci.image.index.v1+json, application/vnd.docker.distribution.manifest.list.v2+json' \ + "https://registry-1.docker.io/v2/rustfs/rustfs/manifests/$APP_VERSION" > /dev/null; then + echo "Release image is available: rustfs/rustfs:$APP_VERSION" + exit 0 + fi + echo "Waiting for rustfs/rustfs:$APP_VERSION ($attempt/60)" + if (( attempt < 60 )); then + sleep 15 + fi + done + + echo "Release image is unavailable; refusing to publish Helm chart" >&2 + exit 1 + - name: Replace chart version and app version env: CHART_VERSION: ${{ steps.version.outputs.chart_version }} diff --git a/README.md b/README.md index ea7309b08..09459b364 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,7 @@ chown -R 10001:10001 data logs docker run -d -p 9000:9000 -p 9001:9001 -v $(pwd)/data:/data -v $(pwd)/logs:/logs rustfs/rustfs:latest # Using specific version -docker run -d -p 9000:9000 -p 9001:9001 -v $(pwd)/data:/data -v $(pwd)/logs:/logs rustfs/rustfs:1.0.1 +docker run -d -p 9000:9000 -p 9001:9001 -v $(pwd)/data:/data -v $(pwd)/logs:/logs rustfs/rustfs:1.0.0 ``` If you use [podman](https://github.com/containers/podman) instead of docker, you can install the RustFS with the below command diff --git a/README_ZH.md b/README_ZH.md index 6426de29a..82361ce9a 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -138,7 +138,7 @@ chown -R 10001:10001 data logs docker run -d -p 9000:9000 -p 9001:9001 -v $(pwd)/data:/data -v $(pwd)/logs:/logs rustfs/rustfs:latest # 使用指定版本运行 -docker run -d -p 9000:9000 -p 9001:9001 -v $(pwd)/data:/data -v $(pwd)/logs:/logs rustfs/rustfs:1.0.1 +docker run -d -p 9000:9000 -p 9001:9001 -v $(pwd)/data:/data -v $(pwd)/logs:/logs rustfs/rustfs:1.0.0 ``` 如果您通过绑定挂载启用 TLS 证书目录,也请用同样方式准备该目录: diff --git a/flake.nix b/flake.nix index a58fcd85f..53b611178 100644 --- a/flake.nix +++ b/flake.nix @@ -77,7 +77,7 @@ rustfs = rustPlatform.buildRustPackage { pname = "rustfs"; - version = "1.0.1"; + version = "1.0.0"; src = ./.; diff --git a/helm/rustfs/Chart.yaml b/helm/rustfs/Chart.yaml index 72ad9abc8..4c7d9b531 100644 --- a/helm/rustfs/Chart.yaml +++ b/helm/rustfs/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 name: rustfs description: RustFS helm chart to deploy RustFS on kubernetes cluster. type: application -version: "1.0.1" -appVersion: "1.0.1" +version: "1.0.0" +appVersion: "1.0.0" home: https://rustfs.com icon: https://media.sys.truenas.net/apps/rustfs/icons/icon.svg maintainers: diff --git a/rustfs.spec b/rustfs.spec index 68913fce0..3682b00c9 100644 --- a/rustfs.spec +++ b/rustfs.spec @@ -1,7 +1,7 @@ %global _enable_debug_packages 0 %global _empty_manifest_terminate_build 0 Name: rustfs -Version: 1.0.1 +Version: 1.0.0 Release: 1 Summary: High-performance distributed object storage for MinIO alternative @@ -57,9 +57,6 @@ install %_builddir/%{name}-%{version}/target/%_arch/%_arch-unknown-linux-gnu/rel %_bindir/rustfs %changelog -* Wed Sep 16 2026 overtrue -- Update RPM package to RustFS 1.0.1 - * Wed Sep 16 2026 overtrue - Record the RustFS 1.0.0 stable release diff --git a/scripts/security/check_preview_release_workflow.sh b/scripts/security/check_preview_release_workflow.sh index 3f7456193..c13bdc5f7 100755 --- a/scripts/security/check_preview_release_workflow.sh +++ b/scripts/security/check_preview_release_workflow.sh @@ -229,6 +229,8 @@ IFS= read -r -d '' expected_helm_guard <<'EOF' || true EOF expected_helm_guard=${expected_helm_guard%$'\n'} require_job_if "$helm_workflow" "build-helm-package" "$expected_helm_guard" +require_line "$helm_workflow" " ref: \${{ github.event.workflow_run.head_sha || (startsWith(inputs.version, 'refs/tags/') && inputs.version || format('refs/tags/{0}', inputs.version)) }}" "Helm release source checkout" +python3 scripts/test_helm_release_workflow.py assert_equal() { local expected="$1" diff --git a/scripts/test_helm_release_workflow.py b/scripts/test_helm_release_workflow.py new file mode 100644 index 000000000..a178f5eca --- /dev/null +++ b/scripts/test_helm_release_workflow.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 +"""Exercise the Helm publication image gate without contacting a registry.""" + +import os +import subprocess +import tempfile +import unittest +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +WORKFLOW = ROOT / ".github/workflows/helm-package.yml" + + +def image_gate(): + lines = WORKFLOW.read_text().splitlines() + start = lines.index(" - name: Wait for release image") + start = lines.index(" run: |", start) + 1 + body = [] + for line in lines[start:]: + if line.strip() and not line.startswith(" "): + break + body.append(line[10:]) + return "\n".join(body) + + +class HelmReleaseWorkflowTests(unittest.TestCase): + def run_gate(self, version="1.0.1", failures=0, auth="ready"): + # Unexpected URLs fail closed; these functions cannot access the network. + mocks = r""" +curl() { + case "${*: -1}" in + 'https://auth.docker.io/token?service=registry.docker.io&scope=repository:rustfs/rustfs:pull') + echo auth >> "$CALLS" + case "$AUTH_STATE" in + unavailable) return 22 ;; + empty) echo '{}' ;; + ready) echo '{"token":"registry-test-token"}' ;; + *) return 99 ;; + esac + ;; + "https://registry-1.docker.io/v2/rustfs/rustfs/manifests/$APP_VERSION") + [[ " $* " == *" --head "* ]] || return 99 + [[ "$*" == *"Authorization: Bearer registry-test-token"* ]] || return 99 + echo image >> "$CALLS" + [[ $(grep -c '^image$' "$CALLS") -gt "$IMAGE_FAILURES" ]] + ;; + *) return 99 ;; + esac +} +sleep() { + [[ "$1" == 15 ]] || return 99 + echo sleep >> "$CALLS" +} +""" + with tempfile.TemporaryDirectory() as directory: + calls = Path(directory) / "calls" + result = subprocess.run( + ["bash", "-e", "-o", "pipefail", "-c", mocks + image_gate()], + env={ + **os.environ, + "APP_VERSION": version, + "IMAGE_FAILURES": str(failures), + "AUTH_STATE": auth, + "CALLS": str(calls), + }, + capture_output=True, + text=True, + check=False, + timeout=30, + ) + events = calls.read_text().splitlines() if calls.exists() else [] + return result, events + + def test_published_stable_and_prerelease_images(self): + for version in ("1.0.1", "1.1.0-beta.1", "1.1.0-rc.1"): + with self.subTest(version=version): + result, events = self.run_gate(version) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual(events, ["auth", "image"]) + + def test_image_published_after_binary_build(self): + result, events = self.run_gate(failures=2) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual(events.count("image"), 3) + self.assertEqual(events.count("sleep"), 2) + + def test_missing_image_blocks_publication_after_bounded_retries(self): + result, events = self.run_gate(failures=60) + self.assertNotEqual(result.returncode, 0) + self.assertIn("refusing to publish Helm chart", result.stderr) + self.assertEqual(events.count("image"), 60) + self.assertEqual(events.count("sleep"), 59) + + def test_auth_failure_is_not_image_availability(self): + for auth in ("unavailable", "empty"): + with self.subTest(auth=auth): + result, events = self.run_gate(auth=auth) + self.assertNotEqual(result.returncode, 0) + self.assertEqual(events.count("auth"), 60) + self.assertNotIn("image", events) + + def test_preview_and_invalid_versions_never_reach_registry(self): + for version in ("1.0.1-preview.1", "1.1.0-beta.1-preview.2", "latest", "", "../tags"): + with self.subTest(version=version): + result, events = self.run_gate(version) + self.assertNotEqual(result.returncode, 0) + self.assertEqual(events, []) + + def test_image_gate_precedes_packaging(self): + workflow = WORKFLOW.read_text() + gate = workflow.index(" - name: Wait for release image") + package = workflow.index(" - name: Package Helm Chart") + self.assertLess(gate, package) + self.assertNotIn("continue-on-error", workflow[gate:package]) + + +if __name__ == "__main__": + unittest.main()