Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
81d2bdd
GH-3547: Add semi-automated release pipeline for Apache Parquet Java
RussellSpitzer May 6, 2026
4ebedf3
Auto-compute next development version in publish-release
RussellSpitzer May 6, 2026
7eb3b2c
Use env var references in Maven settings instead of real credentials
RussellSpitzer May 6, 2026
1524fe4
Strict regex filtering for RC tag lookups
RussellSpitzer May 6, 2026
4d52d06
Fail if GITHUB_TOKEN is missing during real CI check verification
RussellSpitzer May 6, 2026
7dbabbf
Fix CI: configure git identity for bats tests
RussellSpitzer May 6, 2026
a7f8d72
Fix: add git user.name/email to prepare-rc workflow
RussellSpitzer May 7, 2026
4356ea1
Add fork guard to release workflows
RussellSpitzer May 7, 2026
2b898b0
Verify staging repository before destructive Nexus actions
RussellSpitzer May 7, 2026
f27be0c
Add per-version concurrency guards to release workflows
RussellSpitzer May 8, 2026
35f756b
Address review: clean up dead code and harden _redact_secrets
RussellSpitzer May 8, 2026
778472e
Address review: tighten release-time safety guards
RussellSpitzer May 8, 2026
277671c
Address review: extract _svn.sh shared library
RussellSpitzer May 8, 2026
22fb3e7
Scope dist/release cleanup to older patches of the same minor
RussellSpitzer May 8, 2026
fe28241
Update .github/workflows/ci-release-scripts.yml
RussellSpitzer May 22, 2026
216228f
Apply suggestions from code review
RussellSpitzer May 22, 2026
0f33e24
Address review: pin release workflow actions to SHA
RussellSpitzer Jun 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .github/workflows/ci-release-scripts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

name: Test Release Scripts

on:
pull_request:
paths:
- 'release/**'
push:
branches:
- master
paths:
- 'release/**'

jobs:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can rip out all of these tests if folks don't find them useful, it's just a bunch of Bash Unit Testing to try to make sure at least our helper functions do what they are supposed to. They use mocked output though so they have limited utility for testing the real true pathway.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They aren't going to get much maintenance (hopefully), but will be a good regression test against changes in os images.

bats:
name: Release Script Unit Tests
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add

        persist-credentials: false

persist-credentials: false

- name: Install bats-core
run: sudo apt-get update -q && sudo apt-get install -q -y bats

- name: Configure Git identity for tests
run: |
git config --global user.name "CI"
git config --global user.email "ci@test"

- name: Run bats tests
run: bats release/tests/*.bats

- name: Verify scripts are executable
run: |
for script in release/bin/*.sh; do
if [[ ! -x "$script" ]]; then
echo "ERROR: $script is not executable"
exit 1
fi
done
echo "All scripts are executable"
86 changes: 86 additions & 0 deletions .github/workflows/release-cancel-rc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

name: Release - Cancel RC

on:
workflow_dispatch:
inputs:
version:
description: 'Release version (e.g., 1.18.0)'
required: true
type: string
rc_number:
description: 'RC number to cancel (e.g., 0)'
required: true
type: string
staging_repo_id:
description: 'Nexus staging repository ID to drop (e.g., orgapacheparquet-1234)'
required: true
type: string
allow_description_mismatch:
description: 'Bypass the staging-repo description check (recovery only)'
required: false
type: boolean
default: false
dry_run:
description: 'Dry run mode (no actual changes)'
required: false
type: boolean
default: true

concurrency:
group: release-${{ inputs.version }}
cancel-in-progress: false

jobs:
cancel-rc:
if: github.repository_owner == 'apache'
name: Cancel Release Candidate
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: false

- name: Install Subversion
run: sudo apt-get update -q && sudo apt-get install -q -y subversion

- name: Cancel Release Candidate
env:
DRY_RUN: ${{ inputs.dry_run && '1' || '0' }}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

anything in "secrets" is automatically redacted by Github Actions so we don't have to worry about any of this stuff being exposed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • env expansion is the way to defend against malicious inputs before they are executed in scripts

NEXUS_USERNAME: ${{ secrets.PARQUET_NEXUS_USER }}
NEXUS_PASSWORD: ${{ secrets.PARQUET_NEXUS_PASSWORD }}
SVN_USERNAME: ${{ secrets.PARQUET_SVN_DEV_USERNAME }}
SVN_PASSWORD: ${{ secrets.PARQUET_SVN_DEV_PASSWORD }}
INPUT_VERSION: ${{ inputs.version }}
INPUT_RC_NUMBER: ${{ inputs.rc_number }}
INPUT_STAGING_REPO_ID: ${{ inputs.staging_repo_id }}
INPUT_ALLOW_DESCRIPTION_MISMATCH: ${{ inputs.allow_description_mismatch && '1' || '0' }}
run: |
args=("${INPUT_VERSION}" "${INPUT_RC_NUMBER}" "${INPUT_STAGING_REPO_ID}")
if [[ "${INPUT_ALLOW_DESCRIPTION_MISMATCH}" == "1" ]]; then
args+=(--allow-description-mismatch)
fi
./release/bin/cancel-rc.sh "${args[@]}"
94 changes: 94 additions & 0 deletions .github/workflows/release-prepare-rc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

name: Release - Prepare RC

on:
workflow_dispatch:
inputs:
version:
description: 'Release version (e.g., 1.18.0)'
required: true
type: string
rc_number:
description: 'RC number override (leave empty for auto-detect)'
required: false
type: string
default: ''
dry_run:
description: 'Dry run mode (no actual changes)'
required: false
type: boolean
default: true

concurrency:
group: release-${{ inputs.version }}
cancel-in-progress: false

jobs:
prepare-rc:
if: github.repository_owner == 'apache'
name: Prepare Release Candidate
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Set up JDK 11
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: temurin
java-version: '11'

- name: Import GPG key and configure Git
env:
GPG_PRIVATE_KEY: ${{ secrets.PARQUET_GPG_PRIVATE_KEY }}
run: |
echo "${GPG_PRIVATE_KEY}" | gpg --batch --import
KEY_ID=$(gpg --list-keys --with-colons | grep '^fpr' | head -1 | cut -d: -f10)
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git config --global user.signingkey "${KEY_ID}"
git config --global commit.gpgsign true

- name: Install Subversion
run: sudo apt-get update -q && sudo apt-get install -q -y subversion

- name: Prepare Release Candidate
env:
DRY_RUN: ${{ inputs.dry_run && '1' || '0' }}
NEXUS_USERNAME: ${{ secrets.PARQUET_NEXUS_USER }}
NEXUS_PASSWORD: ${{ secrets.PARQUET_NEXUS_PASSWORD }}
SVN_USERNAME: ${{ secrets.PARQUET_SVN_DEV_USERNAME }}
SVN_PASSWORD: ${{ secrets.PARQUET_SVN_DEV_PASSWORD }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
INPUT_VERSION: ${{ inputs.version }}
INPUT_RC_NUMBER: ${{ inputs.rc_number }}
run: |
args=("${INPUT_VERSION}")
if [[ -n "${INPUT_RC_NUMBER}" ]]; then
args+=(--rc "${INPUT_RC_NUMBER}")
fi
./release/bin/prepare-rc.sh "${args[@]}"
102 changes: 102 additions & 0 deletions .github/workflows/release-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

name: Release - Publish After Vote

on:
workflow_dispatch:
inputs:
version:
description: 'Release version (e.g., 1.18.0)'
required: true
type: string
rc_number:
description: 'RC number that passed the vote (leave empty to auto-detect latest)'
required: false
type: string
default: ''
staging_repo_id:
description: 'Nexus staging repository ID (e.g., orgapacheparquet-1234)'
required: true
type: string
allow_description_mismatch:
description: 'Bypass the staging-repo description check (recovery only)'
required: false
type: boolean
default: false
dry_run:
description: 'Dry run mode (no actual changes)'
required: false
type: boolean
default: true

concurrency:
group: release-${{ inputs.version }}
cancel-in-progress: false

jobs:
publish-release:
if: github.repository_owner == 'apache'
name: Publish Release
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Set up JDK 11
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: temurin
java-version: '11'

- name: Install Subversion
run: sudo apt-get update -q && sudo apt-get install -q -y subversion

- name: Configure Git
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"

- name: Publish Release
env:
DRY_RUN: ${{ inputs.dry_run && '1' || '0' }}
NEXUS_USERNAME: ${{ secrets.PARQUET_NEXUS_USER }}
NEXUS_PASSWORD: ${{ secrets.PARQUET_NEXUS_PASSWORD }}
SVN_USERNAME: ${{ secrets.PARQUET_SVN_DEV_USERNAME }}
SVN_PASSWORD: ${{ secrets.PARQUET_SVN_DEV_PASSWORD }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
INPUT_VERSION: ${{ inputs.version }}
INPUT_RC_NUMBER: ${{ inputs.rc_number }}
INPUT_STAGING_REPO_ID: ${{ inputs.staging_repo_id }}
INPUT_ALLOW_DESCRIPTION_MISMATCH: ${{ inputs.allow_description_mismatch && '1' || '0' }}
run: |
args=("${INPUT_VERSION}" "${INPUT_STAGING_REPO_ID}")
if [[ -n "${INPUT_RC_NUMBER}" ]]; then
args+=(--rc "${INPUT_RC_NUMBER}")
fi
if [[ "${INPUT_ALLOW_DESCRIPTION_MISMATCH}" == "1" ]]; then
args+=(--allow-description-mismatch)
fi
./release/bin/publish-release.sh "${args[@]}"
Loading