Skip to content

Commit

Permalink
Add workflow for creating release branches
Browse files Browse the repository at this point in the history
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
austinvazquez committed Jun 1, 2024
1 parent 310a88e commit 9dc5ef0
Show file tree
Hide file tree
Showing 4 changed files with 278 additions and 8 deletions.
151 changes: 151 additions & 0 deletions .github/workflows/create-release-branch.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
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 }}

- 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 }}

Check failure on line 52 in .github/workflows/create-release-branch.yml

View workflow job for this annotation

GitHub Actions / yamllint-lint

52:1 [trailing-spaces] trailing spaces
- 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 --dry-run --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 }}
6 changes: 3 additions & 3 deletions .github/workflows/update-getting-started-guide.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
release:
types: ['released']
pull_request:
branches: ['main', 'release/**']
branches: ['main']
paths:
# Run workflow on changes to the workflow definition itself to spot check
# the core version update functionality.
Expand Down Expand Up @@ -45,8 +45,8 @@ jobs:

permissions:
# Write permissions needed to create pull request.
# Risk is mitigated by seperating jobs such that workflows
# running with write permissions only use code from main.
# Risk for pwn requests is mitigated by seperating jobs such that
# workflows running with write permissions only use code from main.
contents: write
pull-requests: write

Expand Down
116 changes: 116 additions & 0 deletions scripts/create-release-branch.sh
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
13 changes: 8 additions & 5 deletions scripts/update-getting-started-guide-version.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@

set -eux -o pipefail

tag=$1

ASSERT=false
VERBOSE=false

Expand All @@ -41,14 +39,19 @@ while [[ $# -gt 0 ]]; do
exit 1
;;
*)
tag=$1
VERSION=$1
shift # past argument
;;
esac
done

# Strip 'v' prefix from tag if not already stripped.
VERSION=${tag/v/}
sanitize_input() {
# Strip 'v' prefix from input if present.
VERSION=${VERSION/v/}
[[ $VERSION =~ ^([0-9]+\.){2}[0-9]+(-.*){0,1}$ ]] || (echo "Error: version does not match expect <major>.<minor>.<patch> version format" && exit 1)
}

sanitize_input

assert_diff() {
local diff_output
Expand Down

0 comments on commit 9dc5ef0

Please sign in to comment.