From 27389ad54c203a77d31f3ec1ac5fc579e18891dd Mon Sep 17 00:00:00 2001 From: mgoerens Date: Thu, 20 Jul 2023 16:48:28 +0200 Subject: [PATCH] Move release logic to a new workflow - remove steps creating the GitHub release from "build.yaml" workflow. - add steps to tag the main branch with the version tag after an automerge in the "build.yaml" workflow. - create a new GitHub Action for handling GitHub release on new tags on main. - modify the python script handling the release to be able to get the release body directly. fixes #380 --- .github/workflows/build.yaml | 35 +++++--- .github/workflows/release.yaml | 90 ++++++++++++++++++++ scripts/setup.cfg | 4 +- scripts/src/checkautomerge/__init__.py | 0 scripts/src/checkautomerge/checkautomerge.py | 27 ------ scripts/src/release/releasebody.py | 21 +++++ scripts/src/release/releasechecker.py | 17 +--- 7 files changed, 137 insertions(+), 57 deletions(-) create mode 100644 .github/workflows/release.yaml delete mode 100644 scripts/src/checkautomerge/__init__.py delete mode 100644 scripts/src/checkautomerge/checkautomerge.py create mode 100644 scripts/src/release/releasebody.py diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index efceb5bd..358362cd 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -1,4 +1,9 @@ -name: Build, Test and Release +name: Build, Test, Automerge and Tag + +# This workflow runs on all PR that are targetting the main branch. +# +# It runs the test suite. If the PR is a release PR, it automerges and tags the main branch with +# the corresonding new version. Finally, it retags the container image with latest. on: pull_request_target: @@ -118,7 +123,7 @@ jobs: id: create-tarfile working-directory: ./chart-verifier run: | - # check if release file only is included in PR + # create test tarball for the tests ve1/bin/tar-file --release="test" @@ -187,7 +192,7 @@ jobs: - name: Approve PR id: approve_pr if: ${{ steps.check_version_updated.outputs.updated == 'true'}} - uses: hmarr/auto-approve-action@v2 + uses: hmarr/auto-approve-action@v3 with: github-token: ${{ secrets.GITHUB_TOKEN }} @@ -200,21 +205,23 @@ jobs: MERGE_METHOD: squash MERGE_LABELS: "" - - name: Check for PR merge + - name: Get master branch sha + id: master_sha if: ${{ steps.check_version_updated.outputs.updated == 'true'}} run: | - ve1/bin/check-auto-merge --api-url=${{ github.event.pull_request._links.self.href }} + git fetch + export ORIGIN_MASTER_SHA=$(git rev-parse origin/master) + echo "origin_master_sha=$ORIGIN_MASTER_SHA" >> $GITHUB_OUTPUT - - name: Create the the release - id: create_release + - name: Create release tag + id: create_release_tag if: ${{ steps.check_version_updated.outputs.updated == 'true'}} - uses: softprops/action-gh-release@v1 + uses: mathieudutour/github-tag-action@v6.1 with: - tag_name: ${{ steps.check_version_in_PR.outputs.PR_version }} - body: ${{ steps.check_version_in_PR.outputs.PR_release_body }} - files: ${{ steps.check_version_in_PR.outputs.PR_tarball_name }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + github_token: ${{ secrets.PAT_MGOERENS }} + custom_tag: ${{ steps.check_version_in_PR.outputs.PR_version }} + tag_prefix: "" + commit_sha: ${{ steps.master_sha.outputs.origin_master_sha }} - name: Wait for image build to complete # Quay is configured to automatically build our image. This waits @@ -250,4 +257,4 @@ jobs: imageReference=quay.io/redhat-certification/chart-verifier podman pull ${imageReference}:${{ steps.check_version_in_PR.outputs.PR_version }} podman tag ${imageReference}:${{ steps.check_version_in_PR.outputs.PR_version }} ${imageReference}:latest - podman push ${imageReference}:latest \ No newline at end of file + podman push ${imageReference}:latest diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 00000000..de688569 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,90 @@ +name: create release on new tags + +# This workflow is triggered by new version tags (e.g. "1.12.2" without leading "v") on the main +# branch. +# +# Tagging should be automatic after each merged PR release (see the build.yaml workflow). +# Alternatively, this workflow can be triggered by manually creating a tag on the main branch with +# the aforementioned format. Note that the tests are *not* run by this workflow, and that you +# should therefore apply caution before manually tagging the main branch in order to trigger it. +# +# This workflow contains a check that the tag matches the version set in +# ./pkg/chartverifier/version/version_info.json. +# +# In order to recreate a GitHub release and rebuild its associated assets, first the tag needs to +# be manually deleted (e.g `git tag --delete 1.12.2 && git push --delete origin 1.12.2`). The +# GitHub release that was created for this tag automatically turns into a "Draft" release and will +# need to be manually cleaned up, though it doesn't constitute a blocker for this workflow to run. +# Finally, as mentioned above, create a new tag (e.g. `git tag 1.12.2 && git push --tags`) to +# recreate the release. +# +# This workflow builds the tarball, creates the Github release and attaches the tarball to it. + +on: + push: + # Publish semver tags as releases. + tags: '[0-9]+.[0-9]+.[0-9]+' + +jobs: + build-and-release: + name: Create GitHub release + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version-file: go.mod + + - name: Print tag to GITHUB_OUTPUT + id: get_tag + run: | + echo "release_version=${GITHUB_REF#refs/*/}" | tee -a $GITHUB_OUTPUT + + - name: Build binary and make tarball + id: build_bin + run: | + make bin + TARBALL_NAME="chart-verifier.tgz-${{ steps.get_tag.outputs.release_version }}.tgz" + tar -zcvf $TARBALL_NAME -C out/ chart-verifier + export TARBALL_PATH=$(realpath $TARBALL_NAME) + echo "tarball_path=$TARBALL_PATH" | tee -a $GITHUB_OUTPUT + + - name: Check that the tag matches the current version + id: check_tag_and_version + run: | + release_version=${{ steps.get_tag.outputs.release_version }} + bin_version=$(out/chart-verifier version --as-data | jq -r .version) + if [[ "$release_version" != "$bin_version" ]]; then + echo "Binary version ($bin_version) doesn't match tag ($release_version)" && exit 1 + fi + + - name: Set up Python 3.x + uses: actions/setup-python@v2 + with: + python-version: '3.9' + + - name: Set up Python scripts + run: | + # set up python requirements and scripts on PR branch + python3 -m venv ve1 + cd scripts && ../ve1/bin/pip3 install -r requirements.txt && cd .. + cd scripts && ../ve1/bin/python3 setup.py install && cd .. + + - name: Generate release body + id: release_body + run: echo "release_body=$(ve1/bin/print-release-body)" | tee -a $GITHUB_OUTPUT + + - name: Create the the release + id: create_release + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ steps.get_tag.outputs.release_version }} + body: ${{ steps.release_body.outputs.release_body }} + files: ${{ steps.build_bin.outputs.tarball_path }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + diff --git a/scripts/setup.cfg b/scripts/setup.cfg index cbe5e61b..ac633057 100644 --- a/scripts/setup.cfg +++ b/scripts/setup.cfg @@ -36,8 +36,8 @@ where = src [options.entry_points] console_scripts = release-checker = release.releasechecker:main - check-auto-merge = checkautomerge.checkautomerge:main + print-release-body = release.releasebody:main build-and-test = buildandtest.buildandtest:main check-user = owners.checkuser:main sa-for-chart-testing = saforcharttesting.saforcharttesting:main - tar-file = release.tarfile_asset:main \ No newline at end of file + tar-file = release.tarfile_asset:main diff --git a/scripts/src/checkautomerge/__init__.py b/scripts/src/checkautomerge/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/scripts/src/checkautomerge/checkautomerge.py b/scripts/src/checkautomerge/checkautomerge.py deleted file mode 100644 index 4ead5dcf..00000000 --- a/scripts/src/checkautomerge/checkautomerge.py +++ /dev/null @@ -1,27 +0,0 @@ -import time -import sys -import argparse - -import requests - -def ensure_pull_request_not_merged(api_url): - # api_url https://api.github.com/repos///pulls/1 - headers = {'Accept': 'application/vnd.github.v3+json'} - merged = False - for i in range(20): - r = requests.get(api_url, headers=headers) - if r.json()["merged"]: - merged = True - break - time.sleep(10) - - if not merged: - print("[ERROR] Pull request not merged") - sys.exit(1) - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("-u", "--api-url", dest="api_url", type=str, required=True, - help="API URL for the pull request") - args = parser.parse_args() - ensure_pull_request_not_merged(args.api_url) diff --git a/scripts/src/release/releasebody.py b/scripts/src/release/releasebody.py new file mode 100644 index 00000000..b9b4c7ef --- /dev/null +++ b/scripts/src/release/releasebody.py @@ -0,0 +1,21 @@ +import sys + +sys.path.append('./scripts/src/') +from release import releasechecker +from utils import utils + +def get_release_body(version, image_name, release_info): + """Generate the body of the GitHub release""" + body = f"Chart verifier version {version}

Docker Image:
- {image_name}:{version}

" + body += "This version includes:
" + for info in release_info: + if info.startswith("<"): + body += info + else: + body += f"- {info}
" + return body + +def main(): + version_info = releasechecker.get_version_info() + release_body = get_release_body(version_info["version"],version_info["quay-image"],version_info["release-info"]) + print(release_body) diff --git a/scripts/src/release/releasechecker.py b/scripts/src/release/releasechecker.py index 488ee9de..c8152f90 100644 --- a/scripts/src/release/releasechecker.py +++ b/scripts/src/release/releasechecker.py @@ -31,7 +31,7 @@ import semver import sys sys.path.append('./scripts/src/') -from release import tarfile_asset +from release import tarfile_asset, releasebody from utils import utils VERSION_FILE = 'pkg/chartverifier/version/version_info.json' @@ -64,18 +64,6 @@ def check_if_only_version_file_is_modified(api_url): return version_file_found -def make_release_body(version, image_name, release_info): - body = f"Chart verifier version {version}

Docker Image:
- {image_name}:{version}

" - body += "This version includes:
" - for info in release_info: - if info.startswith("<"): - body += info - else: - body += f"- {info}
" - - print(f"[INFO] Release body: {body}") - utils.add_output("PR_release_body",body) - def get_version_info(): data = {} with open(VERSION_FILE) as json_file: @@ -111,7 +99,8 @@ def main(): utils.add_output("PR_release_image",version_info["quay-image"]) utils.add_output("PR_release_info",version_info["release-info"]) utils.add_output("PR_includes_release","true") - make_release_body(version_info["version"],version_info["quay-image"],version_info["release-info"]) + release_body = releasebody.get_release_body(version_info["version"],version_info["quay-image"],version_info["release-info"]) + utils.add_output("PR_release_body",release_body) else: version_info = get_version_info() if args.version: