Add release note extraction script.
Introduces a crude Python script that can extract release notes from the
changelog for a given version and convert it to one of three different
output formats:
- `github` for GitHub Releases. This is just the Markdown itself, but
with the very first line (the version) removed, because the version is
also the title of the release itself.
- `spigot` for Spigot Resources. This is the BBCode format used on the
forums and in the resource descriptions.
- `curse` for CurseForge File Uploads. Curse uses a so-called "WYSIWYG"
format that's really just HTML underneath.
The formats for Spigot and CurseForge are straightforward to convert to
as long as we only use simple text formatting, bullet lists, and links,
but that is really all the changelog should consist of anyway.
While this script already makes the release process quite a bit easier
on its own, the end goal is to _automate_ releases as much as possible,
and to do that, we need to be able to extract release notes, and we need
to be able to do it from GitHub Actions, which is quite a bit simpler if
we don't use third-party libraries.
Publishing releases on GitHub is almost trivial, while CurseForge is
pretty easy, and Hangar should be very doable as well. Spigot, on the
other hand, is stuck in the dark ages, so we must continue to upload
files manually there.
2023-12-31 03:25:14 +01:00
|
|
|
#!/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',
|
2023-12-31 15:14:25 +01:00
|
|
|
choices=['github', 'hangar', 'spigot', 'curse'],
|
Add release note extraction script.
Introduces a crude Python script that can extract release notes from the
changelog for a given version and convert it to one of three different
output formats:
- `github` for GitHub Releases. This is just the Markdown itself, but
with the very first line (the version) removed, because the version is
also the title of the release itself.
- `spigot` for Spigot Resources. This is the BBCode format used on the
forums and in the resource descriptions.
- `curse` for CurseForge File Uploads. Curse uses a so-called "WYSIWYG"
format that's really just HTML underneath.
The formats for Spigot and CurseForge are straightforward to convert to
as long as we only use simple text formatting, bullet lists, and links,
but that is really all the changelog should consist of anyway.
While this script already makes the release process quite a bit easier
on its own, the end goal is to _automate_ releases as much as possible,
and to do that, we need to be able to extract release notes, and we need
to be able to do it from GitHub Actions, which is quite a bit simpler if
we don't use third-party libraries.
Publishing releases on GitHub is almost trivial, while CurseForge is
pretty easy, and Hangar should be very doable as well. Spigot, on the
other hand, is stuck in the dark ages, so we must continue to upload
files manually there.
2023-12-31 03:25:14 +01:00
|
|
|
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)
|
2023-12-31 15:14:25 +01:00
|
|
|
elif fmt == 'hangar':
|
|
|
|
output_as_hangar_markdown(lines)
|
Add release note extraction script.
Introduces a crude Python script that can extract release notes from the
changelog for a given version and convert it to one of three different
output formats:
- `github` for GitHub Releases. This is just the Markdown itself, but
with the very first line (the version) removed, because the version is
also the title of the release itself.
- `spigot` for Spigot Resources. This is the BBCode format used on the
forums and in the resource descriptions.
- `curse` for CurseForge File Uploads. Curse uses a so-called "WYSIWYG"
format that's really just HTML underneath.
The formats for Spigot and CurseForge are straightforward to convert to
as long as we only use simple text formatting, bullet lists, and links,
but that is really all the changelog should consist of anyway.
While this script already makes the release process quite a bit easier
on its own, the end goal is to _automate_ releases as much as possible,
and to do that, we need to be able to extract release notes, and we need
to be able to do it from GitHub Actions, which is quite a bit simpler if
we don't use third-party libraries.
Publishing releases on GitHub is almost trivial, while CurseForge is
pretty easy, and Hangar should be very doable as well. Spigot, on the
other hand, is stuck in the dark ages, so we must continue to upload
files manually there.
2023-12-31 03:25:14 +01:00
|
|
|
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:])
|
|
|
|
|
|
|
|
|
2023-12-31 15:14:25 +01:00
|
|
|
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:])
|
|
|
|
|
|
|
|
|
Add release note extraction script.
Introduces a crude Python script that can extract release notes from the
changelog for a given version and convert it to one of three different
output formats:
- `github` for GitHub Releases. This is just the Markdown itself, but
with the very first line (the version) removed, because the version is
also the title of the release itself.
- `spigot` for Spigot Resources. This is the BBCode format used on the
forums and in the resource descriptions.
- `curse` for CurseForge File Uploads. Curse uses a so-called "WYSIWYG"
format that's really just HTML underneath.
The formats for Spigot and CurseForge are straightforward to convert to
as long as we only use simple text formatting, bullet lists, and links,
but that is really all the changelog should consist of anyway.
While this script already makes the release process quite a bit easier
on its own, the end goal is to _automate_ releases as much as possible,
and to do that, we need to be able to extract release notes, and we need
to be able to do it from GitHub Actions, which is quite a bit simpler if
we don't use third-party libraries.
Publishing releases on GitHub is almost trivial, while CurseForge is
pretty easy, and Hangar should be very doable as well. Spigot, on the
other hand, is stuck in the dark ages, so we must continue to upload
files manually there.
2023-12-31 03:25:14 +01:00
|
|
|
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('<', '<')
|
|
|
|
item = item.replace('>', '>')
|
|
|
|
|
|
|
|
# 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()
|