This is an automated email from the ASF dual-hosted git repository. fokko pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/iceberg-cpp.git
The following commit(s) were added to refs/heads/main by this push: new 57418d4 chore: add release script and github workflow (#193) 57418d4 is described below commit 57418d46049d71d26f1880eb2ecfea1638f4d0b0 Author: Li Feiyang <lifeiy...@zju.edu.cn> AuthorDate: Wed Sep 10 01:51:45 2025 +0800 chore: add release script and github workflow (#193) This contribution introduces release automation tooling including: - `/dev/release/README.md`: Release process documentation - `/dev/release/*.sh`: Release script utilities - `/dev/release/check_rat_report.py`: Check Apache lisence script for release - `/dev/release/rat_exclude_files.txt`: List of files excluded from RAT license checks - `.github/workflows/rc.yml`: GitHub Actions automation for release --- .github/workflows/rc.yml | 133 +++++++++++++++++++++++++++++++ dev/release/README.md | 110 ++++++++++++++++++++++++++ dev/release/check_rat_report.py | 65 ++++++++++++++++ dev/release/rat_exclude_files.txt | 28 +++++++ dev/release/release.sh | 137 ++++++++++++++++++++++++++++++++ dev/release/release_rc.sh | 159 ++++++++++++++++++++++++++++++++++++++ dev/release/run_rat.sh | 54 +++++++++++++ dev/release/verify_rc.sh | 150 +++++++++++++++++++++++++++++++++++ src/iceberg/transform.cc | 24 ------ src/iceberg/transform.h | 25 +++++- 10 files changed, 860 insertions(+), 25 deletions(-) diff --git a/.github/workflows/rc.yml b/.github/workflows/rc.yml new file mode 100644 index 0000000..ee0247e --- /dev/null +++ b/.github/workflows/rc.yml @@ -0,0 +1,133 @@ +# 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: RC +on: + push: + tags: + - '*-rc*' + +concurrency: + group: ${{ github.repository }}-${{ github.head_ref || github.sha }}-${{ github.workflow }} + cancel-in-progress: true +permissions: + contents: read + +jobs: + archive: + name: Archive + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + + - name: Prepare for tag + if: github.ref_type == 'tag' + run: | + version=${GITHUB_REF_NAME#v} + version=${version%-rc*} + rc=${GITHUB_REF_NAME##*-rc} + echo "VERSION=${version}" >> ${GITHUB_ENV} + echo "RC=${rc}" >> ${GITHUB_ENV} + echo "VERSION=${version}" + echo "RC=${rc}" + + - name: Archive + run: | + ARCHIVE_FILE_NAME="apache-iceberg-cpp-${VERSION}-rc${RC}" + tar_gz="${ARCHIVE_FILE_NAME}.tar.gz" + echo "TAR_GZ=${tar_gz}" >> ${GITHUB_ENV} + git archive HEAD --prefix "${ARCHIVE_FILE_NAME}/" --output "${tar_gz}" + sha512sum "${tar_gz}" > "${tar_gz}.sha512" + + - name: Audit + run: | + dev/release/run_rat.sh "${TAR_GZ}" + + - uses: actions/upload-artifact@v4 + with: + name: archive + path: | + apache-iceberg-cpp-* + + verify: + name: Verify + needs: + - archive + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - macos-15 + - ubuntu-24.04 + # - windows-latest + steps: + - name: Checkout + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + + - uses: actions/download-artifact@v4 + with: + name: archive + + - name: Verify + run: | + tar_gz=$(echo apache-iceberg-cpp-*.tar.gz) + version=${tar_gz#apache-iceberg-cpp-} + version=${version%.tar.gz} + version=${version%%-rc*} + if [ "${GITHUB_REF_TYPE}" = "tag" ]; then + rc=${GITHUB_REF_NAME##*-rc} + else + rc=100 + fi + echo "VERSION=${version}" + echo "RC=${rc}" + # The verify_rc.sh script will untar and + # run cmake, build, tests (ctest) and install + VERIFY_SIGN=0 VERIFY_DOWNLOAD=0 dev/release/verify_rc.sh "${version}" "${rc}" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + upload: + name: Upload + if: github.ref_type == 'tag' + needs: + - verify + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + + - uses: actions/download-artifact@v4 + with: + name: archive + + - name: Upload + run: | + gh release create ${GITHUB_REF_NAME} \ + --prerelease \ + --title "Apache Iceberg C++ ${GITHUB_REF_NAME}" \ + --generate-notes \ + --verify-tag \ + apache-iceberg-cpp-*.tar.gz \ + apache-iceberg-cpp-*.tar.gz.sha* + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/dev/release/README.md b/dev/release/README.md new file mode 100644 index 0000000..66ba1ec --- /dev/null +++ b/dev/release/README.md @@ -0,0 +1,110 @@ +<!-- + ~ 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. +--> + +# Release + +## Overview + + 1. Test the revision to be released + 2. Prepare RC and vote (detailed later) + 3. Publish (detailed later) + +### Prepare RC and vote + +Run `dev/release/release_rc.sh` on a working copy of +`g...@github.com:apache/iceberg-cpp` not from your fork: + +```console +$ git clone g...@github.com:apache/iceberg-cpp.git && cd iceberg-cpp +$ dev/release/release_rc.sh ${VERSION} ${RC} +(Send a vote email to d...@iceberg.apache.org. + You can use a draft shown by release_rc.sh for the email.) +``` + +Here is an example to release RC0 of version 0.1.0: + +```console +$ GH_TOKEN=${YOUR_GITHUB_TOKEN} dev/release/release_rc.sh 0.1.0 0 +``` + +The arguments of `release_rc.sh` are the version and the RC number. If RC0 has a problem, we'll increment the RC number such as RC1, RC2 and so on. + +Requirements to run `release_rc.sh`: + + * You must be an Apache Iceberg committer or PMC member + * You must prepare your PGP key for signing + +If you don't have a PGP key, https://infra.apache.org/release-signing.html#generate +may be helpful. + +Your PGP key must be published in the KEYS file, which is hosted at: + + * https://downloads.apache.org/iceberg/KEYS + +See the header comment of them for how to add a PGP key. + +If you are a first-time release manager, you need to add your public key to this file. To prevent formatting errors, please use the following commands instead of editing the file manually: + ++ Check out the release distribution directory: + +```console +$ svn co https://dist.apache.org/repos/dist/release/iceberg +$ cd iceberg +``` ++ Append your GPG public key to the KEYS file. Replace <YOUR_KEY_ID> with your actual GPG key ID. + +```console +$ echo "" >> KEYS # append a newline +$ gpg --list-sigs <YOUR_KEY_ID> >> KEYS # append signatures +$ gpg --armor --export <YOUR_KEY_ID> >> KEYS # append public key block +$ svn commit -m "Add GPG key for <YOUR_NAME>" +``` + +### Publish + +We need to publish to apache.org to publish a new release. + +Run `dev/release/release.sh` to publish to apache.org: + +```console +$ GH_TOKEN=${YOUR_GITHUB_TOKEN} dev/release/release.sh ${VERSION} ${RC} +``` + +Add the release to ASF's report database via [Apache Committee Report Helper](https://reporter.apache.org/addrelease.html?iceberg) + +### Verify + +We have a script for verifying a RC. + +You must install the following to run the script: + + * `curl` + * `gpg` + * `shasum` or `sha512sum` + * `tar` + * `cmake` (3.25 or higher) + * C++23 compliant compiler (GCC 13+ or Clang 16+) + +To verify a RC, run the following: + +```console +$ dev/release/verify_rc.sh ${VERSION} ${RC} +``` + +If the verification is successful, the message `RC looks good!` is shown. diff --git a/dev/release/check_rat_report.py b/dev/release/check_rat_report.py new file mode 100644 index 0000000..15d8b51 --- /dev/null +++ b/dev/release/check_rat_report.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +# +# 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. + +import fnmatch +import re +import sys +import xml.etree.ElementTree as ET + +if len(sys.argv) != 3: + sys.stderr.write("Usage: %s exclude_globs.lst rat_report.xml\n" % + sys.argv[0]) + sys.exit(1) + +exclude_globs_filename = sys.argv[1] +xml_filename = sys.argv[2] + +globs = [] +with open(exclude_globs_filename, "r") as f: + for line in f: + stripped_line = line.strip() + if not stripped_line or stripped_line.startswith('#'): + continue + globs.append(stripped_line) + +tree = ET.parse(xml_filename) +root = tree.getroot() +resources = root.findall('resource') + +all_ok = True +for r in resources: + approvals = r.findall('license-approval') + if not approvals or approvals[0].attrib['name'] == 'true': + continue + clean_name = re.sub('^[^/]+/', '', r.attrib['name']) + excluded = False + for g in globs: + if fnmatch.fnmatch(clean_name, g): + excluded = True + break + if not excluded: + sys.stdout.write("NOT APPROVED: %s (%s): %s\n" % ( + clean_name, r.attrib['name'], approvals[0].attrib['name'])) + all_ok = False + +if not all_ok: + sys.exit(1) + +print('OK') +sys.exit(0) diff --git a/dev/release/rat_exclude_files.txt b/dev/release/rat_exclude_files.txt new file mode 100644 index 0000000..6b15545 --- /dev/null +++ b/dev/release/rat_exclude_files.txt @@ -0,0 +1,28 @@ +# 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. + +.gitignore +LICENSE +NOTICE +build/** +dist/** +.git/** +test/resources/** +*.avro +*.json +*.parquet +src/iceberg/util/murmurhash3_internal.* diff --git a/dev/release/release.sh b/dev/release/release.sh new file mode 100755 index 0000000..27e0a55 --- /dev/null +++ b/dev/release/release.sh @@ -0,0 +1,137 @@ +#!/usr/bin/env bash +# +# 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. + +set -eu + +for cmd in git gh svn; do + if ! command -v ${cmd} &> /dev/null; then + echo "This script requires '${cmd}' but it's not installed. Aborting." + exit 1 + fi +done + +if [ "$#" -ne 2 ]; then + echo "Usage: $0 <version> <rc>" + echo " e.g.: $0 0.1.0 1" + exit 1 +fi + +version=$1 +rc=$2 + +git_origin_url="$(git remote get-url origin)" +repository="${git_origin_url#*github.com?}" +repository="${repository%.git}" + +if [ "${git_origin_url}" != "g...@github.com:apache/iceberg-cpp.git" ]; then + echo "This script must be ran with a working copy of apache/iceberg-cpp." + echo "The origin's URL: ${git_origin_url}" + exit 1 +fi + +tag="v${version}" +rc_tag="${tag}-rc${rc}" +echo "Tagging for release: ${tag}" +git tag "${tag}" "${rc_tag}^{}" -m "Release ${tag}" +git push origin "${tag}" + +release_id="apache-iceberg-cpp-${version}" +dist_url="https://dist.apache.org/repos/dist/release/iceberg" +dist_dev_url="https://dist.apache.org/repos/dist/dev/iceberg" + +svn \ + mv "${dist_dev_url}/${release_id}-rc${rc}/" \ + "${dist_url}/${release_id}" \ + -m "Apache Iceberg C++ ${version}" + +svn co "${dist_url}/${release_id}" +pushd "${release_id}" + +echo "Renaming artifacts to their final release names..." +for fname in ./*; do + mv "${fname}" "${fname//-rc${rc}/}" +done +echo "Renamed files:" +ls -l + +gh release create "${tag}" \ + --repo "${repository}" \ + --title "Apache Iceberg C++ ${version}" \ + --generate-notes \ + --verify-tag \ + *.tar.gz \ + *.tar.gz.asc \ + *.tar.gz.sha512 +popd + +rm -rf "${release_id}" + +echo "Keep only the latest versions" +old_releases=$( + svn ls "${dist_url}" | + grep -E '^apache-iceberg-cpp-' | + sort --version-sort --reverse | + tail -n +2 +) +for old_release_version in ${old_releases}; do + echo "Remove old release ${old_release_version}" + svn \ + delete \ + -m "Remove old Apache Iceberg C++ release: ${old_release_version}" \ + "https://dist.apache.org/repos/dist/release/iceberg/${old_release_version}" +done + +echo "Success! The release is available here:" +echo " https://dist.apache.org/repos/dist/release/iceberg/${release_id}" +echo +echo "Add this release to ASF's report database:" +echo " https://reporter.apache.org/addrelease.html?iceberg" + +echo "Draft email for announcement" +echo "" +echo "---------------------------------------------------------" +cat <<MAIL +To: d...@iceberg.apache.org +Cc: annou...@apache.org +Hello everyone, + +I'm pleased to announce the release of Apache Iceberg C++ v${version}! + +Apache Iceberg is an open table format for huge analytic datasets, +Iceberg delivers high query performance for tables with tens of +petabytes of data, along with atomic commits, concurrent writes, and +SQL-compatible table evolution. + +This release contains <COMMIT_COUNT> commits from <CONTRIBUTOR_COUNT> unique contributors. Among +the changes in this release are the following highlights: + +- <FEATURE_1> +- <FEATURE_2> +- ... +- <FEATURE_N> + +This release is hosted at: https://dist.apache.org/repos/dist/release/iceberg/apache-iceberg-cpp-${version} + +For release details and downloads, please visit: https://github.com/apache/iceberg-cpp/releases/tag/apache-iceberg-cpp-${version} + +Thanks to everyone for all your contributions! + +<AUTHOR> +MAIL +echo "---------------------------------------------------------" diff --git a/dev/release/release_rc.sh b/dev/release/release_rc.sh new file mode 100755 index 0000000..7ef1268 --- /dev/null +++ b/dev/release/release_rc.sh @@ -0,0 +1,159 @@ +#!/usr/bin/env bash +# +# 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. + +set -eu + +for cmd in git gh gpg svn; do + if ! command -v ${cmd} &> /dev/null; then + echo "This script requires '${cmd}' but it's not installed. Aborting." + exit 1 + fi +done + +SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SOURCE_TOP_DIR="$(cd "${SOURCE_DIR}/../../" && pwd)" + +if [ "$#" -ne 2 ]; then + echo "Usage: $0 <version> <rc>" + echo " e.g.: $0 0.1.0 1" + exit 1 +fi + +# TODO: possibly use semantic versioning to auto generate the version? +version=$1 +rc=$2 + +: "${RELEASE_DEFAULT:=1}" +: "${RELEASE_PULL:=${RELEASE_DEFAULT}}" +: "${RELEASE_PUSH_TAG:=${RELEASE_DEFAULT}}" +: "${RELEASE_SIGN:=${RELEASE_DEFAULT}}" +: "${RELEASE_UPLOAD:=${RELEASE_DEFAULT}}" + +cd "${SOURCE_TOP_DIR}" + +if [ "${RELEASE_PULL}" -gt 0 ] || [ "${RELEASE_PUSH_TAG}" -gt 0 ]; then + git_origin_url="$(git remote get-url origin)" + if [ "${git_origin_url}" != "g...@github.com:apache/iceberg-cpp.git" ]; then + echo "This script must be ran with working copy of apache/iceberg-cpp." + echo "The origin's URL: ${git_origin_url}" + exit 1 + fi +fi + +if [ "${RELEASE_PULL}" -gt 0 ]; then + echo "Ensure using the latest commit" + git checkout main + git pull --rebase --prune +fi + +rc_tag="v${version}-rc${rc}" +if [ "${RELEASE_PUSH_TAG}" -gt 0 ]; then + echo "Tagging for RC: ${rc_tag}" + git tag -a -m "${version} RC${rc}" "${rc_tag}" + git push origin "${rc_tag}" +fi + +rc_hash="$(git rev-list --max-count=1 "${rc_tag}")" + +id="apache-iceberg-cpp-${version}-rc${rc}" +tar_gz="${id}.tar.gz" + +if [ "${RELEASE_SIGN}" -gt 0 ]; then + git_origin_url="$(git remote get-url origin)" + repository="${git_origin_url#*github.com?}" + repository="${repository%.git}" + + echo "Looking for GitHub Actions workflow on ${repository}:${rc_tag}" + run_id="" + while [ -z "${run_id}" ]; do + echo "Waiting for run to start..." + run_id=$(gh run list \ + --repo "${repository}" \ + --workflow=rc.yml \ + --json 'databaseId,event,headBranch,status' \ + --jq ".[] | select(.event == \"push\" and .headBranch == \"${rc_tag}\") | .databaseId") + sleep 1 + done + + echo "Found GitHub Actions workflow with ID: ${run_id}" + gh run watch --repo "${repository}" --exit-status "${run_id}" + + mkdir -p "${id}" + + echo "Downloading .tar.gz and .sha512 from GitHub Releases" + gh release download "${rc_tag}" \ + --dir "${id}" \ + --pattern "${tar_gz}" \ + --pattern "${tar_gz}.sha512" \ + --repo "${repository}" \ + --skip-existing + + echo "Signing tar.gz" + cd "${id}" + gpg --armor --output "${tar_gz}.asc" --detach-sig "${tar_gz}" + echo "Add signature to GitHub release" + gh release upload "${rc_tag}" \ + --clobber \ + --repo "${repository}" \ + "${tar_gz}".asc + cd .. +fi + +if [ "${RELEASE_UPLOAD}" -gt 0 ]; then + echo "Uploading to ASF dist/dev..." + # rename files to remove -rc${rc} suffix before uploading + pushd "${id}" + for fname in ./*; do + mv "${fname}" "${fname//-rc${rc}/}" + done + popd + svn import "${id}" "https://dist.apache.org/repos/dist/dev/iceberg/${id}" -m "Apache Iceberg C++ ${version} RC${rc}" +fi + +echo "Draft email for d...@iceberg.apache.org mailing list" +echo "" +echo "---------------------------------------------------------" +cat <<MAIL +To: d...@iceberg.apache.org +Subject: [VOTE][C++] Release Apache Iceberg C++ v${version} RC${rc} + +Hi, + +I would like to propose the following release candidate (RC${rc}) of +Apache Iceberg C++ version v${version}. + +This release candidate is based on commit: +${rc_hash} [1] + +The source release rc${rc} is hosted at [2]. + +Please download, verify checksums and signatures, run the unit tests, +and vote on the release. See [3] for how to validate a release candidate. + +The vote will be open for at least 72 hours. + +[ ] +1 Release this as Apache Iceberg C++ v${version} +[ ] +0 +[ ] -1 Do not release this as Apache Iceberg C++ v${version} because... + +[1]: https://github.com/apache/iceberg-cpp/tree/${rc_hash} +[2]: https://dist.apache.org/repos/dist/dev/iceberg/apache-iceberg-cpp-${version}-rc${rc} +[3]: https://github.com/apache/iceberg-cpp/blob/main/dev/release/README.md#verify +MAIL +echo "---------------------------------------------------------" diff --git a/dev/release/run_rat.sh b/dev/release/run_rat.sh new file mode 100755 index 0000000..2104369 --- /dev/null +++ b/dev/release/run_rat.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# +# 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. + +set -eu + +RELEASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +RAT_VERSION=0.16.1 + +RAT_JAR="${RELEASE_DIR}/apache-rat-${RAT_VERSION}.jar" +if [ ! -f "${RAT_JAR}" ]; then + curl \ + --fail \ + --output "${RAT_JAR}" \ + --show-error \ + --silent \ + https://repo1.maven.org/maven2/org/apache/rat/apache-rat/${RAT_VERSION}/apache-rat-${RAT_VERSION}.jar +fi + +RAT_XML="${RELEASE_DIR}/rat.xml" +java \ + -jar "${RAT_JAR}" \ + --out "${RAT_XML}" \ + --xml \ + "$1" +FILTERED_RAT_TXT="${RELEASE_DIR}/filtered_rat.txt" +if ${PYTHON:-python3} \ + "${RELEASE_DIR}/check_rat_report.py" \ + "${RELEASE_DIR}/rat_exclude_files.txt" \ + "${RAT_XML}" > \ + "${FILTERED_RAT_TXT}"; then + echo "No unapproved licenses" +else + cat "${FILTERED_RAT_TXT}" + N_UNAPPROVED=$(grep -c "NOT APPROVED" "${FILTERED_RAT_TXT}") + echo "${N_UNAPPROVED} unapproved licenses. Check Rat report: ${RAT_XML}" + exit 1 +fi diff --git a/dev/release/verify_rc.sh b/dev/release/verify_rc.sh new file mode 100755 index 0000000..f32626d --- /dev/null +++ b/dev/release/verify_rc.sh @@ -0,0 +1,150 @@ +#!/usr/bin/env bash +# +# 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. + +set -eu + +for cmd in curl gpg cmake; do + if ! command -v ${cmd} &> /dev/null; then + echo "This script requires '${cmd}' but it's not installed. Aborting." + exit 1 + fi +done + +SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +TOP_SOURCE_DIR="$(dirname "$(dirname "${SOURCE_DIR}")")" + +if [ "$#" -ne 2 ]; then + echo "Usage: $0 <version> <rc>" + echo " e.g.: $0 0.1.0 1" + exit 1 +fi + +set -o pipefail +set -x + +VERSION="$1" +RC="$2" + +ICEBERG_DIST_BASE_URL="https://downloads.apache.org/iceberg" +DOWNLOAD_RC_BASE_URL="https://dist.apache.org/repos/dist/dev/iceberg/apache-iceberg-cpp-${VERSION}-rc${RC}" +ARCHIVE_BASE_NAME="apache-iceberg-cpp-${VERSION}-rc${RC}" + +: "${VERIFY_DEFAULT:=1}" +: "${VERIFY_DOWNLOAD:=${VERIFY_DEFAULT}}" +: "${VERIFY_SIGN:=${VERIFY_DEFAULT}}" + +VERIFY_SUCCESS=no + +setup_tmpdir() { + cleanup() { + if [ "${VERIFY_SUCCESS}" = "yes" ]; then + rm -rf "${VERIFY_TMPDIR}" + else + echo "Failed to verify release candidate. See ${VERIFY_TMPDIR} for details." + fi + } + + if [ -z "${VERIFY_TMPDIR:-}" ]; then + VERIFY_TMPDIR="$(mktemp -d -t "$1.XXXXX")" + trap cleanup EXIT + else + mkdir -p "${VERIFY_TMPDIR}" + fi +} + +download() { + curl \ + --fail \ + --location \ + --remote-name \ + --show-error \ + --silent \ + "$1" +} + +download_rc_file() { + if [ "${VERIFY_DOWNLOAD}" -gt 0 ]; then + download "${DOWNLOAD_RC_BASE_URL}/$1" + else + cp "${TOP_SOURCE_DIR}/$1" "$1" + fi +} + +import_gpg_keys() { + if [ "${VERIFY_SIGN}" -gt 0 ]; then + download "${ICEBERG_DIST_BASE_URL}/KEYS" + gpg --import KEYS + fi +} + +if type shasum >/dev/null 2>&1; then + sha512_verify="shasum -a 512 -c" +else + sha512_verify="sha512sum -c" +fi + +fetch_archive() { + download_rc_file "${ARCHIVE_BASE_NAME}.tar.gz" + if [ "${VERIFY_SIGN}" -gt 0 ]; then + download_rc_file "${ARCHIVE_BASE_NAME}.tar.gz.asc" + gpg --verify "${ARCHIVE_BASE_NAME}.tar.gz.asc" "${ARCHIVE_BASE_NAME}.tar.gz" + fi + download_rc_file "${ARCHIVE_BASE_NAME}.tar.gz.sha512" + ${sha512_verify} "${ARCHIVE_BASE_NAME}.tar.gz.sha512" +} + +ensure_source_directory() { + tar xf "${ARCHIVE_BASE_NAME}".tar.gz +} + +test_source_distribution() { + echo "Building and testing Apache Iceberg C++..." + + # Configure build + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DICEBERG_BUILD_STATIC=ON \ + -DICEBERG_BUILD_SHARED=ON + + # Build + cmake --build build --parallel $(nproc || sysctl -n hw.ncpu || echo 4) + + # Run tests + ctest --test-dir build --output-on-failure --parallel $(nproc || sysctl -n hw.ncpu || echo 4) + + # Install + mkdir -p ./install_test + cmake --install build --prefix ./install_test + + echo "Build, test and install completed successfully!" +} + +setup_tmpdir "iceberg-cpp-${VERSION}-${RC}" +echo "Working in sandbox ${VERIFY_TMPDIR}" +cd "${VERIFY_TMPDIR}" + +import_gpg_keys +fetch_archive +ensure_source_directory +pushd "${ARCHIVE_BASE_NAME}" +test_source_distribution +popd + +VERIFY_SUCCESS=yes +echo "RC looks good!" diff --git a/src/iceberg/transform.cc b/src/iceberg/transform.cc index 7898fc6..1de38fc 100644 --- a/src/iceberg/transform.cc +++ b/src/iceberg/transform.cc @@ -39,30 +39,6 @@ constexpr std::string_view kHourName = "hour"; constexpr std::string_view kVoidName = "void"; } // namespace -constexpr std::string_view TransformTypeToString(TransformType type) { - switch (type) { - case TransformType::kUnknown: - return kUnknownName; - case TransformType::kIdentity: - return kIdentityName; - case TransformType::kBucket: - return kBucketName; - case TransformType::kTruncate: - return kTruncateName; - case TransformType::kYear: - return kYearName; - case TransformType::kMonth: - return kMonthName; - case TransformType::kDay: - return kDayName; - case TransformType::kHour: - return kHourName; - case TransformType::kVoid: - return kVoidName; - } - std::unreachable(); -} - std::shared_ptr<Transform> Transform::Identity() { static auto instance = std::shared_ptr<Transform>(new Transform(TransformType::kIdentity)); diff --git a/src/iceberg/transform.h b/src/iceberg/transform.h index 3e6709f..6c771fb 100644 --- a/src/iceberg/transform.h +++ b/src/iceberg/transform.h @@ -23,6 +23,7 @@ #include <cstdint> #include <memory> +#include <utility> #include <variant> #include "iceberg/expression/literal.h" @@ -57,7 +58,29 @@ enum class TransformType { }; /// \brief Get the relative transform name -ICEBERG_EXPORT constexpr std::string_view TransformTypeToString(TransformType type); +ICEBERG_EXPORT constexpr std::string_view TransformTypeToString(TransformType type) { + switch (type) { + case TransformType::kUnknown: + return "unknown"; + case TransformType::kIdentity: + return "identity"; + case TransformType::kBucket: + return "bucket"; + case TransformType::kTruncate: + return "truncate"; + case TransformType::kYear: + return "year"; + case TransformType::kMonth: + return "month"; + case TransformType::kDay: + return "day"; + case TransformType::kHour: + return "hour"; + case TransformType::kVoid: + return "void"; + } + std::unreachable(); +} /// \brief Represents a transform used in partitioning or sorting in Iceberg. ///