From a82d775b92d79f4483128218088e075cbee3bd4e Mon Sep 17 00:00:00 2001 From: Austin Vazquez Date: Thu, 16 May 2024 11:31:50 +0000 Subject: [PATCH] Add workflow for creating release branches This change adds a GitHub Actions workflow for creating release branches with jobs to 1) create the branch and 2) open a pull request with the generated THIRD_PARTY_LICENSES file and updated getting started guide version. Signed-off-by: Austin Vazquez --- .github/workflows/create-release-branch.yml | 130 ++++++++++++++++++ .../update-getting-started-guide.yml | 6 +- scripts/create-release-branch.sh | 90 ++++++++++++ .../update-getting-started-guide-version.sh | 13 +- 4 files changed, 231 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/create-release-branch.yml create mode 100755 scripts/create-release-branch.sh diff --git a/.github/workflows/create-release-branch.yml b/.github/workflows/create-release-branch.yml new file mode 100644 index 000000000..4cfb4c9ed --- /dev/null +++ b/.github/workflows/create-release-branch.yml @@ -0,0 +1,130 @@ +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' + +jobs: + test-create-branch: + if: github.event_name == 'pull_request' + runs-on: ubuntu-20.04 + + env: + VERSION: '' + + steps: + - uses: actions/checkout@v4 + + - name: Mock workflow inputs on pull request + run: | + echo "VERSION=0.${{ github.event.pull_request.number }}" >> $GITHUB_ENV + + - name: Test create release branch + run: bash scripts/create-release-branch.sh --assert --base ${{ github.sha }} --dry-run ${{ env.VERSION }} + + - uses: actions/setup-go@v5 + + - name: Install go-licenses + run: go install github.com/google/go-licenses@v1.6.0 + + - 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.VERSION }}.0 + + 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 + + env: + VERSION: '' + + steps: + - uses: actions/checkout@v4 + with: + ref: main + sparse-checkout: | + scripts/create-release-branch.sh + + - name: Set environment variable version to output to dependent jobs + run: | + echo "VERSION=${{ github.event.inputs.major_minor_version }}" >> $GITHUB_ENV + + - name: Create release branch + run: bash scripts/create-release-branch.sh --base ${{ github.event.inputs.base_commit }} ${{ github.event.inputs.major_minor_version }} + + outputs: + version: ${{ env.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/${{ needs.create-branch.outputs.version }} + + - uses: actions/setup-go@v5 + + - name: Install go-licenses + run: go install github.com/google/go-licenses@v1.6.0 + + - 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 "${{ needs.create-branch.outputs.version }}.0" + + - name: Create PR + uses: peter-evans/create-pull-request@v6 + with: + title: 'Prepare release ${{ needs.create-branch.outputs.version }}' + commit-message: | + Prepare release ${{ needs.create-branch.outputs.version }} + + This change adds the THIRD_PARTY_LICENSES file and updates the getting started guide for release/${{ needs.create-branch.outputs.version }}. + body: | + This change adds the THIRD_PARTY_LICENSES file and updates the getting started guide for release/${{ needs.create-branch.outputs.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 " + signoff: true + branch: 'create-pull-request/prepare-release-${{ needs.create-branch.outputs.version }}' + base: 'release/${{ needs.create-branch.outputs.version }}' + delete-branch: true diff --git a/.github/workflows/update-getting-started-guide.yml b/.github/workflows/update-getting-started-guide.yml index 5f896a681..78d49c5e4 100644 --- a/.github/workflows/update-getting-started-guide.yml +++ b/.github/workflows/update-getting-started-guide.yml @@ -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. @@ -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 diff --git a/scripts/create-release-branch.sh b/scripts/create-release-branch.sh new file mode 100755 index 000000000..c1193f826 --- /dev/null +++ b/scripts/create-release-branch.sh @@ -0,0 +1,90 @@ +#!/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] + +set -eux -o pipefail + +ASSERT=false +BASE_COMMIT="" +DRYRUN=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 + ;; + --*|-*) + 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 . 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() { + 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) +} + +sanitize_input + +git checkout -b "release/${VERSION}" "${BASE_COMMIT}" + +[ $ASSERT = true ] && assert_create_branch + +PUSH_CMD="git push 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. + [[ $PUSH_CMD == "git push origin release/${VERSION}" ]] || (echo "Error: expected: 'git push origin release/${VERSION}', actual: '$PUSH_CMD'" && exit 1) +else + $PUSH_CMD +fi diff --git a/scripts/update-getting-started-guide-version.sh b/scripts/update-getting-started-guide-version.sh index 00147a333..0b57a6890 100755 --- a/scripts/update-getting-started-guide-version.sh +++ b/scripts/update-getting-started-guide-version.sh @@ -21,8 +21,6 @@ set -eux -o pipefail -tag=$1 - ASSERT=false VERBOSE=false @@ -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 .. version format" && exit 1) +} + +sanitize_input assert_diff() { local diff_output