From d8b1e4aa8ceb3a838cee86162c6c129ff8757283 Mon Sep 17 00:00:00 2001 From: Julian Dehm Date: Wed, 5 Jun 2024 11:14:01 +0200 Subject: [PATCH] add script to auto-generate changelog from changelog files --- changelog/README.md | 7 ++++- changelog/parse_changelogs.py | 59 +++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100755 changelog/parse_changelogs.py diff --git a/changelog/README.md b/changelog/README.md index 9ae432d8a..ab684f070 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -31,7 +31,6 @@ The content of the file should look like this: - **Fixed**: for any bug fixes. - **Security**: in case of vulnerabilities. - ## Example ``` @@ -40,3 +39,9 @@ The content of the file should look like this: - improve userdashboard filter performance (#2449) ``` +## Create release changelog + +To create the changelog for a release you can either copy the content +of all the changelog files into CHANGELOG.md manually or use the +`parse_changelogs.py` in this folder by running it here: +`./parse_changelogs.py`. diff --git a/changelog/parse_changelogs.py b/changelog/parse_changelogs.py new file mode 100755 index 000000000..564489a2a --- /dev/null +++ b/changelog/parse_changelogs.py @@ -0,0 +1,59 @@ +#!/bin/python3 + +import logging +import os +import re +from collections import OrderedDict + +logger = logging.getLogger(__name__) + + +def combine_sections_in_folder(folder_path): + """Parser for changelog files following the https://keepachangelog.com + format. + """ + allowed_section_headers = [ + "Added", + "Changed", + "Deprecated", + "Removed", + "Fixed", + "Security", + ] + sections = OrderedDict() + + for filename in os.listdir(folder_path): + if filename.endswith(".md") and filename != "README.md": + filepath = os.path.join(folder_path, filename) + with open(filepath, "r") as file: + current_section = None + for line in file: + # find all headings starting with # (they should always + # start with ### but we seem to sometimes use # or ##) + match = re.match(r"^#+ (.*)", line) + if match: + section_header = match.group(1).strip().capitalize() + if section_header not in allowed_section_headers: + logger.warning( + f"warning: section_header {section_header} " + f"in file {filename} is invalid, " + "see https://keepachangelog.com for a list of " + "allowed types." + ) + current_section = sections.get(section_header, []) + elif current_section is not None and line.strip(): + current_section.append(line) + sections[section_header] = current_section + + combined_md = "" + for section_header, lines in sections.items(): + combined_md += "### " + section_header + "\n\n" + combined_md += "".join(lines) + "\n" + + return combined_md + + +if __name__ == "__main__": + folder_path = "." + combined_md = combine_sections_in_folder(folder_path) + print(combined_md)