Source code for batools.changelog

# Released under the MIT License. See LICENSE for details.
#
"""Generates a pretty html changelog from our markdown."""

from __future__ import annotations  # Docs-generation hack.

import os
import subprocess


[docs] def changelog_version(version: str) -> str: """Map a build version to its changelog section version. Pre-release suffixes (``1.8.0a1``, ``1.8.0b3``) collapse to their base version (``1.8.0``) so all alphas/betas of a release accumulate in a single changelog section rather than each getting its own. """ import re return re.sub(r'(a|b)\d+$', '', version)
[docs] def get_version_changelog(version: str, projroot: str) -> list[str]: """Get changelog text for a given version from CHANGELOG.md.""" import re from efro.error import CleanError version = changelog_version(version) changelog_path = os.path.join(projroot, 'CHANGELOG.md') if not os.path.exists(changelog_path): raise CleanError(f'CHANGELOG.md not found at {changelog_path}') with open(changelog_path, 'r', encoding='utf-8') as infile: changelog_content = infile.read() # Regex to find the section for the given version pattern = rf'^###\s+{re.escape(version)}\b.*?\n(.*?)(?=^###\s+|\Z)' match = re.search(pattern, changelog_content, re.DOTALL | re.MULTILINE) if not match: raise CleanError(f'Changelog entry for version {version} not found.') section_text = match.group(1).rstrip() # Convert changelog section into a list of bullet entries, # preserving internal newlines and indentation. lines = section_text.splitlines() entries: list[str] = [] current_entry: list[str] = [] for line in lines: if line.startswith('- '): # Save previous entry if present if current_entry: entries.append('\n'.join(current_entry).rstrip()) current_entry = [] # Strip "- " but preserve rest exactly current_entry.append(line[2:]) else: # Continuation line (including indentation or blank lines) if current_entry: current_entry.append(line) # Add final entry if current_entry: entries.append('\n'.join(current_entry).rstrip()) changelog_list = entries return changelog_list
[docs] def generate(projroot: str) -> None: """Main script entry point.""" # Make sure we start from root dir (one above this script). os.chdir(projroot) out_path = 'build/changelog.html' out_path_tmp = out_path + '.md' # Do some filtering of our raw changelog. with open('CHANGELOG.md', encoding='utf-8') as infile: lines = infile.read().splitlines() # Strip out anything marked internal. lines = [ line for line in lines if not line.strip().startswith('- (internal)') ] with open(out_path_tmp, 'w', encoding='utf-8') as outfile: outfile.write('\n'.join(lines)) subprocess.run( f'pandoc -f markdown {out_path_tmp} > {out_path}', shell=True, check=True, ) print(f'Generated changelog at \'{out_path}\'.') os.unlink(out_path_tmp)
# Docs-generation hack; import some stuff that we likely only forward-declared # in our actual source code so that docs tools can find it. from typing import (Coroutine, Any, Literal, Callable, Generator, Awaitable, Sequence, Self) import asyncio from concurrent.futures import Future from pathlib import Path from enum import Enum