Skip to content

Commit b834f73

Browse files
authored
During docs builds, leave newsfragments unchanged (#3086)
* Undo towncrier changes when building docs * Restore git index after towncrier run * Add type annotation for history_new
1 parent 7d81c27 commit b834f73

File tree

1 file changed

+55
-9
lines changed

1 file changed

+55
-9
lines changed

docs/source/conf.py

+55-9
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919
from __future__ import annotations
2020

2121
import collections.abc
22+
import glob
2223
import os
2324
import sys
2425
import types
26+
from pathlib import Path
2527
from typing import TYPE_CHECKING, cast
2628

2729
if TYPE_CHECKING:
@@ -36,19 +38,62 @@
3638
# Enable reloading with `typing.TYPE_CHECKING` being True
3739
os.environ["SPHINX_AUTODOC_RELOAD_MODULES"] = "1"
3840

39-
# https://docs.readthedocs.io/en/stable/builds.html#build-environment
40-
if "READTHEDOCS" in os.environ:
41-
import glob
42-
43-
if glob.glob("../../newsfragments/*.*.rst"):
44-
print("-- Found newsfragments; running towncrier --", flush=True)
45-
import subprocess
46-
41+
# Handle writing newsfragments into the history file.
42+
# We want to keep files unchanged when testing locally.
43+
# So immediately revert the contents after running towncrier,
44+
# then substitute when Sphinx wants to read it in.
45+
history_file = Path("history.rst")
46+
47+
history_new: str | None
48+
if glob.glob("../../newsfragments/*.*.rst"):
49+
print("-- Found newsfragments; running towncrier --", flush=True)
50+
history_orig = history_file.read_bytes()
51+
import subprocess
52+
53+
# In case changes were staged, preserve indexed version.
54+
# This grabs the hash of the current staged version.
55+
history_staged = subprocess.run(
56+
["git", "rev-parse", "--verify", ":docs/source/history.rst"],
57+
check=True,
58+
cwd="../..",
59+
stdout=subprocess.PIPE,
60+
encoding="ascii",
61+
).stdout.strip()
62+
try:
4763
subprocess.run(
48-
["towncrier", "--yes", "--date", "not released yet"],
64+
["towncrier", "--keep", "--date", "not released yet"],
4965
cwd="../..",
5066
check=True,
5167
)
68+
history_new = history_file.read_text("utf8")
69+
finally:
70+
# Make sure this reverts even if a failure occurred.
71+
# Restore whatever was staged.
72+
print(f"Restoring history.rst = {history_staged}")
73+
subprocess.run(
74+
[
75+
"git",
76+
"update-index",
77+
"--cacheinfo",
78+
f"100644,{history_staged},docs/source/history.rst",
79+
],
80+
cwd="../..",
81+
check=False,
82+
)
83+
# And restore the working copy.
84+
history_file.write_bytes(history_orig)
85+
del history_orig # We don't need this any more.
86+
else:
87+
# Leave it as is.
88+
history_new = None
89+
90+
91+
def on_read_source(app: Sphinx, docname: str, content: list[str]) -> None:
92+
"""Substitute the modified history file."""
93+
if docname == "history" and history_new is not None:
94+
# This is a 1-item list with the file contents.
95+
content[0] = history_new
96+
5297

5398
# Sphinx is very finicky, and somewhat buggy, so we have several different
5499
# methods to help it resolve links.
@@ -153,6 +198,7 @@ def setup(app: Sphinx) -> None:
153198
app.connect("autodoc-process-signature", autodoc_process_signature)
154199
# After Intersphinx runs, add additional mappings.
155200
app.connect("builder-inited", add_intersphinx, priority=1000)
201+
app.connect("source-read", on_read_source)
156202

157203

158204
# -- General configuration ------------------------------------------------

0 commit comments

Comments
 (0)