diff --git a/scripts/extract-release-notes b/scripts/extract-release-notes new file mode 100755 index 0000000..8b75743 --- /dev/null +++ b/scripts/extract-release-notes @@ -0,0 +1,224 @@ +#!/usr/bin/env python3 + +import argparse +import os +import re +import sys + + +VERSION_PREFIX = '## ' +SECTION_PREFIX = '### ' +LIST_ITEM_PREFIX = '- ' + + +def main(): + args = parse_args() + lines = extract(args.version) + output(lines, args.format) + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument( + 'version', + help='the version to extract release notes from the changelog for', + ) + parser.add_argument( + '--format', + '-f', + choices=['github', 'spigot', 'curse'], + help='the format to output the release notes in', + ) + + return parser.parse_args() + + +def extract(target): + filename = 'changelog.md' + if not os.path.isfile(filename): + filename = os.path.join('..', filename) + if not os.path.isfile(filename): + print('error: changelog.md not found!') + sys.exit(1) + + lines = [] + + with open(filename) as changelog: + found = False + + for entry in changelog: + if entry.startswith(VERSION_PREFIX): + if found: + break + + i = entry.find('[') + 1 + j = entry.find(']') + version = entry[i:j] + + if version == target: + if version[0].isdigit(): + version = f'v{version}' + + lines.append(f'{VERSION_PREFIX}{version}') + lines.append('') + found = True + + continue + + if not found: + continue + + lines.append(entry.strip()) + + if not found: + print(f'error: version {target} not found!') + sys.exit(1) + + return lines + + +def output(lines, fmt): + if fmt == 'github': + output_as_github_markdown(lines) + elif fmt == 'spigot': + output_as_spigot_bbcode(lines) + elif fmt == 'curse': + output_as_curseforge_html(lines) + else: + output_raw(lines) + + +def output_as_github_markdown(lines): + """ + GitHub Releases Markdown is printed as the raw output from the changelog + except for the version header (the first line), because the version number + is already used as the release title, so we don't want it to appear twice. + """ + output_raw(lines[1:]) + + +def output_as_spigot_bbcode(lines): + """ + Spigot uses BBCode for resource update descriptions. It's very similar to + regular HTML, which makes it fairly easy to convert from Markdown. We just + need to use a [FONT] tag with Courier New for code bits. + """ + listing = False + + for line in lines: + line = line.strip() + + if line.startswith(VERSION_PREFIX): + i = len(VERSION_PREFIX) + version = line[i:] + print(f'[B]{version}[/B]') + continue + + if line.startswith(SECTION_PREFIX): + if listing: + print('[/LIST]') + listing = False + + i = len(SECTION_PREFIX) + section = line[i:] + print(f'[B]{section}:[/B]') + continue + + if line.startswith(LIST_ITEM_PREFIX): + if not listing: + print('[LIST]') + listing = True + + i = len(LIST_ITEM_PREFIX) + item = line[i:] + + # Replace **bold** text + item = re.sub(r'\*\*(.*?)\*\*', r'[B]\1[/B]', item) + + # Replace _italic_ text + item = re.sub(r'_(.*?)_', r'[I]\1[/I]', item) + + # Replace `code` text + item = re.sub(r'`(.*?)`', r'[FONT=Courier New]\1[/FONT]', item) + + # Replace [links](url) + item = re.sub(r'\[([^\]]+)]\(([^)]+)\)', r'[URL=\2]\1[/URL]', item) + + print(f'[*]{item}') + continue + + if len(line) > 0: + print(line) + + if listing: + print('[/LIST]') + + +def output_as_curseforge_html(lines): + """ + CurseForge uses regular HTML for file update descriptions, which makes it + fairly easy to convert from Markdown. Angled brackets need to be replaced + with their HTML entity equivalents, but other than that it's very similar + to the Spigot BBCode conversion. + """ + listing = False + + for line in lines: + line = line.strip() + + if line.startswith(VERSION_PREFIX): + i = len(VERSION_PREFIX) + version = line[i:] + print(f'

{version}

') + continue + + if line.startswith(SECTION_PREFIX): + if listing: + print('') + listing = False + + i = len(SECTION_PREFIX) + section = line[i:] + print(f'

{section}:

') + continue + + if line.startswith(LIST_ITEM_PREFIX): + if not listing: + print('') + + +def output_raw(lines): + [print(line.strip()) for line in lines] + + +if __name__ == '__main__': + main()