This is an automated email from the ASF dual-hosted git repository.
etudenhoefner pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-go.git
The following commit(s) were added to refs/heads/main by this push:
new a57a5da ci(release): add release scripts and workflow (#150)
a57a5da is described below
commit a57a5da79305c452ed076ea25aa611efccdbff18
Author: Matt Topol <[email protected]>
AuthorDate: Fri Sep 20 09:27:33 2024 -0400
ci(release): add release scripts and workflow (#150)
---
.github/workflows/go-ci.yml | 2 +-
.github/workflows/rc.yml | 127 +++++++++++++++
.gitignore | 8 +-
dev/.rat-excludes | 8 -
dev/check-license | 2 +-
dev/release/README.md | 105 ++++++++++++
dev/release/check_rat_report.py | 59 +++++++
.gitignore => dev/release/rat_exclude_files.txt | 46 ++----
dev/release/release.sh | 83 ++++++++++
dev/release/release_rc.sh | 140 ++++++++++++++++
dev/release/run_rat.sh | 54 +++++++
dev/release/verify_rc.sh | 206 ++++++++++++++++++++++++
12 files changed, 792 insertions(+), 48 deletions(-)
diff --git a/.github/workflows/go-ci.yml b/.github/workflows/go-ci.yml
index e82a3ed..3f90c29 100644
--- a/.github/workflows/go-ci.yml
+++ b/.github/workflows/go-ci.yml
@@ -42,7 +42,7 @@ jobs:
go: [ '1.21', '1.22' ]
os: [ 'ubuntu-latest', 'windows-latest', 'macos-latest' ]
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v4
with:
diff --git a/.github/workflows/rc.yml b/.github/workflows/rc.yml
new file mode 100644
index 0000000..5a407d8
--- /dev/null
+++ b/.github/workflows/rc.yml
@@ -0,0 +1,127 @@
+# 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:
+ branches:
+ - '**'
+ - '!dependabot/**'
+ tags:
+ - '*-rc*'
+ pull_request:
+
+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@v4
+ - name: Prepare for tag
+ if: github.ref_type == 'tag'
+ run: |
+ version=${GITHUB_REF_NAME%-rc}
+ version=${version#v}
+ rc=${GITHUB_REF_NAME#*-rc}
+ echo "VERSION=${version}" >> ${GITHUB_ENV}
+ echo "RC=${rc}" >> ${GITHUB_ENV}
+ - name: Prepare for branch
+ if: github.ref_type == 'branch'
+ run: |
+ rc=100
+ echo "VERSION=${version}" >> ${GITHUB_ENV}
+ echo "RC=${rc}" >> ${GITHUB_ENV}
+ - name: Archive
+ run: |
+ id="apache-iceberg-go-${VERSION}"
+ tar_gz="${id}.tar.gz"
+ echo "TAR_GZ=${tar_gz}" >> ${GITHUB_ENV}
+ git archive HEAD --prefix "${id}/" --output "${tar_gz}"
+ sha256sum "${tar_gz}" > "${tar_gz}.sha256"
+ 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-go-*
+
+ verify:
+ name: Verify
+ needs:
+ - archive
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os:
+ - macos-latest
+ - ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ - uses: actions/download-artifact@v4
+ with:
+ name: archive
+ - name: Verify
+ run: |
+ tar_gz=$(echo apache-iceberg-go-*.tar.gz)
+ version=${tar_gz#apache-iceberg-go-}
+ version=${version%.tar.gz}
+ if [ "${GITHUB_REF_TYPE}" = "tag" ]; then
+ rc="${GITHUB_REF_NAME#*-rc}"
+ else
+ rc=100
+ fi
+ VERIFY_DEFAULT=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@v4
+ - uses: actions/download-artifact@v4
+ with:
+ name: archive
+ - name: Upload
+ run: |
+ # TODO: Add support for release notes
+ gh release create ${GITHUB_REF_NAME} \
+ --prerelease \
+ --title "Apache Iceberg Go ${GITHUB_REF_NAME}" \
+ --verify-tag \
+ apache-iceberg-go-*.tar.gz \
+ apache-iceberg-go-*.tar.gz.sha*
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
index 8b398c6..99c3976 100644
--- a/.gitignore
+++ b/.gitignore
@@ -49,4 +49,10 @@ lib/
# local catalog environment via docker
dev/notebooks
-dev/warehouse
\ No newline at end of file
+dev/warehouse
+
+/apache-iceberg-go-*.tar.gz
+/apache-iceberg-go-*.tar.gz.asc
+/dev/release/apache-rat-*.jar
+/dev/release/filtered_rat.txt
+/dev/release/rat.xml
diff --git a/dev/.rat-excludes b/dev/.rat-excludes
deleted file mode 100644
index e947260..0000000
--- a/dev/.rat-excludes
+++ /dev/null
@@ -1,8 +0,0 @@
-.gitignore
-.rat-excludes
-LICENSE
-NOTICE
-go.sum
-build
-rat-results.txt
-operation_string.go
\ No newline at end of file
diff --git a/dev/check-license b/dev/check-license
index 23d22f7..7ba2d9a 100755
--- a/dev/check-license
+++ b/dev/check-license
@@ -65,7 +65,7 @@ mkdir -p "$FWDIR"/lib
}
mkdir -p build
-$java_cmd -jar "$rat_jar" -E "$FWDIR"/dev/.rat-excludes -d "$FWDIR" >
build/rat-results.txt
+$java_cmd -jar "$rat_jar" -E "$FWDIR"/dev/release/rat_exclude_files.txt -d
"$FWDIR" > build/rat-results.txt
if [ $? -ne 0 ]; then
echo "RAT exited abnormally"
diff --git a/dev/release/README.md b/dev/release/README.md
new file mode 100644
index 0000000..1f9285f
--- /dev/null
+++ b/dev/release/README.md
@@ -0,0 +1,105 @@
+<!---
+ 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
+`[email protected]:apache/iceberg-go` not from your fork:
+
+```console
+$ git clone [email protected]:apache/iceberg-go.git
+$ dev/release/release_rc.sh ${VERSION} ${RC}
+(Send a vote email to [email protected].
+ You can use a draft shown by release_rc.sh for the email.)
+```
+
+Here is an example to release RC1:
+
+```console
+$ GH_TOKEN=${YOUR_GITHUB_TOKEN} dev/release/release_rc.sh 1.0.0 1
+```
+
+The arguments of `release_rc.sh` are the version and the RC number. If RC1 has
a problem, we'll increment the RC number such as RC2, RC3 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 registered to the following:
+
+ * https://dist.apache.org/repos/dist/dev/iceberg/KEYS
+ * https://dist.apache.org/repos/dist/release/iceberg/KEYS
+
+See the header comment of them for how to add a PGP key.
+
+Apache Iceberg committers can update them by Subversion client with their ASF
account.
+e.g.:
+
+```console
+$ svn co https://dist.apache.org/repos/dist/dev/iceberg
+$ cd iceberg
+$ editor KEYS
+$ svn ci KEYS
+```
+
+### Publish
+
+We need to do the following to publish a new release:
+
+ * Publish to apache.org
+
+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 `sha256sum`/`sha512sum`
+ * `tar`
+
+You don't need to have Go installed, if it isn't on the system the latest Go
will be
+automatically downloaded and used only for verification.
+
+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 100755
index 0000000..c45baa0
--- /dev/null
+++ b/dev/release/check_rat_report.py
@@ -0,0 +1,59 @@
+#!/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 = [line.strip() for line in open(exclude_globs_filename, "r")]
+
+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/.gitignore b/dev/release/rat_exclude_files.txt
similarity index 68%
copy from .gitignore
copy to dev/release/rat_exclude_files.txt
index 8b398c6..08ab050 100644
--- a/.gitignore
+++ b/dev/release/rat_exclude_files.txt
@@ -5,9 +5,9 @@
# 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
@@ -15,38 +15,10 @@
# specific language governing permissions and limitations
# under the License.
-.DS_Store
-.cache
-tmp/
-
-.vscode
-
-# Binaries from programs and plugins
-*.exe
-*.exe~
-*.dll
-*.so
-*.dylib
-
-# rat check
-build/
-lib/
-
-# Test binary, build with `go test -c`
-*.test
-
-# Output of the go coverage tool
-*.out
-
-# intellij files
-.idea/
-.idea_modules/
-*.ipr
-*.iws
-*.iml
-
-.envrc*
-
-# local catalog environment via docker
-dev/notebooks
-dev/warehouse
\ No newline at end of file
+.gitignore
+LICENSE
+NOTICE
+go.sum
+build
+rat-results.txt
+operation_string.go
\ No newline at end of file
diff --git a/dev/release/release.sh b/dev/release/release.sh
new file mode 100755
index 0000000..d67264e
--- /dev/null
+++ b/dev/release/release.sh
@@ -0,0 +1,83 @@
+#!/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
+
+if [ "$#" -ne 2 ]; then
+ echo "Usage: $0 <version> <rc>"
+ echo " e.g.: $0 1.0.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}" != "[email protected]:apache/iceberg-go.git" ]; then
+ echo "This script must be ran with a working copy of apache/iceberg-go."
+ 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}"
+git push origin "${tag}"
+
+dist_url="https://dist.apache.org/repos/dist/release/iceberg"
+dist_dir="dev/release/dist"
+echo "Checking out ${dist_url}"
+rm -rf "${dist_dir}"
+svn co --depth=empty "${dist_url}" "${dist_dir}"
+gh release download "${rc_tag}" \
+ --repo "${repository}" \
+ --dir "${dist_dir}" \
+ --skip-existing
+
+release_id="apache-iceberg-go-${version}"
+echo "Uploading to release/"
+pushd "${dist_dir}"
+svn add .
+svn ci -m "Apache Iceberg Go ${version}"
+popd
+rm -rf "${dist_dir}"
+
+echo "Keep only the latest versions"
+old_releases=$(
+ svn ls https://dist.apache.org/repos/dist/release/iceberg/ |
+ grep -E '^apache-iceberg-go-' |
+ 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 Go 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"
diff --git a/dev/release/release_rc.sh b/dev/release/release_rc.sh
new file mode 100755
index 0000000..3c93f84
--- /dev/null
+++ b/dev/release/release_rc.sh
@@ -0,0 +1,140 @@
+#!/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
+
+SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+SOURCE_TOP_DIR="$(cd "${SOURCE_DIR}/../../" && pwd)"
+
+if [ "$#" -ne 1 ]; then
+ echo "Usage: $0 <version> <rc>"
+ echo " e.g.: $0 1.0.0 1"
+ exit 1
+fi
+
+# TODO: possibly use go-semantic-release 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}" != "[email protected]:apache/iceberg-go.git" ]; then
+ echo "This script must be ran with working copy of apache/iceberg-go."
+ 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-go-${version}"
+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}"
+
+ echo "Downloading .tar.gz from GitHub Releases"
+ gh release download "${rc_tag}" \
+ --dir . \
+ --pattern "${tar_gz}" \
+ --repo "${repository}" \
+ --skip-existing
+
+ echo "Signing tar.gz and creating checksums"
+ gpg --armor --output "${tar_gz}.asc" --detach-sig "${tar_gz}"
+fi
+
+if [ "${RELEASE_UPLOAD}" -gt 0 ]; then
+ echo "Uploading signature"
+ gh release upload "${rc_tag}" \
+ --clobber \
+ --repo "${repository}" \
+ "${tar_gz}.asc"
+fi
+
+echo "Draft email for [email protected] mailing list"
+echo ""
+echo "---------------------------------------------------------"
+cat <<MAIL
+To: [email protected]
+Subject: [VOTE][Go] Release Apache Iceberg Go ${version} RC${rc}
+
+Hi,
+
+I would like to propose the following release candidate (RC${rc}) of
+Apache Iceberg Go version ${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 Go ${version}
+[ ] +0
+[ ] -1 Do not release this as Apache Iceberg Go ${version} because...
+
+[1]: https://github.com/apache/iceberg-go/tree/${rc_hash}
+[2]: https://github.com/apache/iceberg-go/releases/${rc_tag}
+[3]:
https://github.com/apache/iceberg-go/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..a84af66
--- /dev/null
+++ b/dev/release/verify_rc.sh
@@ -0,0 +1,206 @@
+#!/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
+
+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 18.0.0 1"
+ exit 1
+fi
+
+set -o pipefail
+set -x
+
+VERSION="$1"
+RC="$2"
+
+ICEBERG_DIST_BASE_URL="https://dist.apache.org/repos/dist/dev/iceberg"
+DOWNLOAD_RC_BASE_URL="https://github.com/apache/iceberg-go/releases/download/v${VERSION}-rc${RC}"
+ARCHIVE_BASE_NAME="apache-iceberg-go-${VERSION}"
+
+: "${VERIFY_DEFAULT:=1}"
+: "${VERIFY_DOWNLOAD:=${VERIFY_DEFAULT}}"
+: "${VERIFY_FORCE_USE_GO_BINARY:=0}"
+: "${VERIFY_SIGN:=${VERIFY_DEFAULT}}"
+
+VERIFY_SUCCESS=no
+
+setup_tmpdir() {
+ cleanup() {
+ go clean -modcache || :
+ 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
+ sha256_verify="shasum -a 256 -c"
+ sha512_verify="shasum -a 512 -c"
+else
+ sha256_verify="sha256sum -c"
+ 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.sha256"
+ ${sha256_verify} "${ARCHIVE_BASE_NAME}.tar.gz.sha256"
+ 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
+}
+
+latest_go_version() {
+ local -a options
+ options=(
+ --fail
+ --location
+ --show-error
+ --silent
+ )
+ if [ -n "${GITHUB_TOKEN:-}" ]; then
+ options+=("--header" "Authorization: Bearer ${GITHUB_TOKEN}")
+ fi
+ curl \
+ "${options[@]}" \
+ https://api.github.com/repos/golang/go/git/matching-refs/tags/go |
+ grep -o '"ref": "refs/tags/go.*"' |
+ tail -n 1 |
+ sed \
+ -e 's,^"ref": "refs/tags/go,,g' \
+ -e 's/"$//g'
+}
+
+ensure_go() {
+ if [ "${VERIFY_FORCE_USE_GO_BINARY}" -le 0 ]; then
+ if go version; then
+ GOPATH="${VERIFY_TMPDIR}/gopath"
+ export GOPATH
+ mkdir -p "${GOPATH}"
+ return
+ fi
+ fi
+
+ local go_version
+ go_version=$(latest_go_version)
+ local go_os
+ go_os="$(uname)"
+ case "${go_os}" in
+ Darwin)
+ go_os="darwin"
+ ;;
+ Linux)
+ go_os="linux"
+ ;;
+ esac
+ local go_arch
+ go_arch="$(arch)"
+ case "${go_arch}" in
+ i386 | x86_64)
+ go_arch="amd64"
+ ;;
+ aarch64)
+ go_arch="arm64"
+ ;;
+ esac
+ local go_binary_tar_gz
+ go_binary_tar_gz="go${go_version}.${go_os}-${go_arch}.tar.gz"
+ local go_binary_url
+ go_binary_url="https://go.dev/dl/${go_binary_tar_gz}"
+ curl \
+ --fail \
+ --location \
+ --output "${go_binary_tar_gz}" \
+ --show-error \
+ --silent \
+ "${go_binary_url}"
+ tar xf "${go_binary_tar_gz}"
+ GOROOT="$(pwd)/go"
+ export GOROOT
+ GOPATH="$(pwd)/gopath"
+ export GOPATH
+ mkdir -p "${GOPATH}"
+ PATH="${GOROOT}/bin:${GOPATH}/bin:${PATH}"
+}
+
+test_source_distribution() {
+ go test -v ./...
+ # TODO: run integration tests
+}
+
+setup_tmpdir "iceberg-go-${VERSION}-${RC}"
+echo "Working in sandbox ${VERIFY_TMPDIR}"
+cd "${VERIFY_TMPDIR}"
+
+import_gpg_keys
+fetch_archive
+ensure_source_directory
+ensure_go
+pushd "${ARCHIVE_BASE_NAME}"
+test_source_distribution
+popd
+
+VERIFY_SUCCESS=yes
+echo "RC looks good!"