You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tsfile.apache.org by co...@apache.org on 2026/09/17 06:30:44 UTC

(tsfile) 01/24: build: support Python dev release versioning

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

ColinLeeo pushed a commit to branch feat/native-package-artifacts
in repository https://gitbox.apache.org/repos/asf/tsfile.git

commit 3adc6c8efcef82344e3df3cea69e3f46761fd4b4
Author: ColinLee <sh...@163.com>
AuthorDate: Mon Aug 31 08:56:22 2026 +0800

    build: support Python dev release versioning
---
 .github/workflows/wheels.yml            |  40 +++++++++++
 cpp/CMakeLists.txt                      |   2 +-
 cpp/pom.xml                             |   2 +-
 java/common/pom.xml                     |   2 +-
 java/examples/pom.xml                   |   4 +-
 java/pom.xml                            |   4 +-
 java/tools/pom.xml                      |   6 +-
 java/tsfile/pom.xml                     |   4 +-
 pom.xml                                 |   2 +-
 python/VersionUpdater.groovy            |   9 ++-
 python/pom.xml                          |   2 +-
 python/set_python_version.py            | 122 ++++++++++++++++++++++++++++++++
 python/tests/test_set_python_version.py |  93 ++++++++++++++++++++++++
 13 files changed, 277 insertions(+), 15 deletions(-)

diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml
index 64b5b6fe5..34672d910 100644
--- a/.github/workflows/wheels.yml
+++ b/.github/workflows/wheels.yml
@@ -5,6 +5,14 @@ on:
     branches:
       - "rc/**"
   workflow_dispatch:
+    inputs:
+      dev_number:
+        description: "Python development release number; leave empty to use the checked-in version"
+        required: false
+        type: string
+
+env:
+  TSFILE_PYTHON_DEV_NUMBER: ${{ inputs.dev_number }}
 
 jobs:
   build:
@@ -46,6 +54,16 @@ jobs:
         uses: actions/setup-python@v7
         with:
           python-version: "3.11"
+
+      - name: Set Python development version
+        if: github.event_name == 'workflow_dispatch' && inputs.dev_number != ''
+        shell: bash
+        run: |
+          set -euo pipefail
+          python_version="$(python python/set_python_version.py \
+            --dev-number "$TSFILE_PYTHON_DEV_NUMBER")"
+          echo "TSFILE_PYTHON_VERSION=$python_version" >> "$GITHUB_ENV"
+          echo "Building Python package version $python_version"
       
       - name: Set up Java 17
         uses: actions/setup-java@v5.6.0
@@ -163,6 +181,11 @@ jobs:
           CIBW_BUILD_VERBOSITY: "1"
         run: cibuildwheel --output-dir wheelhouse python
 
+      - name: Verify Python development version
+        if: github.event_name == 'workflow_dispatch' && inputs.dev_number != ''
+        shell: bash
+        run: ls "wheelhouse/tsfile-${TSFILE_PYTHON_VERSION}-"*.whl
+
       - name: Upload wheels as artifact
         uses: actions/upload-artifact@v7
         with:
@@ -244,6 +267,18 @@ jobs:
         with:
           python-version: ${{ matrix.python-version }}
 
+      - name: Set Python development version
+        if: github.event_name == 'workflow_dispatch' && inputs.dev_number != ''
+        shell: pwsh
+        run: |
+          $pythonVersion = python python/set_python_version.py `
+            --dev-number "$env:TSFILE_PYTHON_DEV_NUMBER"
+          if ($LASTEXITCODE -ne 0) {
+            exit $LASTEXITCODE
+          }
+          "TSFILE_PYTHON_VERSION=$pythonVersion" >> $env:GITHUB_ENV
+          Write-Host "Building Python package version $pythonVersion"
+
       - name: Set up Java 17
         uses: actions/setup-java@v5.6.0
         with:
@@ -298,6 +333,11 @@ jobs:
             ${BLACK_VER_PROP}
           ls -la dist/
 
+      - name: Verify Python development version
+        if: github.event_name == 'workflow_dispatch' && inputs.dev_number != ''
+        shell: msys2 {0}
+        run: ls "python/dist/tsfile-${TSFILE_PYTHON_VERSION}-"*.whl
+
       - name: Verify wheel
         shell: msys2 {0}
         run: |
diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt
index 7ff07a786..f45409e93 100755
--- a/cpp/CMakeLists.txt
+++ b/cpp/CMakeLists.txt
@@ -32,7 +32,7 @@ endif ()
 if (POLICY CMP0074)
     cmake_policy(SET CMP0074 NEW)
 endif ()
-set(TsFile_CPP_VERSION 2.3.2.dev)
+set(TsFile_CPP_VERSION 2.5.0.dev)
 
 include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/DependencySource.cmake)
 list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
diff --git a/cpp/pom.xml b/cpp/pom.xml
index c0fbbc2c5..50674ad02 100644
--- a/cpp/pom.xml
+++ b/cpp/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.tsfile</groupId>
         <artifactId>tsfile-parent</artifactId>
-        <version>2.3.2-SNAPSHOT</version>
+        <version>2.5.0-SNAPSHOT</version>
     </parent>
     <artifactId>tsfile-cpp</artifactId>
     <packaging>pom</packaging>
diff --git a/java/common/pom.xml b/java/common/pom.xml
index 53e98732c..dec9154b2 100644
--- a/java/common/pom.xml
+++ b/java/common/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.tsfile</groupId>
         <artifactId>tsfile-java</artifactId>
-        <version>2.3.2-SNAPSHOT</version>
+        <version>2.5.0-SNAPSHOT</version>
     </parent>
     <artifactId>common</artifactId>
     <name>TsFile: Java: Common</name>
diff --git a/java/examples/pom.xml b/java/examples/pom.xml
index 075a70e52..92748cb61 100644
--- a/java/examples/pom.xml
+++ b/java/examples/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.tsfile</groupId>
         <artifactId>tsfile-java</artifactId>
-        <version>2.3.2-SNAPSHOT</version>
+        <version>2.5.0-SNAPSHOT</version>
     </parent>
     <artifactId>examples</artifactId>
     <name>TsFile: Java: Examples</name>
@@ -36,7 +36,7 @@
         <dependency>
             <groupId>org.apache.tsfile</groupId>
             <artifactId>tsfile</artifactId>
-            <version>2.3.2-SNAPSHOT</version>
+            <version>2.5.0-SNAPSHOT</version>
         </dependency>
     </dependencies>
     <build>
diff --git a/java/pom.xml b/java/pom.xml
index 13c781bea..8c2c319a4 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -24,10 +24,10 @@
     <parent>
         <groupId>org.apache.tsfile</groupId>
         <artifactId>tsfile-parent</artifactId>
-        <version>2.3.2-SNAPSHOT</version>
+        <version>2.5.0-SNAPSHOT</version>
     </parent>
     <artifactId>tsfile-java</artifactId>
-    <version>2.3.2-SNAPSHOT</version>
+    <version>2.5.0-SNAPSHOT</version>
     <packaging>pom</packaging>
     <name>TsFile: Java</name>
     <modules>
diff --git a/java/tools/pom.xml b/java/tools/pom.xml
index df148f652..0c62cbb06 100644
--- a/java/tools/pom.xml
+++ b/java/tools/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.tsfile</groupId>
         <artifactId>tsfile-java</artifactId>
-        <version>2.3.2-SNAPSHOT</version>
+        <version>2.5.0-SNAPSHOT</version>
     </parent>
     <artifactId>tools</artifactId>
     <name>TsFile: Java: Tools</name>
@@ -32,7 +32,7 @@
         <dependency>
             <groupId>org.apache.tsfile</groupId>
             <artifactId>common</artifactId>
-            <version>2.3.2-SNAPSHOT</version>
+            <version>2.5.0-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>commons-cli</groupId>
@@ -41,7 +41,7 @@
         <dependency>
             <groupId>org.apache.tsfile</groupId>
             <artifactId>tsfile</artifactId>
-            <version>2.3.2-SNAPSHOT</version>
+            <version>2.5.0-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>ch.qos.logback</groupId>
diff --git a/java/tsfile/pom.xml b/java/tsfile/pom.xml
index ec327381c..427a563d1 100644
--- a/java/tsfile/pom.xml
+++ b/java/tsfile/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.tsfile</groupId>
         <artifactId>tsfile-java</artifactId>
-        <version>2.3.2-SNAPSHOT</version>
+        <version>2.5.0-SNAPSHOT</version>
     </parent>
     <artifactId>tsfile</artifactId>
     <name>TsFile: Java: TsFile</name>
@@ -38,7 +38,7 @@
         <dependency>
             <groupId>org.apache.tsfile</groupId>
             <artifactId>common</artifactId>
-            <version>2.3.2-SNAPSHOT</version>
+            <version>2.5.0-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>com.github.luben</groupId>
diff --git a/pom.xml b/pom.xml
index 0e5988130..dfa7dea28 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
     </parent>
     <groupId>org.apache.tsfile</groupId>
     <artifactId>tsfile-parent</artifactId>
-    <version>2.3.2-SNAPSHOT</version>
+    <version>2.5.0-SNAPSHOT</version>
     <packaging>pom</packaging>
     <name>Apache TsFile Project Parent POM</name>
     <properties>
diff --git a/python/VersionUpdater.groovy b/python/VersionUpdater.groovy
index a586fe936..0b18cd5f3 100644
--- a/python/VersionUpdater.groovy
+++ b/python/VersionUpdater.groovy
@@ -23,10 +23,17 @@
 
 def currentMavenVersion = project.version as String
 def currentPyVersion = currentMavenVersion
-if(currentMavenVersion.contains("-SNAPSHOT")) {
+def overriddenPyVersion = System.getenv("TSFILE_PYTHON_VERSION")
+if(overriddenPyVersion != null && !overriddenPyVersion.isEmpty()) {
+    if(!(overriddenPyVersion ==~ /^[0-9]+\.[0-9]+\.[0-9]+(?:\.dev(?:0|[1-9][0-9]*))?$/)) {
+        throw new IllegalArgumentException("Invalid TSFILE_PYTHON_VERSION: " + overriddenPyVersion)
+    }
+    currentPyVersion = overriddenPyVersion
+} else if(currentMavenVersion.contains("-SNAPSHOT")) {
     currentPyVersion = currentMavenVersion.split("-SNAPSHOT")[0] + ".dev"
 }
 println "Current Project Version in Maven:  " + currentMavenVersion
+println "Current Project Version for Python: " + currentPyVersion
 
 // Sync setup.py
 def pyProjectFile = new File(project.basedir, "setup.py")
diff --git a/python/pom.xml b/python/pom.xml
index 047315215..c8b025111 100644
--- a/python/pom.xml
+++ b/python/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.tsfile</groupId>
         <artifactId>tsfile-parent</artifactId>
-        <version>2.3.2-SNAPSHOT</version>
+        <version>2.5.0-SNAPSHOT</version>
     </parent>
     <artifactId>tsfile-python</artifactId>
     <packaging>pom</packaging>
diff --git a/python/set_python_version.py b/python/set_python_version.py
new file mode 100644
index 000000000..910274214
--- /dev/null
+++ b/python/set_python_version.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python3
+#
+# 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.
+#
+
+from __future__ import annotations
+
+import argparse
+import re
+import sys
+import xml.etree.ElementTree as ET
+from pathlib import Path
+
+_VERSION_COMPONENT = r"(?:0|[1-9][0-9]*)"
+_MAVEN_VERSION = re.compile(
+    rf"^({_VERSION_COMPONENT}\.{_VERSION_COMPONENT}\.{_VERSION_COMPONENT})"
+    rf"(?:(?:-[0-9]+)?-SNAPSHOT)?$"
+)
+_DEV_NUMBER = re.compile(r"^(?:0|[1-9][0-9]*)$")
+_VERSION_ASSIGNMENT = re.compile(r'(?m)^(version\s*=\s*")[^"\r\n]+(")')
+
+
+def read_maven_version(pom_path: Path) -> str:
+    root = ET.parse(pom_path).getroot()
+    namespace = root.tag.partition("}")[0] + "}" if "}" in root.tag else ""
+    version = root.find(f"{namespace}version")
+    if version is None or not version.text:
+        raise ValueError(f"project version is missing from {pom_path}")
+    return version.text.strip()
+
+
+def resolve_dev_version(maven_version: str, dev_number: str) -> str:
+    if not _DEV_NUMBER.fullmatch(dev_number):
+        raise ValueError(
+            "development release number must be 0 or a positive integer "
+            "without leading zeros"
+        )
+
+    match = _MAVEN_VERSION.fullmatch(maven_version)
+    if match is None:
+        raise ValueError(
+            "Maven version must be X.Y.Z, X.Y.Z-SNAPSHOT, or "
+            "X.Y.Z-<date>-SNAPSHOT; got "
+            f"{maven_version!r}"
+        )
+    return f"{match.group(1)}.dev{dev_number}"
+
+
+def _updated_version_text(path: Path, version: str) -> tuple[str, str]:
+    with path.open("r", encoding="utf-8", newline="") as stream:
+        original = stream.read()
+    updated, replacements = _VERSION_ASSIGNMENT.subn(rf"\g<1>{version}\g<2>", original)
+    if replacements != 1:
+        raise ValueError(
+            f"expected exactly one version assignment in {path}, found {replacements}"
+        )
+    return original, updated
+
+
+def synchronize_python_version(project_root: Path, version: str) -> None:
+    paths = (
+        project_root / "python" / "pyproject.toml",
+        project_root / "python" / "setup.py",
+    )
+    updates = [(path, *_updated_version_text(path, version)) for path in paths]
+    for path, original, updated in updates:
+        if updated == original:
+            continue
+        with path.open("w", encoding="utf-8", newline="") as stream:
+            stream.write(updated)
+
+
+def parse_args(argv: list[str]) -> argparse.Namespace:
+    parser = argparse.ArgumentParser(
+        description="Set a Python development version derived from the root Maven POM."
+    )
+    parser.add_argument(
+        "--dev-number",
+        required=True,
+        help="PEP 440 development release number, for example 0, 1, or 2.",
+    )
+    parser.add_argument(
+        "--project-root",
+        type=Path,
+        default=Path(__file__).resolve().parent.parent,
+        help=argparse.SUPPRESS,
+    )
+    return parser.parse_args(argv)
+
+
+def main(argv: list[str] | None = None) -> int:
+    args = parse_args(argv if argv is not None else sys.argv[1:])
+    try:
+        project_root = args.project_root.resolve()
+        maven_version = read_maven_version(project_root / "pom.xml")
+        python_version = resolve_dev_version(maven_version, args.dev_number)
+        synchronize_python_version(project_root, python_version)
+    except (OSError, ET.ParseError, ValueError) as error:
+        print(f"error: {error}", file=sys.stderr)
+        return 2
+
+    print(python_version)
+    return 0
+
+
+if __name__ == "__main__":
+    raise SystemExit(main())
diff --git a/python/tests/test_set_python_version.py b/python/tests/test_set_python_version.py
new file mode 100644
index 000000000..5eef6825e
--- /dev/null
+++ b/python/tests/test_set_python_version.py
@@ -0,0 +1,93 @@
+# 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.
+#
+
+import importlib.util
+from pathlib import Path
+
+import pytest
+
+SCRIPT_PATH = Path(__file__).parents[1] / "set_python_version.py"
+SPEC = importlib.util.spec_from_file_location("set_python_version", SCRIPT_PATH)
+set_python_version = importlib.util.module_from_spec(SPEC)
+assert SPEC.loader is not None
+SPEC.loader.exec_module(set_python_version)
+
+
+def test_read_maven_version_uses_project_version(tmp_path):
+    pom = tmp_path / "pom.xml"
+    pom.write_text(
+        """<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0">
+  <parent>
+    <groupId>org.apache</groupId>
+    <artifactId>apache</artifactId>
+    <version>33</version>
+  </parent>
+  <version>2.4.1-SNAPSHOT</version>
+</project>
+""",
+        encoding="utf-8",
+    )
+
+    assert set_python_version.read_maven_version(pom) == "2.4.1-SNAPSHOT"
+
+
+@pytest.mark.parametrize(
+    ("maven_version", "dev_number", "expected"),
+    [
+        ("2.4.1-SNAPSHOT", "0", "2.4.1.dev0"),
+        ("2.4.1-SNAPSHOT", "2", "2.4.1.dev2"),
+        ("2.4.1-260806-SNAPSHOT", "12", "2.4.1.dev12"),
+        ("2.4.1", "1", "2.4.1.dev1"),
+    ],
+)
+def test_resolve_dev_version(maven_version, dev_number, expected):
+    assert set_python_version.resolve_dev_version(maven_version, dev_number) == expected
+
+
+@pytest.mark.parametrize("dev_number", ["", "-1", "01", "1.0", "dev1"])
+def test_resolve_dev_version_rejects_invalid_dev_number(dev_number):
+    with pytest.raises(ValueError, match="development release number"):
+        set_python_version.resolve_dev_version("2.4.1-SNAPSHOT", dev_number)
+
+
+@pytest.mark.parametrize(
+    "maven_version", ["2.4-SNAPSHOT", "2.4.1-RC1", "2.4.1-feature-SNAPSHOT"]
+)
+def test_resolve_dev_version_rejects_unsupported_maven_version(maven_version):
+    with pytest.raises(ValueError, match="Maven version must be"):
+        set_python_version.resolve_dev_version(maven_version, "1")
+
+
+def test_synchronize_python_version_only_updates_python_metadata(tmp_path):
+    python_dir = tmp_path / "python"
+    cpp_dir = tmp_path / "cpp"
+    python_dir.mkdir()
+    cpp_dir.mkdir()
+    pyproject = python_dir / "pyproject.toml"
+    setup = python_dir / "setup.py"
+    cmake = cpp_dir / "CMakeLists.txt"
+    pyproject.write_text('[project]\nversion = "2.4.1.dev"\n', encoding="utf-8")
+    setup.write_text('version = "2.4.1.dev"\n', encoding="utf-8")
+    cmake.write_text("set(TsFile_CPP_VERSION 2.4.1.dev)\n", encoding="utf-8")
+
+    set_python_version.synchronize_python_version(tmp_path, "2.4.1.dev2")
+
+    assert 'version = "2.4.1.dev2"' in pyproject.read_text(encoding="utf-8")
+    assert 'version = "2.4.1.dev2"' in setup.read_text(encoding="utf-8")
+    assert cmake.read_text(encoding="utf-8") == ("set(TsFile_CPP_VERSION 2.4.1.dev)\n")