Skip to content

Commit 4f6fc02

Browse files
authored
Fix Markdown headers (#696)
2 parents f080db6 + f1dd3a8 commit 4f6fc02

File tree

6 files changed

+22
-15
lines changed

6 files changed

+22
-15
lines changed

docs/configuration.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ Top level keys
8282
When using reStructuredText, formatted titles are underlined using the ``underlines`` configuration.
8383
For titles, the first value from ``underlines`` is used to create the underline (which is inserted on the line following the title).
8484
If the template has an ``.md`` suffix, we assume we are looking at markdown format and the title is applied as, i.e. full control over the title format is given to the user.
85-
This choice is made because setting the correct markdown header level automatically is non-trivial (mainly because you don't know what context the generated CHANGELOG entries are being written into).
85+
The top header level is inferred from this, e.g. ``title_format = "(v{version})=\n### {version}"`` will render the title at level 3, categories at level 4, and so on.
8686

8787
``issue_format``
8888
A format string for rendering the issue/ticket number in newsfiles.

src/towncrier/_builder.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ def render_fragments(
362362
top_underline: str = "=",
363363
all_bullets: bool = False,
364364
render_title: bool = True,
365+
md_header_level: int = 1,
365366
) -> str:
366367
"""
367368
Render the fragments into a news file.
@@ -435,6 +436,7 @@ def get_indent(text: str) -> str:
435436
top_underline=top_underline,
436437
get_indent=get_indent, # simplify indentation in the jinja template.
437438
issues_by_category=issues_by_category,
439+
header_prefix="#" * md_header_level,
438440
)
439441

440442
for line in res.split("\n"):

src/towncrier/build.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from __future__ import annotations
99

1010
import os
11+
import re
1112
import sys
1213

1314
from datetime import date
@@ -213,6 +214,16 @@ def __main(
213214
# in the template.
214215
render_title = config.title_format == ""
215216

217+
# Add format-specific context to the template
218+
md_header_level = 1
219+
if is_markdown:
220+
if config.title_format:
221+
m = re.search(r"^#+(?=\s)", config.title_format, re.MULTILINE)
222+
lvl = len(m[0]) if m else 0
223+
else: # TODO: derive from template or make configurable?
224+
lvl = 1 if render_title else 0
225+
md_header_level = lvl
226+
216227
rendered = render_fragments(
217228
# The 0th underline is used for the top line
218229
template,
@@ -225,6 +236,7 @@ def __main(
225236
top_underline=config.underlines[0],
226237
all_bullets=config.all_bullets,
227238
render_title=render_title,
239+
md_header_level=md_header_level,
228240
)
229241

230242
if config.title_format:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Markdown header level is correctly inferred from ``title_format``.

src/towncrier/templates/default.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
{% if render_title %}
22
{% if versiondata.name %}
3-
# {{ versiondata.name }} {{ versiondata.version }} ({{ versiondata.date }})
3+
{{header_prefix}} {{ versiondata.name }} {{ versiondata.version }} ({{ versiondata.date }})
44
{% else %}
5-
# {{ versiondata.version }} ({{ versiondata.date }})
5+
{{header_prefix}} {{ versiondata.version }} ({{ versiondata.date }})
66
{% endif %}
77
{% endif %}
88
{% for section, _ in sections.items() %}
99
{% if section %}
1010

11-
## {{section}}
11+
{{header_prefix}}# {{section}}
1212
{% endif %}
1313

1414
{% if sections[section] %}
1515
{% for category, val in definitions.items() if category in sections[section] %}
16-
##{% if section %}#{% endif %} {{ definitions[category]['name'] }}
16+
{{header_prefix}}#{% if section %}#{% endif %} {{ definitions[category]['name'] }}
1717

1818
{% for text, values in sections[section][category].items() %}
1919
- {{ text }}

src/towncrier/test/test_build.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
from .._shell import cli
1818
from ..build import _main
19-
from .helpers import read, read_pkg_resource, with_git_project, with_project, write
19+
from .helpers import read, with_git_project, with_project, write
2020

2121

2222
class TestCli(TestCase):
@@ -1086,7 +1086,7 @@ def test_title_format_custom_markdown(self, runner):
10861086
10871087
[20-01-2001] CUSTOM RELEASE for FooBarBaz version 7.8.9
10881088
1089-
## Features
1089+
# Features
10901090
10911091
- Adds levitation (#123)
10921092
@@ -1104,7 +1104,6 @@ def test_title_format_custom_markdown(self, runner):
11041104
package = "foo"
11051105
filename = "NEWS.md"
11061106
title_format = "### [{project_date}] CUSTOM RELEASE for {name} version {version}"
1107-
template = "custom_template.md"
11081107
"""
11091108
)
11101109
def test_markdown_injected_after_header(self, runner):
@@ -1136,13 +1135,6 @@ def test_markdown_injected_after_header(self, runner):
11361135
dedent=True,
11371136
)
11381137

1139-
default_template = read_pkg_resource("templates/default.md")
1140-
assert "##{%" in default_template
1141-
write(
1142-
"custom_template.md",
1143-
contents=default_template.replace("##{%", "####{%"),
1144-
)
1145-
11461138
result = runner.invoke(_main, ["--date", "01-01-2001"], catch_exceptions=False)
11471139

11481140
with open("foo/newsfragments/123.feature", "w") as f:

0 commit comments

Comments
 (0)