Creating a Release
Guide for Release Managers of Apache Paimon Mosaic, following ASF Release Policy.
Overview
The release process consists of:
- Decide to release
- Prepare for the release
- Build a release candidate
- Vote on the release candidate
- If necessary, fix any issues and go back to step 3
- Finalize the release
- Promote the release
Automated Publishing
When a version tag is pushed, the Release workflow orchestrates language-specific release jobs:
| Component | Tag Pattern | Published To | Pre-release (-rc) Behavior | Ordering |
|---|---|---|---|---|
| Rust crate | v0.1.0 | crates.io | Dry-run only | Runs in parallel |
| Java binding | v0.1.0 | Apache Nexus staging | Deploys to staging | Runs in parallel |
| Python binding | v0.1.0 | PyPI | Publishes to TestPyPI | Publishes only after Rust and Java jobs succeed |
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 tag is pushed.
Decide to Release
Anybody can propose a release on the dev mailing list, giving a short rationale and nominating a committer as Release Manager (including themselves).
Checklist:
- Community agrees to release
- A Release Manager is selected
Prepare for the Release
One-time Release Manager Setup
GPG Key
-
Install GnuPG:
# macOS brew install gnupg # Ubuntu / Debian sudo apt install gnupg2 -
Generate a key pair (RSA 4096, does not expire, use your
@apache.orgemail):gpg --full-gen-key -
Find your key ID:
gpg --list-keys --keyid-format short -
Upload to key server:
gpg --keyserver hkps://keyserver.ubuntu.com --send-keys <YOUR_KEY_ID> -
Append to the project KEYS file:
svn co https://dist.apache.org/repos/dist/release/paimon/ paimon-dist-release --depth=files cd paimon-dist-release (gpg --list-sigs <YOUR_KEY_ID> && gpg --armor --export <YOUR_KEY_ID>) >> KEYS svn ci -m "Add <YOUR_NAME>'s public key" -
Configure Git to sign tags:
git config --global user.signingkey <YOUR_KEY_ID>
GitHub Actions Secrets
Ensure the following repository secrets are configured:
| Secret | Purpose |
|---|---|
CARGO_REGISTRY_TOKEN | crates.io publishing |
NEXUS_STAGE_DEPLOYER_USER | Apache Nexus staging |
NEXUS_STAGE_DEPLOYER_PW | Apache Nexus staging |
GPG_SECRET_KEY | Java artifact signing |
GPG_PASSPHRASE | Java artifact signing |
PYPI_API_TOKEN | PyPI publishing |
TEST_PYPI_API_TOKEN | TestPyPI publishing |
Clone into a Fresh Workspace
git clone https://github.com/apache/paimon-mosaic.git
cd paimon-mosaic
Set Up Environment Variables
RELEASE_VERSION="0.1.0"
SHORT_RELEASE_VERSION="0.1"
NEXT_VERSION="0.2.0"
RC_NUM="1"
RELEASE_BRANCH="release-${SHORT_RELEASE_VERSION}"
RC_TAG="v${RELEASE_VERSION}-rc${RC_NUM}"
RELEASE_TAG="v${RELEASE_VERSION}"
Generate Dependency License Manifests
ASF releases must include a declaration of third-party dependency licenses. Generate and commit dependency manifests on main before creating the release branch, so the release branch and source archive contain the same reviewed manifests.
# Install cargo-deny (one-time)
cargo install cargo-deny
git checkout main
git pull --ff-only origin main
# Check all dependency licenses are approved
python3 tools/dependencies.py check
# Generate DEPENDENCIES.rust.tsv
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
Fix any license violations before proceeding. The generated files must be committed before tagging because create_source_release.sh builds the archive from the committed Git tree.
Create a Release Branch
Create one stable release branch for the release line. Do not include the RC number in the branch name; RC attempts are represented by tags such as v0.1.0-rc1 and v0.1.0-rc2.
git checkout main
git pull --ff-only origin main
git checkout -b ${RELEASE_BRANCH}
git push origin ${RELEASE_BRANCH}
Bump Version on Main
After cutting the release branch, bump main to the next development version:
git checkout main
git pull --ff-only origin main
cd tools
OLD_VERSION=${RELEASE_VERSION} NEW_VERSION=${NEXT_VERSION}-SNAPSHOT ./update_branch_version.sh
cd ..
git push origin main
The script updates version strings in all pom.xml (matching both ${OLD_VERSION} and ${OLD_VERSION}-SNAPSHOT), Cargo.toml (excluding target/), and python/pyproject.toml files, then creates a commit.
Build a Release Candidate
Update Versions on the Release Branch
Before tagging, update the release branch to non-SNAPSHOT versions (removing -SNAPSHOT from pom.xml):
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 ..
This ensures the Java artifacts deployed from the RC tag carry the final release version (e.g. 0.1.0) rather than a SNAPSHOT suffix.
Create the RC Tag
Push a signed RC tag to trigger CI workflows:
git tag -s ${RC_TAG} -m "${RC_TAG}"
git tag -v ${RC_TAG}
git push origin ${RELEASE_BRANCH}
git push origin ${RC_TAG}
After pushing, verify in GitHub Actions that the Release workflow succeeds:
- Rust release — dry-run check (does not publish for RC tags)
- Java release — builds native JNI libraries for 4 platforms, deploys JAR to Apache Nexus staging
- Python wheels — builds wheels for 4 platforms
- Python publish — publishes to TestPyPI only after the Rust, Java, and Python wheel jobs succeed
If only the Python publish job fails due to a transient PyPI or TestPyPI issue, use Re-run failed jobs on the Release workflow. The successful Rust, Java, and Python wheel jobs do not need to be repeated.
Create Source Release Artifacts
Create source release artifacts from the same commit as the RC tag:
git checkout ${RC_TAG}
cd tools
RELEASE_VERSION=${RELEASE_VERSION} ./create_source_release.sh
This creates the following under tools/release/:
apache-paimon-mosaic-${RELEASE_VERSION}-src.tgz— source archiveapache-paimon-mosaic-${RELEASE_VERSION}-src.tgz.asc— GPG signatureapache-paimon-mosaic-${RELEASE_VERSION}-src.tgz.sha512— SHA-512 checksum
Stage Artifacts to SVN
svn checkout https://dist.apache.org/repos/dist/dev/paimon/ paimon-dist-dev --depth=immediates
cd paimon-dist-dev
mkdir paimon-mosaic-${RELEASE_VERSION}-rc${RC_NUM}
cp ../paimon-mosaic/tools/release/apache-paimon-mosaic-${RELEASE_VERSION}-src.* \
paimon-mosaic-${RELEASE_VERSION}-rc${RC_NUM}/
svn add paimon-mosaic-${RELEASE_VERSION}-rc${RC_NUM}
svn commit -m "Add paimon-mosaic ${RELEASE_VERSION} RC${RC_NUM}"
Checklist:
- RC tag pushed and the CI release workflow succeeded
- Source tarball, signature, and checksum staged to dist.apache.org dev
- Java artifacts deployed to Nexus staging repository
- Python wheels published to TestPyPI
Vote on the Release Candidate
Start a vote on the dev mailing list.
Subject: [VOTE] Release Apache Paimon Mosaic ${RELEASE_VERSION} (RC${RC_NUM})
Hi everyone,
Please review and vote on release candidate #${RC_NUM} for Apache Paimon Mosaic ${RELEASE_VERSION}.
[ ] +1 Approve the release
[ ] +0 No opinion
[ ] -1 Do not approve (please provide specific comments)
The release candidate is available at:
https://dist.apache.org/repos/dist/dev/paimon/paimon-mosaic-${RELEASE_VERSION}-rc${RC_NUM}/
Git tag:
https://github.com/apache/paimon-mosaic/releases/tag/${RC_TAG}
Git commit:
<RC_COMMIT_SHA>
KEYS for signature verification:
https://downloads.apache.org/paimon/KEYS
Java artifacts (Nexus staging):
https://repository.apache.org/content/repositories/orgapachepaimon-XXXX/
Python wheels (TestPyPI):
https://test.pypi.org/project/paimon-mosaic/${RELEASE_VERSION}rc${RC_NUM}/
Verification guide:
https://github.com/apache/paimon-mosaic/blob/main/docs/verifying-a-release-candidate.html
The vote will be open for at least 72 hours.
Thanks,
Release Manager
After the vote passes, send a result email with subject: [RESULT][VOTE] Release Apache Paimon Mosaic ${RELEASE_VERSION} (RC${RC_NUM})
Fix Any Issues
If the vote reveals issues:
- Fix them on the release branch via normal PRs.
- Remove the old RC from dist dev (optional):
cd paimon-dist-dev svn remove paimon-mosaic-${RELEASE_VERSION}-rc${RC_NUM} svn commit -m "Remove paimon-mosaic ${RELEASE_VERSION} RC${RC_NUM} (superseded)" - Drop the Nexus staging repository via the Nexus UI.
- Increment
RC_NUM, then go back to Build a release candidate.
Finalize the Release
Push the Release Tag
Once the vote passes, create and push the final release tag. This triggers CI to publish to crates.io and PyPI automatically; PyPI publishing runs only after the Rust and Java release jobs succeed.
git checkout ${RC_TAG}
git tag -s ${RELEASE_TAG} -m "Release Apache Paimon Mosaic ${RELEASE_VERSION}"
git tag -v ${RELEASE_TAG}
git push origin ${RELEASE_TAG}
Move Source Artifacts to the Release Repository
svn mv -m "Release paimon-mosaic ${RELEASE_VERSION}" \
https://dist.apache.org/repos/dist/dev/paimon/paimon-mosaic-${RELEASE_VERSION}-rc${RC_NUM} \
https://dist.apache.org/repos/dist/release/paimon/paimon-mosaic-${RELEASE_VERSION}
Release the Java Artifacts
- Go to Apache Nexus Staging Repositories.
- Find the staging repository for
orgapachepaimon-XXXX. - Close the repository (runs validation rules).
- Once closed, Release the repository to Maven Central.
Verify Published Artifacts
- Rust: crates.io/crates/paimon-mosaic-core shows version
${RELEASE_VERSION} - Java: Maven Central shows version
${RELEASE_VERSION} - Python: PyPI — paimon-mosaic shows version
${RELEASE_VERSION}
Create GitHub Release
- Go to Releases — New release.
- Choose tag
v${RELEASE_VERSION}. - Click Generate release notes and review.
- Click Publish release.
Checklist:
- Release tag pushed; CI published to crates.io and PyPI
- Source artifacts moved to dist release
- Java artifacts released to Maven Central via Nexus
- GitHub Release created
Promote the Release
Update the Releases Page
Update the Releases page: move the released version from "Upcoming" to "Past Releases" with a summary of key features and a link to the GitHub release notes.
Announce the Release
Wait at least 24 hours after finalizing. Send the announcement to dev@paimon.apache.org and announce@apache.org using your @apache.org email in plain text.
Subject: [ANNOUNCE] Release Apache Paimon Mosaic ${RELEASE_VERSION}
The Apache Paimon community is pleased to announce the release of
Apache Paimon Mosaic ${RELEASE_VERSION}.
Apache Paimon Mosaic is a columnar-bucket hybrid format optimized for
wide tables of Apache Paimon.
Rust: cargo add paimon-mosaic-core
Java: <dependency>
<groupId>org.apache.paimon</groupId>
<artifactId>mosaic</artifactId>
<version>${RELEASE_VERSION}</version>
</dependency>
Python: pip install paimon-mosaic
Release notes:
https://github.com/apache/paimon-mosaic/releases/tag/v${RELEASE_VERSION}
Thanks to all contributors!
Clean Up Old Releases
ASF policy requires only the latest release in the dist release area. Remove older versions:
svn rm -m "Remove old release" \
https://dist.apache.org/repos/dist/release/paimon/paimon-mosaic-${OLD_VERSION}