From ea5fcc43e695fc302a4ea083c91849ed109d49e5 Mon Sep 17 00:00:00 2001 From: Doug Hellmann Date: Mon, 13 Feb 2023 18:14:04 -0500 Subject: [PATCH] USHIFT-793: add a script to automatically produce EC release notes This script partially automates the process of publishing release notes for engineering candidates. --- scripts/release-notes/gen-ec-release-notes.py | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100755 scripts/release-notes/gen-ec-release-notes.py diff --git a/scripts/release-notes/gen-ec-release-notes.py b/scripts/release-notes/gen-ec-release-notes.py new file mode 100755 index 0000000000..bb7611057f --- /dev/null +++ b/scripts/release-notes/gen-ec-release-notes.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python3 + +"""Engineering Candidate Release Note Tool + +This script partially automates the process of publishing release +notes for engineering candidate builds of MicroShift. + +It looks for the most recent RPM to have been published to the mirror, +and uses information encoded in that filename to determine the SHA of +the commit that was used for the build and the version number given to +it. + +Then it looks for that tag in the local repository, and emits +instructions for tagging the commit if there is no tag already. + +Then it uses gh to produce a draft release with a preamble that +includes download URLs and a body that is auto-generated by GitHub's +service based on the pull requests that have merged since the last +tagged release. + +The script creates a draft release, which must be published by hand to +make it public. Open the link printed at the end of the script run and +use the web interface to review and then publish the release. + +NOTE: To use this script, you must have the GitHub command line tool +"gh" installed and you must have enough privileges on the +openshift/microshift repository to create releases. + +""" + +import re +import subprocess +import textwrap +from urllib import request + +VERSION="4.13" +RPM_LIST_URL=f"https://mirror.openshift.com/pub/openshift-v4/aarch64/microshift/ocp-dev-preview/latest-{VERSION}/el8/os/rpm_list" +MICROSHIFT_RPM_NAME_PREFIX=f"microshift-{VERSION}" + +# An RPM filename looks like +# microshift-4.13.0~ec.3-202302130757.p0.ge636e15.assembly.ec.3.el8.aarch64.rpm +VERSION_RE = re.compile( + """ + microshift- # prefix + (?P\d+\.\d+\.\d+) # product version + ~ # separator + ec\.(?P\d+) # ec number + - + (?P\d+)\. # date + p(?P\d+)\. # patch number + g(?P[\dabcdef]+)\. # commit SHA prefix + """, + re.VERBOSE, +) + + +def main(): + # Get the list of the latest RPMs for the VERSION of MicroShift. + rpm_list_response = request.urlopen(RPM_LIST_URL) + rpm_list = rpm_list_response.read().decode("utf-8").splitlines() + + # Look for the RPM for MicroShift itself, with a name like + # + # Packages/microshift-4.13.0~ec.3-202302130757.p0.ge636e15.assembly.ec.3.el8__aarch64/microshift-4.13.0~ec.3-202302130757.p0.ge636e15.assembly.ec.3.el8.aarch64.rpm + # + # then parse out the EC version number and other details needed to + # build the release tag. + microshift_rpm_filename = None + for package_path in rpm_list: + parts = package_path.split("/") + if parts[-1].startswith(MICROSHIFT_RPM_NAME_PREFIX): + microshift_rpm_filename = parts[-1] + break + else: + raise RuntimeError(f"Did not find {MICROSHIFT_RPM_NAME_PREFIX} in {rpm_list}") + + match = VERSION_RE.search(microshift_rpm_filename) + if match is None: + raise RuntimeError(f"Could not parse version info from '{microshift_rpm_filename}'") + rpm_version_details = match.groupdict() + product_version = rpm_version_details["product_version"] + ec_number = rpm_version_details["ec_number"] + commit_sha = rpm_version_details["commit_sha"] + + # To be consistent with past releases, the release name should + # look like: 4.13.0-ec-2 + release_name = "-".join([ + rpm_version_details["product_version"], + "ec", + rpm_version_details["ec_number"], + ]) + + # Check if the release already exists + print(f"Checking for {release_name}...") + try: + subprocess.run(["gh", "release", "view", release_name], + check=True, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + except subprocess.CalledProcessError: + print("Not found") + else: + print("Found, no work to do") + return + + # Check for the tag to be present in the local git repository + try: + subprocess.run(["git", "show", release_name], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + check=True) + except subprocess.CalledProcessError: + print(f"Check for tag {release_name} on commit {commit_sha}") + print("") + print(f"git tag -s -m '{product_version} EC {ec_number}' {release_name} {commit_sha}") + print(f"git push origin {release_name}") + return + + # Set up the release notes preamble with download links + notes = textwrap.dedent(f""" + This is a pre-release Engineering Candidate for {product_version}. + + See the mirror for build artifacts: + - https://mirror.openshift.com/pub/openshift-v4/x86_64/microshift/ocp-dev-preview/{product_version}-ec.{ec_number}/ + - https://mirror.openshift.com/pub/openshift-v4/aarch64/microshift/ocp-dev-preview/{product_version}-ec.{ec_number}/ + + """) + + # Create draft release with message that includes download URLs and history + try: + subprocess.run(["gh", "release", "create", + "--draft", + "--prerelease", + "--notes", notes, + "--generate-notes", + release_name, + ], + check=True) + except subprocess.CalledProcessError as err: + print(f"Failed to create the release: {err}") + return + + +if __name__ == "__main__": + main()