From 0f2588e4ec305f9a202b8d76d3caa48c17004c63 Mon Sep 17 00:00:00 2001 From: Chris Beaven Date: Thu, 29 Sep 2022 12:31:33 +1300 Subject: [PATCH 01/11] Output to markdown compatible format when configured filename extension is `.md` --- src/towncrier/_builder.py | 4 +++ src/towncrier/_settings/load.py | 11 +++++-- src/towncrier/build.py | 1 + src/towncrier/templates/default.rst | 28 +++++++++++------- src/towncrier/test/test_format.py | 45 +++++++++++++++++++++++++---- 5 files changed, 71 insertions(+), 18 deletions(-) diff --git a/src/towncrier/_builder.py b/src/towncrier/_builder.py index de8a720a..9e48d583 100644 --- a/src/towncrier/_builder.py +++ b/src/towncrier/_builder.py @@ -251,6 +251,7 @@ def render_fragments( top_underline: str = "=", all_bullets: bool = False, render_title: bool = True, + title_prefixes: Sequence[str] = ["", "", ""], ) -> str: """ Render the fragments into a news file. @@ -315,6 +316,9 @@ def get_indent(text: str) -> str: versiondata=versiondata, top_underline=top_underline, get_indent=get_indent, # simplify indentation in the jinja template. + title_prefix = title_prefixes[0], + section_prefix = title_prefixes[1], + category_prefix = title_prefixes[2], ) for line in res.split("\n"): diff --git a/src/towncrier/_settings/load.py b/src/towncrier/_settings/load.py index c4fb95d6..220049d4 100644 --- a/src/towncrier/_settings/load.py +++ b/src/towncrier/_settings/load.py @@ -45,6 +45,7 @@ class Config: title_format: str | Literal[False] issue_format: str | None underlines: list[str] + title_prefixes: list[str] wrap: bool all_bullets: bool orphan_prefix: str @@ -60,6 +61,9 @@ def __init__(self, *args: str, **kwargs: str): _title_format = None _template_fname = "towncrier:default" _underlines = ["=", "-", "~"] +_md_underlines = ["", "", ""] +_prefixes = ["", "", ""] +_md_prefixes = ["# ", "## ", "### "] def load_config_from_options( @@ -164,11 +168,13 @@ def parse_toml(base_path: str, config: Mapping[str, Any]) -> Config: failing_option="template", ) + filename = config.get("filename", "NEWS.rst") + is_md = filename.endswith(".md") return Config( package=config.get("package", ""), package_dir=config.get("package_dir", "."), single_file=single_file, - filename=config.get("filename", "NEWS.rst"), + filename=filename, directory=config.get("directory"), version=config.get("version"), name=config.get("name"), @@ -178,7 +184,8 @@ def parse_toml(base_path: str, config: Mapping[str, Any]) -> Config: start_string=config.get("start_string", _start_string), title_format=config.get("title_format", _title_format), issue_format=config.get("issue_format"), - underlines=config.get("underlines", _underlines), + underlines=config.get("underlines", _md_underlines if is_md else _underlines), + title_prefixes=config.get("title_prefixes", _md_prefixes if is_md else _prefixes), wrap=wrap, all_bullets=all_bullets, orphan_prefix=config.get("orphan_prefix", "+"), diff --git a/src/towncrier/build.py b/src/towncrier/build.py index 6dd87aea..a7d17ae6 100644 --- a/src/towncrier/build.py +++ b/src/towncrier/build.py @@ -193,6 +193,7 @@ def __main( top_underline=config.underlines[0], all_bullets=config.all_bullets, render_title=render_title_with_fragments, + title_prefixes=config.title_prefixes, ) if render_title_separately: diff --git a/src/towncrier/templates/default.rst b/src/towncrier/templates/default.rst index f494036d..704c4211 100644 --- a/src/towncrier/templates/default.rst +++ b/src/towncrier/templates/default.rst @@ -1,22 +1,30 @@ {% if render_title %} +{% set version_title %} {% if versiondata.name %} -{{ versiondata.name }} {{ versiondata.version }} ({{ versiondata.date }}) -{{ top_underline * ((versiondata.name + versiondata.version + versiondata.date)|length + 4)}} -{% else %} -{{ versiondata.version }} ({{ versiondata.date }}) -{{ top_underline * ((versiondata.version + versiondata.date)|length + 3)}} +{{ versiondata.name }} {{ versiondata.version }} ({{ versiondata.date }}){% else %} +{{ versiondata.version }} ({{ versiondata.date }}){% endif %} +{% endset %} +{{ title_prefix }}{{ version_title }} +{% if top_underline %} +{{ top_underline * (version_title|length) }} {% endif %} {% endif %} {% for section, _ in sections.items() %} -{% set underline = underlines[0] %}{% if section %}{{section}} -{{ underline * section|length }}{% set underline = underlines[1] %} - +{% set underline = underlines[0] %} +{% if section %} +{{ section_prefix }}{{ section }} +{% if underline %} +{{ underline * section|length }} +{% endif %} +{% set underline = underlines[1] %} {% endif %} {% if sections[section] %} {% for category, val in definitions.items() if category in sections[section]%} -{{ definitions[category]['name'] }} +{{ category_prefix }}{{ definitions[category]['name'] }} +{% if underline %} {{ underline * definitions[category]['name']|length }} +{% endif %} {% if definitions[category]['showcontent'] %} {% for text, values in sections[section][category].items() %} @@ -28,7 +36,7 @@ - {{ sections[section][category]['']|join(', ') }} {% endif %} -{% if sections[section][category]|length == 0 %} +{% if not sections[section][category] %} No significant changes. {% else %} diff --git a/src/towncrier/test/test_format.py b/src/towncrier/test/test_format.py index bdf6f387..52c98739 100644 --- a/src/towncrier/test/test_format.py +++ b/src/towncrier/test/test_format.py @@ -117,6 +117,31 @@ def test_basic(self): Bugfixes ~~~~~~~~ +- Web fixed. (#3) +""" + expected_md_output = """# MyProject 1.0 (never) + +### Features + +- Fun! (baz) +- Foo added. (#2, #9, #72) +- Stuff! (#4) + + +### Misc + +- bar, #1, #9, #142 + + +## Names + +No significant changes. + + +## Web + +### Bugfixes + - Web fixed. (#3) """ @@ -125,16 +150,24 @@ def test_basic(self): ).decode("utf8") fragments = split_fragments(fragments, definitions) - output = render_fragments( - template, - None, - fragments, - definitions, - ["-", "~"], + render_kwargs = dict( + template=template, + issue_format=None, + fragments=fragments, + definitions=definitions, + underlines=["-", "~"], wrap=True, versiondata={"name": "MyProject", "version": "1.0", "date": "never"}, + title_prefixes = ["", "", ""] ) + output = render_fragments(**render_kwargs) self.assertEqual(output, expected_output) + render_kwargs["top_underline"] = "" + render_kwargs["underlines"] = ["", ""] + render_kwargs["title_prefixes"] = ["# ", "## ", "### "] + output = render_fragments(**render_kwargs) + print(output) + self.assertEqual(output, expected_md_output) # Check again with non-default underlines expected_output_weird_underlines = """MyProject 1.0 (never) From 3e6b620c6d87fb1323bd66b16219807e7b49cc85 Mon Sep 17 00:00:00 2001 From: Chris Beaven Date: Thu, 29 Sep 2022 12:43:32 +1300 Subject: [PATCH 02/11] Add test for different configured underlines/title_prefixes defaults when configured filename ends with '.md' --- src/towncrier/test/test_build.py | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/towncrier/test/test_build.py b/src/towncrier/test/test_build.py index 58213424..b7f2bf6b 100644 --- a/src/towncrier/test/test_build.py +++ b/src/towncrier/test/test_build.py @@ -1173,3 +1173,36 @@ def test_with_topline_and_template_and_draft(self): self.assertEqual(0, result.exit_code, result.output) self.assertEqual(expected_output, result.output) + + def test_markdown_filename(self): + """ + When a filename ending with `.md` is configured, the configuration defaults for + underlines and title_prefixes change to be markdown compatible. + """ + runner = CliRunner() + + with runner.isolated_filesystem(): + setup_simple_project(extra_config='filename = "CHANGELOG.md"') + Path("foo/newsfragments/123.feature").write_text("Adds levitation") + result = runner.invoke(_main, ["--date=01-01-2001", "--draft"]) + + self.assertEqual(0, result.exit_code, result.output) + self.assertEqual( + result.output, + dedent( + """ + Loading template... + Finding news fragments... + Rendering news fragments... + Draft only -- nothing has been written. + What is seen below is what would be written. + + # Foo 1.2.3 (01-01-2001) + + ### Features + + - Adds levitation (#123) + + """ + ).lstrip(), + ) From 7f6e545a0957ea18d5cee0b41d13936b9a2b8431 Mon Sep 17 00:00:00 2001 From: Chris Beaven Date: Thu, 29 Sep 2022 13:59:36 +1300 Subject: [PATCH 03/11] Test markdown options against both draft and build modes --- src/towncrier/test/test_build.py | 54 ++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/src/towncrier/test/test_build.py b/src/towncrier/test/test_build.py index b7f2bf6b..3f0f92ca 100644 --- a/src/towncrier/test/test_build.py +++ b/src/towncrier/test/test_build.py @@ -1178,31 +1178,51 @@ def test_markdown_filename(self): """ When a filename ending with `.md` is configured, the configuration defaults for underlines and title_prefixes change to be markdown compatible. + + Test against both draft and build mode. """ runner = CliRunner() with runner.isolated_filesystem(): - setup_simple_project(extra_config='filename = "CHANGELOG.md"') + setup_simple_project(extra_config='filename = "CHANGES.md"') Path("foo/newsfragments/123.feature").write_text("Adds levitation") - result = runner.invoke(_main, ["--date=01-01-2001", "--draft"]) - self.assertEqual(0, result.exit_code, result.output) - self.assertEqual( - result.output, - dedent( + draft_result = runner.invoke(_main, ["--date=01-01-2001", "--draft"]) + self.assertEqual(0, draft_result.exit_code, draft_result.output) + self.assertEqual( + draft_result.output, + dedent( + """ + Loading template... + Finding news fragments... + Rendering news fragments... + Draft only -- nothing has been written. + What is seen below is what would be written. + + # Foo 1.2.3 (01-01-2001) + + ### Features + + - Adds levitation (#123) + """ - Loading template... - Finding news fragments... - Rendering news fragments... - Draft only -- nothing has been written. - What is seen below is what would be written. + ).lstrip(), + ) - # Foo 1.2.3 (01-01-2001) + result = runner.invoke(_main, ["--date=01-01-2001"]) + changes_text = Path("CHANGES.md").read_text() - ### Features + self.assertEqual(0, result.exit_code, result.output) - - Adds levitation (#123) + self.assertEqual( + changes_text, + dedent( + """ + # Foo 1.2.3 (01-01-2001) - """ - ).lstrip(), - ) + ### Features + + - Adds levitation (#123) + """ + ).lstrip(), + ) From 8116d902dd34cbd3d2a119a717cc25b40488fa3b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 01:02:50 +0000 Subject: [PATCH 04/11] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/towncrier/_builder.py | 6 +++--- src/towncrier/_settings/load.py | 4 +++- src/towncrier/test/test_build.py | 2 +- src/towncrier/test/test_format.py | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/towncrier/_builder.py b/src/towncrier/_builder.py index 9e48d583..b28e9156 100644 --- a/src/towncrier/_builder.py +++ b/src/towncrier/_builder.py @@ -316,9 +316,9 @@ def get_indent(text: str) -> str: versiondata=versiondata, top_underline=top_underline, get_indent=get_indent, # simplify indentation in the jinja template. - title_prefix = title_prefixes[0], - section_prefix = title_prefixes[1], - category_prefix = title_prefixes[2], + title_prefix=title_prefixes[0], + section_prefix=title_prefixes[1], + category_prefix=title_prefixes[2], ) for line in res.split("\n"): diff --git a/src/towncrier/_settings/load.py b/src/towncrier/_settings/load.py index 220049d4..7ab431a0 100644 --- a/src/towncrier/_settings/load.py +++ b/src/towncrier/_settings/load.py @@ -185,7 +185,9 @@ def parse_toml(base_path: str, config: Mapping[str, Any]) -> Config: title_format=config.get("title_format", _title_format), issue_format=config.get("issue_format"), underlines=config.get("underlines", _md_underlines if is_md else _underlines), - title_prefixes=config.get("title_prefixes", _md_prefixes if is_md else _prefixes), + title_prefixes=config.get( + "title_prefixes", _md_prefixes if is_md else _prefixes + ), wrap=wrap, all_bullets=all_bullets, orphan_prefix=config.get("orphan_prefix", "+"), diff --git a/src/towncrier/test/test_build.py b/src/towncrier/test/test_build.py index 3f0f92ca..f3378fef 100644 --- a/src/towncrier/test/test_build.py +++ b/src/towncrier/test/test_build.py @@ -1225,4 +1225,4 @@ def test_markdown_filename(self): - Adds levitation (#123) """ ).lstrip(), - ) + ) diff --git a/src/towncrier/test/test_format.py b/src/towncrier/test/test_format.py index 52c98739..28a75c23 100644 --- a/src/towncrier/test/test_format.py +++ b/src/towncrier/test/test_format.py @@ -158,7 +158,7 @@ def test_basic(self): underlines=["-", "~"], wrap=True, versiondata={"name": "MyProject", "version": "1.0", "date": "never"}, - title_prefixes = ["", "", ""] + title_prefixes=["", "", ""], ) output = render_fragments(**render_kwargs) self.assertEqual(output, expected_output) From a0dcb2276d0d37a34040795346ddbf3a7bc3b6a9 Mon Sep 17 00:00:00 2001 From: Chris Beaven Date: Thu, 29 Sep 2022 14:17:39 +1300 Subject: [PATCH 05/11] Add newsfragment and docs --- docs/configuration.rst | 4 +++- docs/tutorial.rst | 5 ++++- src/towncrier/newsfragments/439.feature | 9 +++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 src/towncrier/newsfragments/439.feature diff --git a/docs/configuration.rst b/docs/configuration.rst index 160ad60e..b6b47fd3 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -28,7 +28,9 @@ Top level keys - ``issue_format`` -- A format string for rendering the issue/ticket number in newsfiles. ``#{issue}`` by default. - ``underlines`` -- The characters used for underlining headers. - ``["=", "-", "~"]`` by default. + ``["=", "-", "~"]`` by default (unless ``filename`` has an ``.md`` extension, in which case it's ``["", "", ""]``). +- ``title_prefix`` -- Strings to prefix to the title, sections, and categories. + ``["", "", ""] by default (unless ``filename`` has an ``.md`` extension, in which case it is ``["# ", "## ", "### "]``). Custom fragment types diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 7b893b1d..10333480 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -1,7 +1,7 @@ Tutorial ======== -This tutorial assumes you have a Python project with a *reStructuredText* (rst) news file (also known as changelog) file that you wish to use ``towncrier`` on, to generate its news file. +This tutorial assumes you have a Python project with a *reStructuredText* (rst) or *markdown* (md) news file (also known as changelog) file that you wish to use ``towncrier`` on, to generate its news file. It will cover setting up your project with a basic configuration, which you can then feel free to `customize `_. Install from PyPI:: @@ -145,6 +145,9 @@ You should get an output similar to this:: - #1, #2 +Note: if you configure a markdown file (for example, ``filename = "CHANGES.md"`` in your configuration file), the titles will be output in markdown format instead. + + Producing News Files In Production ---------------------------------- diff --git a/src/towncrier/newsfragments/439.feature b/src/towncrier/newsfragments/439.feature new file mode 100644 index 00000000..69744364 --- /dev/null +++ b/src/towncrier/newsfragments/439.feature @@ -0,0 +1,9 @@ +We now have easy markdown-compatible rendering! + +When the configured filename has a ``.md`` extension, the default value of +``underlines`` and (the new) ``title_prefixes`` configuration values are +changed to ``["", "", ""]`` and ``["# ", "## ", "###"]``, respectively. + +The default template no longer renders an empty line for empty underlines +configurations, and templates are rendered with extra context for +``title_prefix``, ``section_prefix``, and ``category_prefix. \ No newline at end of file From e6277d5b5ac699947ed685b2778f5f7381bd3061 Mon Sep 17 00:00:00 2001 From: Chris Beaven Date: Thu, 29 Sep 2022 14:19:16 +1300 Subject: [PATCH 06/11] Fix docs formatting typo --- docs/configuration.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index b6b47fd3..a986d41f 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -30,7 +30,7 @@ Top level keys - ``underlines`` -- The characters used for underlining headers. ``["=", "-", "~"]`` by default (unless ``filename`` has an ``.md`` extension, in which case it's ``["", "", ""]``). - ``title_prefix`` -- Strings to prefix to the title, sections, and categories. - ``["", "", ""] by default (unless ``filename`` has an ``.md`` extension, in which case it is ``["# ", "## ", "### "]``). + ``["", "", ""]`` by default (unless ``filename`` has an ``.md`` extension, in which case it is ``["# ", "## ", "### "]``). Custom fragment types From 729f92512973a4ecee7543d10948cb6d6b7f5a3b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 01:20:13 +0000 Subject: [PATCH 07/11] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/configuration.rst | 2 +- src/towncrier/newsfragments/439.feature | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index a986d41f..da237c2a 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -30,7 +30,7 @@ Top level keys - ``underlines`` -- The characters used for underlining headers. ``["=", "-", "~"]`` by default (unless ``filename`` has an ``.md`` extension, in which case it's ``["", "", ""]``). - ``title_prefix`` -- Strings to prefix to the title, sections, and categories. - ``["", "", ""]`` by default (unless ``filename`` has an ``.md`` extension, in which case it is ``["# ", "## ", "### "]``). + ``["", "", ""]`` by default (unless ``filename`` has an ``.md`` extension, in which case it is ``["# ", "## ", "### "]``). Custom fragment types diff --git a/src/towncrier/newsfragments/439.feature b/src/towncrier/newsfragments/439.feature index 69744364..84752243 100644 --- a/src/towncrier/newsfragments/439.feature +++ b/src/towncrier/newsfragments/439.feature @@ -6,4 +6,4 @@ changed to ``["", "", ""]`` and ``["# ", "## ", "###"]``, respectively. The default template no longer renders an empty line for empty underlines configurations, and templates are rendered with extra context for -``title_prefix``, ``section_prefix``, and ``category_prefix. \ No newline at end of file +``title_prefix``, ``section_prefix``, and ``category_prefix. From 70f93645f67cac05ac3ee924c3e7d942ff1b2d70 Mon Sep 17 00:00:00 2001 From: Chris Beaven Date: Thu, 29 Sep 2022 15:36:08 +1300 Subject: [PATCH 08/11] Python's standard markdown implementation needs indentation and an empty line between bullets to render multi-line bullets correctly --- docs/configuration.rst | 4 ++++ src/towncrier/_builder.py | 12 ++++++---- src/towncrier/_settings/load.py | 16 +++++++++++++ src/towncrier/build.py | 6 ++++- src/towncrier/newsfragments/439.feature | 14 +++++++----- src/towncrier/templates/default.rst | 7 ++++-- src/towncrier/test/test_build.py | 11 +++++++-- src/towncrier/test/test_format.py | 30 ++++++++++++++++--------- 8 files changed, 74 insertions(+), 26 deletions(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index da237c2a..c638a1ec 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -31,6 +31,10 @@ Top level keys ``["=", "-", "~"]`` by default (unless ``filename`` has an ``.md`` extension, in which case it's ``["", "", ""]``). - ``title_prefix`` -- Strings to prefix to the title, sections, and categories. ``["", "", ""]`` by default (unless ``filename`` has an ``.md`` extension, in which case it is ``["# ", "## ", "### "]``). +- ``bullet`` -- The bullet string to use before issues. + ``"- "`` by default (unless ``filename`` has an ``.md`` extension, in which case it is ``" - "``). +- ``issues_spacing`` -- Add an empty newline between issues when rendering. + ``False`` by default (unless ``filename`` has an ``.md`` extension, in which case it is ``True``). Custom fragment types diff --git a/src/towncrier/_builder.py b/src/towncrier/_builder.py index b28e9156..7a20c871 100644 --- a/src/towncrier/_builder.py +++ b/src/towncrier/_builder.py @@ -163,7 +163,7 @@ def prefixed_lines() -> Iterator[str]: def split_fragments( fragments: Mapping[str, Mapping[tuple[str, str, int], str]], definitions: Mapping[str, Mapping[str, Any]], - all_bullets: bool = True, + bullet_indent: int | None = 2, ) -> Mapping[str, Mapping[str, Mapping[str, Sequence[str]]]]: output = OrderedDict() @@ -173,11 +173,11 @@ def split_fragments( for (ticket, category, counter), content in section_fragments.items(): - if all_bullets: - # By default all fragmetns are append by "-" automatically, + if bullet_indent: + # By default all fragments are append by "- " automatically, # and need to be indented because of that. # (otherwise, assume they are formatted correctly) - content = indent(content.strip(), " ")[2:] + content = indent(content.strip(), " " * bullet_indent)[bullet_indent:] else: # Assume the text is formatted correctly content = content.rstrip() @@ -252,6 +252,8 @@ def render_fragments( all_bullets: bool = False, render_title: bool = True, title_prefixes: Sequence[str] = ["", "", ""], + bullet: str = "- ", + issues_spaced: bool=False, ) -> str: """ Render the fragments into a news file. @@ -319,6 +321,8 @@ def get_indent(text: str) -> str: title_prefix=title_prefixes[0], section_prefix=title_prefixes[1], category_prefix=title_prefixes[2], + bullet=bullet, + issues_spaced=issues_spaced, ) for line in res.split("\n"): diff --git a/src/towncrier/_settings/load.py b/src/towncrier/_settings/load.py index 7ab431a0..db694f21 100644 --- a/src/towncrier/_settings/load.py +++ b/src/towncrier/_settings/load.py @@ -49,6 +49,8 @@ class Config: wrap: bool all_bullets: bool orphan_prefix: str + bullet: str + issues_spaced: bool class ConfigError(Exception): @@ -64,6 +66,18 @@ def __init__(self, *args: str, **kwargs: str): _md_underlines = ["", "", ""] _prefixes = ["", "", ""] _md_prefixes = ["# ", "## ", "### "] +_bullet = "- " +_md_bullet = " - " + + +# The default options differ when using a filename that has an extension of ``.md``: + +# Firstly, no underlines are used, but instead markdown h1, h2 and h3 prefixes are used +# for the title, categories, and sections respectively. + +# Secondly, Python's standard markdown implementation needs indentation and an empty +# line between bullets to render multi-line bullets correctly, so the bullet +# representation is ``" - "`` and the ``issues_spaced`` defaults to True. def load_config_from_options( @@ -189,6 +203,8 @@ def parse_toml(base_path: str, config: Mapping[str, Any]) -> Config: "title_prefixes", _md_prefixes if is_md else _prefixes ), wrap=wrap, + bullet=_md_bullet if is_md else _bullet, + issues_spaced=is_md, all_bullets=all_bullets, orphan_prefix=config.get("orphan_prefix", "+"), ) diff --git a/src/towncrier/build.py b/src/towncrier/build.py index a7d17ae6..a84118eb 100644 --- a/src/towncrier/build.py +++ b/src/towncrier/build.py @@ -138,7 +138,9 @@ def __main( click.echo("Rendering news fragments...", err=to_err) fragments = split_fragments( - fragment_contents, config.types, all_bullets=config.all_bullets + fragment_contents, + config.types, + bullet_indent=config.all_bullets and len(config.bullet), ) if project_version is None: @@ -194,6 +196,8 @@ def __main( all_bullets=config.all_bullets, render_title=render_title_with_fragments, title_prefixes=config.title_prefixes, + bullet=config.bullet, + issues_spaced=config.issues_spaced, ) if render_title_separately: diff --git a/src/towncrier/newsfragments/439.feature b/src/towncrier/newsfragments/439.feature index 84752243..0ce3fa87 100644 --- a/src/towncrier/newsfragments/439.feature +++ b/src/towncrier/newsfragments/439.feature @@ -1,9 +1,11 @@ We now have easy markdown-compatible rendering! -When the configured filename has a ``.md`` extension, the default value of -``underlines`` and (the new) ``title_prefixes`` configuration values are -changed to ``["", "", ""]`` and ``["# ", "## ", "###"]``, respectively. +When the configured filename has a ``.md`` extension: the title, sections, and +newsfragment categories are output respectively with #, ## and ### markdown +headings prefixed (and without any underlines). Bulleted issues are also +indented, with multi-line spaces between to rendered correctly with Python's +standard markdown implementation. -The default template no longer renders an empty line for empty underlines -configurations, and templates are rendered with extra context for -``title_prefix``, ``section_prefix``, and ``category_prefix. +The default template no longer renders an empty newline for empty underlines +configurations, and templates are rendered with extra context for ``bullet``, +``title_prefix``, ``section_prefix``, and ``category_prefix``. diff --git a/src/towncrier/templates/default.rst b/src/towncrier/templates/default.rst index 704c4211..2d1cb255 100644 --- a/src/towncrier/templates/default.rst +++ b/src/towncrier/templates/default.rst @@ -28,12 +28,15 @@ {% if definitions[category]['showcontent'] %} {% for text, values in sections[section][category].items() %} -- {{ text }}{% if values %} ({{ values|join(', ') }}){% endif %} +{{ bullet }}{{ text }}{% if values %} ({{ values|join(', ') }}){% endif %} +{% if issues_spaced and not loop.last %} + +{% endif %} {% endfor %} {% else %} -- {{ sections[section][category]['']|join(', ') }} +{{ bullet }}{{ sections[section][category]['']|join(', ') }} {% endif %} {% if not sections[section][category] %} diff --git a/src/towncrier/test/test_build.py b/src/towncrier/test/test_build.py index f3378fef..2e0c2fc6 100644 --- a/src/towncrier/test/test_build.py +++ b/src/towncrier/test/test_build.py @@ -1186,6 +1186,7 @@ def test_markdown_filename(self): with runner.isolated_filesystem(): setup_simple_project(extra_config='filename = "CHANGES.md"') Path("foo/newsfragments/123.feature").write_text("Adds levitation") + Path("foo/newsfragments/456.feature").write_text("Revert levitation change\nIt was a bad idea...") draft_result = runner.invoke(_main, ["--date=01-01-2001", "--draft"]) self.assertEqual(0, draft_result.exit_code, draft_result.output) @@ -1203,7 +1204,10 @@ def test_markdown_filename(self): ### Features - - Adds levitation (#123) + - Adds levitation (#123) + + - Revert levitation change + It was a bad idea... (#456) """ ).lstrip(), @@ -1222,7 +1226,10 @@ def test_markdown_filename(self): ### Features - - Adds levitation (#123) + - Adds levitation (#123) + + - Revert levitation change + It was a bad idea... (#456) """ ).lstrip(), ) diff --git a/src/towncrier/test/test_format.py b/src/towncrier/test/test_format.py index 28a75c23..1fbbd23b 100644 --- a/src/towncrier/test/test_format.py +++ b/src/towncrier/test/test_format.py @@ -57,7 +57,7 @@ def test_basic(self): Basic functionality -- getting a bunch of news fragments and formatting them into a rST file -- works. """ - fragments = OrderedDict( + raw_fragments = OrderedDict( [ ( "", @@ -72,7 +72,7 @@ def test_basic(self): ("2", "feature", 0): "Foo added.", ("72", "feature", 0): "Foo added.", ("9", "feature", 0): "Foo added.", - ("baz", "feature", 0): "Fun!", + ("baz", "feature", 0): "Fun!\nLines.", }, ), ("Names", {}), @@ -94,7 +94,8 @@ def test_basic(self): Features -------- -- Fun! (baz) +- Fun! + Lines. (baz) - Foo added. (#2, #9, #72) - Stuff! (#4) @@ -123,14 +124,17 @@ def test_basic(self): ### Features -- Fun! (baz) -- Foo added. (#2, #9, #72) -- Stuff! (#4) + - Fun! + Lines. (baz) + + - Foo added. (#2, #9, #72) + + - Stuff! (#4) ### Misc -- bar, #1, #9, #142 + - bar, #1, #9, #142 ## Names @@ -142,14 +146,14 @@ def test_basic(self): ### Bugfixes -- Web fixed. (#3) + - Web fixed. (#3) """ template = pkg_resources.resource_string( "towncrier", "templates/default.rst" ).decode("utf8") - fragments = split_fragments(fragments, definitions) + fragments = split_fragments(raw_fragments, definitions) render_kwargs = dict( template=template, issue_format=None, @@ -165,8 +169,11 @@ def test_basic(self): render_kwargs["top_underline"] = "" render_kwargs["underlines"] = ["", ""] render_kwargs["title_prefixes"] = ["# ", "## ", "### "] + render_kwargs["bullet"] = " - " + render_kwargs["issues_spaced"] = True + + render_kwargs["fragments"] = split_fragments(raw_fragments, definitions, bullet_indent=4) output = render_fragments(**render_kwargs) - print(output) self.assertEqual(output, expected_md_output) # Check again with non-default underlines @@ -176,7 +183,8 @@ def test_basic(self): Features ******** -- Fun! (baz) +- Fun! + Lines. (baz) - Foo added. (#2, #9, #72) - Stuff! (#4) From 7bacdcf434e11d0079e6f05047a4b89d5189346d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 02:46:12 +0000 Subject: [PATCH 09/11] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/towncrier/_builder.py | 2 +- src/towncrier/test/test_build.py | 4 +++- src/towncrier/test/test_format.py | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/towncrier/_builder.py b/src/towncrier/_builder.py index 7a20c871..1aed025c 100644 --- a/src/towncrier/_builder.py +++ b/src/towncrier/_builder.py @@ -253,7 +253,7 @@ def render_fragments( render_title: bool = True, title_prefixes: Sequence[str] = ["", "", ""], bullet: str = "- ", - issues_spaced: bool=False, + issues_spaced: bool = False, ) -> str: """ Render the fragments into a news file. diff --git a/src/towncrier/test/test_build.py b/src/towncrier/test/test_build.py index 2e0c2fc6..24a9f5a2 100644 --- a/src/towncrier/test/test_build.py +++ b/src/towncrier/test/test_build.py @@ -1186,7 +1186,9 @@ def test_markdown_filename(self): with runner.isolated_filesystem(): setup_simple_project(extra_config='filename = "CHANGES.md"') Path("foo/newsfragments/123.feature").write_text("Adds levitation") - Path("foo/newsfragments/456.feature").write_text("Revert levitation change\nIt was a bad idea...") + Path("foo/newsfragments/456.feature").write_text( + "Revert levitation change\nIt was a bad idea..." + ) draft_result = runner.invoke(_main, ["--date=01-01-2001", "--draft"]) self.assertEqual(0, draft_result.exit_code, draft_result.output) diff --git a/src/towncrier/test/test_format.py b/src/towncrier/test/test_format.py index 1fbbd23b..e1e1d797 100644 --- a/src/towncrier/test/test_format.py +++ b/src/towncrier/test/test_format.py @@ -172,7 +172,9 @@ def test_basic(self): render_kwargs["bullet"] = " - " render_kwargs["issues_spaced"] = True - render_kwargs["fragments"] = split_fragments(raw_fragments, definitions, bullet_indent=4) + render_kwargs["fragments"] = split_fragments( + raw_fragments, definitions, bullet_indent=4 + ) output = render_fragments(**render_kwargs) self.assertEqual(output, expected_md_output) From 904d266d53b1278aa1f124e59e5d83c82a0e1653 Mon Sep 17 00:00:00 2001 From: Chris Beaven Date: Thu, 29 Sep 2022 15:55:20 +1300 Subject: [PATCH 10/11] Fix test for windows --- src/towncrier/test/test_build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/towncrier/test/test_build.py b/src/towncrier/test/test_build.py index 24a9f5a2..4502af9d 100644 --- a/src/towncrier/test/test_build.py +++ b/src/towncrier/test/test_build.py @@ -1187,7 +1187,7 @@ def test_markdown_filename(self): setup_simple_project(extra_config='filename = "CHANGES.md"') Path("foo/newsfragments/123.feature").write_text("Adds levitation") Path("foo/newsfragments/456.feature").write_text( - "Revert levitation change\nIt was a bad idea..." + "Revert levitation change\r\nIt was a bad idea..." ) draft_result = runner.invoke(_main, ["--date=01-01-2001", "--draft"]) From ea7d1a69579801e61e6b2e4646cff0e45d364f23 Mon Sep 17 00:00:00 2001 From: Chris Beaven Date: Thu, 29 Sep 2022 16:06:12 +1300 Subject: [PATCH 11/11] Try to fix windows test again --- src/towncrier/test/test_build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/towncrier/test/test_build.py b/src/towncrier/test/test_build.py index 4502af9d..12f77e2b 100644 --- a/src/towncrier/test/test_build.py +++ b/src/towncrier/test/test_build.py @@ -1187,7 +1187,7 @@ def test_markdown_filename(self): setup_simple_project(extra_config='filename = "CHANGES.md"') Path("foo/newsfragments/123.feature").write_text("Adds levitation") Path("foo/newsfragments/456.feature").write_text( - "Revert levitation change\r\nIt was a bad idea..." + "Revert levitation change\nIt was a bad idea...", newline="" ) draft_result = runner.invoke(_main, ["--date=01-01-2001", "--draft"])