Release Manager guide · ASF release policy

Creating a release

Prepare a reproducible source candidate, stage the Java and Python convenience artifacts, coordinate the community vote, and publish only the candidate that was approved.

Signed source archive72-hour voteRC-is-final bitsLocal Java signing

Overview

Release the voted commit, unchangedThe final vVERSION tag must point to the same commit as the successful vVERSION-rcN tag. Never rebuild or modify the source archive after the vote.
  1. Agree on the release and select a Release Manager.
  2. Prepare dependency declarations, versions, and the release branch.
  3. Sign an RC tag, run the release workflow, create the source archive, and stage Java.
  4. Upload the source candidate and call a vote lasting at least 72 hours.
  5. Fix issues and create a new RC when required.
  6. After a successful vote, promote the exact RC and release staged artifacts.
  7. Publish release notes, update this page, and announce the release.
ComponentRC tag behaviorFinal tag behavior
SourceRM creates, signs, and uploads the archive to ASF dist devThe approved files move unchanged to ASF dist release
Rustcargo publish --dry-runPublishes paimon-vindex-core to crates.io
JavaCI builds four JNI libraries; the RM signs and deploys the JAR to Nexus staging locallyThe RM closes and releases the approved Nexus repository
PythonBuilds four wheels and publishes VERSIONrcN to TestPyPI after Rust, Java, and wheel jobs passPublishes VERSION to PyPI

This procedure follows the ASF Release Policy. The source archive is the release; registry packages are convenience artifacts.

One-time Release Manager setup

Signing key and ASF distribution repositories

  1. Create a long-lived GPG signing key associated with your @apache.org identity and publish it to a public key server.
  2. Append the public key and signatures to the Paimon KEYS file through the ASF distribution SVN repository.
  3. Configure Git to use the same key and confirm that git tag -s and gpg --verify work.
Shell · inspect signing setup
gpg --list-secret-keys --keyid-format LONG
git config user.signingkey
svn --version

Publishing credentials

The GitHub repository needs CARGO_REGISTRY_TOKEN, TEST_PYPI_API_TOKEN, and PYPI_API_TOKEN. Java is deliberately deployed from the RM machine: configure GPG plus Maven server ID apache.releases.https, and authenticate gh for access to the RC workflow artifacts. See tools/README.md for Nexus credential options.

Prepare the release

Work from a fresh clone and substitute the intended values. A release branch represents a minor release line; RC attempts are tags on that branch.

Shell · example values
RELEASE_VERSION="0.3.0"
SHORT_RELEASE_VERSION="0.3"
NEXT_VERSION="0.4.0"
RC_NUM="1"
RELEASE_BRANCH="release-${SHORT_RELEASE_VERSION}"
RC_TAG="v${RELEASE_VERSION}-rc${RC_NUM}"
RELEASE_TAG="v${RELEASE_VERSION}"

Refresh dependency declarations on main

Install cargo-deny, check every workspace crate, generate the dependency TSV files, review the changes, and commit them before cutting the branch.

Shell
git checkout main
git pull --ff-only origin main
cargo install cargo-deny
python3 tools/dependencies.py check
python3 tools/dependencies.py generate
git add DEPENDENCIES.rust.tsv \
  core/DEPENDENCIES.rust.tsv ffi/DEPENDENCIES.rust.tsv jni/DEPENDENCIES.rust.tsv
git commit -m "chore: update dependency list for release ${RELEASE_VERSION}"
git push origin main

Cut the release branch and advance main

Shell
git checkout -b "${RELEASE_BRANCH}" origin/main
git push origin "${RELEASE_BRANCH}"

git checkout main
cd tools
OLD_VERSION="${RELEASE_VERSION}" \
NEW_VERSION="${NEXT_VERSION}-SNAPSHOT" \
  ./update_branch_version.sh
cd ..
git push origin main

If the current Java version already carries -SNAPSHOT, the helper accepts either the clean or snapshot old version. Cargo and Python use the clean SemVer value.

Build and stage a release candidate

Set release versions and tag the candidate

Shell
git checkout "${RELEASE_BRANCH}"
git pull --ff-only origin "${RELEASE_BRANCH}"
cd tools
OLD_VERSION="${RELEASE_VERSION}-SNAPSHOT" \
NEW_VERSION="${RELEASE_VERSION}" \
  ./update_branch_version.sh
cd ..
git push origin "${RELEASE_BRANCH}"

git tag -s "${RC_TAG}" -m "Apache Paimon Vector Index ${RELEASE_VERSION} RC${RC_NUM}"
git tag -v "${RC_TAG}"
git push origin "${RC_TAG}"

Wait for the tag-triggered Release workflow. Rust must pass its publish dry-run; Java must build the Linux x86-64, Linux aarch64, macOS aarch64, and Windows x86-64 JNI libraries; Python must build the same platform set and publish the RC wheels to TestPyPI.

Create and upload the source candidate

Shell
git checkout "${RC_TAG}"
cd tools
RELEASE_VERSION="${RELEASE_VERSION}" ./create_source_release.sh
cd ..

svn checkout https://dist.apache.org/repos/dist/dev/paimon/ \
  paimon-dist-dev --depth=immediates
mkdir "paimon-dist-dev/paimon-vector-index-${RELEASE_VERSION}-rc${RC_NUM}"
cp tools/release/apache-paimon-vector-index-${RELEASE_VERSION}-src.* \
  "paimon-dist-dev/paimon-vector-index-${RELEASE_VERSION}-rc${RC_NUM}/"
svn add "paimon-dist-dev/paimon-vector-index-${RELEASE_VERSION}-rc${RC_NUM}"
svn commit -m "Add Paimon Vector Index ${RELEASE_VERSION} RC${RC_NUM}" \
  paimon-dist-dev

The script archives the current commit with its stable commit timestamp, excludes development-only files, writes a reproducible gzip stream, creates an armored detached signature, and records a SHA-512 checksum. Re-running it for the same commit and release version must produce the same .tgz bytes.

Stage the Java convenience artifact

Find the numeric run ID of the successful RC-tag Release workflow, then validate the exact CI native artifacts before any remote deploy.

Shell · dry-run, then deploy
./tools/deploy_java_staging.sh \
  --release-version "${RELEASE_VERSION}" \
  --rc "${RC_NUM}" \
  --run-id 12345678901 \
  --dry-run

./tools/deploy_java_staging.sh \
  --release-version "${RELEASE_VERSION}" \
  --rc "${RC_NUM}" \
  --run-id 12345678901

Record the resulting orgapachepaimon-XXXX Nexus repository ID. Leave the repository staged until the vote finishes.

Call the vote

Send a plain-text message to dev@paimon.apache.org. Following the ASF voting process, the vote must remain open for at least 72 hours and pass with at least three binding +1 votes and more binding +1 than -1 votes.

Vote template
Subject: [VOTE] Release Apache Paimon Vector Index ${RELEASE_VERSION} (RC${RC_NUM})

Please review and vote on Apache Paimon Vector Index
${RELEASE_VERSION}, release candidate ${RC_NUM}.

[ ] +1 Approve
[ ]  0 No opinion
[ ] -1 Do not approve (please explain)

Source candidate:
https://dist.apache.org/repos/dist/dev/paimon/paimon-vector-index-${RELEASE_VERSION}-rc${RC_NUM}/

Git tag and commit:
https://github.com/apache/paimon-vector-index/releases/tag/${RC_TAG}
<RC_COMMIT_SHA>

KEYS:
https://downloads.apache.org/paimon/KEYS

Java staging repository:
https://repository.apache.org/content/repositories/orgapachepaimon-XXXX/

Python RC:
https://test.pypi.org/project/paimon-vindex/${RELEASE_VERSION}rc${RC_NUM}/

Verification guide:
https://github.com/apache/paimon-vector-index/blob/${RC_TAG}/docs/verifying-a-release-candidate.html

The vote will remain open for at least 72 hours.

After the deadline, tally binding and non-binding votes separately and send [RESULT][VOTE] Release Apache Paimon Vector Index VERSION (RCN).

Replace a rejected candidate

  1. Apply fixes to the release branch through normal review.
  2. Drop the old Nexus staging repository.
  3. Remove or retain the superseded dist-dev directory according to the vote thread, but never overwrite its files.
  4. Increment RC_NUM, create a new signed RC tag, rebuild every candidate artifact, and start a new vote.

Finalize an approved release

Tag and promote the exact RC

Shell
git checkout "${RC_TAG}"
git tag -s "${RELEASE_TAG}" \
  -m "Release Apache Paimon Vector Index ${RELEASE_VERSION}"
test "$(git rev-parse "${RC_TAG}^{commit}")" = \
     "$(git rev-parse "${RELEASE_TAG}^{commit}")"
git tag -v "${RELEASE_TAG}"
git push origin "${RELEASE_TAG}"

svn mv -m "Release Paimon Vector Index ${RELEASE_VERSION}" \
  "https://dist.apache.org/repos/dist/dev/paimon/paimon-vector-index-${RELEASE_VERSION}-rc${RC_NUM}" \
  "https://dist.apache.org/repos/dist/release/paimon/paimon-vector-index-${RELEASE_VERSION}"

The final tag publishes Rust to crates.io and Python to PyPI. In Nexus, close the previously recorded Java staging repository, inspect all validation rules, then release it to Maven Central. Do not stage a new Java build.

Verify and publish release notes

  • The source archive, signature, and checksum are visible through Apache mirrors.
  • paimon-vindex-core VERSION is on crates.io.
  • org.apache.paimon:paimon-vector-index-java:VERSION is on Maven Central.
  • paimon-vindex VERSION is on PyPI for all supported platforms.
  • A GitHub release exists for vVERSION, with reviewed generated notes.

Update and announce

Wait at least one hour after source publication, then update the releases page with the mirrored source-download, notes, and registry links. After mirrors and registries have converged, announce the release from an @apache.org address to dev@paimon.apache.org and announce@apache.org. Remove superseded releases from the live distribution area when required by ASF policy; they remain in the Apache archive.