MobArena/scripts/extract-release-notes
Andreas Troelsen b881943656 Add hangar format to release note script.
Hangar uses Markdown, so this is a very easy release note "conversion"
just like GitHub Releases.
2023-12-31 15:14:25 +01:00

236 lines
6.0 KiB
Python
Executable File

#!/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', 'hangar', '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 == 'hangar':
output_as_hangar_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_hangar_markdown(lines):
"""
Hangar Versions use Markdown in the same format as GitHub Releases, so we
don't actually need to do anything else here either. Just strip the first
line so we don't get a duplicate header.
"""
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'<p><strong>{version}</strong></p>')
continue
if line.startswith(SECTION_PREFIX):
if listing:
print('</ul>')
listing = False
i = len(SECTION_PREFIX)
section = line[i:]
print(f'<p><strong>{section}:</strong></p>')
continue
if line.startswith(LIST_ITEM_PREFIX):
if not listing:
print('<ul>')
listing = True
i = len(LIST_ITEM_PREFIX)
item = line[i:]
# Replace angled brackets
item = item.replace('<', '&lt;')
item = item.replace('>', '&gt;')
# Replace **bold** text
item = re.sub(r'\*\*(.*?)\*\*', r'<strong>\1</strong>', item)
# Replace _italic_ text
item = re.sub(r'_(.*?)_', r'<emph>\1</emph>', item)
# Replace `code` text
item = re.sub(r'`(.*?)`', r'<code>\1</code>', item)
# Replace [links](url)
item = re.sub(r'\[([^\]]+)]\(([^)]+)\)', r'<a href="\2">\1</a>', item)
print(f'<li>{item}</li>')
continue
if len(line) > 0:
print(line)
if listing:
print('</ul>')
def output_raw(lines):
[print(line.strip()) for line in lines]
if __name__ == '__main__':
main()