diff --git a/README.rst b/README.rst index 1c79c9d9..0e805872 100644 --- a/README.rst +++ b/README.rst @@ -137,7 +137,7 @@ Towncrier has the following global options, which can be specified in the toml f version = "1.2.3" # project version if maintained separately name = "arbitrary project name" template = "path/to/template.rst" - start_line = "start of generated content" + start_string = "Text used to detect where to add the generated content in the middle of a file. Generated content added after this text. Newline auto added." title_format = "{name} {version} ({project_date})" # or false if template includes title issue_format = "format string for {issue} (issue is the first part of fragment name)" underlines: "=-~" diff --git a/src/towncrier/_settings.py b/src/towncrier/_settings.py index f84dcb99..e1bdb2f5 100644 --- a/src/towncrier/_settings.py +++ b/src/towncrier/_settings.py @@ -149,7 +149,7 @@ def parse_toml(base_path, config): "sections": sections, "types": types, "template": template, - "start_line": config.get("start_string", _start_string), + "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), diff --git a/src/towncrier/_writer.py b/src/towncrier/_writer.py index 1a2c31dc..a09a72d1 100644 --- a/src/towncrier/_writer.py +++ b/src/towncrier/_writer.py @@ -13,7 +13,7 @@ def append_to_newsfile( - directory, filename, start_line, top_line, content, single_file=True + directory, filename, start_string, top_line, content, single_file=True ): news_file = os.path.join(directory, filename) @@ -24,7 +24,7 @@ def append_to_newsfile( else: with io.open(news_file, "r", encoding="utf8") as f: existing_content = f.read() - existing_content = existing_content.split(start_line, 1) + existing_content = existing_content.split(start_string, 1) else: existing_content = [u""] @@ -35,11 +35,12 @@ def append_to_newsfile( if len(existing_content) > 1: f.write(existing_content.pop(0).rstrip().encode("utf8")) - if start_line: - f.write((u"\n\n" + start_line + u"\n").encode("utf8")) + if start_string: + f.write((u"\n\n" + start_string + u"\n").encode("utf8")) f.write(top_line.encode("utf8")) f.write(content.encode("utf8")) - if existing_content[0]: - f.write(b"\n\n") - f.write(existing_content[0].lstrip().encode("utf8")) + if existing_content: + if existing_content[0]: + f.write(b"\n\n") + f.write(existing_content[0].lstrip().encode("utf8")) diff --git a/src/towncrier/build.py b/src/towncrier/build.py index 18b606c7..2f02eec2 100644 --- a/src/towncrier/build.py +++ b/src/towncrier/build.py @@ -167,7 +167,7 @@ def __main( click.echo(rendered) else: click.echo("Writing to newsfile...", err=to_err) - start_line = config["start_line"] + start_string = config["start_string"] news_file = config["filename"] if config["single_file"]: @@ -179,7 +179,7 @@ def __main( append_to_newsfile( base_directory, news_file, - start_line, + start_string, top_line, rendered, single_file=config["single_file"], diff --git a/src/towncrier/newsfragments/277.doc.rst b/src/towncrier/newsfragments/277.doc.rst new file mode 100644 index 00000000..ef22943d --- /dev/null +++ b/src/towncrier/newsfragments/277.doc.rst @@ -0,0 +1 @@ +``start_line`` corrected to ``start_string`` in the readme to match the long standing implementation. diff --git a/src/towncrier/test/test_build.py b/src/towncrier/test/test_build.py index 29ad6130..fb3955f7 100644 --- a/src/towncrier/test/test_build.py +++ b/src/towncrier/test/test_build.py @@ -779,3 +779,60 @@ def test_title_format_false(self): self.assertEqual(0, result.exit_code) self.assertEqual(expected_output, result.output) + + def test_start_string(self): + """ + The `start_string` configuration is used to detect the starting point + for inserting the generated release notes. A newline is automatically + added to the configured value. + """ + runner = CliRunner() + + with runner.isolated_filesystem(): + with open("pyproject.toml", "w") as f: + f.write(dedent("""\ + [tool.towncrier] + start_string="Release notes start marker" + """)) + os.mkdir("newsfragments") + with open("newsfragments/123.feature", "w") as f: + f.write("Adds levitation") + with open("NEWS.rst", "w") as f: + f.write("a line\n\nanother\n\nRelease notes start marker\n") + + result = runner.invoke( + _main, + [ + "--version", + "7.8.9", + "--name", + "foo", + "--date", + "01-01-2001", + "--yes", + ], + ) + + self.assertEqual(0, result.exit_code, result.output) + self.assertTrue(os.path.exists("NEWS.rst"), os.listdir(".")) + with open("NEWS.rst", "r") as f: + output = f.read() + + expected_output = dedent("""\ + a line + + another + + Release notes start marker + foo 7.8.9 (01-01-2001) + ====================== + + Features + -------- + + - Adds levitation (#123) + + + """) + + self.assertEqual(expected_output, output) diff --git a/src/towncrier/test/test_write.py b/src/towncrier/test/test_write.py index 7ad4853e..12c5bad8 100644 --- a/src/towncrier/test/test_write.py +++ b/src/towncrier/test/test_write.py @@ -5,6 +5,7 @@ import pkg_resources import os +from textwrap import dedent from collections import OrderedDict @@ -226,3 +227,47 @@ def test_append_at_top_with_hint(self): output = f.read() self.assertEqual(expected_output, output) + + def test_multiple_file_no_start_string(self): + """ + When no `start_string` is defined, the generated content is added at + the start of the file. + """ + tempdir = self.mktemp() + os.mkdir(tempdir) + + definitions = {} + fragments = split_fragments(fragments={}, definitions=definitions) + + template = pkg_resources.resource_string( + "towncrier", "templates/default.rst" + ).decode("utf8") + + content = render_fragments( + template=template, + issue_format=None, + top_line="", + fragments=fragments, + definitions=definitions, + underlines=["-", "~"], + wrap=True, + versiondata={"name": "MyProject", "version": "1.0", "date": "never"}, + ) + + append_to_newsfile( + directory=tempdir, + filename="NEWS.rst", + start_string=None, + top_line="", + content=content, + ) + + with open(os.path.join(tempdir, "NEWS.rst"), "r") as f: + output = f.read() + + expected_output = dedent("""\ + MyProject 1.0 (never) + ===================== + """) + + self.assertEqual(expected_output, output)