Skip to content

Commit

Permalink
Insert newlines if issue numbers would be inserted inside a code block (
Browse files Browse the repository at this point in the history
  • Loading branch information
adiroiban authored Nov 19, 2024
2 parents 331422b + fb995e1 commit 0a5bc32
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 0 deletions.
24 changes: 24 additions & 0 deletions src/towncrier/_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,29 @@ def render_issue(issue_format: str | None, issue: str) -> str:
return issue_format.format(issue=issue)


def append_newlines_if_trailing_code_block(text: str) -> str:
"""
Appends two newlines to a text string if it ends with a code block.
Used by `render_fragments` to avoid appending link to issue number into the code block.
"""
# Search for the existence of a code block at the end. We do this by searching for:
# 1. start of code block: two ":", followed by two newlines
# 2. any number of indented, or empty, lines (or the code block would end)
# 3. one line of indented text w/o a trailing newline (because the string is stripped)
# 4. end of the string.
indented_text = r" [ \t]+[^\n]*"
empty_or_indented_text_lines = f"(({indented_text})?\n)*"
regex = r"::\n\n" + empty_or_indented_text_lines + indented_text + "$"
if re.search(regex, text):
# We insert one space, the default template inserts another, which results
# in the correct indentation given default bullet indentation.
# Non-default templates with different indentation will likely encounter issues
# if they have trailing code blocks.
return text + "\n\n "
return text


def render_fragments(
template: str,
issue_format: str | None,
Expand Down Expand Up @@ -381,6 +404,7 @@ def render_fragments(
# for the template, after formatting each issue number
categories = {}
for text, issues in entries:
text = append_newlines_if_trailing_code_block(text)
rendered = [render_issue(issue_format, i) for i in issues]
categories[text] = rendered

Expand Down
1 change: 1 addition & 0 deletions src/towncrier/newsfragments/614.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Multi-line newsfragments that ends with a code block will now have a newline inserted before appending the link to the issue, to avoid breaking formatting.
71 changes: 71 additions & 0 deletions src/towncrier/test/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,3 +462,74 @@ def test_line_wrapping_disabled(self):
versiondata={"name": "MyProject", "version": "1.0", "date": "never"},
)
self.assertEqual(output, expected_output)

def test_trailing_block(self) -> None:
"""
Make sure a newline gets inserted before appending the issue number, if the
newsfragment ends with an indented block.
"""

fragments = {
"": {
(
"1",
"feature",
0,
): (
"this fragment has a trailing code block::\n\n"
" def foo(): ...\n\n"
" \n"
" def bar(): ..."
),
(
"2",
"feature",
0,
): (
"this block is not trailing::\n\n"
" def foo(): ...\n"
" def bar(): ...\n\n"
"so we can append the issue number directly after this"
),
}
}
# the line with 3 spaces (and nothing else) is stripped
expected_output = """MyProject 1.0 (never)
=====================
Features
--------
- this fragment has a trailing code block::
def foo(): ...
def bar(): ...
(#1)
- this block is not trailing::
def foo(): ...
def bar(): ...
so we can append the issue number directly after this (#2)
"""

definitions = {
"feature": {"name": "Features", "showcontent": True},
}
template = read_pkg_resource("templates/default.rst")
fragments_split = split_fragments(fragments, definitions)
output = render_fragments(
template,
None,
fragments_split,
definitions,
["-", "~"],
wrap=True,
versiondata={"name": "MyProject", "version": "1.0", "date": "never"},
)
self.assertEqual(output, expected_output)

0 comments on commit 0a5bc32

Please sign in to comment.