snazy commented on code in PR #2156:
URL: https://github.com/apache/polaris/pull/2156#discussion_r2256234425


##########
releasey/02-create-release-branch.sh:
##########
@@ -0,0 +1,201 @@
+#!/bin/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.
+#
+
+#
+# Create Release Branch Script
+#
+# Automates the "Create release branch" section of the release guide.
+# Creates a new release branch and sets the target release version.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") --version VERSION [--commit GIT_COMMIT] [--recreate] [--help 
| -h]
+
+  Creates a release branch and sets the target release version.
+
+  Behavior:
+  - RC1: Creates the release branch and sets up the version
+  - RC2+: Exits successfully if release branch exists, errors if it doesn't
+
+  Options:
+    --version VERSION
+        The release version in format x.y.z-incubating-rcN where N is the RC 
number
+    --commit GIT_COMMIT
+        The Git commit SHA to create the release branch from. Defaults to 
current HEAD.
+    --recreate
+        Drop the release branch if it already exists and recreate it to the 
new SHA.
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0") --version 1.0.0-incubating-rc1 --commit HEAD
+    $(basename "$0") --version 0.1.0-incubating-rc1 --commit abc123def456
+    $(basename "$0") --version 1.0.0-incubating-rc1 --commit HEAD --recreate
+    $(basename "$0") --version 1.0.0-incubating-rc2  # Will exit successfully 
if branch exists
+
+EOF
+}
+
+version=""
+commit="HEAD"
+recreate=false
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --version)
+      if [[ $# -lt 2 ]]; then
+        print_error "Missing argument for --version"
+        usage >&2
+        exit 1
+      fi
+      version="$2"
+      shift 2
+      ;;
+    --commit)
+      if [[ $# -lt 2 ]]; then
+        print_error "Missing argument for --commit"
+        usage >&2
+        exit 1
+      fi
+      commit="$2"
+      shift 2
+      ;;
+    --recreate)
+      recreate=true
+      shift
+      ;;
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+# Ensure the version is provided
+if [[ -z ${version} ]]; then
+  print_error "Missing version"
+  usage >&2
+  exit 1
+fi
+
+# Validate that the commit exists
+if ! git rev-parse --verify "${commit}" >/dev/null 2>&1; then
+  print_error "Invalid Git commit: ${commit}"
+  usage >&2
+  exit 1
+fi
+
+# Validate version format: x.y.z-incubating-rcN
+# TODO: Remove incubating when we are a TLP

Review Comment:
   Guess the TODO can go away, or have it everywhere (which isn't great either).
   Maybe have a constant `VERSION_INCUBATING="-incubating"`, so there's only 
one place to change in that case.



##########
releasey/02-create-release-branch.sh:
##########
@@ -0,0 +1,201 @@
+#!/bin/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.
+#
+
+#
+# Create Release Branch Script
+#
+# Automates the "Create release branch" section of the release guide.
+# Creates a new release branch and sets the target release version.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") --version VERSION [--commit GIT_COMMIT] [--recreate] [--help 
| -h]
+
+  Creates a release branch and sets the target release version.
+
+  Behavior:
+  - RC1: Creates the release branch and sets up the version
+  - RC2+: Exits successfully if release branch exists, errors if it doesn't
+
+  Options:
+    --version VERSION
+        The release version in format x.y.z-incubating-rcN where N is the RC 
number
+    --commit GIT_COMMIT
+        The Git commit SHA to create the release branch from. Defaults to 
current HEAD.
+    --recreate
+        Drop the release branch if it already exists and recreate it to the 
new SHA.
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0") --version 1.0.0-incubating-rc1 --commit HEAD
+    $(basename "$0") --version 0.1.0-incubating-rc1 --commit abc123def456
+    $(basename "$0") --version 1.0.0-incubating-rc1 --commit HEAD --recreate
+    $(basename "$0") --version 1.0.0-incubating-rc2  # Will exit successfully 
if branch exists
+
+EOF
+}
+
+version=""
+commit="HEAD"
+recreate=false
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --version)
+      if [[ $# -lt 2 ]]; then
+        print_error "Missing argument for --version"
+        usage >&2
+        exit 1
+      fi
+      version="$2"
+      shift 2
+      ;;
+    --commit)
+      if [[ $# -lt 2 ]]; then
+        print_error "Missing argument for --commit"
+        usage >&2
+        exit 1
+      fi
+      commit="$2"
+      shift 2
+      ;;
+    --recreate)
+      recreate=true
+      shift
+      ;;
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+# Ensure the version is provided
+if [[ -z ${version} ]]; then
+  print_error "Missing version"
+  usage >&2
+  exit 1
+fi
+
+# Validate that the commit exists
+if ! git rev-parse --verify "${commit}" >/dev/null 2>&1; then
+  print_error "Invalid Git commit: ${commit}"
+  usage >&2
+  exit 1
+fi
+
+# Validate version format: x.y.z-incubating-rcN
+# TODO: Remove incubating when we are a TLP
+if ! validate_and_extract_rc_version "${version}"; then
+  print_error "Invalid version format. Expected: x.y.z-incubating-rcN where 
N>0, got: ${version}"
+  usage >&2
+  exit 1
+fi
+
+# Define polaris_version from extracted components
+polaris_version="${major}.${minor}.${patch}-incubating"
+release_branch="release/${polaris_version}"
+
+# Handle RC > 1 scenarios
+if [[ ${rc_number} -gt 1 ]]; then
+  # Check if release branch already exists
+  if git show-ref --verify --quiet "refs/heads/${release_branch}"; then
+    print_info "RC${rc_number} detected and release branch ${release_branch} 
already exists."
+    print_info "This script only creates release branches for RC1. Nothing to 
do."
+    exit 0
+  else
+    print_error "RC${rc_number} detected but release branch ${release_branch} 
does not exist."
+    exit 1
+  fi
+fi
+
+print_info "Starting release branch creation..."
+print_info "Version: ${version}"
+print_info "Polaris version: ${polaris_version}"
+print_info "From commit: ${commit}"
+echo
+
+# Check if release branch already exists
+if git show-ref --verify --quiet "refs/heads/${release_branch}"; then
+  if [[ "${recreate}" == "true" ]]; then
+    print_info "Release branch ${release_branch} already exists, deleting 
it..."
+    exec_process git branch -D "${release_branch}"
+    if git show-ref --verify --quiet 
"refs/remotes/${APACHE_REMOTE_NAME}/${release_branch}"; then
+      print_info "Deleting remote release branch from ${APACHE_REMOTE_NAME}..."
+      exec_process git push "${APACHE_REMOTE_NAME}" --delete 
"${release_branch}"
+    fi
+  else
+    print_error "Release branch ${release_branch} already exists. Use 
--recreate to delete and recreate it."
+    exit 1
+  fi
+fi
+
+print_info "Checking out commit: ${commit}"
+exec_process git checkout "${commit}"
+
+print_info "Creating release branch: ${release_branch}"
+exec_process git branch "${release_branch}"
+
+print_info "Pushing release branch to ${APACHE_REMOTE_NAME}"
+exec_process git push "${APACHE_REMOTE_NAME}" "${release_branch}" 
--set-upstream
+
+print_info "Checking out release branch"
+exec_process git checkout "${release_branch}"
+
+print_info "Setting version to ${polaris_version} in version.txt"
+update_version "${polaris_version}"
+
+print_info "Committing and pushing version change"
+exec_process git add "$VERSION_FILE" "$HELM_CHART_YAML_FILE" 
"$HELM_README_FILE" "$HELM_VALUES_FILE"
+exec_process git commit -m "[chore] Bump version to ${polaris_version} for 
release"
+exec_process git push
+
+print_info "Updating CHANGELOG.md"
+exec_process cd "${releasey_dir}/.."
+exec_process ./gradlew patchChangelog
+
+print_info "Committing changelog change"
+exec_process git add "$CHANGELOG_FILE"
+exec_process git commit -m "[chore] Update changelog for release"

Review Comment:
   ```suggestion
   exec_process git commit -m "[chore] Update changelog for ${version}"
   ```



##########
releasey/03-create-release-candidate-tag.sh:
##########
@@ -0,0 +1,142 @@
+#!/bin/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.
+#
+
+#
+# Create Release Candidate Tag Script
+#
+# Automates the "Create release candidate tag" section of the release guide.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") --version VERSION [--help | -h]
+
+  Creates a release candidate tag for a release candidate.
+
+  Options:
+    --version VERSION
+        The release version in format x.y.z-incubating-rcN where N is the RC 
number
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0") --version 1.0.0-incubating-rc1
+    $(basename "$0") --version 0.1.0-incubating-rc2
+
+EOF
+}
+
+version=""
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --version)
+      if [[ $# -lt 2 ]]; then
+        print_error "Missing argument for --version"
+        usage >&2
+        exit 1
+      fi
+      version="$2"
+      shift 2
+      ;;
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+# Ensure the version is provided
+if [[ -z ${version} ]]; then
+  print_error "Missing version"
+  usage >&2
+  exit 1
+fi
+
+# Validate version format: x.y.z-incubating-rcN
+# TODO: Remove incubating when we are a TLP
+if ! validate_and_extract_rc_version "${version}"; then
+  print_error "Invalid version format. Expected: x.y.z-incubating-rcN where 
N>0, got: ${version}"
+  usage >&2
+  exit 1
+fi
+
+# Define polaris_version from extracted components
+polaris_version="${major}.${minor}.${patch}-incubating"
+
+print_info "Starting release candidate tag creation..."
+print_info "Version: ${version}"
+print_info "Polaris version: ${polaris_version}"
+print_info "RC number: ${rc_number}"
+echo
+
+# If we're creating RC2 or later, verify previous RC tag exists
+if [[ ${rc_number} -gt 1 ]]; then
+  previous_rc=$((rc_number - 1))
+  previous_tag="apache-polaris-${version%-rc*}-rc${previous_rc}"

Review Comment:
   Super nit: maybe extract `${version%-rc*}` into a separate variable, just 
for clarity.



##########
releasey/04-build-and-test.sh:
##########
@@ -0,0 +1,90 @@
+#!/bin/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.
+#
+
+#
+# Build and Test Script
+#
+# Builds Polaris completely and ensures that all integration and regression 
tests
+# have been run prior to releasing by verifying the status of all GitHub 
Actions
+# workflows for the current commit.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+source "${LIBS_DIR}/_github.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") [--help | -h]
+
+  Builds Polaris completely and ensures that all integration and regression 
tests
+  have been run prior to releasing by verifying GitHub CI status.
+
+  Options:
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0")
+
+EOF
+}
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+print_info "Starting build and test process..."
+echo
+
+# Clean and build Polaris
+print_info "Building Polaris..."
+exec_process cd "${releasey_dir}/.."
+exec_process ./gradlew clean build
+
+current_commit=$(git rev-parse HEAD)
+print_info "Current commit: ${current_commit}"
+
+if ! check_github_checks_passed "${current_commit}"; then
+  print_error "Integration and regression tests have not all passed for commit 
${current_commit}"
+  print_error "Please ensure all CI workflows are successful before proceeding 
with the release"
+  print_info "You can check the status at: 
https://github.com/${GITHUB_REPO_OWNER}/${GITHUB_REPO_NAME}/commit/${current_commit}";
+  exit 1
+fi

Review Comment:
   Might want to move this before the Gradle build (why build something that's 
known to not pass CI).



##########
releasey/05-build-and-stage-distributions.sh:
##########
@@ -0,0 +1,155 @@
+#!/bin/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.
+#
+
+#
+# Build and Stage Distributions Script
+#
+# Builds source and binary distributions and stages them to the Apache dist 
dev repository.
+# This script automates the "Build and stage the distributions" step from the 
release guide.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+source "${LIBS_DIR}/_gpg.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") [--help | -h]
+
+  Builds source and binary distributions and stages them to the Apache dist 
dev repository.
+  The version is automatically determined from the current git tag.  I.e. this 
script must
+  be run from a release candidate tag.
+
+  Options:
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0")
+
+EOF
+}
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+# Determine version from current git tag
+print_info "Determining version from current git tag..."
+
+if ! git_tag=$(git describe --tags --exact-match HEAD 2>/dev/null); then
+  print_error "Current HEAD is not on a release candidate tag. Please checkout 
a release candidate tag first."
+  print_error "Use: git checkout apache-polaris-x.y.z-incubating-rcN"
+  exit 1
+fi
+print_info "Found git tag: ${git_tag}"
+
+# Validate git tag format and extract version components
+if ! validate_and_extract_git_tag_version "${git_tag}"; then
+  print_error "Invalid git tag format: ${git_tag}"
+  print_error "Expected format: apache-polaris-x.y.z-incubating-rcN"
+  exit 1
+fi
+
+polaris_version="${major}.${minor}.${patch}-incubating"
+
+print_info "Starting build and stage distributions process..."
+print_info "Version: ${polaris_version}"
+print_info "RC number: ${rc_number}"
+echo
+
+# Build distributions
+print_info "Building source and binary distributions..."
+exec_process cd "${releasey_dir}/.."
+exec_process ./gradlew build sourceTarball -Prelease -PuseGpgAgent -x test -x 
intTest
+
+# Create Helm package
+print_info "Creating Helm package..."
+exec_process cd "${releasey_dir}/../helm"
+exec_process helm package polaris
+exec_process helm gpg sign polaris-${polaris_version}.tgz

Review Comment:
   `helm gpg sign` implicitly uses the GPG agent, if necessary? I suspect the 
answer is "yes".



##########
releasey/02-create-release-branch.sh:
##########
@@ -0,0 +1,201 @@
+#!/bin/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.
+#
+
+#
+# Create Release Branch Script
+#
+# Automates the "Create release branch" section of the release guide.
+# Creates a new release branch and sets the target release version.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") --version VERSION [--commit GIT_COMMIT] [--recreate] [--help 
| -h]
+
+  Creates a release branch and sets the target release version.
+
+  Behavior:
+  - RC1: Creates the release branch and sets up the version
+  - RC2+: Exits successfully if release branch exists, errors if it doesn't
+
+  Options:
+    --version VERSION
+        The release version in format x.y.z-incubating-rcN where N is the RC 
number
+    --commit GIT_COMMIT
+        The Git commit SHA to create the release branch from. Defaults to 
current HEAD.
+    --recreate
+        Drop the release branch if it already exists and recreate it to the 
new SHA.
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0") --version 1.0.0-incubating-rc1 --commit HEAD
+    $(basename "$0") --version 0.1.0-incubating-rc1 --commit abc123def456
+    $(basename "$0") --version 1.0.0-incubating-rc1 --commit HEAD --recreate
+    $(basename "$0") --version 1.0.0-incubating-rc2  # Will exit successfully 
if branch exists
+
+EOF
+}
+
+version=""
+commit="HEAD"
+recreate=false
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --version)
+      if [[ $# -lt 2 ]]; then
+        print_error "Missing argument for --version"
+        usage >&2
+        exit 1
+      fi
+      version="$2"
+      shift 2
+      ;;
+    --commit)
+      if [[ $# -lt 2 ]]; then
+        print_error "Missing argument for --commit"
+        usage >&2
+        exit 1
+      fi
+      commit="$2"
+      shift 2
+      ;;
+    --recreate)
+      recreate=true
+      shift
+      ;;
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+# Ensure the version is provided
+if [[ -z ${version} ]]; then
+  print_error "Missing version"
+  usage >&2
+  exit 1
+fi
+
+# Validate that the commit exists
+if ! git rev-parse --verify "${commit}" >/dev/null 2>&1; then
+  print_error "Invalid Git commit: ${commit}"
+  usage >&2
+  exit 1
+fi
+
+# Validate version format: x.y.z-incubating-rcN
+# TODO: Remove incubating when we are a TLP
+if ! validate_and_extract_rc_version "${version}"; then
+  print_error "Invalid version format. Expected: x.y.z-incubating-rcN where 
N>0, got: ${version}"
+  usage >&2
+  exit 1
+fi
+
+# Define polaris_version from extracted components
+polaris_version="${major}.${minor}.${patch}-incubating"
+release_branch="release/${polaris_version}"
+
+# Handle RC > 1 scenarios
+if [[ ${rc_number} -gt 1 ]]; then
+  # Check if release branch already exists
+  if git show-ref --verify --quiet "refs/heads/${release_branch}"; then
+    print_info "RC${rc_number} detected and release branch ${release_branch} 
already exists."
+    print_info "This script only creates release branches for RC1. Nothing to 
do."
+    exit 0
+  else
+    print_error "RC${rc_number} detected but release branch ${release_branch} 
does not exist."
+    exit 1
+  fi
+fi
+
+print_info "Starting release branch creation..."
+print_info "Version: ${version}"
+print_info "Polaris version: ${polaris_version}"
+print_info "From commit: ${commit}"
+echo
+

Review Comment:
   I guess a `git fetch [remote]` doesn't hurt here, just to be safe.



##########
releasey/libs/_github.sh:
##########
@@ -0,0 +1,154 @@
+#!/bin/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.
+#
+
+#
+# Git Remote Setup Script
+#
+# This script ensures that the Git repository has the proper remote 
configuration for Apache Polaris releases:
+# 1. Checks whether there is a Git remote named 'apache' pointing to 
https://github.com/apache/polaris.git
+# 2. If the remote doesn't exist, it will be added
+# 3. If the remote exists but points to the wrong URL, error out
+#
+# Returns non-zero exit code if any verification fails.
+#
+
+set -euo pipefail
+
+LIBS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+# Source common logging functions and constants
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+
+function check_remote_exists() {
+  # Check if a remote exists, return 0 if it exists, 1 if not
+  local remote_name="$1"
+  git remote | grep -q "^${remote_name}$"
+}
+
+function get_remote_url() {
+  # Get the URL for a given remote, return non-zero if remote doesn't exist
+  local remote_name="$1"
+  git remote get-url "${remote_name}" 2>/dev/null || return 1
+}
+
+function ensure_no_uncommitted_change() {
+  if [[ -n $(git status --porcelain) ]]; then
+    print_error "There are uncommitted changes in the repository."
+    print_error "A release can only be performed from a clean state."
+    return 1
+  fi
+}
+
+function add_apache_remote() {
+  # Add the apache remote to the current repository, return non-zero if it 
fails
+  print_info "Adding remote '${APACHE_REMOTE_NAME}' with URL 
'${APACHE_REMOTE_URL}'..."
+  if exec_process git remote add "${APACHE_REMOTE_NAME}" 
"${APACHE_REMOTE_URL}"; then
+    print_success "Successfully added remote '${APACHE_REMOTE_NAME}'"
+    return 0
+  else
+    print_error "Failed to add remote '${APACHE_REMOTE_NAME}'"
+    return 1
+  fi
+}
+
+function check_github_token() {
+  # Check if GitHub token is available, return 0 if available, 1 if not
+  if [[ -n "${GITHUB_TOKEN:-}" ]]; then
+    return 0
+  else
+    return 1
+  fi
+}
+
+function check_github_checks_passed() {
+  # Check that all GitHub checks have passed for a specific commit SHA.
+  # More specifically, we check that all check runs have a conclusion of 
"success" or "skipped".
+  # Returns 0 if all checks are "success" or "skipped", 1 otherwise
+  local commit_sha="$1"
+
+  print_info "Checking that all Github checks have passed for commit 
${commit_sha}..."
+
+  local num_invalid_checks
+  local num_invalid_checks_retrieval_command="curl -s -H \"Authorization: 
Bearer ${GITHUB_TOKEN}\" -H \"Accept: application/vnd.github+json\" -H 
\"X-GitHub-Api-Version: 2022-11-28\" 
https://api.github.com/repos/${GITHUB_REPO_OWNER}/${GITHUB_REPO_NAME}/commits/${commit_sha}/check-runs
 | jq -r '[.check_runs[].conclusion | select(. != \"success\" and . != 
\"skipped\")] | length'"
+  if [ ${DRY_RUN} -eq 1 ]; then
+    print_info "DRY_RUN is enabled, skipping GitHub check verification"
+    print_command "${num_invalid_checks_retrieval_command}"
+    return 0
+    num_invalid_checks=0
+  else
+    num_invalid_checks=$(num_invalid_checks_retrieval_command)
+  fi
+
+  if [[ $? -ne 0 ]]; then
+    print_error "Failed to fetch GitHub check runs for commit ${commit_sha}"
+    return 1
+  fi
+
+  if [[ ${num_invalid_checks} -ne 0 ]]; then
+    print_error "Found ${num_invalid_checks} failed or in-progress GitHub 
checks for commit ${commit_sha}"
+    return 1
+  fi
+
+  print_info "All GitHub checks passed for commit ${commit_sha}"
+  return 0
+}
+
+function ensure_github_token_is_configured() {
+  # Ensure that GitHub token is configured, return non-zero if not
+  print_info "Checking GitHub token configuration..."
+
+  if check_github_token; then
+    print_success "GitHub token is configured"
+    return 0
+  else
+    print_error "GITHUB_TOKEN environment variable is not set"
+    print_error "A GitHub token is required to check CI status for releases"

Review Comment:
   It's technically not required. The "anonymous" rate limit should be 
sufficient for a few runs of the script (Commit status checks). Setting up a 
GITHUB_TOKEN may lead to unnecessarily creating PATs or the like.
   I suggest to change this to a warning.



##########
releasey/02-create-release-branch.sh:
##########
@@ -0,0 +1,201 @@
+#!/bin/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.
+#
+
+#
+# Create Release Branch Script
+#
+# Automates the "Create release branch" section of the release guide.
+# Creates a new release branch and sets the target release version.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") --version VERSION [--commit GIT_COMMIT] [--recreate] [--help 
| -h]
+
+  Creates a release branch and sets the target release version.
+
+  Behavior:
+  - RC1: Creates the release branch and sets up the version
+  - RC2+: Exits successfully if release branch exists, errors if it doesn't
+
+  Options:
+    --version VERSION
+        The release version in format x.y.z-incubating-rcN where N is the RC 
number
+    --commit GIT_COMMIT
+        The Git commit SHA to create the release branch from. Defaults to 
current HEAD.
+    --recreate
+        Drop the release branch if it already exists and recreate it to the 
new SHA.
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0") --version 1.0.0-incubating-rc1 --commit HEAD
+    $(basename "$0") --version 0.1.0-incubating-rc1 --commit abc123def456
+    $(basename "$0") --version 1.0.0-incubating-rc1 --commit HEAD --recreate
+    $(basename "$0") --version 1.0.0-incubating-rc2  # Will exit successfully 
if branch exists
+
+EOF
+}
+
+version=""
+commit="HEAD"
+recreate=false
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --version)
+      if [[ $# -lt 2 ]]; then
+        print_error "Missing argument for --version"
+        usage >&2
+        exit 1
+      fi
+      version="$2"
+      shift 2
+      ;;
+    --commit)
+      if [[ $# -lt 2 ]]; then
+        print_error "Missing argument for --commit"
+        usage >&2
+        exit 1
+      fi
+      commit="$2"
+      shift 2
+      ;;
+    --recreate)
+      recreate=true
+      shift
+      ;;
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+# Ensure the version is provided
+if [[ -z ${version} ]]; then
+  print_error "Missing version"
+  usage >&2
+  exit 1
+fi
+
+# Validate that the commit exists
+if ! git rev-parse --verify "${commit}" >/dev/null 2>&1; then
+  print_error "Invalid Git commit: ${commit}"
+  usage >&2
+  exit 1
+fi
+
+# Validate version format: x.y.z-incubating-rcN
+# TODO: Remove incubating when we are a TLP
+if ! validate_and_extract_rc_version "${version}"; then
+  print_error "Invalid version format. Expected: x.y.z-incubating-rcN where 
N>0, got: ${version}"
+  usage >&2
+  exit 1
+fi
+
+# Define polaris_version from extracted components
+polaris_version="${major}.${minor}.${patch}-incubating"
+release_branch="release/${polaris_version}"
+
+# Handle RC > 1 scenarios
+if [[ ${rc_number} -gt 1 ]]; then
+  # Check if release branch already exists
+  if git show-ref --verify --quiet "refs/heads/${release_branch}"; then
+    print_info "RC${rc_number} detected and release branch ${release_branch} 
already exists."
+    print_info "This script only creates release branches for RC1. Nothing to 
do."
+    exit 0
+  else
+    print_error "RC${rc_number} detected but release branch ${release_branch} 
does not exist."
+    exit 1
+  fi
+fi
+
+print_info "Starting release branch creation..."
+print_info "Version: ${version}"
+print_info "Polaris version: ${polaris_version}"
+print_info "From commit: ${commit}"
+echo
+
+# Check if release branch already exists
+if git show-ref --verify --quiet "refs/heads/${release_branch}"; then
+  if [[ "${recreate}" == "true" ]]; then
+    print_info "Release branch ${release_branch} already exists, deleting 
it..."
+    exec_process git branch -D "${release_branch}"
+    if git show-ref --verify --quiet 
"refs/remotes/${APACHE_REMOTE_NAME}/${release_branch}"; then
+      print_info "Deleting remote release branch from ${APACHE_REMOTE_NAME}..."
+      exec_process git push "${APACHE_REMOTE_NAME}" --delete 
"${release_branch}"
+    fi
+  else
+    print_error "Release branch ${release_branch} already exists. Use 
--recreate to delete and recreate it."
+    exit 1
+  fi
+fi
+
+print_info "Checking out commit: ${commit}"
+exec_process git checkout "${commit}"
+
+print_info "Creating release branch: ${release_branch}"
+exec_process git branch "${release_branch}"
+
+print_info "Pushing release branch to ${APACHE_REMOTE_NAME}"
+exec_process git push "${APACHE_REMOTE_NAME}" "${release_branch}" 
--set-upstream
+
+print_info "Checking out release branch"
+exec_process git checkout "${release_branch}"
+
+print_info "Setting version to ${polaris_version} in version.txt"
+update_version "${polaris_version}"
+
+print_info "Committing and pushing version change"
+exec_process git add "$VERSION_FILE" "$HELM_CHART_YAML_FILE" 
"$HELM_README_FILE" "$HELM_VALUES_FILE"
+exec_process git commit -m "[chore] Bump version to ${polaris_version} for 
release"
+exec_process git push
+
+print_info "Updating CHANGELOG.md"
+exec_process cd "${releasey_dir}/.."
+exec_process ./gradlew patchChangelog

Review Comment:
   TL;DR `CHANGELOG.md` has to be (re)generated for every version/RC/branch 
independently.
   
   Content of `CHANGELOG.md` is maintained manually w/ the PRs being merged, 
it's the contributor's/reviewer's who update `CHANGELOG.md`. So changes to that 
file already exist and nothing has to be "merged back", and in fact cannot as 
the contents on "all the branches" can be different.



##########
releasey/04-build-and-test.sh:
##########
@@ -0,0 +1,90 @@
+#!/bin/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.
+#
+
+#
+# Build and Test Script
+#
+# Builds Polaris completely and ensures that all integration and regression 
tests
+# have been run prior to releasing by verifying the status of all GitHub 
Actions
+# workflows for the current commit.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+source "${LIBS_DIR}/_github.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") [--help | -h]
+
+  Builds Polaris completely and ensures that all integration and regression 
tests
+  have been run prior to releasing by verifying GitHub CI status.
+
+  Options:
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0")
+
+EOF
+}
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+print_info "Starting build and test process..."
+echo
+
+# Clean and build Polaris
+print_info "Building Polaris..."
+exec_process cd "${releasey_dir}/.."
+exec_process ./gradlew clean build

Review Comment:
   Technically, you rather want 
   ```suggestion
   exec_process ./gradlew assemble -Prelease
   ```
   here, likely also with ` -PuseGpgAgent`



##########
releasey/05-build-and-stage-distributions.sh:
##########
@@ -0,0 +1,155 @@
+#!/bin/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.
+#
+
+#
+# Build and Stage Distributions Script
+#
+# Builds source and binary distributions and stages them to the Apache dist 
dev repository.
+# This script automates the "Build and stage the distributions" step from the 
release guide.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+source "${LIBS_DIR}/_gpg.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") [--help | -h]
+
+  Builds source and binary distributions and stages them to the Apache dist 
dev repository.
+  The version is automatically determined from the current git tag.  I.e. this 
script must
+  be run from a release candidate tag.
+
+  Options:
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0")
+
+EOF
+}
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+# Determine version from current git tag
+print_info "Determining version from current git tag..."
+
+if ! git_tag=$(git describe --tags --exact-match HEAD 2>/dev/null); then
+  print_error "Current HEAD is not on a release candidate tag. Please checkout 
a release candidate tag first."
+  print_error "Use: git checkout apache-polaris-x.y.z-incubating-rcN"
+  exit 1
+fi
+print_info "Found git tag: ${git_tag}"
+
+# Validate git tag format and extract version components
+if ! validate_and_extract_git_tag_version "${git_tag}"; then
+  print_error "Invalid git tag format: ${git_tag}"
+  print_error "Expected format: apache-polaris-x.y.z-incubating-rcN"
+  exit 1
+fi
+
+polaris_version="${major}.${minor}.${patch}-incubating"
+
+print_info "Starting build and stage distributions process..."
+print_info "Version: ${polaris_version}"
+print_info "RC number: ${rc_number}"
+echo
+
+# Build distributions
+print_info "Building source and binary distributions..."
+exec_process cd "${releasey_dir}/.."
+exec_process ./gradlew build sourceTarball -Prelease -PuseGpgAgent -x test -x 
intTest

Review Comment:
   Also note that `test` and `intTest` are not conventions, there are more test 
tasks, so using `build` is rather discouraged.



##########
releasey/libs/_gpg.sh:
##########
@@ -0,0 +1,188 @@
+#!/bin/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.
+#
+
+#
+# GPG Setup Verification Script
+#
+# This script verifies that GPG is properly configured for Apache Polaris 
releases:
+# 1. Checks that GPG is installed and available in PATH
+# 1. Checks that the signing key configured in ~/.gradle/gradle.properties 
exists in the local GPG keyring
+# 2. Verifies that the key has been published to hkps://keyserver.ubuntu.com
+# 3. Confirms that the key is part of the KEYS file
+#
+# Returns non-zero exit code if any verification fails.
+#
+
+set -euo pipefail
+
+LIBS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+# Source common logging functions and constants
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+
+function get_secret_keys() {
+  # Get list of secret keys (private keys) that can be used for signing
+  gpg --list-secret-keys --with-colons 2>/dev/null | grep '^sec:' | cut -d: -f5
+}
+
+function get_gradle_signing_key_id() {
+  # Get the signing key ID from gradle.properties
+  grep '^signing.gnupg.keyName' "${GRADLE_PROPERTIES_FILE}" 2>/dev/null | cut 
-d'=' -f2
+}

Review Comment:
   This won't be an issue in GH workflows, where the workflows do the right 
thing anyways.



##########
releasey/libs/_version.sh:
##########
@@ -0,0 +1,97 @@
+#!/bin/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.
+#
+
+#
+# Utility functions for version validation and version.txt manipulation
+#
+
+LIBS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+source "$LIBS_DIR/_constants.sh"
+source "$LIBS_DIR/_log.sh"
+
+function validate_and_extract_rc_version {
+  # This function validates the format of a release candidate version and 
extracts its components (major.minor.patch and rc number).
+  # It returns 0 if the version is valid and sets the global variables major, 
minor, patch, and rc_number.
+  # Otherwise, it returns 1.
+  local version="$1"
+
+  if [[ ! ${version} =~ ${VERSION_REGEX_RC} ]]; then
+    return 1
+  fi
+
+  major="${BASH_REMATCH[1]}"

Review Comment:
   Wonder whether the global variables should be explicitly declared in a 
"lib", commenting where/how those are populated. WDYT?



##########
releasey/03-create-release-candidate-tag.sh:
##########
@@ -0,0 +1,142 @@
+#!/bin/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.
+#
+
+#
+# Create Release Candidate Tag Script
+#
+# Automates the "Create release candidate tag" section of the release guide.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") --version VERSION [--help | -h]
+
+  Creates a release candidate tag for a release candidate.
+
+  Options:
+    --version VERSION
+        The release version in format x.y.z-incubating-rcN where N is the RC 
number
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0") --version 1.0.0-incubating-rc1
+    $(basename "$0") --version 0.1.0-incubating-rc2
+
+EOF
+}
+
+version=""
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --version)
+      if [[ $# -lt 2 ]]; then
+        print_error "Missing argument for --version"
+        usage >&2
+        exit 1
+      fi
+      version="$2"
+      shift 2
+      ;;
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+# Ensure the version is provided
+if [[ -z ${version} ]]; then
+  print_error "Missing version"
+  usage >&2
+  exit 1
+fi
+
+# Validate version format: x.y.z-incubating-rcN
+# TODO: Remove incubating when we are a TLP
+if ! validate_and_extract_rc_version "${version}"; then
+  print_error "Invalid version format. Expected: x.y.z-incubating-rcN where 
N>0, got: ${version}"
+  usage >&2
+  exit 1
+fi
+
+# Define polaris_version from extracted components
+polaris_version="${major}.${minor}.${patch}-incubating"
+
+print_info "Starting release candidate tag creation..."
+print_info "Version: ${version}"
+print_info "Polaris version: ${polaris_version}"
+print_info "RC number: ${rc_number}"
+echo
+
+# If we're creating RC2 or later, verify previous RC tag exists
+if [[ ${rc_number} -gt 1 ]]; then
+  previous_rc=$((rc_number - 1))

Review Comment:
   Nit: `local`



##########
releasey/04-build-and-test.sh:
##########
@@ -0,0 +1,90 @@
+#!/bin/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.
+#
+
+#
+# Build and Test Script
+#
+# Builds Polaris completely and ensures that all integration and regression 
tests
+# have been run prior to releasing by verifying the status of all GitHub 
Actions
+# workflows for the current commit.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+source "${LIBS_DIR}/_github.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") [--help | -h]
+
+  Builds Polaris completely and ensures that all integration and regression 
tests
+  have been run prior to releasing by verifying GitHub CI status.
+
+  Options:
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0")
+
+EOF
+}
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+print_info "Starting build and test process..."
+echo
+
+# Clean and build Polaris
+print_info "Building Polaris..."
+exec_process cd "${releasey_dir}/.."
+exec_process ./gradlew clean build

Review Comment:
   Might check for a clean working copy a `[[ -z "$(git status --porcelain)" 
]]` for extra safety.
   



##########
releasey/02-create-release-branch.sh:
##########
@@ -0,0 +1,201 @@
+#!/bin/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.
+#
+
+#
+# Create Release Branch Script
+#
+# Automates the "Create release branch" section of the release guide.
+# Creates a new release branch and sets the target release version.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") --version VERSION [--commit GIT_COMMIT] [--recreate] [--help 
| -h]
+
+  Creates a release branch and sets the target release version.
+
+  Behavior:
+  - RC1: Creates the release branch and sets up the version
+  - RC2+: Exits successfully if release branch exists, errors if it doesn't
+
+  Options:
+    --version VERSION
+        The release version in format x.y.z-incubating-rcN where N is the RC 
number
+    --commit GIT_COMMIT
+        The Git commit SHA to create the release branch from. Defaults to 
current HEAD.
+    --recreate
+        Drop the release branch if it already exists and recreate it to the 
new SHA.
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0") --version 1.0.0-incubating-rc1 --commit HEAD
+    $(basename "$0") --version 0.1.0-incubating-rc1 --commit abc123def456
+    $(basename "$0") --version 1.0.0-incubating-rc1 --commit HEAD --recreate
+    $(basename "$0") --version 1.0.0-incubating-rc2  # Will exit successfully 
if branch exists
+
+EOF
+}
+
+version=""
+commit="HEAD"
+recreate=false
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --version)
+      if [[ $# -lt 2 ]]; then
+        print_error "Missing argument for --version"
+        usage >&2
+        exit 1
+      fi
+      version="$2"
+      shift 2
+      ;;
+    --commit)
+      if [[ $# -lt 2 ]]; then
+        print_error "Missing argument for --commit"
+        usage >&2
+        exit 1
+      fi
+      commit="$2"
+      shift 2
+      ;;
+    --recreate)
+      recreate=true
+      shift
+      ;;
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+# Ensure the version is provided
+if [[ -z ${version} ]]; then
+  print_error "Missing version"
+  usage >&2
+  exit 1
+fi
+
+# Validate that the commit exists
+if ! git rev-parse --verify "${commit}" >/dev/null 2>&1; then
+  print_error "Invalid Git commit: ${commit}"
+  usage >&2
+  exit 1
+fi
+
+# Validate version format: x.y.z-incubating-rcN
+# TODO: Remove incubating when we are a TLP
+if ! validate_and_extract_rc_version "${version}"; then
+  print_error "Invalid version format. Expected: x.y.z-incubating-rcN where 
N>0, got: ${version}"
+  usage >&2
+  exit 1
+fi
+
+# Define polaris_version from extracted components
+polaris_version="${major}.${minor}.${patch}-incubating"
+release_branch="release/${polaris_version}"
+
+# Handle RC > 1 scenarios
+if [[ ${rc_number} -gt 1 ]]; then
+  # Check if release branch already exists
+  if git show-ref --verify --quiet "refs/heads/${release_branch}"; then
+    print_info "RC${rc_number} detected and release branch ${release_branch} 
already exists."
+    print_info "This script only creates release branches for RC1. Nothing to 
do."
+    exit 0
+  else
+    print_error "RC${rc_number} detected but release branch ${release_branch} 
does not exist."
+    exit 1
+  fi
+fi
+
+print_info "Starting release branch creation..."
+print_info "Version: ${version}"
+print_info "Polaris version: ${polaris_version}"
+print_info "From commit: ${commit}"
+echo
+
+# Check if release branch already exists
+if git show-ref --verify --quiet "refs/heads/${release_branch}"; then
+  if [[ "${recreate}" == "true" ]]; then
+    print_info "Release branch ${release_branch} already exists, deleting 
it..."
+    exec_process git branch -D "${release_branch}"
+    if git show-ref --verify --quiet 
"refs/remotes/${APACHE_REMOTE_NAME}/${release_branch}"; then
+      print_info "Deleting remote release branch from ${APACHE_REMOTE_NAME}..."
+      exec_process git push "${APACHE_REMOTE_NAME}" --delete 
"${release_branch}"
+    fi
+  else
+    print_error "Release branch ${release_branch} already exists. Use 
--recreate to delete and recreate it."
+    exit 1
+  fi
+fi
+
+print_info "Checking out commit: ${commit}"
+exec_process git checkout "${commit}"
+
+print_info "Creating release branch: ${release_branch}"
+exec_process git branch "${release_branch}"
+
+print_info "Pushing release branch to ${APACHE_REMOTE_NAME}"
+exec_process git push "${APACHE_REMOTE_NAME}" "${release_branch}" 
--set-upstream
+
+print_info "Checking out release branch"
+exec_process git checkout "${release_branch}"
+
+print_info "Setting version to ${polaris_version} in version.txt"
+update_version "${polaris_version}"
+
+print_info "Committing and pushing version change"
+exec_process git add "$VERSION_FILE" "$HELM_CHART_YAML_FILE" 
"$HELM_README_FILE" "$HELM_VALUES_FILE"
+exec_process git commit -m "[chore] Bump version to ${polaris_version} for 
release"
+exec_process git push
+
+print_info "Updating CHANGELOG.md"
+exec_process cd "${releasey_dir}/.."
+exec_process ./gradlew patchChangelog
+
+print_info "Committing changelog change"
+exec_process git add "$CHANGELOG_FILE"
+exec_process git commit -m "[chore] Update changelog for release"
+exec_process git push
+
+echo
+print_success "🎉 Release branch ${release_branch} created successfully!"
+echo
+print_info "Next steps:"
+print_info "* Submit a PR on main branch to propagate CHANGELOG updates from 
the release branch to main 
(https://github.com/${APACHE_REMOTE_NAME}/polaris/pull/new/${release_branch})."

Review Comment:
   Let's remove this, see my comment above.



##########
releasey/05-build-and-stage-distributions.sh:
##########
@@ -0,0 +1,155 @@
+#!/bin/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.
+#
+
+#
+# Build and Stage Distributions Script
+#
+# Builds source and binary distributions and stages them to the Apache dist 
dev repository.
+# This script automates the "Build and stage the distributions" step from the 
release guide.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+source "${LIBS_DIR}/_gpg.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") [--help | -h]
+
+  Builds source and binary distributions and stages them to the Apache dist 
dev repository.
+  The version is automatically determined from the current git tag.  I.e. this 
script must
+  be run from a release candidate tag.
+
+  Options:
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0")
+
+EOF
+}
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+# Determine version from current git tag
+print_info "Determining version from current git tag..."
+
+if ! git_tag=$(git describe --tags --exact-match HEAD 2>/dev/null); then
+  print_error "Current HEAD is not on a release candidate tag. Please checkout 
a release candidate tag first."
+  print_error "Use: git checkout apache-polaris-x.y.z-incubating-rcN"
+  exit 1
+fi
+print_info "Found git tag: ${git_tag}"
+
+# Validate git tag format and extract version components
+if ! validate_and_extract_git_tag_version "${git_tag}"; then
+  print_error "Invalid git tag format: ${git_tag}"
+  print_error "Expected format: apache-polaris-x.y.z-incubating-rcN"
+  exit 1
+fi
+
+polaris_version="${major}.${minor}.${patch}-incubating"
+
+print_info "Starting build and stage distributions process..."
+print_info "Version: ${polaris_version}"
+print_info "RC number: ${rc_number}"
+echo
+
+# Build distributions
+print_info "Building source and binary distributions..."
+exec_process cd "${releasey_dir}/.."
+exec_process ./gradlew build sourceTarball -Prelease -PuseGpgAgent -x test -x 
intTest

Review Comment:
   ```suggestion
   exec_process ./gradlew sourceTarball -Prelease -PuseGpgAgent
   ```
   No need to repeat what's been done in `04-...sh`



##########
releasey/04-build-and-test.sh:
##########
@@ -0,0 +1,90 @@
+#!/bin/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.
+#
+
+#
+# Build and Test Script
+#
+# Builds Polaris completely and ensures that all integration and regression 
tests
+# have been run prior to releasing by verifying the status of all GitHub 
Actions
+# workflows for the current commit.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+source "${LIBS_DIR}/_github.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") [--help | -h]
+
+  Builds Polaris completely and ensures that all integration and regression 
tests
+  have been run prior to releasing by verifying GitHub CI status.
+
+  Options:
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0")
+
+EOF
+}
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+print_info "Starting build and test process..."
+echo
+
+# Clean and build Polaris
+print_info "Building Polaris..."
+exec_process cd "${releasey_dir}/.."
+exec_process ./gradlew clean build

Review Comment:
   You actually only need
   ```suggestion
   exec_process ./gradlew assemble
   ```
   
   No need to run tests (with `build``) as the Git commit status is verified 
elsewhere.



##########
releasey/04-build-and-test.sh:
##########
@@ -0,0 +1,90 @@
+#!/bin/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.
+#
+
+#
+# Build and Test Script
+#
+# Builds Polaris completely and ensures that all integration and regression 
tests
+# have been run prior to releasing by verifying the status of all GitHub 
Actions
+# workflows for the current commit.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+source "${LIBS_DIR}/_github.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") [--help | -h]
+
+  Builds Polaris completely and ensures that all integration and regression 
tests
+  have been run prior to releasing by verifying GitHub CI status.
+
+  Options:
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0")
+
+EOF
+}
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+print_info "Starting build and test process..."
+echo
+
+# Clean and build Polaris
+print_info "Building Polaris..."
+exec_process cd "${releasey_dir}/.."
+exec_process ./gradlew clean build
+
+current_commit=$(git rev-parse HEAD)
+print_info "Current commit: ${current_commit}"
+
+if ! check_github_checks_passed "${current_commit}"; then
+  print_error "Integration and regression tests have not all passed for commit 
${current_commit}"
+  print_error "Please ensure all CI workflows are successful before proceeding 
with the release"
+  print_info "You can check the status at: 
https://github.com/${GITHUB_REPO_OWNER}/${GITHUB_REPO_NAME}/commit/${current_commit}";
+  exit 1
+fi
+
+echo
+print_success "🎉 Build and test verification completed successfully!"

Review Comment:
   No next steps here? ;)



##########
releasey/01-prerequisites.sh:
##########
@@ -0,0 +1,135 @@
+#!/bin/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.
+#
+
+#
+# Release Prerequisites Verification Script
+#
+# This script ensures everything is ready for release:
+# 1. GPG setup verification
+# 2. Maven/Gradle credentials verification
+# 3. Git remote setup verification
+# 4. Docker setup verification (for Docker image releases)
+#
+# Returns non-zero exit code if any setup verification fails.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

Review Comment:
   ```suggestion
   releasy_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
   ```
   ;) 



##########
releasey/05-build-and-stage-distributions.sh:
##########
@@ -0,0 +1,155 @@
+#!/bin/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.
+#
+
+#
+# Build and Stage Distributions Script
+#
+# Builds source and binary distributions and stages them to the Apache dist 
dev repository.
+# This script automates the "Build and stage the distributions" step from the 
release guide.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+source "${LIBS_DIR}/_gpg.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") [--help | -h]
+
+  Builds source and binary distributions and stages them to the Apache dist 
dev repository.
+  The version is automatically determined from the current git tag.  I.e. this 
script must
+  be run from a release candidate tag.
+
+  Options:
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0")
+
+EOF
+}
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+# Determine version from current git tag
+print_info "Determining version from current git tag..."
+
+if ! git_tag=$(git describe --tags --exact-match HEAD 2>/dev/null); then
+  print_error "Current HEAD is not on a release candidate tag. Please checkout 
a release candidate tag first."
+  print_error "Use: git checkout apache-polaris-x.y.z-incubating-rcN"
+  exit 1
+fi
+print_info "Found git tag: ${git_tag}"
+
+# Validate git tag format and extract version components
+if ! validate_and_extract_git_tag_version "${git_tag}"; then
+  print_error "Invalid git tag format: ${git_tag}"
+  print_error "Expected format: apache-polaris-x.y.z-incubating-rcN"
+  exit 1
+fi
+
+polaris_version="${major}.${minor}.${patch}-incubating"
+
+print_info "Starting build and stage distributions process..."
+print_info "Version: ${polaris_version}"
+print_info "RC number: ${rc_number}"
+echo
+
+# Build distributions
+print_info "Building source and binary distributions..."
+exec_process cd "${releasey_dir}/.."
+exec_process ./gradlew build sourceTarball -Prelease -PuseGpgAgent -x test -x 
intTest
+
+# Create Helm package
+print_info "Creating Helm package..."
+exec_process cd "${releasey_dir}/../helm"
+exec_process helm package polaris
+exec_process helm gpg sign polaris-${polaris_version}.tgz
+calculate_sha512 polaris-${polaris_version}.tgz 
polaris-${polaris_version}.tgz.sha512
+exec_process gpg --armor --output polaris-${polaris_version}.tgz.asc 
--detach-sig polaris-${polaris_version}.tgz
+calculate_sha512 polaris-${polaris_version}.tgz.prov 
polaris-${polaris_version}.tgz.prov.sha512
+exec_process gpg --armor --output polaris-${polaris_version}.tgz.prov.asc 
--detach-sig polaris-${polaris_version}.tgz.prov
+
+# Stage to Apache dist dev repository
+print_info "Staging artifacts to Apache dist dev repository..."
+
+dist_dev_dir=${releasey_dir}/polaris-dist-dev
+print_info "Checking out ${APACHE_DIST_URL}${APACHE_DIST_PATH} to 
${dist_dev_dir}..."
+exec_process svn co "${APACHE_DIST_URL}${APACHE_DIST_PATH}" "${dist_dev_dir}"
+
+print_info "Copying files to destination directory..."
+version_dir="${dist_dev_dir}/${polaris_version}"
+helm_chart_version_dir="${dist_dev_dir}/helm-chart/${polaris_version}"

Review Comment:
   Extra safety:
   Remove existing files in `version_dir` and `helm_chart_version_dir`, in case 
something temporary was left there before.



##########
releasey/05-build-and-stage-distributions.sh:
##########
@@ -0,0 +1,155 @@
+#!/bin/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.
+#
+
+#
+# Build and Stage Distributions Script
+#
+# Builds source and binary distributions and stages them to the Apache dist 
dev repository.
+# This script automates the "Build and stage the distributions" step from the 
release guide.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+source "${LIBS_DIR}/_gpg.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") [--help | -h]
+
+  Builds source and binary distributions and stages them to the Apache dist 
dev repository.
+  The version is automatically determined from the current git tag.  I.e. this 
script must
+  be run from a release candidate tag.
+
+  Options:
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0")
+
+EOF
+}
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+# Determine version from current git tag
+print_info "Determining version from current git tag..."
+
+if ! git_tag=$(git describe --tags --exact-match HEAD 2>/dev/null); then
+  print_error "Current HEAD is not on a release candidate tag. Please checkout 
a release candidate tag first."
+  print_error "Use: git checkout apache-polaris-x.y.z-incubating-rcN"
+  exit 1
+fi
+print_info "Found git tag: ${git_tag}"
+
+# Validate git tag format and extract version components
+if ! validate_and_extract_git_tag_version "${git_tag}"; then
+  print_error "Invalid git tag format: ${git_tag}"
+  print_error "Expected format: apache-polaris-x.y.z-incubating-rcN"
+  exit 1
+fi
+
+polaris_version="${major}.${minor}.${patch}-incubating"
+
+print_info "Starting build and stage distributions process..."
+print_info "Version: ${polaris_version}"
+print_info "RC number: ${rc_number}"
+echo
+
+# Build distributions
+print_info "Building source and binary distributions..."
+exec_process cd "${releasey_dir}/.."
+exec_process ./gradlew build sourceTarball -Prelease -PuseGpgAgent -x test -x 
intTest
+
+# Create Helm package
+print_info "Creating Helm package..."
+exec_process cd "${releasey_dir}/../helm"
+exec_process helm package polaris
+exec_process helm gpg sign polaris-${polaris_version}.tgz
+calculate_sha512 polaris-${polaris_version}.tgz 
polaris-${polaris_version}.tgz.sha512
+exec_process gpg --armor --output polaris-${polaris_version}.tgz.asc 
--detach-sig polaris-${polaris_version}.tgz
+calculate_sha512 polaris-${polaris_version}.tgz.prov 
polaris-${polaris_version}.tgz.prov.sha512
+exec_process gpg --armor --output polaris-${polaris_version}.tgz.prov.asc 
--detach-sig polaris-${polaris_version}.tgz.prov
+
+# Stage to Apache dist dev repository
+print_info "Staging artifacts to Apache dist dev repository..."
+
+dist_dev_dir=${releasey_dir}/polaris-dist-dev
+print_info "Checking out ${APACHE_DIST_URL}${APACHE_DIST_PATH} to 
${dist_dev_dir}..."
+exec_process svn co "${APACHE_DIST_URL}${APACHE_DIST_PATH}" "${dist_dev_dir}"
+
+print_info "Copying files to destination directory..."
+version_dir="${dist_dev_dir}/${polaris_version}"
+helm_chart_version_dir="${dist_dev_dir}/helm-chart/${polaris_version}"
+exec_process mkdir -p "${version_dir}"
+exec_process mkdir -p "${helm_chart_version_dir}"
+exec_process cp "build/distribution/*" "${version_dir}/"
+exec_process cp "runtime/distribution/build/distributions/*" "${version_dir}/"
+
+print_info "Copying Helm package files..."
+exec_process cp helm/polaris-${polaris_version}.tgz* 
"${helm_chart_version_dir}/"
+
+print_info "Adding files to SVN..."
+exec_process svn add "${version_dir}"
+exec_process svn add "${helm_chart_version_dir}"
+
+print_info "Committing changes..."
+exec_process svn commit -m "Stage Apache Polaris ${polaris_version} 
RC${rc_number}"
+
+print_info "Updating Helm index..."
+exec_process cd "${dist_dev_dir}/helm-chart"
+exec_process helm repo index .
+exec_process cd "${releasey_dir}/.."
+
+# Publish Maven artifacts
+print_info "Publishing Maven artifacts to Apache staging repository..."
+exec_process ./gradlew publishToApache -Prelease -PuseGpgAgent 
-Dorg.gradle.parallel=false

Review Comment:
   The Nexus staging repository URL + ID will be required.
   
   You can get those from the Gradle output (`tee` to a log file) and grep for 
`Created staging repository`.
   `s/^Created staging repository .([a-z0-9-]+). at (.*)/\1/` gives you the 
staging repo ID, `\2` the URL.
   
   I'd also suggest to write both values to files in the Git tree and commit & 
push those to be included in the Git tag, so that data isn't lost. Maybe into 
`releasy/current-release/nexus-repo-id` and 
`releasy/current-release/nexus-repo-url`?



##########
releasey/libs/_github.sh:
##########
@@ -0,0 +1,154 @@
+#!/bin/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.
+#
+
+#
+# Git Remote Setup Script
+#
+# This script ensures that the Git repository has the proper remote 
configuration for Apache Polaris releases:
+# 1. Checks whether there is a Git remote named 'apache' pointing to 
https://github.com/apache/polaris.git
+# 2. If the remote doesn't exist, it will be added
+# 3. If the remote exists but points to the wrong URL, error out
+#
+# Returns non-zero exit code if any verification fails.
+#
+
+set -euo pipefail
+
+LIBS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+# Source common logging functions and constants
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+
+function check_remote_exists() {
+  # Check if a remote exists, return 0 if it exists, 1 if not
+  local remote_name="$1"
+  git remote | grep -q "^${remote_name}$"
+}
+
+function get_remote_url() {
+  # Get the URL for a given remote, return non-zero if remote doesn't exist
+  local remote_name="$1"
+  git remote get-url "${remote_name}" 2>/dev/null || return 1
+}
+
+function ensure_no_uncommitted_change() {
+  if [[ -n $(git status --porcelain) ]]; then
+    print_error "There are uncommitted changes in the repository."
+    print_error "A release can only be performed from a clean state."
+    return 1
+  fi
+}
+
+function add_apache_remote() {

Review Comment:
   Not a fan of this.
   Having multiple remotes, especially those that point to the exact same repo, 
break developer experience in IDEs. Things appear twice for example.



##########
releasey/05-build-and-stage-distributions.sh:
##########
@@ -0,0 +1,155 @@
+#!/bin/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.
+#
+
+#
+# Build and Stage Distributions Script
+#
+# Builds source and binary distributions and stages them to the Apache dist 
dev repository.
+# This script automates the "Build and stage the distributions" step from the 
release guide.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+source "${LIBS_DIR}/_gpg.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") [--help | -h]
+
+  Builds source and binary distributions and stages them to the Apache dist 
dev repository.
+  The version is automatically determined from the current git tag.  I.e. this 
script must
+  be run from a release candidate tag.
+
+  Options:
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0")
+
+EOF
+}
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+# Determine version from current git tag
+print_info "Determining version from current git tag..."
+
+if ! git_tag=$(git describe --tags --exact-match HEAD 2>/dev/null); then
+  print_error "Current HEAD is not on a release candidate tag. Please checkout 
a release candidate tag first."
+  print_error "Use: git checkout apache-polaris-x.y.z-incubating-rcN"
+  exit 1
+fi
+print_info "Found git tag: ${git_tag}"
+
+# Validate git tag format and extract version components
+if ! validate_and_extract_git_tag_version "${git_tag}"; then
+  print_error "Invalid git tag format: ${git_tag}"
+  print_error "Expected format: apache-polaris-x.y.z-incubating-rcN"
+  exit 1
+fi
+
+polaris_version="${major}.${minor}.${patch}-incubating"
+
+print_info "Starting build and stage distributions process..."
+print_info "Version: ${polaris_version}"
+print_info "RC number: ${rc_number}"
+echo
+
+# Build distributions
+print_info "Building source and binary distributions..."
+exec_process cd "${releasey_dir}/.."
+exec_process ./gradlew build sourceTarball -Prelease -PuseGpgAgent -x test -x 
intTest
+
+# Create Helm package
+print_info "Creating Helm package..."
+exec_process cd "${releasey_dir}/../helm"
+exec_process helm package polaris
+exec_process helm gpg sign polaris-${polaris_version}.tgz
+calculate_sha512 polaris-${polaris_version}.tgz 
polaris-${polaris_version}.tgz.sha512
+exec_process gpg --armor --output polaris-${polaris_version}.tgz.asc 
--detach-sig polaris-${polaris_version}.tgz
+calculate_sha512 polaris-${polaris_version}.tgz.prov 
polaris-${polaris_version}.tgz.prov.sha512
+exec_process gpg --armor --output polaris-${polaris_version}.tgz.prov.asc 
--detach-sig polaris-${polaris_version}.tgz.prov
+
+# Stage to Apache dist dev repository
+print_info "Staging artifacts to Apache dist dev repository..."
+
+dist_dev_dir=${releasey_dir}/polaris-dist-dev
+print_info "Checking out ${APACHE_DIST_URL}${APACHE_DIST_PATH} to 
${dist_dev_dir}..."
+exec_process svn co "${APACHE_DIST_URL}${APACHE_DIST_PATH}" "${dist_dev_dir}"
+
+print_info "Copying files to destination directory..."
+version_dir="${dist_dev_dir}/${polaris_version}"
+helm_chart_version_dir="${dist_dev_dir}/helm-chart/${polaris_version}"

Review Comment:
   Actually we should move the helm-chart into `version_dir`, so we can clearly 
distinguish two parallel release processes (say: 4.2 and 5.0). And it would be 
"safe" to if there's something else than helm-charts that deserves it's own 
subdirectory.



##########
releasey/libs/_constants.sh:
##########
@@ -0,0 +1,43 @@
+#!/bin/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.
+#
+
+libs_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+# GPG constants
+KEYS_URL=${KEYS_URL:-"https://downloads.apache.org/incubator/polaris/KEYS"}
+KEYSERVER=${KEYSERVER:-"hkps://keyserver.ubuntu.com"}
+
+# Git/SVN repository constants
+APACHE_REMOTE_NAME=${APACHE_REMOTE_NAME:-"apache"}

Review Comment:
   I think sticking to Git defaults is better, the name `apache` is a 
custom/personal setting.



##########
releasey/05-build-and-stage-distributions.sh:
##########
@@ -0,0 +1,155 @@
+#!/bin/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.
+#
+
+#
+# Build and Stage Distributions Script
+#
+# Builds source and binary distributions and stages them to the Apache dist 
dev repository.
+# This script automates the "Build and stage the distributions" step from the 
release guide.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+source "${LIBS_DIR}/_gpg.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") [--help | -h]
+
+  Builds source and binary distributions and stages them to the Apache dist 
dev repository.
+  The version is automatically determined from the current git tag.  I.e. this 
script must
+  be run from a release candidate tag.
+
+  Options:
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0")
+
+EOF
+}
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+# Determine version from current git tag
+print_info "Determining version from current git tag..."
+
+if ! git_tag=$(git describe --tags --exact-match HEAD 2>/dev/null); then
+  print_error "Current HEAD is not on a release candidate tag. Please checkout 
a release candidate tag first."
+  print_error "Use: git checkout apache-polaris-x.y.z-incubating-rcN"
+  exit 1
+fi
+print_info "Found git tag: ${git_tag}"
+
+# Validate git tag format and extract version components
+if ! validate_and_extract_git_tag_version "${git_tag}"; then
+  print_error "Invalid git tag format: ${git_tag}"
+  print_error "Expected format: apache-polaris-x.y.z-incubating-rcN"
+  exit 1
+fi
+
+polaris_version="${major}.${minor}.${patch}-incubating"
+
+print_info "Starting build and stage distributions process..."
+print_info "Version: ${polaris_version}"
+print_info "RC number: ${rc_number}"
+echo
+
+# Build distributions
+print_info "Building source and binary distributions..."
+exec_process cd "${releasey_dir}/.."
+exec_process ./gradlew build sourceTarball -Prelease -PuseGpgAgent -x test -x 
intTest
+
+# Create Helm package
+print_info "Creating Helm package..."
+exec_process cd "${releasey_dir}/../helm"
+exec_process helm package polaris
+exec_process helm gpg sign polaris-${polaris_version}.tgz
+calculate_sha512 polaris-${polaris_version}.tgz 
polaris-${polaris_version}.tgz.sha512
+exec_process gpg --armor --output polaris-${polaris_version}.tgz.asc 
--detach-sig polaris-${polaris_version}.tgz
+calculate_sha512 polaris-${polaris_version}.tgz.prov 
polaris-${polaris_version}.tgz.prov.sha512
+exec_process gpg --armor --output polaris-${polaris_version}.tgz.prov.asc 
--detach-sig polaris-${polaris_version}.tgz.prov
+
+# Stage to Apache dist dev repository
+print_info "Staging artifacts to Apache dist dev repository..."
+
+dist_dev_dir=${releasey_dir}/polaris-dist-dev
+print_info "Checking out ${APACHE_DIST_URL}${APACHE_DIST_PATH} to 
${dist_dev_dir}..."
+exec_process svn co "${APACHE_DIST_URL}${APACHE_DIST_PATH}" "${dist_dev_dir}"

Review Comment:
   ```suggestion
   exec_process svn checkout "${APACHE_DIST_URL}${APACHE_DIST_PATH}" 
"${dist_dev_dir}"
   ```
   Nit: use full names for clarity



##########
releasey/libs/_gpg.sh:
##########
@@ -0,0 +1,188 @@
+#!/bin/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.
+#
+
+#
+# GPG Setup Verification Script
+#
+# This script verifies that GPG is properly configured for Apache Polaris 
releases:
+# 1. Checks that GPG is installed and available in PATH
+# 1. Checks that the signing key configured in ~/.gradle/gradle.properties 
exists in the local GPG keyring
+# 2. Verifies that the key has been published to hkps://keyserver.ubuntu.com
+# 3. Confirms that the key is part of the KEYS file
+#
+# Returns non-zero exit code if any verification fails.
+#
+
+set -euo pipefail
+
+LIBS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+# Source common logging functions and constants
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+
+function get_secret_keys() {
+  # Get list of secret keys (private keys) that can be used for signing
+  gpg --list-secret-keys --with-colons 2>/dev/null | grep '^sec:' | cut -d: -f5
+}
+
+function get_gradle_signing_key_id() {
+  # Get the signing key ID from gradle.properties
+  grep '^signing.gnupg.keyName' "${GRADLE_PROPERTIES_FILE}" 2>/dev/null | cut 
-d'=' -f2
+}

Review Comment:
   Having this setting isn't technically required. It's rather the release 
manager's responsibility to ensure that the key is properly setup. Nothing 
prevents release managers to configure only one GPG key at all and/or set 
`default-key` in `~/.gnupg/gpg.conf`.



##########
releasey/libs/_docker.sh:
##########
@@ -0,0 +1,120 @@
+#!/bin/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.
+#
+
+#
+# Docker Setup Verification Script
+#
+# This script verifies that Docker is properly configured for Apache Polaris 
releases:
+# 1. Checks that Docker is installed and available in PATH
+# 2. Verifies that Docker daemon is running and accessible
+# 3. Confirms that Docker buildx is available for multi-platform builds
+# 4. Checks Docker Hub login status (optional)
+#
+# Returns non-zero exit code if any verification fails.
+#
+
+set -euo pipefail
+
+libs_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+# Source common logging functions and constants
+source "${libs_dir}/_log.sh"
+source "${libs_dir}/_constants.sh"
+source "${libs_dir}/_exec.sh"
+
+function ensure_docker_is_available() {
+  # Check if Docker is installed, return non-zero if not
+  print_info "Checking if Docker is available..."
+  if ! command -v docker >/dev/null 2>&1; then
+    print_error "Docker is not installed or not in PATH"
+    print_error "Please install Docker to build and publish Docker images"
+    return 1
+  fi
+  print_success "✓ Docker is installed"
+  return 0
+}
+
+function ensure_docker_daemon_is_accessible() {
+  # Check if Docker daemon is running and accessible, return non-zero if not
+  print_info "Checking if Docker daemon is accessible..."
+  if ! docker info >/dev/null 2>&1; then
+    print_error "Docker daemon is not running or not accessible"
+    print_error "Please start Docker daemon and ensure you have permissions to 
access it"
+    return 1
+  fi
+  print_success "✓ Docker daemon is accessible"
+  return 0
+}
+
+function ensure_docker_buildx_is_available() {
+  # Check if Docker buildx is available, return non-zero if not
+  print_info "Checking if Docker buildx is available..."
+  if ! docker buildx version >/dev/null 2>&1; then
+    print_error "Docker buildx is not available"
+    print_error "Please install Docker with buildx support for multi-platform 
builds"
+    return 1
+  fi
+  print_success "✓ Docker buildx is available"
+  return 0
+}
+
+function check_docker_hub_login_status() {
+  # Check if user is logged in to Docker Hub (optional check)
+  print_info "Checking Docker Hub login status..."
+  if docker info 2>/dev/null | grep -q "Username:"; then

Review Comment:
   Yea - let's drop it.
   How a login happens and particularly whether and how that appears in `docker 
info` is not standardized at all. It can actually be a very different login 
(different repo), so the check isn't that helpful.



##########
releasey/06-build-and-stage-docker-images.sh:
##########
@@ -0,0 +1,137 @@
+#!/bin/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.
+#
+
+#
+# Build and Stage Docker Images Script
+#
+# Builds and publishes multi-platform Docker images to DockerHub for release 
candidates.
+# This script automates the "Build and staging Docker images" step from the 
release guide.
+#
+
+set -euo pipefail
+
+releases_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+libs_dir="${releases_dir}/libs"
+
+source "${libs_dir}/_log.sh"
+source "${libs_dir}/_constants.sh"
+source "${libs_dir}/_exec.sh"
+source "${libs_dir}/_files.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") [--help | -h]
+
+  Builds and publishes multi-platform Docker images to DockerHub for release 
candidates.
+  The version is automatically determined from the current git tag. I.e. this 
script must
+  be run from a release tag.
+
+  Prerequisites:
+    - Docker with buildx support must be installed and configured
+    - DockerHub credentials must be configured (docker login)
+    - Must be run from a release tag (apache-polaris-x.y.z-incubating-rcN)
+
+  Options:
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0")
+
+EOF
+}
+
+ensure_cwd_is_project_root
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+# Determine version from current git tag
+print_info "Determining version from current git tag..."
+
+if ! git_tag=$(git describe --tags --exact-match HEAD 2>/dev/null); then
+  print_error "Current HEAD is not on a release tag. Please checkout a release 
tag first."
+  print_error "Use: git checkout apache-polaris-x.y.z-incubating-rcN"
+  exit 1
+fi
+print_info "Found git tag: ${git_tag}"
+
+# Extract version components from git tag in one regex match
+git_tag_regex="^apache-polaris-([0-9]+)\.([0-9]+)\.([0-9]+)-incubating-rc([0-9]+)$"
+if [[ ! ${git_tag} =~ ${git_tag_regex} ]]; then
+  print_error "Invalid git tag format: ${git_tag}"
+  print_error "Expected format: apache-polaris-x.y.z-incubating-rcN"
+  exit 1
+fi
+
+# Extract version components from regex match
+major="${BASH_REMATCH[1]}"
+minor="${BASH_REMATCH[2]}"
+patch="${BASH_REMATCH[3]}"
+rc_number="${BASH_REMATCH[4]}"
+version="${major}.${minor}.${patch}-incubating"

Review Comment:
   I'd prefer to avoid the `-incubating` string everywhere, the "empty" 
constant use can be cleaned up later. Or maybe another project borrows our 
scripts?



##########
releasey/03-create-release-candidate-tag.sh:
##########
@@ -0,0 +1,142 @@
+#!/bin/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.
+#
+
+#
+# Create Release Candidate Tag Script
+#
+# Automates the "Create release candidate tag" section of the release guide.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") --version VERSION [--help | -h]
+
+  Creates a release candidate tag for a release candidate.
+
+  Options:
+    --version VERSION
+        The release version in format x.y.z-incubating-rcN where N is the RC 
number
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0") --version 1.0.0-incubating-rc1
+    $(basename "$0") --version 0.1.0-incubating-rc2
+
+EOF
+}
+
+version=""
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --version)
+      if [[ $# -lt 2 ]]; then
+        print_error "Missing argument for --version"
+        usage >&2
+        exit 1
+      fi
+      version="$2"
+      shift 2
+      ;;
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+# Ensure the version is provided
+if [[ -z ${version} ]]; then
+  print_error "Missing version"
+  usage >&2
+  exit 1
+fi
+
+# Validate version format: x.y.z-incubating-rcN
+# TODO: Remove incubating when we are a TLP
+if ! validate_and_extract_rc_version "${version}"; then
+  print_error "Invalid version format. Expected: x.y.z-incubating-rcN where 
N>0, got: ${version}"
+  usage >&2
+  exit 1
+fi
+
+# Define polaris_version from extracted components
+polaris_version="${major}.${minor}.${patch}-incubating"
+
+print_info "Starting release candidate tag creation..."
+print_info "Version: ${version}"
+print_info "Polaris version: ${polaris_version}"
+print_info "RC number: ${rc_number}"
+echo
+
+# If we're creating RC2 or later, verify previous RC tag exists
+if [[ ${rc_number} -gt 1 ]]; then
+  previous_rc=$((rc_number - 1))
+  previous_tag="apache-polaris-${version%-rc*}-rc${previous_rc}"
+  
+  print_info "Checking for previous RC tag: ${previous_tag}"
+  if ! git tag -l "${previous_tag}" | grep -q "^${previous_tag}$"; then
+    print_error "Previous RC tag ${previous_tag} does not exist. Cannot create 
RC${rc_number} without RC${previous_rc}."
+    exit 1
+  fi
+  print_info "Previous RC tag ${previous_tag} found"
+fi

Review Comment:
   Deleting tags is not good practice and should really never happen, it breaks 
things.
   Tags are referred from released artifacts/poms, that alone actually forbids 
deleting those.



##########
releasey/libs/_github.sh:
##########
@@ -0,0 +1,154 @@
+#!/bin/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.
+#
+
+#
+# Git Remote Setup Script
+#
+# This script ensures that the Git repository has the proper remote 
configuration for Apache Polaris releases:
+# 1. Checks whether there is a Git remote named 'apache' pointing to 
https://github.com/apache/polaris.git
+# 2. If the remote doesn't exist, it will be added
+# 3. If the remote exists but points to the wrong URL, error out
+#
+# Returns non-zero exit code if any verification fails.
+#
+
+set -euo pipefail
+
+LIBS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+# Source common logging functions and constants
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+
+function check_remote_exists() {
+  # Check if a remote exists, return 0 if it exists, 1 if not
+  local remote_name="$1"
+  git remote | grep -q "^${remote_name}$"
+}
+
+function get_remote_url() {
+  # Get the URL for a given remote, return non-zero if remote doesn't exist
+  local remote_name="$1"
+  git remote get-url "${remote_name}" 2>/dev/null || return 1
+}
+
+function ensure_no_uncommitted_change() {
+  if [[ -n $(git status --porcelain) ]]; then
+    print_error "There are uncommitted changes in the repository."
+    print_error "A release can only be performed from a clean state."
+    return 1
+  fi
+}
+
+function add_apache_remote() {

Review Comment:
   You can figure out the "right" remote name via `git remote -v` and looking 
for `https://github.com/apache/polaris.git`.



##########
releasey/05-build-and-stage-distributions.sh:
##########
@@ -0,0 +1,155 @@
+#!/bin/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.
+#
+
+#
+# Build and Stage Distributions Script
+#
+# Builds source and binary distributions and stages them to the Apache dist 
dev repository.
+# This script automates the "Build and stage the distributions" step from the 
release guide.
+#
+
+set -euo pipefail
+
+releasey_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+LIBS_DIR="${releasey_dir}/libs"
+
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+source "${LIBS_DIR}/_version.sh"
+source "${LIBS_DIR}/_gpg.sh"
+
+function usage() {
+  cat << EOF
+$(basename "$0") [--help | -h]
+
+  Builds source and binary distributions and stages them to the Apache dist 
dev repository.
+  The version is automatically determined from the current git tag.  I.e. this 
script must
+  be run from a release candidate tag.
+
+  Options:
+    -h --help
+        Print usage information.
+
+  Examples:
+    $(basename "$0")
+
+EOF
+}
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --help|-h)
+      usage
+      exit 0
+      ;;
+    *)
+      print_error "Unknown option/argument $1"
+      usage >&2
+      exit 1
+      ;;
+  esac
+done
+
+# Determine version from current git tag
+print_info "Determining version from current git tag..."
+
+if ! git_tag=$(git describe --tags --exact-match HEAD 2>/dev/null); then
+  print_error "Current HEAD is not on a release candidate tag. Please checkout 
a release candidate tag first."
+  print_error "Use: git checkout apache-polaris-x.y.z-incubating-rcN"
+  exit 1
+fi
+print_info "Found git tag: ${git_tag}"
+
+# Validate git tag format and extract version components
+if ! validate_and_extract_git_tag_version "${git_tag}"; then
+  print_error "Invalid git tag format: ${git_tag}"
+  print_error "Expected format: apache-polaris-x.y.z-incubating-rcN"
+  exit 1
+fi
+
+polaris_version="${major}.${minor}.${patch}-incubating"
+
+print_info "Starting build and stage distributions process..."
+print_info "Version: ${polaris_version}"
+print_info "RC number: ${rc_number}"
+echo
+
+# Build distributions
+print_info "Building source and binary distributions..."
+exec_process cd "${releasey_dir}/.."
+exec_process ./gradlew build sourceTarball -Prelease -PuseGpgAgent -x test -x 
intTest
+
+# Create Helm package
+print_info "Creating Helm package..."
+exec_process cd "${releasey_dir}/../helm"
+exec_process helm package polaris
+exec_process helm gpg sign polaris-${polaris_version}.tgz
+calculate_sha512 polaris-${polaris_version}.tgz 
polaris-${polaris_version}.tgz.sha512
+exec_process gpg --armor --output polaris-${polaris_version}.tgz.asc 
--detach-sig polaris-${polaris_version}.tgz
+calculate_sha512 polaris-${polaris_version}.tgz.prov 
polaris-${polaris_version}.tgz.prov.sha512
+exec_process gpg --armor --output polaris-${polaris_version}.tgz.prov.asc 
--detach-sig polaris-${polaris_version}.tgz.prov
+
+# Stage to Apache dist dev repository
+print_info "Staging artifacts to Apache dist dev repository..."
+
+dist_dev_dir=${releasey_dir}/polaris-dist-dev
+print_info "Checking out ${APACHE_DIST_URL}${APACHE_DIST_PATH} to 
${dist_dev_dir}..."
+exec_process svn co "${APACHE_DIST_URL}${APACHE_DIST_PATH}" "${dist_dev_dir}"
+
+print_info "Copying files to destination directory..."
+version_dir="${dist_dev_dir}/${polaris_version}"
+helm_chart_version_dir="${dist_dev_dir}/helm-chart/${polaris_version}"
+exec_process mkdir -p "${version_dir}"
+exec_process mkdir -p "${helm_chart_version_dir}"
+exec_process cp "build/distribution/*" "${version_dir}/"
+exec_process cp "runtime/distribution/build/distributions/*" "${version_dir}/"
+
+print_info "Copying Helm package files..."
+exec_process cp helm/polaris-${polaris_version}.tgz* 
"${helm_chart_version_dir}/"
+
+print_info "Adding files to SVN..."
+exec_process svn add "${version_dir}"
+exec_process svn add "${helm_chart_version_dir}"
+
+print_info "Committing changes..."
+exec_process svn commit -m "Stage Apache Polaris ${polaris_version} 
RC${rc_number}"
+
+print_info "Updating Helm index..."
+exec_process cd "${dist_dev_dir}/helm-chart"
+exec_process helm repo index .
+exec_process cd "${releasey_dir}/.."
+
+# Publish Maven artifacts
+print_info "Publishing Maven artifacts to Apache staging repository..."
+exec_process ./gradlew publishToApache -Prelease -PuseGpgAgent 
-Dorg.gradle.parallel=false
+
+echo
+print_success "🎉 Distributions built and staged successfully!"
+echo
+print_info "Staged artifacts:"
+print_info "- Source and binary distributions: ${version_dir}"
+print_info "- Helm charts: ${helm_chart_version_dir}"
+print_info "- Maven artifacts: Published to Apache staging repository"
+echo
+print_info "Next steps:"
+print_info "1. Close the staging repository in Nexus"

Review Comment:
   I propose to already start with semi-automatic releases. The required GH 
workflows require the scripts to be different, leading to two different 
implementations that have to be both verified and kept in sync, which is quite 
a big effort.



##########
releasey/libs/_gpg.sh:
##########
@@ -0,0 +1,188 @@
+#!/bin/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.
+#
+
+#
+# GPG Setup Verification Script
+#
+# This script verifies that GPG is properly configured for Apache Polaris 
releases:
+# 1. Checks that GPG is installed and available in PATH
+# 1. Checks that the signing key configured in ~/.gradle/gradle.properties 
exists in the local GPG keyring
+# 2. Verifies that the key has been published to hkps://keyserver.ubuntu.com
+# 3. Confirms that the key is part of the KEYS file
+#
+# Returns non-zero exit code if any verification fails.
+#
+
+set -euo pipefail
+
+LIBS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+# Source common logging functions and constants
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+
+function get_secret_keys() {
+  # Get list of secret keys (private keys) that can be used for signing
+  gpg --list-secret-keys --with-colons 2>/dev/null | grep '^sec:' | cut -d: -f5
+}
+
+function get_gradle_signing_key_id() {
+  # Get the signing key ID from gradle.properties
+  grep '^signing.gnupg.keyName' "${GRADLE_PROPERTIES_FILE}" 2>/dev/null | cut 
-d'=' -f2
+}

Review Comment:
   For (locally executed) scripts, you can list the available secrets and 
explicitly ask the release manager to explicitly confirm that their settings 
are correct.



##########
releasey/libs/_gpg.sh:
##########
@@ -0,0 +1,188 @@
+#!/bin/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.
+#
+
+#
+# GPG Setup Verification Script
+#
+# This script verifies that GPG is properly configured for Apache Polaris 
releases:
+# 1. Checks that GPG is installed and available in PATH
+# 1. Checks that the signing key configured in ~/.gradle/gradle.properties 
exists in the local GPG keyring
+# 2. Verifies that the key has been published to hkps://keyserver.ubuntu.com
+# 3. Confirms that the key is part of the KEYS file
+#
+# Returns non-zero exit code if any verification fails.
+#
+
+set -euo pipefail
+
+LIBS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+# Source common logging functions and constants
+source "${LIBS_DIR}/_log.sh"
+source "${LIBS_DIR}/_constants.sh"
+source "${LIBS_DIR}/_exec.sh"
+
+function get_secret_keys() {
+  # Get list of secret keys (private keys) that can be used for signing
+  gpg --list-secret-keys --with-colons 2>/dev/null | grep '^sec:' | cut -d: -f5
+}
+
+function get_gradle_signing_key_id() {
+  # Get the signing key ID from gradle.properties
+  grep '^signing.gnupg.keyName' "${GRADLE_PROPERTIES_FILE}" 2>/dev/null | cut 
-d'=' -f2
+}

Review Comment:
   It also forces a _global_ setting, which can easily interfere with other 
stuff that people have to do with Gradle signing. So this actually adds burden 
to people who sign artifacts with Gradle for multiple projects.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to