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")