You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fluss.apache.org by ja...@apache.org on 2026/09/18 02:10:36 UTC

(fluss) branch release-1.0 updated: [build] Give Python release candidates distinct versions (#4412)

This is an automated email from the ASF dual-hosted git repository.

wuchong pushed a commit to branch release-1.0
in repository https://gitbox.apache.org/repos/asf/fluss.git


The following commit(s) were added to refs/heads/release-1.0 by this push:
     new e25f7464ff [build] Give Python release candidates distinct versions (#4412)
e25f7464ff is described below

commit e25f7464fffe5dc0e84efcdd071c2de2360a3b54
Author: Jark Wu <ja...@apache.org>
AuthorDate: Fri Sep 18 10:10:32 2026 +0800

    [build] Give Python release candidates distinct versions (#4412)
---
 .github/workflows/python-release.yml          | 12 +++++
 fluss-rust/bindings/python/DEVELOPMENT.md     |  7 +++
 tools/releasing/set_python_release_version.py | 63 +++++++++++++++++++++++++++
 3 files changed, 82 insertions(+)

diff --git a/.github/workflows/python-release.yml b/.github/workflows/python-release.yml
index dc58d892e6..c6fa693caa 100644
--- a/.github/workflows/python-release.yml
+++ b/.github/workflows/python-release.yml
@@ -48,6 +48,12 @@ jobs:
     needs: [version-check]
     steps:
       - uses: actions/checkout@v6
+      - name: Set Python release version
+        shell: bash
+        env:
+          RELEASE_TAG: ${{ github.ref_name }}
+        run: python tools/releasing/set_python_release_version.py "$RELEASE_TAG"
+
       - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4
         with:
           toolchain: stable
@@ -80,6 +86,12 @@ jobs:
           - { os: ubuntu-latest, target: "aarch64", manylinux: "manylinux_2_28", license-target: "aarch64-unknown-linux-gnu" }
     steps:
       - uses: actions/checkout@v6
+      - name: Set Python release version
+        shell: bash
+        env:
+          RELEASE_TAG: ${{ github.ref_name }}
+        run: python tools/releasing/set_python_release_version.py "$RELEASE_TAG"
+
       - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4
         with:
           toolchain: stable
diff --git a/fluss-rust/bindings/python/DEVELOPMENT.md b/fluss-rust/bindings/python/DEVELOPMENT.md
index 8a916ce4e9..c756b796bb 100644
--- a/fluss-rust/bindings/python/DEVELOPMENT.md
+++ b/fluss-rust/bindings/python/DEVELOPMENT.md
@@ -92,6 +92,13 @@ uv run pdoc fluss
 
 ## Release
 
+The tag-triggered Python release workflow publishes each release candidate to
+TestPyPI with its own PEP 440 version: `v1.0.0-rc3` builds `pyfluss==1.0.0rc3`.
+Before building both the sdist and wheels, it sets the Python package version in
+`pyproject.toml`; Rust workspace versions and lockfiles remain unchanged. The
+sdist retains this version when rebuilt. Final tags such as `v1.0.0` keep the
+Cargo-derived `1.0.0` version and publish to PyPI.
+
 ```bash
 # Build wheel
 uv run maturin build --release
diff --git a/tools/releasing/set_python_release_version.py b/tools/releasing/set_python_release_version.py
new file mode 100644
index 0000000000..14cf5ae4ff
--- /dev/null
+++ b/tools/releasing/set_python_release_version.py
@@ -0,0 +1,63 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+
+"""Give each TestPyPI candidate its own version before running maturin."""
+
+import argparse
+import re
+from pathlib import Path
+
+
+def set_release_version(pyproject: Path, tag: str) -> str:
+    """Set PEP 440 RC metadata; final releases keep the Cargo-derived version."""
+    match = re.fullmatch(r"v([0-9]+\.[0-9]+\.[0-9]+)(?:-rc\.?([0-9]+))?", tag)
+    if match is None:
+        raise ValueError(f"Expected vX.Y.Z or vX.Y.Z-rcN, got {tag!r}")
+
+    version, candidate = match.groups()
+    if candidate is None:
+        return version
+
+    version = f"{version}rc{int(candidate)}"
+    content = pyproject.read_text(encoding="utf-8")
+    # Keep the Rust workspace and lockfile at the final version. Static Python
+    # metadata takes precedence in maturin and survives rebuilding the sdist.
+    content, count = re.subn(
+        r'^dynamic[ \t]*=[ \t]*\["version"\][ \t]*$',
+        f'version = "{version}"',
+        content,
+        flags=re.MULTILINE,
+    )
+    if count != 1:
+        raise ValueError(f"Expected exactly one dynamic version field in {pyproject}")
+    pyproject.write_text(content, encoding="utf-8")
+    return version
+
+
+def main() -> None:
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument("tag", help="Release tag already checked against Cargo.toml")
+    args = parser.parse_args()
+    root = Path(__file__).resolve().parents[2]
+    version = set_release_version(
+        root / "fluss-rust/bindings/python/pyproject.toml", args.tag
+    )
+    print(f"Python distribution version: {version}")
+
+
+if __name__ == "__main__":
+    main()