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

jerry-024 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/paimon-vector-index.git


The following commit(s) were added to refs/heads/main by this push:
     new 84d1a40  chore: prepare release 0.4.0 (#79)
84d1a40 is described below

commit 84d1a40840b5286fcf1ade88bf32e33586505528
Author: shyjsarah <[email protected]>
AuthorDate: Mon Aug 17 14:37:49 2026 +0800

    chore: prepare release 0.4.0 (#79)
    
    Co-authored-by: shyjsarah <[email protected]>
---
 .asf.yaml                           |   2 +-
 .github/workflows/ci.yml            |   3 +
 DEPENDENCIES.rust.tsv               |   6 +-
 core/DEPENDENCIES.rust.tsv          |   2 +-
 docs/releases.html                  |  12 +-
 ffi/DEPENDENCIES.rust.tsv           |   4 +-
 jni/DEPENDENCIES.rust.tsv           |   4 +-
 tools/create_release_branch.sh      |   8 +-
 tools/tests/test_release_scripts.py | 252 ++++++++++++++++++++++++++++++++++++
 tools/update_branch_version.sh      |  30 +++--
 10 files changed, 296 insertions(+), 27 deletions(-)

diff --git a/.asf.yaml b/.asf.yaml
index d492498..a64c7fb 100644
--- a/.asf.yaml
+++ b/.asf.yaml
@@ -44,7 +44,7 @@ github:
       branches:
         includes:
           - "~DEFAULT_BRANCH"
-          - "release/*"
+          - "release-*"
         excludes: []
       bypass_teams:
         - root
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index edeae96..ad678c5 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -51,6 +51,9 @@ jobs:
             tools/convert_ann_benchmarks.py \
             tools/verify_binary_artifact.py
 
+      - name: Test release helper scripts
+        run: python3 -m unittest discover -s tools/tests -p 'test_*.py' -v
+
       - name: Validate .asf.yaml
         run: pip install pyyaml -q && python3 tools/validate_asf_yaml.py
 
diff --git a/DEPENDENCIES.rust.tsv b/DEPENDENCIES.rust.tsv
index 191f681..9a04218 100644
--- a/DEPENDENCIES.rust.tsv
+++ b/DEPENDENCIES.rust.tsv
@@ -51,9 +51,9 @@ [email protected]    X                               X
 [email protected]      X                               X                       
        
 [email protected]       X                               X                       
        
 [email protected]      X                               X               
                
[email protected]       X                                               
                
[email protected]        X                                               
                
[email protected]        X                                               
                
[email protected]       X                                               
                
[email protected]        X                                               
                
[email protected]        X                                               
                
 [email protected]   X                               X                               
 [email protected]      X                               X                       
        
 [email protected]    X                               X                       
        
diff --git a/core/DEPENDENCIES.rust.tsv b/core/DEPENDENCIES.rust.tsv
index 5b0a16f..2c37814 100644
--- a/core/DEPENDENCIES.rust.tsv
+++ b/core/DEPENDENCIES.rust.tsv
@@ -19,7 +19,7 @@ [email protected]     X                       X
 [email protected]     X                       X                       
 [email protected]     X                       X                       
 [email protected]      X                       X                       
[email protected]       X                                               
[email protected]       X                                               
 [email protected]   X                       X                       
 [email protected]      X                       X                       
 [email protected]    X                       X                       
diff --git a/docs/releases.html b/docs/releases.html
index aed9f95..46f2d32 100644
--- a/docs/releases.html
+++ b/docs/releases.html
@@ -31,7 +31,7 @@
     </section>
 
     <div class="doc-layout">
-      <aside class="toc" aria-label="On this page"><strong>On this 
page</strong><a href="#channels">Distribution channels</a><a 
href="#upcoming">Upcoming</a><a href="#release-020">0.2.0</a><a 
href="#release-010">0.1.0</a><a href="#guides">Release guides</a></aside>
+      <aside class="toc" aria-label="On this page"><strong>On this 
page</strong><a href="#channels">Distribution channels</a><a 
href="#upcoming">Upcoming</a><a href="#release-030">0.3.0</a><a 
href="#release-020">0.2.0</a><a href="#release-010">0.1.0</a><a 
href="#guides">Release guides</a></aside>
       <article class="article">
         <section class="article-section" id="channels">
           <h2>Distribution channels</h2>
@@ -47,9 +47,15 @@
         </section>
 
         <section class="article-section" id="upcoming">
-          <h2>Upcoming: 0.3.0</h2>
-          <p>The repository is currently developing the 0.3.0 line. Until an 
ASF vote passes and the signed source archive appears under Apache downloads, 
code and packages from this line are development artifacts rather than an 
Apache release.</p>
+          <h2>Upcoming: 0.4.0</h2>
+          <p>The repository is currently developing the 0.4.0 line. The 
planned release improves filtered and batched IVF scans, stabilizes IVF-PQ 
training, adds extensible search parameters across language bindings, bridges 
native diagnostics to Java logging, and tightens serialization allocation 
bounds. Until an ASF vote passes and the signed source archive appears under 
Apache downloads, code and packages from this line are development artifacts 
rather than an Apache release.</p>
+        </section>
+
+        <section class="article-section" id="release-030">
+          <h2>0.3.0</h2>
+          <p>Released 30 July 2026. This release added native DiskANN and 
adaptive IVF indexes, IVF-RQ query-width controls and search optimizations, 
batched positional reads across C and Python, expanded architecture and API 
documentation, and reproducible source and multi-platform convenience-artifact 
release verification.</p>
           <div class="callout warning"><strong>Stored-index upgrade 
note</strong>Version 0.3.0 intentionally does not read the experimental 
IVF-HNSW-FLAT (<code>IHFL</code>) and IVF-HNSW-SQ (<code>IHSQ</code>) files 
written by 0.2.x. Rebuild those indexes with a 0.3.0-supported index type 
during upgrade. Index files written by 0.3.0 are likewise not a safe rollback 
boundary for 0.2.x; retain source vectors or a 0.2-compatible index copy until 
the upgrade is accepted.</div>
+          <p><a 
href="https://www.apache.org/dyn/closer.lua/paimon/paimon-vector-index-0.3.0/apache-paimon-vector-index-0.3.0-src.tgz?action=download";>Source
 release</a> · <a 
href="https://github.com/apache/paimon-vector-index/releases/tag/v0.3.0";>Release
 notes</a> · <a href="https://crates.io/crates/paimon-vindex-core/0.3.0";>Rust 
crate</a> · <a 
href="https://repo.maven.apache.org/maven2/org/apache/paimon/paimon-vector-index-java/0.3.0/";>Java
 artifacts</a> · <a href="https://pypi.org/pro [...]
         </section>
 
         <section class="article-section" id="release-020">
diff --git a/ffi/DEPENDENCIES.rust.tsv b/ffi/DEPENDENCIES.rust.tsv
index ee61049..d136320 100644
--- a/ffi/DEPENDENCIES.rust.tsv
+++ b/ffi/DEPENDENCIES.rust.tsv
@@ -44,8 +44,8 @@ [email protected]    X                               X
 [email protected]      X                               X                       
        
 [email protected]       X                               X                       
        
 [email protected]      X                               X               
                
[email protected]       X                                               
                
[email protected]        X                                               
                
[email protected]       X                                               
                
[email protected]        X                                               
                
 [email protected]   X                               X                               
 [email protected]      X                               X                       
        
 [email protected]    X                               X                       
        
diff --git a/jni/DEPENDENCIES.rust.tsv b/jni/DEPENDENCIES.rust.tsv
index 8a6e73a..e069be3 100644
--- a/jni/DEPENDENCIES.rust.tsv
+++ b/jni/DEPENDENCIES.rust.tsv
@@ -28,8 +28,8 @@ [email protected]     X                       X
 [email protected]     X                       X                       
 [email protected]     X                       X                       
 [email protected]      X                       X                       
[email protected]       X                                               
[email protected]        X                                               
[email protected]       X                                               
[email protected]        X                                               
 [email protected]   X                       X                       
 [email protected]      X                       X                       
 [email protected]    X                       X                       
diff --git a/tools/create_release_branch.sh b/tools/create_release_branch.sh
index 71fd87c..c2b44f8 100755
--- a/tools/create_release_branch.sh
+++ b/tools/create_release_branch.sh
@@ -26,6 +26,7 @@ MVN=${MVN:-mvn}
 # fail immediately
 set -o errexit
 set -o nounset
+set -o pipefail
 # print command before executing
 set -o xtrace
 
@@ -37,19 +38,20 @@ fi
 
 ###########################
 
-if [ -z "${RELEASE_VERSION}" ]; then
+if [ -z "${RELEASE_VERSION:-}" ]; then
        echo "RELEASE_VERSION is unset"
        exit 1
 fi
 
 cd ..
 
-target_branch=release-${RELEASE_VERSION}
+SHORT_RELEASE_VERSION=${RELEASE_VERSION%.*}
+target_branch=release-${SHORT_RELEASE_VERSION}
 if [ "${RELEASE_CANDIDATE}" != "none" ]; then
   target_branch=${target_branch}-rc${RELEASE_CANDIDATE}
 fi
 
-git checkout -b ${target_branch}
+git checkout -b "${target_branch}"
 
 RELEASE_HASH=`git rev-parse HEAD`
 echo "Echo created release hash $RELEASE_HASH"
diff --git a/tools/tests/test_release_scripts.py 
b/tools/tests/test_release_scripts.py
new file mode 100644
index 0000000..aa650ca
--- /dev/null
+++ b/tools/tests/test_release_scripts.py
@@ -0,0 +1,252 @@
+# 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 os
+import shutil
+import subprocess
+import tempfile
+import unittest
+from pathlib import Path
+
+
+REPO_ROOT = Path(__file__).resolve().parents[2]
+
+
+class ReleaseScriptTest(unittest.TestCase):
+    def setUp(self):
+        self.temp_dir = tempfile.TemporaryDirectory()
+        self.repo = Path(self.temp_dir.name)
+        (self.repo / "tools").mkdir()
+        (self.repo / "core").mkdir()
+        (self.repo / "ffi").mkdir()
+        (self.repo / "jni").mkdir()
+        (self.repo / "python").mkdir()
+        (self.repo / "java").mkdir()
+
+        shutil.copy(
+            REPO_ROOT / "tools" / "update_branch_version.sh",
+            self.repo / "tools" / "update_branch_version.sh",
+        )
+        shutil.copy(
+            REPO_ROOT / "tools" / "create_release_branch.sh",
+            self.repo / "tools" / "create_release_branch.sh",
+        )
+
+        self._write(
+            "Cargo.toml",
+            """
+[workspace]
+members = ["core", "ffi", "jni"]
+resolver = "2"
+""",
+        )
+        self._write(".gitignore", "/target/\n")
+        self._write(
+            "core/Cargo.toml",
+            """
+[package]
+name = "paimon-vindex-core"
+version = "0.4.0"
+edition = "2021"
+""",
+        )
+        self._write("core/src/lib.rs", "")
+        self._write(
+            "ffi/Cargo.toml",
+            """
+[package]
+name = "paimon-vindex-ffi"
+version = "0.4.0"
+edition = "2021"
+
+[dependencies]
+paimon-vindex-core = { path = "../core", version = "0.4.0" }
+""",
+        )
+        self._write("ffi/src/lib.rs", "")
+        self._write(
+            "jni/Cargo.toml",
+            """
+[package]
+name = "paimon-vindex-jni"
+version = "0.4.0"
+edition = "2021"
+
+[dependencies]
+paimon-vindex-core = { path = "../core", version = "0.4.0" }
+""",
+        )
+        self._write("jni/src/lib.rs", "")
+        self._write(
+            "python/pyproject.toml",
+            """
+[project]
+name = "paimon-vindex"
+version = "0.4.0"
+""",
+        )
+        self._write(
+            "java/pom.xml",
+            """
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.paimon</groupId>
+  <artifactId>paimon-vector-index-java</artifactId>
+  <version>0.4.0-SNAPSHOT</version>
+</project>
+""",
+        )
+
+        self._run(["git", "init", "-q"])
+        self._run(["git", "config", "user.name", "Release Script Test"])
+        self._run(["git", "config", "user.email", 
"[email protected]"])
+        self._run(["cargo", "generate-lockfile"])
+        self._run(["git", "add", "."])
+        self._run(["git", "commit", "-q", "-m", "initial"])
+
+    def tearDown(self):
+        self.temp_dir.cleanup()
+
+    def test_update_branch_version_keeps_workspace_versions_consistent(self):
+        env = os.environ.copy()
+        env.update(
+            {
+                "OLD_VERSION": "0.4.0",
+                "NEW_VERSION": "0.5.0-SNAPSHOT",
+            }
+        )
+        self._run(
+            ["bash", "update_branch_version.sh"],
+            cwd=self.repo / "tools",
+            env=env,
+        )
+
+        self.assertFalse(
+            (self.repo / "target").exists(),
+            "version updates should not compile the workspace",
+        )
+        self.assertIn(
+            'version = "0.5.0"',
+            (self.repo / "core" / "Cargo.toml").read_text(),
+        )
+        for crate in ("ffi", "jni"):
+            manifest = (self.repo / crate / "Cargo.toml").read_text()
+            self.assertIn('version = "0.5.0"', manifest)
+            self.assertIn(
+                'paimon-vindex-core = { path = "../core", version = "0.5.0" }',
+                manifest,
+            )
+        self.assertIn(
+            'version = "0.5.0"',
+            (self.repo / "python" / "pyproject.toml").read_text(),
+        )
+        self.assertIn(
+            "<version>0.5.0-SNAPSHOT</version>",
+            (self.repo / "java" / "pom.xml").read_text(),
+        )
+
+        lockfile = (self.repo / "Cargo.lock").read_text()
+        for package in (
+            "paimon-vindex-core",
+            "paimon-vindex-ffi",
+            "paimon-vindex-jni",
+        ):
+            self.assertIn(
+                f'name = "{package}"\nversion = "0.5.0"',
+                lockfile,
+            )
+
+        subject = self._run(
+            ["git", "log", "-1", "--format=%s"],
+            capture_output=True,
+        ).stdout.strip()
+        self.assertEqual("Update version to 0.5.0-SNAPSHOT", subject)
+        self.assertEqual(
+            "",
+            self._run(
+                ["git", "status", "--short"],
+                capture_output=True,
+            ).stdout.strip(),
+        )
+
+    def test_create_release_branch_uses_minor_release_line(self):
+        env = os.environ.copy()
+        env["RELEASE_VERSION"] = "0.4.0"
+        self._run(
+            ["bash", "create_release_branch.sh"],
+            cwd=self.repo / "tools",
+            env=env,
+        )
+
+        branch = self._run(
+            ["git", "branch", "--show-current"],
+            capture_output=True,
+        ).stdout.strip()
+        self.assertEqual("release-0.4", branch)
+
+    def test_update_branch_version_reports_missing_old_version(self):
+        env = os.environ.copy()
+        env.pop("OLD_VERSION", None)
+        env["NEW_VERSION"] = "0.5.0-SNAPSHOT"
+        result = self._run(
+            ["bash", "update_branch_version.sh"],
+            cwd=self.repo / "tools",
+            env=env,
+            check=False,
+            capture_output=True,
+        )
+
+        self.assertNotEqual(0, result.returncode)
+        self.assertIn(
+            "OLD_VERSION is unset",
+            result.stdout + result.stderr,
+        )
+
+    def test_create_release_branch_reports_missing_release_version(self):
+        env = os.environ.copy()
+        env.pop("RELEASE_VERSION", None)
+        result = self._run(
+            ["bash", "create_release_branch.sh"],
+            cwd=self.repo / "tools",
+            env=env,
+            check=False,
+            capture_output=True,
+        )
+
+        self.assertNotEqual(0, result.returncode)
+        self.assertIn(
+            "RELEASE_VERSION is unset",
+            result.stdout + result.stderr,
+        )
+
+    def _write(self, relative_path, content):
+        path = self.repo / relative_path
+        path.parent.mkdir(parents=True, exist_ok=True)
+        path.write_text(content.lstrip())
+
+    def _run(self, command, cwd=None, env=None, check=True, 
capture_output=False):
+        return subprocess.run(
+            command,
+            cwd=cwd or self.repo,
+            env=env,
+            check=check,
+            text=True,
+            capture_output=capture_output,
+        )
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/tools/update_branch_version.sh b/tools/update_branch_version.sh
index 03ec8a8..9999ad0 100755
--- a/tools/update_branch_version.sh
+++ b/tools/update_branch_version.sh
@@ -25,6 +25,7 @@ MVN=${MVN:-mvn}
 # fail immediately
 set -o errexit
 set -o nounset
+set -o pipefail
 # print command before executing
 set -o xtrace
 
@@ -36,33 +37,38 @@ fi
 
 ###########################
 
-OLD_VERSION=${OLD_VERSION}
-NEW_VERSION=${NEW_VERSION}
-
-
-if [ -z "${OLD_VERSION}" ]; then
+if [ -z "${OLD_VERSION:-}" ]; then
        echo "OLD_VERSION is unset"
        exit 1
 fi
 
-if [ -z "${NEW_VERSION}" ]; then
+if [ -z "${NEW_VERSION:-}" ]; then
        echo "NEW_VERSION is unset"
        exit 1
 fi
 
 cd ..
 
-# For Cargo.toml and pyproject.toml, strip any -SNAPSHOT suffix (not valid in 
those ecosystems)
+# Cargo and Python use clean SemVer versions without Maven's -SNAPSHOT suffix.
+OLD_VERSION_CLEAN=$(echo "$OLD_VERSION" | sed 's/-SNAPSHOT//')
 NEW_VERSION_CLEAN=$(echo "$NEW_VERSION" | sed 's/-SNAPSHOT//')
 
-#change version in all pom files (match both exact and -SNAPSHOT suffix)
+# Change version in all pom files (match both exact and -SNAPSHOT suffix).
 find . -name 'pom.xml' -type f -exec perl -pi -e 
's#<version>'$OLD_VERSION'(-SNAPSHOT)?</version>#<version>'$NEW_VERSION'</version>#'
 {} \;
 
-#change version in Cargo.toml files
-find . -name 'Cargo.toml' -not -path '*/target/*' -type f -exec perl -pi -e 
's#^version = "'$OLD_VERSION'"#version = "'$NEW_VERSION_CLEAN'"#' {} \;
+# Change workspace package versions and version requirements for local
+# paimon-vindex path dependencies without touching unrelated dependencies.
+find . -name 'Cargo.toml' -not -path '*/target/*' -type f \
+       -exec perl -pi -e 's#^version = "'$OLD_VERSION_CLEAN'"#version = 
"'$NEW_VERSION_CLEAN'"#' {} \;
+find . -name 'Cargo.toml' -not -path '*/target/*' -type f \
+       -exec perl -pi -e 'if (/^paimon-vindex-/) { s#version = 
"'$OLD_VERSION_CLEAN'"#version = "'$NEW_VERSION_CLEAN'"# }' {} \;
+
+# Change the Python package version.
+perl -pi -e 's#^version = "'$OLD_VERSION_CLEAN'"#version = 
"'$NEW_VERSION_CLEAN'"#' python/pyproject.toml
 
-#change version in pyproject.toml
-perl -pi -e 's#^version = "'$OLD_VERSION'"#version = "'$NEW_VERSION_CLEAN'"#' 
python/pyproject.toml
+# Refresh workspace package versions in Cargo.lock while preserving the
+# already locked third-party dependency set without compiling the workspace.
+cargo update --workspace
 
 git commit -am "Update version to $NEW_VERSION"
 

Reply via email to