From dbac2b1af3c3e9a2663571a70087a1374da016b3 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Mon, 22 Apr 2024 14:43:48 +0300 Subject: [PATCH] Sphinx extension to add dates to release notes --- docs/conf.py | 1 + docs/dater.py | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 docs/dater.py diff --git a/docs/conf.py b/docs/conf.py index 392cf317e5f..f12b30e65fb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -28,6 +28,7 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ + "dater", "sphinx.ext.autodoc", "sphinx.ext.extlinks", "sphinx.ext.intersphinx", diff --git a/docs/dater.py b/docs/dater.py new file mode 100644 index 00000000000..d9e583547bd --- /dev/null +++ b/docs/dater.py @@ -0,0 +1,52 @@ +""" +Sphinx extension to add timestamps to release notes based on Git versions. + +Based on https://github.com/jaraco/rst.linker, with thanks to Jason R. Coombs. +""" + +from __future__ import annotations + +import datetime as dt +import os +import re +import subprocess +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from sphinx.application import Sphinx + +DOC_NAME_REGEX = re.compile(r"releasenotes/\d+\.\d+\.\d+") +VERSION_TITLE_REGEX = re.compile(r"^(\d+\.\d+\.\d+)\n-+\n") + + +def get_date_for(git_version: str) -> dt.datetime | None: + cmd = ["git", "log", "-1", "--format=%ai", git_version] + try: + with open(os.devnull, "w", encoding="utf-8") as devnull: + out = subprocess.check_output( + cmd, stderr=devnull, text=True, encoding="utf-8" + ) + ts = out.strip() + return dt.datetime.fromisoformat(ts) + except subprocess.CalledProcessError: + return None + + +def add_date(app: Sphinx, doc_name: str, source: list[str]) -> None: + if DOC_NAME_REGEX.match(doc_name) and (m := VERSION_TITLE_REGEX.match(source[0])): + old_title = m.group(1) + + if tag_datetime := get_date_for(old_title): + new_title = f"{old_title} ({tag_datetime:%Y-%m-%d})" + else: + new_title = f"{old_title} (unreleased)" + + new_underline = "-" * len(new_title) + + result = source[0].replace(m.group(0), f"{new_title}\n{new_underline}\n", 1) + source[0] = result + + +def setup(app: Sphinx) -> dict[str, bool]: + app.connect("source-read", add_date) + return {"parallel_read_safe": True}