From 63d09fba0c60c934c45b0c0e7266b43831e29fd8 Mon Sep 17 00:00:00 2001 From: gatewayJ <835269233@qq.com> Date: Sun, 25 Oct 2026 19:10:08 +0800 Subject: [PATCH] fix(release): correct 0.0.8 metadata and test chart image versions --- .github/workflows/ci.yml | 1 + CHANGELOG.md | 2 + Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- deploy/rustfs-operator/Chart.yaml | 4 +- deploy/rustfs-tenant/Chart.yaml | 2 +- e2e/Cargo.lock | 2 +- e2e/tests/release_metadata.rs | 182 ++++++++++++++++++++++++++++++ scripts/check-release-metadata.sh | 7 ++ 10 files changed, 199 insertions(+), 7 deletions(-) create mode 100644 e2e/tests/release_metadata.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8517412..ab304b2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,7 @@ name: Continuous Integration on: push: branches: [ main ] + tags: [ "[0-9]*", "v[0-9]*" ] paths-ignore: - "**.md" - "**.txt" diff --git a/CHANGELOG.md b/CHANGELOG.md index 3331562..b35f216 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,8 @@ All notable changes to RustFS Operator are documented in this file. The format i ### Fixed +- Update source release metadata to `0.0.8` so source Helm installs select the + `0.0.8` Operator and Console images, and verify release tags and chart images in CI. - Use `docker.io/rustfs/operator` as the default Helm image repository for the Operator, Console, and COSI driver, while preserving repository overrides through Helm values. - Reject multi-pool Tenants containing a single-node single-disk pool before applying pool workloads, matching RustFS startup constraints. diff --git a/Cargo.lock b/Cargo.lock index 1bdf9f9..dfb3ef6 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -1870,7 +1870,7 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "operator" -version = "0.0.6" +version = "0.0.8" dependencies = [ "async-trait", "axum", diff --git a/Cargo.toml b/Cargo.toml index a1dba84..95239b6 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "operator" -version = "0.0.6" +version = "0.0.8" edition = "2024" repository = "https://github.com/rustfs/operator" license = "Apache-2.0" diff --git a/README.md b/README.md index 9591b7e..3d85f1f 100755 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A Kubernetes operator for [RustFS](https://rustfs.com/) object storage, written in Rust with [kube-rs](https://github.com/kube-rs/kube). It reconciles a **`Tenant` custom resource** (`rustfs.com/v1alpha1`), validates referenced credential and KMS Secrets, and applies ServiceAccounts, Services, and StatefulSets so RustFS runs inside your cluster, from single-node single-disk development tenants to erasure-coded distributed clusters. -**Status:** v0.0.6 — under active development. +**Status:** v0.0.8 — under active development. ## Features diff --git a/deploy/rustfs-operator/Chart.yaml b/deploy/rustfs-operator/Chart.yaml index 43ec2df..45d4f04 100755 --- a/deploy/rustfs-operator/Chart.yaml +++ b/deploy/rustfs-operator/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 name: rustfs-operator description: Kubernetes operator for managing RustFS storage clusters type: application -version: 0.0.6 -appVersion: "0.0.6" +version: 0.0.8 +appVersion: "0.0.8" home: https://rustfs.com sources: - https://github.com/rustfs/operator diff --git a/deploy/rustfs-tenant/Chart.yaml b/deploy/rustfs-tenant/Chart.yaml index 22ed5b6..48c219a 100644 --- a/deploy/rustfs-tenant/Chart.yaml +++ b/deploy/rustfs-tenant/Chart.yaml @@ -16,7 +16,7 @@ apiVersion: v2 name: rustfs-tenant description: A RustFS Tenant with optional S3 and Console ingress resources type: application -version: 0.0.6 +version: 0.0.8 home: https://rustfs.com sources: - https://github.com/rustfs/operator diff --git a/e2e/Cargo.lock b/e2e/Cargo.lock index 128a117..cc5210f 100644 --- a/e2e/Cargo.lock +++ b/e2e/Cargo.lock @@ -2620,7 +2620,7 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "operator" -version = "0.0.6" +version = "0.0.8" dependencies = [ "async-trait", "axum", diff --git a/e2e/tests/release_metadata.rs b/e2e/tests/release_metadata.rs new file mode 100644 index 0000000..91831e1 --- /dev/null +++ b/e2e/tests/release_metadata.rs @@ -0,0 +1,182 @@ +// Copyright 2026 RustFS Team +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use serde::Deserialize; +use serde_yaml_ng::Value; +use std::{ + collections::BTreeMap, + path::Path, + process::{Command, Output}, +}; + +fn repository() -> &'static Path { + Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .expect("e2e is inside the repository") +} + +fn chart_version() -> String { + let metadata: Value = serde_yaml_ng::from_str( + &std::fs::read_to_string(repository().join("deploy/rustfs-operator/Chart.yaml")) + .expect("chart metadata exists"), + ) + .expect("chart metadata parses"); + metadata["version"] + .as_str() + .expect("chart version is a string") + .to_owned() +} + +fn check_metadata(ref_type: &str, ref_name: &str) -> Output { + Command::new("bash") + .current_dir(repository()) + .arg("scripts/check-release-metadata.sh") + .env("GITHUB_REF_TYPE", ref_type) + .env("GITHUB_REF_NAME", ref_name) + .output() + .expect("release metadata check runs") +} + +fn successful_output(command: &mut Command) -> Vec { + let output = command + .output() + .expect("install Helm 3 to run release tests"); + assert!( + output.status.success(), + "{command:?}: {}", + String::from_utf8_lossy(&output.stderr) + ); + output.stdout +} + +fn chart_images(chart: &Path, version: &str) -> BTreeMap { + let output = successful_output( + Command::new("helm") + .args(["template", "release-test"]) + .arg(chart) + .args(["--namespace", "rustfs-system"]), + ); + let mut images = BTreeMap::new(); + for document in serde_yaml_ng::Deserializer::from_slice(&output) { + let document = Value::deserialize(document).expect("rendered YAML parses"); + if document["kind"] != "Deployment" { + continue; + } + let component = document["metadata"]["labels"]["app.kubernetes.io/component"] + .as_str() + .expect("Deployment has a component label"); + if !["operator", "console"].contains(&component) { + continue; + } + let container = document["spec"]["template"]["spec"]["containers"] + .as_sequence() + .expect("Deployment has containers") + .iter() + .find(|container| container["name"] == component) + .expect("component container exists"); + let image = container["image"].as_str().expect("container has an image"); + assert!( + image.ends_with(&format!(":{version}")), + "{component} image {image} must use release version {version}" + ); + assert!( + images + .insert(component.to_owned(), image.to_owned()) + .is_none() + ); + } + assert_eq!( + images.keys().map(String::as_str).collect::>(), + ["console", "operator"] + ); + images +} + +#[test] +fn release_metadata_accepts_branches_and_matching_release_tags() { + let version = chart_version(); + for (ref_type, ref_name) in [ + ("branch", "main".to_owned()), + ("tag", version.clone()), + ("tag", format!("v{version}")), + ] { + let output = check_metadata(ref_type, &ref_name); + assert!( + output.status.success(), + "{ref_type} {ref_name}: {}", + String::from_utf8_lossy(&output.stderr) + ); + } +} + +#[test] +fn release_metadata_rejects_mismatched_tags_even_when_files_are_consistent() { + let version = chart_version(); + let baseline = check_metadata("branch", "main"); + assert!( + baseline.status.success(), + "{}", + String::from_utf8_lossy(&baseline.stderr) + ); + let mismatched_version = format!("{version}-mismatch"); + for tag in [mismatched_version.clone(), format!("v{mismatched_version}")] { + let output = check_metadata("tag", &tag); + assert!(!output.status.success(), "mismatched tag {tag} must fail"); + assert!(String::from_utf8_lossy(&output.stderr).contains(&format!( + "release tag version is '{mismatched_version}', expected '{version}'" + ))); + } +} + +#[test] +fn release_metadata_requires_a_version_for_tag_refs() { + for tag in ["", "v"] { + let output = check_metadata("tag", tag); + assert!(!output.status.success(), "empty release version must fail"); + assert!( + String::from_utf8_lossy(&output.stderr).contains("could not read release tag version") + ); + } +} + +#[test] +fn source_and_packaged_charts_use_the_release_image_version() { + let version = if std::env::var("GITHUB_REF_TYPE").as_deref() == Ok("tag") { + let tag = std::env::var("GITHUB_REF_NAME").expect("tag CI provides the release tag"); + tag.strip_prefix('v').unwrap_or(&tag).to_owned() + } else { + chart_version() + }; + let chart = repository().join("deploy/rustfs-operator"); + let source_images = chart_images(&chart, &version); + let packages = tempfile::tempdir().expect("chart package directory is created"); + successful_output( + Command::new("helm") + .arg("package") + .arg(&chart) + .args(["--version", &version, "--app-version", &version]) + .arg("--destination") + .arg(packages.path()), + ); + let package = packages + .path() + .join(format!("rustfs-operator-{version}.tgz")); + let metadata: Value = serde_yaml_ng::from_slice(&successful_output( + Command::new("helm").args(["show", "chart"]).arg(&package), + )) + .expect("packaged chart metadata parses"); + assert_eq!(metadata["version"], version); + assert_eq!(metadata["appVersion"], version); + assert_eq!(chart_images(&package, &version), source_images); +} diff --git a/scripts/check-release-metadata.sh b/scripts/check-release-metadata.sh index 7310681..27f63d6 100755 --- a/scripts/check-release-metadata.sh +++ b/scripts/check-release-metadata.sh @@ -133,6 +133,13 @@ require_equal "Docker Rust version" "$docker_rust_version" "$toolchain_version" require_equal "Cargo.lock Operator version" "$root_lock_version" "$cargo_version" require_equal "e2e/Cargo.lock Operator version" "$e2e_lock_version" "$cargo_version" +if [[ "${GITHUB_REF_TYPE:-}" == "tag" ]]; then + release_version="${GITHUB_REF_NAME:-}" + release_version="${release_version#v}" + require_value "release tag version" "$release_version" + require_equal "release tag version" "$release_version" "$cargo_version" +fi + grep -Fq 'ENV RUSTFS_OPERATOR_VERSION=${VERSION}' Dockerfile || { echo "release metadata check failed: Docker does not pass VERSION to the Rust build" >&2 exit 1