This is an automated email from the ASF dual-hosted git repository.
JingsongLi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/paimon-rust.git
The following commit(s) were added to refs/heads/main by this push:
new c5d66217 build: prepare the 0.4.0 release (#790)
c5d66217 is described below
commit c5d66217f134d7f130af7668db67dcb3abfc1dd1
Author: XiaoHongbo <[email protected]>
AuthorDate: Fri Sep 4 10:05:49 2026 +0800
build: prepare the 0.4.0 release (#790)
---
.asf.yaml | 2 +-
.github/workflows/release-go-binding.yml | 214 ++++++++++++++++++---
.github/workflows/release-rust.yml | 2 +-
Cargo.lock | 4 +-
DEPENDENCIES.rust.tsv | 2 +-
bindings/go/RELEASE.md | 39 ++--
bindings/python/DEPENDENCIES.rust.tsv | 2 +-
.../integrations/datafusion/DEPENDENCIES.rust.tsv | 2 +-
crates/paimon/DEPENDENCIES.rust.tsv | 2 +-
docs/src/index.md | 2 +-
docs/src/release/creating-a-release.md | 21 +-
docs/src/release/verifying-a-release-candidate.md | 2 +-
docs/src/releases.md | 26 ++-
scripts/release.sh | 64 ++++--
14 files changed, 313 insertions(+), 71 deletions(-)
diff --git a/.asf.yaml b/.asf.yaml
index 33ebc904..e2aba478 100644
--- a/.asf.yaml
+++ b/.asf.yaml
@@ -47,7 +47,7 @@ github:
branches:
includes:
- "~DEFAULT_BRANCH"
- - "release/*"
+ - "release-*"
- "rel/*"
excludes: []
bypass_teams:
diff --git a/.github/workflows/release-go-binding.yml
b/.github/workflows/release-go-binding.yml
index 455b0ae0..d4430057 100644
--- a/.github/workflows/release-go-binding.yml
+++ b/.github/workflows/release-go-binding.yml
@@ -38,6 +38,10 @@ on:
permissions:
contents: read
+concurrency:
+ group: ${{ github.workflow }}-${{ inputs.version || github.ref_name }}
+ cancel-in-progress: false
+
jobs:
validate:
runs-on: ubuntu-latest
@@ -46,6 +50,7 @@ jobs:
source_ref: ${{ steps.meta.outputs.source_ref }}
tag: ${{ steps.meta.outputs.tag }}
source_sha: ${{ steps.meta.outputs.source_sha }}
+ tag_object: ${{ steps.meta.outputs.tag_object }}
steps:
- uses: actions/checkout@v7
with:
@@ -55,44 +60,91 @@ jobs:
- name: Validate release version and tag
id: meta
shell: bash
+ env:
+ INPUT_VERSION: ${{ inputs.version }}
+ INPUT_SOURCE_REF: ${{ inputs.source_ref }}
run: |
- event_name='${{ github.event_name }}'
+ set -euo pipefail
+ event_name="${GITHUB_EVENT_NAME}"
version=''
source_ref=''
if [[ "$event_name" == "workflow_dispatch" ]]; then
- version='${{ inputs.version }}'
- source_ref='${{ inputs.source_ref }}'
+ version="$INPUT_VERSION"
+ source_ref="$INPUT_SOURCE_REF"
else
- tag_name='${{ github.ref_name }}'
- source_ref='${{ github.sha }}'
+ tag_name="$GITHUB_REF_NAME"
+ source_ref="$GITHUB_SHA"
version="$tag_name"
fi
- if [[ ! "$version" =~ ^v[0-9]+\.[0-9]+\.[0-9]+([-.][0-9A-Za-z.-]+)?$
]]; then
- echo "invalid version: $version; expected vX.Y.Z or vX.Y.Z-rc.N"
>&2
+ if [[ ! "$version" =~ ^v([0-9]+\.[0-9]+\.[0-9]+)(-rc[1-9][0-9]*)?$
]]; then
+ echo "invalid version: $version; expected vX.Y.Z or vX.Y.Z-rcN" >&2
exit 1
fi
+ tag_version="${BASH_REMATCH[1]}"
if [[ -z "$source_ref" ]]; then
echo "source_ref must not be empty" >&2
exit 1
fi
- git rev-parse --verify "$source_ref^{commit}" >/dev/null 2>&1 || {
+ source_sha=$(git rev-parse --verify "$source_ref^{commit}") || {
echo "source_ref does not resolve to a commit: $source_ref" >&2
exit 1
}
- tag="bindings/go/$version"
- if git rev-parse "$tag" >/dev/null 2>&1; then
- echo "tag already exists: $tag" >&2
+ workspace_version=$(
+ cargo metadata --locked --format-version 1 --no-deps |
+ jq -er '.packages[] | select(.name == "paimon") | .version'
+ )
+ if [[ "$tag_version" != "$workspace_version" ]]; then
+ echo "version $tag_version does not match workspace
$workspace_version" >&2
exit 1
fi
+ tag="bindings/go/$version"
+ tag_ref="refs/tags/$tag"
+ tag_object=''
+ if git show-ref --verify --quiet "$tag_ref"; then
+ tag_object=$(git rev-parse "$tag_ref")
+ if [[ "$(git cat-file -t "$tag_ref")" != "tag" ]]; then
+ echo "existing release tag is not annotated: $tag" >&2
+ exit 1
+ fi
+ tag_commit=$(git rev-parse "$tag_ref^{commit}")
+ tag_line=$(git rev-list --parents -n 1 "$tag_commit")
+ if [[ "$tag_commit" != "$source_sha" && "$tag_line" !=
"$tag_commit $source_sha" ]]; then
+ echo "existing tag $tag is not based on $source_sha" >&2
+ exit 1
+ fi
+ if [[ "$tag_commit" != "$source_sha" ]]; then
+ while IFS= read -r path; do
+ case "$path" in
+ bindings/go/LICENSE | \
+ bindings/go/NOTICE | \
+ bindings/go/libpaimon_c.linux.amd64.so.zst | \
+ bindings/go/libpaimon_c.linux.arm64.so.zst | \
+ bindings/go/libpaimon_c.darwin.amd64.dylib.zst | \
+ bindings/go/libpaimon_c.darwin.arm64.dylib.zst | \
+ bindings/go/THIRD-PARTY-LICENSES.linux.amd64.html | \
+ bindings/go/THIRD-PARTY-LICENSES.linux.arm64.html | \
+ bindings/go/THIRD-PARTY-LICENSES.darwin.amd64.html | \
+ bindings/go/THIRD-PARTY-LICENSES.darwin.arm64.html) ;;
+ *)
+ echo "existing tag $tag changes unexpected path: $path" >&2
+ exit 1
+ ;;
+ esac
+ done < <(git diff-tree --no-commit-id --name-only -r
"$source_sha" "$tag_commit")
+ fi
+ echo "existing tag $tag is based on the requested source; the
release can resume"
+ fi
+
echo "tag=$tag" >> "$GITHUB_OUTPUT"
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "source_ref=$source_ref" >> "$GITHUB_OUTPUT"
- echo "source_sha=$(git rev-parse "$source_ref^{commit}")" >>
"$GITHUB_OUTPUT"
+ echo "source_sha=$source_sha" >> "$GITHUB_OUTPUT"
+ echo "tag_object=$tag_object" >> "$GITHUB_OUTPUT"
build:
needs: validate
@@ -194,10 +246,12 @@ jobs:
release/go/${{ matrix.license_file }}
if-no-files-found: error
- publish:
+ tag:
needs:
- validate
- build
+ outputs:
+ tag_object: ${{ steps.tag_state.outputs.tag_object }}
runs-on: ubuntu-latest
permissions:
contents: write
@@ -236,16 +290,50 @@ jobs:
python3 scripts/verify_go_release_artifacts.py --artifacts-dir
release/go
- name: Create release tag commit
+ id: tag_state
env:
TAG: ${{ needs.validate.outputs.tag }}
VERSION: ${{ needs.validate.outputs.version }}
SOURCE_REF: ${{ needs.validate.outputs.source_ref }}
SOURCE_SHA: ${{ needs.validate.outputs.source_sha }}
+ EXPECTED_TAG_OBJECT: ${{ needs.validate.outputs.tag_object }}
shell: bash
run: |
+ set -euo pipefail
git config user.name 'github-actions[bot]'
git config user.email
'41898282+github-actions[bot]@users.noreply.github.com'
+ release_files=(
+ LICENSE
+ NOTICE
+ libpaimon_c.linux.amd64.so.zst
+ libpaimon_c.linux.arm64.so.zst
+ libpaimon_c.darwin.amd64.dylib.zst
+ libpaimon_c.darwin.arm64.dylib.zst
+ THIRD-PARTY-LICENSES.linux.amd64.html
+ THIRD-PARTY-LICENSES.linux.arm64.html
+ THIRD-PARTY-LICENSES.darwin.amd64.html
+ THIRD-PARTY-LICENSES.darwin.arm64.html
+ )
+ tag_ref="refs/tags/$TAG"
+ current_tag_object=''
+ if git show-ref --verify --quiet "$tag_ref"; then
+ current_tag_object=$(git rev-parse "$tag_ref")
+ fi
+ if [[ "$current_tag_object" != "$EXPECTED_TAG_OBJECT" ]]; then
+ echo "tag $TAG changed after validation" >&2
+ exit 1
+ fi
+ if [[ -n "$EXPECTED_TAG_OBJECT" ]]; then
+ echo "Reusing artifacts from existing tag: $TAG"
+ for file in "${release_files[@]}"; do
+ git show "${EXPECTED_TAG_OBJECT}^{commit}:bindings/go/${file}" >
"release/go/${file}"
+ done
+ python3 scripts/verify_go_release_artifacts.py --artifacts-dir
release/go
+ echo "tag_object=$EXPECTED_TAG_OBJECT" >> "$GITHUB_OUTPUT"
+ exit 0
+ fi
+
cp release/go/libpaimon_c.*.zst bindings/go/
cp \
release/go/LICENSE \
@@ -264,24 +352,100 @@ jobs:
git tag -a "$TAG" -m "Release Go binding ${VERSION} from
${SOURCE_REF}@${SOURCE_SHA}"
git push origin "refs/tags/$TAG"
+ tag_object=$(git rev-parse "refs/tags/$TAG")
+ echo "tag_object=$tag_object" >> "$GITHUB_OUTPUT"
+
+ publish:
+ needs:
+ - validate
+ - tag
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ steps:
+ - uses: actions/checkout@v7
+ with:
+ fetch-depth: 0
+ ref: ${{ needs.validate.outputs.source_sha }}
+
+ - uses: actions/setup-python@v6
+ with:
+ python-version: "3.11"
+
+ - name: Install artifact verification tools
+ run: sudo apt-get update && sudo apt-get install -y file zstd
+
+ - name: Restore and verify tagged release artifacts
+ env:
+ TAG_OBJECT: ${{ needs.tag.outputs.tag_object }}
+ shell: bash
+ run: |
+ set -euo pipefail
+ mkdir -p release/go
+ release_files=(
+ LICENSE
+ NOTICE
+ libpaimon_c.linux.amd64.so.zst
+ libpaimon_c.linux.arm64.so.zst
+ libpaimon_c.darwin.amd64.dylib.zst
+ libpaimon_c.darwin.arm64.dylib.zst
+ THIRD-PARTY-LICENSES.linux.amd64.html
+ THIRD-PARTY-LICENSES.linux.arm64.html
+ THIRD-PARTY-LICENSES.darwin.amd64.html
+ THIRD-PARTY-LICENSES.darwin.arm64.html
+ )
+ for file in "${release_files[@]}"; do
+ git show "${TAG_OBJECT}^{commit}:bindings/go/${file}" >
"release/go/${file}"
+ done
+ python3 scripts/verify_go_release_artifacts.py --artifacts-dir
release/go
- name: Create GitHub release
env:
TAG: ${{ needs.validate.outputs.tag }}
VERSION: ${{ needs.validate.outputs.version }}
+ TAG_OBJECT: ${{ needs.tag.outputs.tag_object }}
GH_TOKEN: ${{ github.token }}
working-directory: release/go
run: |
- gh release create "$TAG" \
- --title "Release Go binding $VERSION" \
- --generate-notes \
- LICENSE \
- NOTICE \
- libpaimon_c.linux.amd64.so.zst \
- libpaimon_c.linux.arm64.so.zst \
- libpaimon_c.darwin.amd64.dylib.zst \
- libpaimon_c.darwin.arm64.dylib.zst \
- THIRD-PARTY-LICENSES.linux.amd64.html \
- THIRD-PARTY-LICENSES.linux.arm64.html \
- THIRD-PARTY-LICENSES.darwin.amd64.html \
+ set -euo pipefail
+ remote_tag_object=$(
+ git ls-remote --refs origin "refs/tags/$TAG" |
+ awk 'NR == 1 { print $1 }'
+ )
+ if [[ "$remote_tag_object" != "$TAG_OBJECT" ]]; then
+ echo "remote tag $TAG changed before GitHub Release creation" >&2
+ exit 1
+ fi
+ release_files=(
+ LICENSE
+ NOTICE
+ libpaimon_c.linux.amd64.so.zst
+ libpaimon_c.linux.arm64.so.zst
+ libpaimon_c.darwin.amd64.dylib.zst
+ libpaimon_c.darwin.arm64.dylib.zst
+ THIRD-PARTY-LICENSES.linux.amd64.html
+ THIRD-PARTY-LICENSES.linux.arm64.html
+ THIRD-PARTY-LICENSES.darwin.amd64.html
THIRD-PARTY-LICENSES.darwin.arm64.html
+ )
+ prerelease=false
+ release_flags=(--verify-tag --latest=false)
+ if [[ "$VERSION" == *-rc* ]]; then
+ prerelease=true
+ release_flags+=(--prerelease)
+ fi
+ if gh release view "$TAG" >/dev/null 2>&1; then
+ echo "Updating assets on existing GitHub release: $TAG"
+ gh release upload "$TAG" "${release_files[@]}" --clobber
+ gh release edit "$TAG" \
+ --title "Release Go binding $VERSION" \
+ --draft=false \
+ --prerelease="$prerelease" \
+ --latest=false
+ else
+ gh release create "$TAG" \
+ --title "Release Go binding $VERSION" \
+ --generate-notes \
+ "${release_flags[@]}" \
+ "${release_files[@]}"
+ fi
diff --git a/.github/workflows/release-rust.yml
b/.github/workflows/release-rust.yml
index a71f0f3a..f7d58233 100644
--- a/.github/workflows/release-rust.yml
+++ b/.github/workflows/release-rust.yml
@@ -49,7 +49,7 @@ jobs:
shell: bash
run: |
set -euo pipefail
- if [[ ! "${GITHUB_REF_NAME}" =~
^v([0-9]+\.[0-9]+\.[0-9]+)(-rc[0-9]+)?$ ]]; then
+ if [[ ! "${GITHUB_REF_NAME}" =~
^v([0-9]+\.[0-9]+\.[0-9]+)(-rc[1-9][0-9]*)?$ ]]; then
echo "::error::invalid release tag: ${GITHUB_REF_NAME}"
exit 1
fi
diff --git a/Cargo.lock b/Cargo.lock
index 6af8279c..11ec61ea 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1089,9 +1089,9 @@ checksum =
"f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527"
[[package]]
name = "chacha20"
-version = "0.10.1"
+version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81"
+checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06"
dependencies = [
"cfg-if",
"cpufeatures 0.3.0",
diff --git a/DEPENDENCIES.rust.tsv b/DEPENDENCIES.rust.tsv
index 98277510..bc275a51 100644
--- a/DEPENDENCIES.rust.tsv
+++ b/DEPENDENCIES.rust.tsv
@@ -95,7 +95,7 @@ [email protected] X
[email protected]
X
[email protected] X
X
[email protected] X
X
[email protected] X
X
[email protected] X
X
[email protected] X
X
[email protected] X
X
[email protected] X
X
diff --git a/bindings/go/RELEASE.md b/bindings/go/RELEASE.md
index 2c1c19f6..668ad17b 100644
--- a/bindings/go/RELEASE.md
+++ b/bindings/go/RELEASE.md
@@ -44,19 +44,19 @@ In practice, the release relationship should look like this:
3. build the Go embedded libraries from the same baseline,
4. create a Go release commit that contains the generated `libpaimon_c.*.zst`
files, and
-5. tag that commit as `bindings/go/vX.Y.Z` or `bindings/go/vX.Y.Z-rc.N`.
+5. tag that commit as `bindings/go/vX.Y.Z` or `bindings/go/vX.Y.Z-rcN`.
This keeps a clear link to the Rust release baseline while allowing the Go
submodule tag to contain the embedded artifacts required by Go module
consumers.
## Recommended Sequence
-- For an ASF-style release process, first complete the source release steps for
- the Rust project.
-- After the corresponding release candidate has been approved, run the Go
- binding release workflow to publish the convenience Go module tag.
-- If you publish release candidates for the Go binding, base them on the same
- reviewed Rust release-candidate commit.
+- For an ASF-style release process, first prepare the Rust source release.
+- Pushing a root Rust RC tag automatically publishes the Go RC convenience tag
+ from the same source commit. After the RC is approved, pushing the final root
+ tag does the same for the final Go version.
+- For a manual recovery or standalone Go release, use the same reviewed Rust
+ release commit or immutable tag as `source_ref`.
## Before Release
@@ -64,9 +64,11 @@ submodule tag to contain the embedded artifacts required by
Go module consumers.
- Confirm the target version is decided, for example `v0.1.0`.
- Confirm the Rust release baseline commit for this Go release is recorded.
- Decide the exact `source_ref` to pass into the release workflow.
+- Confirm the base version in `version` matches the Paimon workspace version at
+ `source_ref`; after `main` is bumped, it cannot be used to publish the
previous version.
- Confirm whether this Go release is based on a Rust GA tag or an approved Rust
release-candidate commit.
-- Use `vX.Y.Z-rc.N` for release candidates, for example `v0.1.0-rc.1`.
+- Use `vX.Y.Z-rcN` for release candidates, for example `v0.1.0-rc1`.
- Use `vX.Y.Z` for the final general-availability release.
- Confirm the version has not already been used as a Go submodule tag:
`bindings/go/v0.1.0`.
@@ -82,10 +84,12 @@ submodule tag to contain the embedded artifacts required by
Go module consumers.
## Publish
-- Open GitHub Actions and run `Release Go Binding`.
-- Provide the release version, for example `v0.1.0`.
-- Provide `source_ref`, for example `main`, `v0.1.0-rc.1`, or a specific
commit SHA.
-- For release candidates, publish `bindings/go/vX.Y.Z-rc.N` first and verify
it before the final tag.
+- For a coordinated Rust release, pushing the root `vX.Y.Z-rcN` or `vX.Y.Z`
+ tag starts `Release Go Binding` automatically with that exact source commit.
+- For a manual recovery or standalone Go release, open GitHub Actions and run
+ `Release Go Binding`. Provide the release version, for example `v0.1.0`, and
+ `source_ref`, for example `main`, `v0.1.0-rc1`, or a specific commit SHA.
+- For release candidates, publish `bindings/go/vX.Y.Z-rcN` first and verify it
before the final tag.
- Make sure the workflow is started from the intended Rust release baseline
branch or commit lineage.
- Wait for all matrix builds to finish successfully:
@@ -95,7 +99,8 @@ submodule tag to contain the embedded artifacts required by
Go module consumers.
- `darwin/arm64`
- Confirm each build job generates and verifies the target-specific legal
report.
- Confirm the workflow creates the annotated tag `bindings/go/v0.1.0`.
-- Confirm the workflow publishes a GitHub release for that tag.
+- Confirm the workflow publishes a GitHub release for that tag, marks an RC
+ release as a pre-release, and does not replace the root project's latest
release.
## After Release
@@ -130,7 +135,11 @@ import paimon "github.com/apache/paimon-rust/bindings/go"
## Rollback Notes
- Do not reuse a broken Go module version once it has been observed externally.
-- Do not delete and recreate an existing `bindings/go/vX.Y.Z-rc.N` or
`bindings/go/vX.Y.Z` tag.
+- Do not delete and recreate an existing `bindings/go/vX.Y.Z-rcN` or
`bindings/go/vX.Y.Z` tag.
- Publish a new patch version instead, for example move from `v0.1.0` to
`v0.1.1`.
-- If an RC is bad, publish the next RC, for example move from `v0.1.0-rc.1` to
`v0.1.0-rc.2`.
+- If an RC is bad, publish the next RC, for example move from `v0.1.0-rc1` to
`v0.1.0-rc2`.
- If the workflow fails before pushing the tag, fix the issue and rerun with
the same intended version.
+- If the workflow fails after pushing the tag, rerun it with the same version
and
+ original source commit SHA or immutable tag. It verifies that the existing
tag
+ contains only the expected release artifacts on top of that source, restores
+ the tagged artifacts, and resumes GitHub Release creation.
diff --git a/bindings/python/DEPENDENCIES.rust.tsv
b/bindings/python/DEPENDENCIES.rust.tsv
index f77beb38..f486406b 100644
--- a/bindings/python/DEPENDENCIES.rust.tsv
+++ b/bindings/python/DEPENDENCIES.rust.tsv
@@ -71,7 +71,7 @@ [email protected] X
X
[email protected] X
[email protected]
X
[email protected] X
X
[email protected] X
X
[email protected] X
X
[email protected] X
X
[email protected] X
X
[email protected] X
X
diff --git a/crates/integrations/datafusion/DEPENDENCIES.rust.tsv
b/crates/integrations/datafusion/DEPENDENCIES.rust.tsv
index 09433b81..413c2dfe 100644
--- a/crates/integrations/datafusion/DEPENDENCIES.rust.tsv
+++ b/crates/integrations/datafusion/DEPENDENCIES.rust.tsv
@@ -78,7 +78,7 @@ [email protected] X
[email protected]
X
[email protected] X
X
[email protected] X
X
[email protected] X
X
[email protected] X
X
[email protected] X
X
[email protected] X
X
[email protected] X
diff --git a/crates/paimon/DEPENDENCIES.rust.tsv
b/crates/paimon/DEPENDENCIES.rust.tsv
index 9225deb9..62cf71a3 100644
--- a/crates/paimon/DEPENDENCIES.rust.tsv
+++ b/crates/paimon/DEPENDENCIES.rust.tsv
@@ -78,7 +78,7 @@ [email protected] X
[email protected]
X
[email protected] X
X
[email protected] X
X
[email protected] X
X
[email protected] X
X
[email protected] X
X
[email protected] X
X
[email protected] X
X
diff --git a/docs/src/index.md b/docs/src/index.md
index 8203607d..228e7288 100644
--- a/docs/src/index.md
+++ b/docs/src/index.md
@@ -43,7 +43,7 @@ ZSTD data files use 23.25% less physical storage than the
SNAPPY source files.
## Status
-The project is under active development (0.3.0 in development).
+The project is under active development (0.4.0 in development).
## License
diff --git a/docs/src/release/creating-a-release.md
b/docs/src/release/creating-a-release.md
index 57553a05..0474b1d9 100644
--- a/docs/src/release/creating-a-release.md
+++ b/docs/src/release/creating-a-release.md
@@ -39,11 +39,11 @@ The release process consists of:
When a version tag is pushed, GitHub Actions automatically publishes the
language-specific artifacts:
-| Component | Tag Pattern | Published To |
Pre-release (`-rc`) Behavior |
-|------------------|--------------------------|-------------------|---------------------------------------|
-| Rust crates | `v0.1.0` | crates.io | Dry-run
only |
-| Python binding | `v0.1.0` | PyPI | Publishes
to TestPyPI |
-| Go binding | `v0.1.0` | Go module proxy | Publishes
as `bindings/go/vX.Y.Z-rcN` |
+| Component | Root Tag Pattern | Published To |
Release-candidate Behavior |
+|------------------|----------------------|---------------------------------|------------------------------------------------------------|
+| Rust crates | `vX.Y.Z[-rcN]` | crates.io |
Validates packages and performs a dry run only |
+| Python binding | `vX.Y.Z[-rcN]` | PyPI / TestPyPI |
Publishes the corresponding PEP 440 RC version to TestPyPI |
+| Go binding | `vX.Y.Z[-rcN]` | Go module tag and GitHub Release |
Creates `bindings/go/vX.Y.Z-rcN` as a GitHub pre-release |
The Release Manager's primary responsibility is managing the **source
release** (tarball + signature) and coordinating the community vote. Language
artifact publishing is handled by CI once the final tag is pushed.
@@ -244,9 +244,12 @@ After pushing, verify in [GitHub
Actions](https://github.com/apache/paimon-rust/
### Create source release artifacts
-From the repository root (on the release branch, at the commit you tagged):
+From the repository root, check out and verify the exact RC tag before
building:
```bash
+git switch --detach ${RC_TAG}
+git tag -v ${RC_TAG}
+test "$(git rev-parse HEAD)" = "$(git rev-parse "${RC_TAG}^{commit}")"
./scripts/release.sh ${RELEASE_VERSION}
```
@@ -256,7 +259,7 @@ This creates the following under `dist/`:
- `paimon-rust-${RELEASE_VERSION}.tar.gz.asc` — GPG signature
- `paimon-rust-${RELEASE_VERSION}.tar.gz.sha512` — SHA-512 checksum
-The script automatically generates the archive from `HEAD` via `git archive`,
signs it with your GPG key, and verifies the signature.
+The script verifies that the version matches `Cargo.toml` at `HEAD` and that
`HEAD` has an exact signed release tag. It then generates the archive via `git
archive`, signs it with the Git-configured signing key when available, and
verifies the signature.
### Stage artifacts to SVN
@@ -266,7 +269,7 @@ Upload the source release to the ASF dev area:
svn checkout https://dist.apache.org/repos/dist/dev/paimon/ paimon-dist-dev
--depth=immediates
cd paimon-dist-dev
mkdir paimon-rust-${RELEASE_VERSION}-rc${RC_NUM}
-cp ../paimon-rust-${RELEASE_VERSION}.tar.gz*
paimon-rust-${RELEASE_VERSION}-rc${RC_NUM}/
+cp ../dist/paimon-rust-${RELEASE_VERSION}.tar.gz*
paimon-rust-${RELEASE_VERSION}-rc${RC_NUM}/
svn add paimon-rust-${RELEASE_VERSION}-rc${RC_NUM}
svn commit -m "Add paimon-rust ${RELEASE_VERSION} RC${RC_NUM}"
```
@@ -297,7 +300,7 @@ The release candidate is available at:
https://dist.apache.org/repos/dist/dev/paimon/paimon-rust-${RELEASE_VERSION}-rc${RC_NUM}/
Git tag:
-https://github.com/apache/paimon-rust/releases/tag/${RC_TAG}
+https://github.com/apache/paimon-rust/tree/${RC_TAG}
KEYS for signature verification:
https://downloads.apache.org/paimon/KEYS
diff --git a/docs/src/release/verifying-a-release-candidate.md
b/docs/src/release/verifying-a-release-candidate.md
index b8c5c896..736eeecb 100644
--- a/docs/src/release/verifying-a-release-candidate.md
+++ b/docs/src/release/verifying-a-release-candidate.md
@@ -89,7 +89,7 @@ cd paimon-rust-${RELEASE_VERSION}
Build the workspace:
```bash
-cargo build --workspace --release
+cargo build --locked --workspace --release
```
For Python binding, see `bindings/python/`. For Go binding, see `bindings/go/`.
diff --git a/docs/src/releases.md b/docs/src/releases.md
index ed716b7c..355ac14c 100644
--- a/docs/src/releases.md
+++ b/docs/src/releases.md
@@ -25,12 +25,36 @@ Apache Paimon Rust follows [Semantic
Versioning](https://semver.org/). All relea
## Upcoming
-### 0.3.0 (In Development)
+### 0.4.0 (In Development)
See [GitHub Issues](https://github.com/apache/paimon-rust/issues) for the
current roadmap.
+The minimum supported Rust version for 0.4.0 is 1.94.
+
+Key features:
+
+- Expanded primary-key vector and hybrid search with vector/full-text fusion,
streamed index builds, DiskANN and quantized IVF backends, scalar
pre-filtering, and externally planned bucket splits
+- Java-compatible file and global indexes, including Bloom, Bitmap V1/V2 reads
and V2 writes, multi-value array indexes, and exact FM substring search
+- Native read-only object tables and `TableType`-based routing to pluggable
external table engines
+- Batch incremental-diff reads, watermark-based time travel, and
deletion-vector merge-on-read for uncompacted primary-key snapshots
+- Expanded DataFusion SQL with `ALTER COLUMN`, database lifecycle statements,
configurable runtime resources, and the Java-compatible `$consumers` system
table
+- Expanded Go table-write support plus postpone-table fixed-bucket write
primitives for Rust, C, and Go, with Python commit rollback
+- Standalone `BlobDescriptor` batch reads and seekable streams, with Go batch
and stream APIs and `MAP<STRING, BLOB>` descriptor reads
+- Extensible and cached I/O through caller-provided OpenDAL operators, an
in-memory local block cache, and C cache callbacks
+
## Past Releases
+### [0.3.0](https://github.com/apache/paimon-rust/releases/tag/v0.3.0)
+
+Key features:
+
+- Primary-key changelog writes plus aggregation and partial-update merge
improvements
+- Java-compatible Mosaic, Vortex, schema-evolution, and data-evolution read
paths
+- Lumina and vindex vector search, hybrid search, and BTree, bitmap, and
full-text global indexes
+- Dedicated vector storage plus BLOB and VARIANT type support
+- DataFusion 54 integration, REST catalog views and functions, and a
filesystem-backed REST server
+- Expanded Python DataFrame-style read/write APIs and C and Go binding coverage
+
### [0.2.0](https://github.com/apache/paimon-rust/releases/tag/v0.2.0)
Key features:
diff --git a/scripts/release.sh b/scripts/release.sh
index 6c95f089..67edfc2c 100755
--- a/scripts/release.sh
+++ b/scripts/release.sh
@@ -21,23 +21,60 @@
#
# Run from repo root. Check out the release tag first (e.g. git checkout
v0.1.0-rc1).
# Usage: ./scripts/release.sh [version]
-# If version is omitted, it is read from Cargo.toml
(workspace.package.version).
+# If version is omitted, it is read from Cargo.toml at HEAD
(workspace.package.version).
-set -e
+set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$REPO_ROOT"
-if [ -n "$1" ]; then
- VERSION="$1"
-else
- VERSION=$(grep -E '^version\s*=' Cargo.toml | head -1 | sed
's/.*"\([^"]*\)".*/\1/')
- if [ -z "$VERSION" ]; then
- echo "Could not read version from Cargo.toml. Pass version as argument: $0
<version>"
- exit 1
- fi
+if [ "$#" -gt 1 ]; then
+ echo "Usage: $0 [version]"
+ exit 1
+fi
+
+WORKSPACE_VERSION=$(
+ git show HEAD:Cargo.toml |
+ awk '
+ /^\[workspace\.package\]$/ { in_workspace_package = 1; next }
+ in_workspace_package && /^\[/ { exit }
+ in_workspace_package && /^version[[:space:]]*=/ {
+ if (match($0, /"[^"]+"/)) {
+ print substr($0, RSTART + 1, RLENGTH - 2)
+ exit
+ }
+ }
+ '
+)
+if [ -z "$WORKSPACE_VERSION" ]; then
+ echo "Could not read workspace version from Cargo.toml at HEAD"
+ exit 1
+fi
+
+VERSION="${1:-$WORKSPACE_VERSION}"
+if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
+ echo "Invalid release version: ${VERSION}; expected X.Y.Z"
+ exit 1
+fi
+if [ "$VERSION" != "$WORKSPACE_VERSION" ]; then
+ echo "Release version ${VERSION} does not match workspace
${WORKSPACE_VERSION} at HEAD"
+ exit 1
fi
+VERSION_PATTERN=${VERSION//./\\.}
+RELEASE_TAG=$(
+ git tag --points-at HEAD |
+ grep -E "^v${VERSION_PATTERN}(-rc[1-9][0-9]*)?$" |
+ head -1 || true
+)
+if [ -z "$RELEASE_TAG" ]; then
+ echo "HEAD must have an exact v${VERSION} or v${VERSION}-rcN release tag"
+ exit 1
+fi
+
+echo "Verifying signed release tag: ${RELEASE_TAG}"
+git tag -v "$RELEASE_TAG"
+
PREFIX="paimon-rust-${VERSION}"
DIST_DIR="${REPO_ROOT}/dist"
TARBALL="${PREFIX}.tar.gz"
@@ -56,7 +93,12 @@ else
fi
echo "Signing with GPG: ${TARBALL}.asc"
-(cd "$DIST_DIR" && gpg --armor --detach-sig "$TARBALL")
+SIGNING_KEY=$(git config --get user.signingkey || true)
+if [ -n "$SIGNING_KEY" ]; then
+ (cd "$DIST_DIR" && gpg --local-user "$SIGNING_KEY" --armor --detach-sig
"$TARBALL")
+else
+ (cd "$DIST_DIR" && gpg --armor --detach-sig "$TARBALL")
+fi
echo "Verifying signature"
(cd "$DIST_DIR" && gpg --verify "${TARBALL}.asc" "$TARBALL")