-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add workflow for creating release branches
This change adds a GitHub Actions workflow for creating release branches with jobs to 1) create the branch, 2) open a pull request with the generated THIRD_PARTY_LICENSES file and updated getting started guide version, and auto-rollback the branch on error. Signed-off-by: Austin Vazquez <[email protected]>
- Loading branch information
1 parent
310a88e
commit 4b247af
Showing
4 changed files
with
280 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
name: Create release branch | ||
|
||
on: | ||
workflow_dispatch: | ||
inputs: | ||
major_minor_version: | ||
description: 'Major.Minor release version' | ||
required: true | ||
base_commit: | ||
description: 'Base commit SHA' | ||
required: true | ||
pull_request: | ||
# Workflow should only ever be run from main, so exclude | ||
# running on pull requests to release branch resources. | ||
branches: ['main'] | ||
paths: | ||
# Run workflow on changes to the workflow definition and its | ||
# dependencies to spot check the workflow functionality. | ||
- '.github/workflows/create-release-branch.yml' | ||
- 'scripts/create-release-branch.sh' | ||
- 'scripts/build-third-party-licenses.sh' | ||
- 'scripts/update-getting-started-guide-.sh' | ||
|
||
env: | ||
MAJOR_MINOR_VERSION: '' | ||
BASE_COMMIT: '' | ||
|
||
jobs: | ||
test-create-branch: | ||
if: github.event_name == 'pull_request' | ||
runs-on: ubuntu-20.04 | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Mock workflow inputs on pull request | ||
run: | | ||
echo "MAJOR_MINOR_VERSION=0.${{ github.event.pull_request.number }}" >> $GITHUB_ENV | ||
echo "BASE_COMMIT=${{ github.sha }}" >> $GITHUB_ENV | ||
- name: Test create release branch | ||
run: bash scripts/create-release-branch.sh --assert --base ${{ env.BASE_COMMIT }} --dry-run ${{ env.MAJOR_MINOR_VERSION }} | ||
|
||
- uses: actions/setup-go@v5 | ||
|
||
- name: Install go-licenses | ||
run: go install github.com/google/[email protected] | ||
|
||
- name: Generate third party licenses file | ||
run: bash scripts/build-third-party-licenses.sh | ||
|
||
- name: Test update getting started version in release branch | ||
run: bash scripts/update-getting-started-guide-version.sh --assert ${{ env.MAJOR_MINOR_VERSION }}.0 | ||
|
||
- name: Test rollback create releae branch | ||
run: bash scripts/create-release-branch.sh --assert --dry-run --rollback ${{ env.MAJOR_MINOR_VERSION }} | ||
|
||
create-branch: | ||
if: github.event_name == 'workflow_dispatch' | ||
runs-on: ubuntu-20.04 | ||
|
||
permissions: | ||
# Write permissions needed to create release branch. | ||
# Risk for pwn requests is mitigated by seperating jobs such that | ||
# workflows running with write permissions only use code from main. | ||
contents: write | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
with: | ||
ref: main | ||
sparse-checkout: | | ||
scripts/create-release-branch.sh | ||
- name: Set environment variables for workflow | ||
run: | | ||
echo "MAJOR_MINOR_VERSION=${{ github.event.inputs.major_minor_version }}" >> $GITHUB_ENV | ||
echo "BASE_COMMIT=${{ github.event.inputs.base_commit }}" >> $GITHUB_ENV | ||
- name: Create release branch | ||
run: bash scripts/create-release-branch.sh --base ${{ env.BASE_COMMIT }} ${{ env.MAJOR_MINOR_VERSION }} | ||
|
||
initial-pr: | ||
needs: create-branch | ||
if: github.event_name == 'workflow_dispatch' && needs.create-branch.result == 'success' | ||
runs-on: ubuntu-20.04 | ||
|
||
permissions: | ||
# Write permissions needed to create pull request. | ||
# Risk for pwn requests is mitigated by seperating jobs such that | ||
# workflows running with write permissions only use code from the | ||
# branch which was cut from main. | ||
contents: write | ||
pull-requests: write | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
with: | ||
ref: release/${{ env.MAJOR_MINOR_VERSION }} | ||
|
||
- uses: actions/setup-go@v5 | ||
|
||
- name: Install go-licenses | ||
run: go install github.com/google/[email protected] | ||
|
||
- name: Generate third party licenses file | ||
run: bash scripts/build-third-party-licenses.sh | ||
|
||
- name: Update getting started version in release branch | ||
run: bash scripts/update-getting-started-guide-version.sh --verbose "${{ env.MAJOR_MINOR_VERSION }}.0" | ||
|
||
- name: Create PR | ||
uses: peter-evans/create-pull-request@v6 | ||
with: | ||
title: 'Prepare release ${{ env.MAJOR_MINOR_VERSION }}' | ||
commit-message: | | ||
Prepare release ${{ env.MAJOR_MINOR_VERSION }} | ||
This change adds the THIRD_PARTY_LICENSES file and updates the getting started guide for release/${{ env.MAJOR_MINOR_VERSION }}. | ||
body: | | ||
This change adds the THIRD_PARTY_LICENSES file and updates the getting started guide for release/${{ env.MAJOR_MINOR_VERSION }}. | ||
Auto-generated by [create-pull-request](https://github.com/peter-evans/create-pull-request) | ||
labels: easy-to-review, automated-pr | ||
token: ${{ secrets.GITHUB_TOKEN }} | ||
author: "GitHub <[email protected]>" | ||
signoff: true | ||
branch: 'create-pull-request/prepare-release-${{ env.MAJOR_MINOR_VERSION }}' | ||
base: 'release/${{ env.MAJOR_MINOR_VERSION }}' | ||
delete-branch: true | ||
|
||
auto-rollback: | ||
needs: initial-pr | ||
# If the workflow was unable to create the pull request with the THIRD_PARTY_LICENSES file | ||
# and getting started guide version updates, then the release branch should be rolled back. | ||
if: github.event_name == 'workflow_dispatch' && needs.initial-pr.result == 'failure' | ||
runs-on: ubuntu-20.04 | ||
|
||
permissions: | ||
# Write permissions needed to rollback release branch. | ||
# Risk for pwn requests is mitigated by seperating jobs such that | ||
# workflows running with write permissions only use code from main. | ||
contents: write | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
with: | ||
ref: main | ||
sparse-checkout: | | ||
scripts/create-release-branch.sh | ||
- name: Delete release branch | ||
run: bash scripts/create-release-branch.sh --rollback ${{ env.MAJOR_MINOR_VERSION }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
#!/usr/bin/env bash | ||
|
||
# Copyright The Soci Snapshotter Authors. | ||
|
||
# Licensed 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. | ||
|
||
# A script to create a release branch on origin from the given commit. | ||
# | ||
# Usage: bash create-release-branch.sh [-a|--assert] [-b|--base] [-d|--dry-run] [-r|--rollback] <MAJOR_MINOR_VERSION> | ||
|
||
set -eux -o pipefail | ||
|
||
ASSERT=false | ||
BASE_COMMIT="" | ||
DRYRUN=false | ||
ROLLBACK=false | ||
|
||
while [[ $# -gt 0 ]]; do | ||
case $1 in | ||
--assert|-a) | ||
ASSERT=true | ||
shift # past argument | ||
;; | ||
--base|-b) | ||
shift # past argument | ||
BASE_COMMIT=$1 | ||
shift # past value | ||
;; | ||
--dry-run|-d) | ||
DRYRUN=true | ||
shift # past argument | ||
;; | ||
--rollback|-r) | ||
ROLLBACK=true | ||
shift # past argument | ||
;; | ||
--*|-*) | ||
echo "Unknown option $1" | ||
exit 1 | ||
;; | ||
*) | ||
VERSION=$1 | ||
shift # past argument | ||
;; | ||
esac | ||
done | ||
|
||
sanitize_input() { | ||
# Strip 'v' prefix from input if present. | ||
VERSION=${VERSION/v/} | ||
[[ $VERSION =~ ^[0-9]+\.[0-9]+$ ]] || (echo "Error: version does not match expected <major>.<minor> format" && exit 1) | ||
|
||
if [ -n "$BASE_COMMIT" ]; then | ||
[[ $BASE_COMMIT =~ ^[0-9a-fA-F]{7,40}$ ]] || (echo "Error: base commit does not match expected short|full format" && exit 1) | ||
FOUND=$(git log --pretty=format:"%H" | grep "$BASE_COMMIT") | ||
[ -n "$FOUND" ] || (echo "Error: base commit not found in history" && exit 1) | ||
fi | ||
} | ||
|
||
assert_create_branch() { | ||
if [ $ROLLBACK = true ]; then | ||
[ ${#PUSH_OPTS[@]} -eq 0 ] || (echo "Error: rollback request but '--delete' not set as push option" && exit 1) | ||
else | ||
local current_branch | ||
current_branch=$(git rev-parse --abbrev-ref HEAD) | ||
[ $current_branch = "release/${VERSION}" ] || (echo "Error: incorrect branch, expected: release/${VERSION}, actual: $current_branch" && exit 1) | ||
|
||
local base_commit | ||
base_commit=$(git show -s --format="%H") | ||
[ $base_commit = $BASE_COMMIT ] || (echo "Error: incorrect base commit, expected: $BASE_COMMIT, actual: $base_commit" && exit 1) | ||
fi | ||
} | ||
|
||
assert_push_command() { | ||
local push_cmd | ||
push_cmd=$1 | ||
|
||
if [ $ROLLBACK = true ]; then | ||
[[ $push_cmd == "git push --delete origin release/${VERSION}" ]] || (echo "Error: expected '--delete' in git push for rollback" && exit 1) | ||
else | ||
[[ $push_cmd == "git push origin release/${VERSION}" ]] || (echo "Error: expected: 'git push origin release/${VERSION}', actual: '$push_cmd'" && exit 1) | ||
fi | ||
} | ||
|
||
sanitize_input | ||
|
||
PUSH_OPTS=() | ||
if [ $ROLLBACK = true ]; then | ||
echo "Rollback: setting '--delete' for git push" | ||
PUSH_OPTS+=("--delete") | ||
else | ||
git checkout -b "release/${VERSION}" "${BASE_COMMIT}" | ||
fi | ||
|
||
[ $ASSERT = true ] && assert_create_branch | ||
|
||
PUSH_CMD='git push "${PUSH_OPTS[@]}" origin "release/${VERSION}"' | ||
if [ $DRYRUN = true ]; then | ||
# Dry-run mode is not able to use git push --dry-run as it still requires | ||
# write permissions to the remote repository. The intent is to run dry-run mode | ||
# in pull request workflows with a reduced permission set to mitigate risk for pwn requests. | ||
# Alternatively assert the push command is correct. | ||
assert_push_command "$(eval echo ${PUSH_CMD})" | ||
else | ||
$PUSH_CMD | ||
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters