Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 227 additions & 0 deletions .github/workflows/release-java.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
################################################################################
# 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.
################################################################################

name: Release Java

on:
workflow_call:
workflow_dispatch:

concurrency:
group: release-java-${{ github.ref }}
cancel-in-progress: false

permissions:
contents: read

jobs:
package:
name: Package ${{ matrix.lane }}
if: >-
github.repository == 'apache/paimon' &&
startsWith(github.ref, 'refs/tags/') &&
contains(github.ref_name, '-rc')
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- lane: jdk8
java_version: 8
- lane: jdk11
java_version: 11
- lane: jdk17
java_version: 17
steps:
- uses: actions/checkout@v6

- name: Set up JDK ${{ matrix.java_version }}
uses: actions/setup-java@v5
with:
java-version: ${{ matrix.java_version }}
distribution: temurin
cache: maven

- name: Set up Maven
uses: stCarolas/setup-maven@d6af6abeda15e98926a57b5aa970a96bb37f97d1 # v5
with:
maven-version: 3.8.8

- name: Validate release tag and version
id: release
shell: bash
run: |
set -euo pipefail

release_version="$(
mvn -q -DforceStdout help:evaluate \
-Dexpression=project.version
)"
rc_number="${GITHUB_REF_NAME##*-rc}"
expected_tag="release-${release_version}-rc${rc_number}"

if [[ "${GITHUB_REF_NAME}" != "${expected_tag}" ]]; then
echo "Tag ${GITHUB_REF_NAME} does not match Maven version ${release_version}" >&2
exit 1
fi
if [[ "${release_version}" == *-SNAPSHOT ]]; then
echo "Release version must not contain -SNAPSHOT" >&2
exit 1
fi

echo "version=${release_version}" >> "${GITHUB_OUTPUT}"
echo "rc_number=${rc_number}" >> "${GITHUB_OUTPUT}"

java -version
mvn -version

- name: Reject SNAPSHOT project versions and dependencies
shell: bash
env:
LANE: ${{ matrix.lane }}
run: |
set -euo pipefail

enforcer_goal="org.apache.maven.plugins:maven-enforcer-plugin:3.6.3:enforce"
enforcer_rules="requireReleaseVersion,requireReleaseDeps"
case "${LANE}" in
jdk8)
mvn -ntp -B "${enforcer_goal}" \
-Denforcer.rules="${enforcer_rules}" \
-Papache-release,docs-and-source,spark3,flink1
;;
jdk11)
mvn -ntp -B "${enforcer_goal}" \
-Denforcer.rules="${enforcer_rules}" \
-Papache-release,docs-and-source,flink2 \
-pl org.apache.paimon:paimon-flink-2.0,org.apache.paimon:paimon-flink-2.1,org.apache.paimon:paimon-flink-2.2,org.apache.paimon:paimon-flink2-common,org.apache.paimon:paimon-iceberg \
-am
;;
jdk17)
mvn -ntp -B "${enforcer_goal}" \
-Denforcer.rules="${enforcer_rules}" \
-Papache-release,docs-and-source,spark4 \
-pl org.apache.paimon:paimon-spark-common_2.13,org.apache.paimon:paimon-spark4-common_2.13,org.apache.paimon:paimon-spark-4.0_2.13,org.apache.paimon:paimon-spark-4.1_2.13 \
-am
;;
*)
echo "Unknown Java release lane: ${LANE}" >&2
exit 1
;;
esac

- name: Package Java release artifacts
shell: bash
env:
LANE: ${{ matrix.lane }}
MAVEN_OPTS: -Xmx4096m
run: |
set -euo pipefail

mkdir -p release-java
log="release-java/${LANE}.log"
install_log="release-java/${LANE}-install.log"
case "${LANE}" in
jdk8)
mvn clean install -ntp -B \
-Papache-release,docs-and-source,spark3,flink1 \
-DskipTests -Dgpg.skip=true -Dstyle.color=never \
2>&1 | tee "${log}" "${install_log}"
;;
jdk11)
mvn clean install -ntp -B \
-Pdocs-and-source,flink2 \
-DskipTests -Dstyle.color=never \
-pl org.apache.paimon:paimon-flink-2.0,org.apache.paimon:paimon-flink-2.1,org.apache.paimon:paimon-flink-2.2,org.apache.paimon:paimon-iceberg \
-am \
2>&1 | tee "${log}"
mvn install -ntp -B \
-Papache-release,docs-and-source,flink2 \
-DskipTests -Dgpg.skip=true -Dstyle.color=never \
-pl org.apache.paimon:paimon-flink-2.0,org.apache.paimon:paimon-flink-2.1,org.apache.paimon:paimon-flink-2.2,org.apache.paimon:paimon-flink2-common,org.apache.paimon:paimon-iceberg \
2>&1 | tee -a "${log}" "${install_log}"
;;
jdk17)
mvn clean install -ntp -B \
-Pdocs-and-source,spark4 \
-DskipTests -Dstyle.color=never \
-pl paimon-spark/paimon-spark-4.0,paimon-spark/paimon-spark-4.1 \
-am \
2>&1 | tee "${log}"
mvn install -ntp -B \
-Papache-release,docs-and-source,spark4 \
-DskipTests -Dgpg.skip=true -Dstyle.color=never \
-pl org.apache.paimon:paimon-spark-common_2.13,org.apache.paimon:paimon-spark4-common_2.13,org.apache.paimon:paimon-spark-4.0_2.13,org.apache.paimon:paimon-spark-4.1_2.13 \
2>&1 | tee -a "${log}" "${install_log}"
;;
*)
echo "Unknown Java release lane: ${LANE}" >&2
exit 1
;;
esac

files="release-java/${LANE}-files.txt"
while IFS= read -r artifact; do
if [[ "${artifact}" == "${GITHUB_WORKSPACE}/"* ]]; then
artifact="./${artifact#"${GITHUB_WORKSPACE}/"}"
elif [[ "${artifact}" != ./* ]]; then
echo "Unexpected installed artifact path: ${artifact}" >&2
exit 1
fi
if [[ ! -f "${artifact}" ]]; then
echo "Installed artifact does not exist: ${artifact}" >&2
exit 1
fi
printf '%s\n' "${artifact}"
done < <(
sed -n \
's/^\[INFO\] Installing \(.*\.jar\) to .*$/\1/p' \
"${install_log}"
) | LC_ALL=C sort -u > "${files}"
if [[ ! -s "${files}" ]]; then
echo "No installed Java release artifacts were found for ${LANE}" >&2
exit 1
fi

while IFS= read -r artifact; do
sha512sum "${artifact}"
done < "${files}" \
> "release-java/${LANE}-sha512.txt"

tar -czf "release-java/${LANE}-packages.tar.gz" \
-T "${files}"
sha512sum "release-java/${LANE}-packages.tar.gz" \
> "release-java/${LANE}-packages.tar.gz.sha512"

{
echo "lane=${LANE}"
echo "jdk=${{ matrix.java_version }}"
echo "version=${{ steps.release.outputs.version }}"
echo "rc=${{ steps.release.outputs.rc_number }}"
echo "commit=${GITHUB_SHA}"
echo "signed=false"
echo "staged=false"
echo "artifact_source=maven-install-log"
} > "release-java/${LANE}-manifest.txt"

- name: Upload Java packages
uses: actions/upload-artifact@v5
with:
name: java-package-${{ matrix.lane }}
path: release-java/
if-no-files-found: error
118 changes: 118 additions & 0 deletions .github/workflows/release-python-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
################################################################################
# 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.
################################################################################

name: Release PyPaimon Publish

on:
workflow_call:

concurrency:
group: release-python-publish-${{ github.ref }}
cancel-in-progress: false

permissions:
actions: read
contents: read

jobs:
publish:
name: Publish PyPaimon
if: >-
github.repository == 'apache/paimon' &&
startsWith(github.ref, 'refs/tags/')
environment:
name: ${{ contains(github.ref_name, '-rc') && 'testpypi' || 'pypi' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- uses: actions/download-artifact@v5
with:
name: pypaimon-distributions
path: dist

- name: Verify package versions
id: package_version
shell: bash
run: |
set -euo pipefail

base_version="$(
sed -n 's/^VERSION = "\(.*\)"/\1/p' \
paimon-python/setup.py
)"
expected_version="${base_version}"
if [[ "${GITHUB_REF_NAME}" == *-rc* ]]; then
expected_version="${base_version}rc${GITHUB_REF_NAME##*-rc}"
fi

test -f "dist/pypaimon-${expected_version}.tar.gz"
compgen -G "dist/pypaimon-${expected_version}-*.whl" > /dev/null

shopt -s nullglob
distributions=(dist/*)
if [[ "${#distributions[@]}" -ne 2 ]]; then
echo "Expected one sdist and one wheel, found ${#distributions[@]} files" >&2
printf '%s\n' "${distributions[@]}" >&2
exit 1
fi

echo "version=${expected_version}" >> "${GITHUB_OUTPUT}"

- name: Reject existing TestPyPI RC version
if: contains(github.ref_name, '-rc')
shell: bash
env:
EXPECTED_VERSION: ${{ steps.package_version.outputs.version }}
run: |
set -euo pipefail

status="$(
curl --silent --show-error --output /dev/null \
--write-out '%{http_code}' \
"https://test.pypi.org/pypi/pypaimon/${EXPECTED_VERSION}/json"
)"

case "${status}" in
404)
;;
200)
echo "pypaimon ${EXPECTED_VERSION} already exists on TestPyPI; create a new RC" >&2
exit 1
;;
*)
echo "TestPyPI version check returned HTTP ${status}; refusing to publish" >&2
exit 1
;;
esac

- name: Publish RC to TestPyPI
if: contains(github.ref_name, '-rc')
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e
with:
repository-url: https://test.pypi.org/legacy/
skip-existing: false
packages-dir: dist
password: ${{ secrets.TEST_PYPI_API_TOKEN }}

- name: Publish final release to PyPI
if: ${{ !contains(github.ref_name, '-rc') }}
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e
with:
packages-dir: dist
password: ${{ secrets.PYPI_API_TOKEN }}
Loading
Loading