From c7002097434c100f919c7d23261c8b33aa7fcc2a Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Fri, 15 Aug 2025 13:10:21 +0100 Subject: [PATCH] Add script for creating a rollback changelog --- .../workflows/script/rollback_changelog.py | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 .github/workflows/script/rollback_changelog.py diff --git a/.github/workflows/script/rollback_changelog.py b/.github/workflows/script/rollback_changelog.py new file mode 100644 index 000000000..d4515da86 --- /dev/null +++ b/.github/workflows/script/rollback_changelog.py @@ -0,0 +1,62 @@ +import datetime +import os +import sys + +EMPTY_CHANGELOG = """# CodeQL Action Changelog + +""" + +def get_today_string(): + today = datetime.datetime.today() + return '{:%d %b %Y}'.format(today) + +# Include everything up to and after the first heading, +# but not the first heading and body. +def drop_unreleased_section(lines: list[str]): + before_first_section = '' + after_first_section = '' + found_first_section = False + skipped_first_section = False + + for i, line in enumerate(lines): + if line.startswith('## ') and not found_first_section: + found_first_section = True + elif line.startswith('## ') and found_first_section: + skipped_first_section = True + + if not found_first_section: + before_first_section += line + if skipped_first_section: + after_first_section += line + + return (before_first_section, after_first_section) + +def update_changelog(target_version, rollback_version, new_version): + before_first_section = EMPTY_CHANGELOG + after_first_section = '' + + if (os.path.exists('CHANGELOG.md')): + with open('CHANGELOG.md', 'r') as f: + (before_first_section, after_first_section) = drop_unreleased_section(f.readlines()) + + newHeader = f'## {new_version} - {get_today_string()}\n' + + print(before_first_section, end="") + print(newHeader) + print(f"This release rolls back {rollback_version} due to issues with that release. It is identical to {target_version}.\n") + print(after_first_section) + +# We expect three version strings as input: +# +# - target_version: the version that we are re-releasing as `new_version` +# - rollback_version: the version that we are rolling back, typically the one that followed `target_version` +# - new_version: the new version that we are releasing `target_version` as, typically the one that follows `rollback_version` +# +# Example: python3 .github/workflows/script/rollback_changelog.py "1.2.3" "1.2.4" "1.2.5" +if len(sys.argv) < 4: + raise Exception('Expecting argument: target_version rollback_version new_version') + +target_version = sys.argv[1] +rollback_version = sys.argv[2] +new_version = sys.argv[3] +update_changelog(target_version, rollback_version, new_version)