blob: a71f0f3a26fe12933ce64b787a818a3717d7558a [file]
# 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.
# GA tags publish; RC tags validate only.
# Secret: CARGO_REGISTRY_TOKEN.
name: Release Rust
on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
- "v[0-9]+.[0-9]+.[0-9]+-rc[0-9]+"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
jobs:
validate:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v7
- name: Setup Rust toolchain
run: |
rustup update stable
rustup default stable
- name: Validate release tag
if: github.ref_type == 'tag'
shell: bash
run: |
set -euo pipefail
if [[ ! "${GITHUB_REF_NAME}" =~ ^v([0-9]+\.[0-9]+\.[0-9]+)(-rc[0-9]+)?$ ]]; then
echo "::error::invalid release tag: ${GITHUB_REF_NAME}"
exit 1
fi
TAG_VERSION="${BASH_REMATCH[1]}"
WORKSPACE_VERSION=$(
cargo metadata --locked --format-version 1 --no-deps |
jq -er '
[.packages[] |
select(.name == "paimon" or .name == "paimon-datafusion") |
.version] as $versions |
if ($versions | length) == 2 and
($versions | unique | length) == 1
then $versions[0]
else error("release crate versions differ")
end
'
)
if [ "${TAG_VERSION}" != "${WORKSPACE_VERSION}" ]; then
echo "::error::tag ${TAG_VERSION} does not match workspace ${WORKSPACE_VERSION}"
exit 1
fi
- name: Check package inventory
shell: bash
run: |
set -euo pipefail
for crate_dir in crates/paimon crates/integrations/datafusion; do
for legal_file in LICENSE NOTICE; do
cmp --silent "${legal_file}" "${crate_dir}/${legal_file}" || {
echo "::error::${crate_dir}/${legal_file} differs from ${legal_file}"
exit 1
}
done
done
for package in paimon paimon-datafusion; do
files="/tmp/${package}-package-files.txt"
cargo package --locked -p "${package}" --list > "${files}"
for required in LICENSE NOTICE DEPENDENCIES.rust.tsv test_utils.rs; do
grep --fixed-strings --line-regexp --quiet "${required}" "${files}" || {
echo "::error::${package} package is missing ${required}"
exit 1
}
done
grep --quiet '^testdata/' "${files}" || {
echo "::error::${package} package is missing testdata"
exit 1
}
done
grep --fixed-strings --line-regexp --quiet \
blob_test_utils.rs /tmp/paimon-package-files.txt || {
echo "::error::paimon package is missing blob_test_utils.rs"
exit 1
}
- name: Package release crates
# Cargo verifies workspace dependencies through its temporary registry.
run: >
cargo package --locked
-p paimon
-p paimon-datafusion
--all-features
- name: Dry run paimon
run: cargo publish --locked -p paimon --all-features --dry-run
publish-paimon:
needs: validate
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref_name, '-')
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v7
- name: Setup Rust toolchain
run: |
rustup update stable
rustup default stable
- name: Publish paimon if absent
shell: bash
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: |
set -euo pipefail
VERSION=$(
cargo metadata --locked --format-version 1 --no-deps |
jq -er '.packages[] | select(.name == "paimon") | .version'
)
USER_AGENT="paimon-rust-release/1.0 (${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY})"
STATUS=$(
curl --silent --show-error --retry 3 \
--user-agent "${USER_AGENT}" \
--output /tmp/paimon-version.json \
--write-out '%{http_code}' \
"https://crates.io/api/v1/crates/paimon/${VERSION}"
)
if [ "${STATUS}" = 200 ]; then
jq -e --arg version "${VERSION}" '.version.num == $version' \
/tmp/paimon-version.json >/dev/null
echo "paimon ${VERSION} already exists; skipping"
elif [ "${STATUS}" = 404 ]; then
cargo publish --locked -p paimon --all-features
else
echo "::error::crates.io returned HTTP ${STATUS} for paimon ${VERSION}"
exit 1
fi
- name: Wait for paimon on crates.io
shell: bash
run: |
set -euo pipefail
VERSION=$(
cargo metadata --locked --format-version 1 --no-deps |
jq -er '.packages[] | select(.name == "paimon") | .version'
)
USER_AGENT="paimon-rust-release/1.0 (${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY})"
for attempt in {1..20}; do
CURRENT=$(
curl --fail-with-body --silent --show-error --retry 3 \
--user-agent "${USER_AGENT}" \
"https://crates.io/api/v1/crates/paimon/${VERSION}" |
jq -r '.version.num // empty' || true
)
if [ "${CURRENT}" = "${VERSION}" ]; then
echo "paimon ${VERSION} is available"
exit 0
fi
echo "Waiting for paimon ${VERSION}... ${attempt}/20"
sleep 30
done
echo "::error::paimon ${VERSION} did not appear before timeout"
exit 1
publish-paimon-datafusion:
needs: publish-paimon
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref_name, '-')
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v7
- name: Setup Rust toolchain
run: |
rustup update stable
rustup default stable
- name: Dry run paimon-datafusion
run: cargo publish --locked -p paimon-datafusion --all-features --dry-run
- name: Publish paimon-datafusion if absent
shell: bash
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: |
set -euo pipefail
VERSION=$(
cargo metadata --locked --format-version 1 --no-deps |
jq -er '.packages[] | select(.name == "paimon-datafusion") | .version'
)
USER_AGENT="paimon-rust-release/1.0 (${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY})"
STATUS=$(
curl --silent --show-error --retry 3 \
--user-agent "${USER_AGENT}" \
--output /tmp/paimon-datafusion-version.json \
--write-out '%{http_code}' \
"https://crates.io/api/v1/crates/paimon-datafusion/${VERSION}"
)
if [ "${STATUS}" = 200 ]; then
jq -e --arg version "${VERSION}" '.version.num == $version' \
/tmp/paimon-datafusion-version.json >/dev/null
echo "paimon-datafusion ${VERSION} already exists; skipping"
elif [ "${STATUS}" = 404 ]; then
cargo publish --locked -p paimon-datafusion --all-features
else
echo "::error::crates.io returned HTTP ${STATUS} for paimon-datafusion ${VERSION}"
exit 1
fi