From 41781d96a7774304962b08a9b49aab0404a75516 Mon Sep 17 00:00:00 2001 From: Amber Brown Date: Mon, 6 May 2019 15:00:26 -0400 Subject: [PATCH 1/4] fixes --- src/towncrier/__init__.py | 39 +++++++++------ src/towncrier/_builder.py | 18 ++++++- src/towncrier/_project.py | 6 +-- src/towncrier/_settings.py | 2 +- src/towncrier/_writer.py | 3 +- src/towncrier/check.py | 10 ++-- src/towncrier/templates/template.rst | 2 + src/towncrier/test/test_check.py | 22 ++------- src/towncrier/test/test_cli.py | 15 ++---- src/towncrier/test/test_format.py | 72 ++++++++++++++++++++-------- src/towncrier/test/test_write.py | 28 +++++++---- 11 files changed, 133 insertions(+), 84 deletions(-) diff --git a/src/towncrier/__init__.py b/src/towncrier/__init__.py index 14fd7c0c..d0fa4ad8 100644 --- a/src/towncrier/__init__.py +++ b/src/towncrier/__init__.py @@ -91,20 +91,11 @@ def __main(draft, directory, project_name, project_version, project_date, answer click.echo("Rendering news fragments...", err=to_err) fragments = split_fragments(fragments, definitions) - rendered = render_fragments( - # The 0th underline is used for the top line - template, - config["issue_format"], - fragments, - definitions, - config["underlines"][1:], - config["wrap"], - ) if project_version is None: project_version = get_version( os.path.join(directory, config["package_dir"]), config["package"] - ) + ).strip() if project_name is None: package = config.get("package") @@ -117,12 +108,27 @@ def __main(draft, directory, project_name, project_version, project_date, answer project_name = "" if project_date is None: - project_date = _get_date() + project_date = _get_date().strip() + + if config["title_format"]: + top_line = config["title_format"].format( + name=project_name, version=project_version, project_date=project_date + ) + top_line += u"\n" + (config["underlines"][0] * len(top_line)) + u"\n" + else: + top_line = "" - top_line = config["title_format"].format( - name=project_name, version=project_version, project_date=project_date + rendered = render_fragments( + # The 0th underline is used for the top line + template, + config["issue_format"], + fragments, + definitions, + config["underlines"][1:], + config["wrap"], + {"name": project_name, "version": project_version, "date": project_date}, + top_underline=config["underlines"][0], ) - top_line += u"\n" + (config["underlines"][0] * len(top_line)) + u"\n" if draft: click.echo( @@ -130,7 +136,10 @@ def __main(draft, directory, project_name, project_version, project_date, answer "What is seen below is what would be written.\n", err=to_err, ) - click.echo("%s\n%s" % (top_line, rendered)) + if top_line: + click.echo("\n%s\n%s" % (top_line, rendered)) + else: + click.echo(rendered) else: click.echo("Writing to newsfile...", err=to_err) start_line = config["start_line"] diff --git a/src/towncrier/_builder.py b/src/towncrier/_builder.py index 41437ab4..e1314f39 100644 --- a/src/towncrier/_builder.py +++ b/src/towncrier/_builder.py @@ -92,6 +92,7 @@ def indent(text, prefix): def prefixed_lines(): for line in text.splitlines(True): yield (prefix + line if line.strip() else line) + return u"".join(prefixed_lines()) @@ -153,7 +154,16 @@ def render_issue(issue_format, issue): return issue_format.format(issue=issue) -def render_fragments(template, issue_format, fragments, definitions, underlines, wrap): +def render_fragments( + template, + issue_format, + fragments, + definitions, + underlines, + wrap, + versiondata, + top_underline="=", +): """ Render the fragments into a news file. """ @@ -198,7 +208,11 @@ def render_fragments(template, issue_format, fragments, definitions, underlines, done = [] res = jinja_template.render( - sections=data, definitions=definitions, underlines=underlines + sections=data, + definitions=definitions, + underlines=underlines, + versiondata=versiondata, + top_underline=top_underline, ) for line in res.split(u"\n"): diff --git a/src/towncrier/_project.py b/src/towncrier/_project.py index bd21084e..7b337982 100644 --- a/src/towncrier/_project.py +++ b/src/towncrier/_project.py @@ -50,13 +50,13 @@ def get_version(package_dir, package): raise Exception("No __version__, I don't know how else to look") if isinstance(version, str): - return version + return version.strip() if isinstance(version, Version): - return version.base() + return version.base().strip() if isinstance(version, tuple): - return ".".join(map(str, version)) + return ".".join(map(str, version)).strip() raise Exception( ( diff --git a/src/towncrier/_settings.py b/src/towncrier/_settings.py index 9913134e..4e1794d9 100644 --- a/src/towncrier/_settings.py +++ b/src/towncrier/_settings.py @@ -8,7 +8,7 @@ _start_string = u".. towncrier release notes start\n" -_title_format = u"{name} {version} ({project_date})" +_title_format = None _template_fname = None _default_types = OrderedDict( [ diff --git a/src/towncrier/_writer.py b/src/towncrier/_writer.py index a42e9fa4..7d2644b6 100644 --- a/src/towncrier/_writer.py +++ b/src/towncrier/_writer.py @@ -30,7 +30,8 @@ def append_to_newsfile(directory, filename, start_line, top_line, content): if len(existing_content) > 1: f.write(existing_content.pop(0).rstrip().encode("utf8")) - f.write((u"\n\n" + start_line + u"\n").encode("utf8")) + if start_line: + f.write((u"\n\n" + start_line + u"\n").encode("utf8")) f.write(top_line.encode("utf8")) f.write(content.encode("utf8")) diff --git a/src/towncrier/check.py b/src/towncrier/check.py index f10e2721..bdb140fe 100644 --- a/src/towncrier/check.py +++ b/src/towncrier/check.py @@ -8,11 +8,7 @@ import click -from subprocess import ( - CalledProcessError, - check_output, - STDOUT, -) +from subprocess import CalledProcessError, check_output, STDOUT from ._settings import load_config, load_config_from_file from ._builder import find_fragments @@ -40,7 +36,9 @@ def __main(comparewith, directory, pyproject): try: files_changed = ( - _run(["git", "diff", "--name-only", comparewith + "..."], cwd=base_directory) + _run( + ["git", "diff", "--name-only", comparewith + "..."], cwd=base_directory + ) .decode(getattr(sys.stdout, "encoding", "utf8")) .strip() ) diff --git a/src/towncrier/templates/template.rst b/src/towncrier/templates/template.rst index d77e1c10..e6f10836 100644 --- a/src/towncrier/templates/template.rst +++ b/src/towncrier/templates/template.rst @@ -1,3 +1,5 @@ +{{ versiondata.name }} {{ versiondata.version }} ({{ versiondata.date }}) +{{ top_underline * ((versiondata.name + versiondata.version + versiondata.date)|length + 4)}} {% for section, _ in sections.items() %} {% set underline = underlines[0] %}{% if section %}{{section}} {{ underline * section|length }}{% set underline = underlines[1] %} diff --git a/src/towncrier/test/test_check.py b/src/towncrier/test/test_check.py index d4d7c39d..6cf01d16 100644 --- a/src/towncrier/test/test_check.py +++ b/src/towncrier/test/test_check.py @@ -42,19 +42,12 @@ def test_git_fails(self): create_project("pyproject.toml") result = runner.invoke(_main, ["--compare-with", "hblaugh"]) - self.assertIn( - "git produced output while failing", - result.output, - ) - self.assertIn( - "hblaugh", - result.output, - ) + self.assertIn("git produced output while failing", result.output) + self.assertIn("hblaugh", result.output) def test_no_changes_made(self): self._test_no_changes_made( - "pyproject.toml", - lambda runner, main, argv: runner.invoke(main, argv), + "pyproject.toml", lambda runner, main, argv: runner.invoke(main, argv) ) def test_no_changes_made_pyproject_path(self): @@ -62,8 +55,7 @@ def test_no_changes_made_pyproject_path(self): self._test_no_changes_made( pyproject, lambda runner, main, argv: runner.invoke( - main, - argv + ["--pyproject", pyproject], + main, argv + ["--pyproject", pyproject] ), ) @@ -108,11 +100,7 @@ def test_fragment_exists(self): ), result, ) - self.assertEqual( - 0, - result.exit_code, - result, - ) + self.assertEqual(0, result.exit_code, result) def test_fragment_missing(self): runner = CliRunner() diff --git a/src/towncrier/test/test_cli.py b/src/towncrier/test/test_cli.py index 1cf3232e..c820038e 100644 --- a/src/towncrier/test/test_cli.py +++ b/src/towncrier/test/test_cli.py @@ -47,8 +47,8 @@ def test_happy_path(self): u"Loading template...\nFinding news fragments...\nRendering news " u"fragments...\nDraft only -- nothing has been written.\nWhat is " u"seen below is what would be written.\n\nFoo 1.2.3 (01-01-2001)" - u"\n======================\n" - u"\n\nFeatures\n--------\n\n- Adds levitation (#123)\n" + u"\n======================\n\n" + u"Features\n--------\n\n- Adds levitation (#123)\n" u"- Extends levitation (#124)\n\n", ) @@ -140,7 +140,7 @@ def run_order_scenario(sections, types): u"Loading template...\nFinding news fragments...\nRendering news " u"fragments...\nDraft only -- nothing has been written.\nWhat is " u"seen below is what would be written.\n\nFoo 1.2.3 (01-01-2001)" - u"\n======================\n" + u"\n======================" + dedent( """ section-a @@ -183,7 +183,7 @@ def run_order_scenario(sections, types): u"Loading template...\nFinding news fragments...\nRendering news " u"fragments...\nDraft only -- nothing has been written.\nWhat is " u"seen below is what would be written.\n\nFoo 1.2.3 (01-01-2001)" - u"\n======================\n" + u"\n======================" + dedent( """ section-b @@ -291,7 +291,6 @@ def test_projectless_changelog(self): FooBarBaz 7.8.9 (01-01-2001) ============================ - Features -------- @@ -314,10 +313,6 @@ def test_no_package_changelog(self): runner = CliRunner() with runner.isolated_filesystem(): - with open("pyproject.toml", "w") as f: - f.write( - "[tool.towncrier]\n" 'title_format = "{version} ({project_date})"\n' - ) os.mkdir("newsfragments") with open("newsfragments/123.feature", "w") as f: f.write("Adds levitation") @@ -326,6 +321,7 @@ def test_no_package_changelog(self): _main, ["--version", "7.8.9", "--date", "01-01-2001", "--draft"] ) + print(result.stderr) self.assertEqual(0, result.exit_code) self.assertEqual( result.output, @@ -340,7 +336,6 @@ def test_no_package_changelog(self): 7.8.9 (01-01-2001) ================== - Features -------- diff --git a/src/towncrier/test/test_format.py b/src/towncrier/test/test_format.py index 3b95f972..8d5ecc27 100644 --- a/src/towncrier/test/test_format.py +++ b/src/towncrier/test/test_format.py @@ -89,8 +89,9 @@ def test_basic(self): ] ) - expected_output = ( - u""" + expected_output = u"""MyProject 1.0 (never) +===================== + Features -------- @@ -119,7 +120,6 @@ def test_basic(self): - Web fixed. (#3) """ - ) template = pkg_resources.resource_string( "towncrier", "templates/template.rst" @@ -127,13 +127,20 @@ def test_basic(self): fragments = split_fragments(fragments, definitions) output = render_fragments( - template, None, fragments, definitions, ["-", "~"], wrap=True + template, + None, + fragments, + definitions, + ["-", "~"], + wrap=True, + versiondata={"name": "MyProject", "version": "1.0", "date": "never"}, ) self.assertEqual(output, expected_output) # Check again with non-default underlines - expected_output_weird_underlines = ( - u""" + expected_output_weird_underlines = u"""MyProject 1.0 (never) +===================== + Features ******** @@ -162,10 +169,15 @@ def test_basic(self): - Web fixed. (#3) """ - ) output = render_fragments( - template, None, fragments, definitions, ["*", "^"], wrap=True + template, + None, + fragments, + definitions, + ["*", "^"], + wrap=True, + versiondata={"name": "MyProject", "version": "1.0", "date": "never"}, ) self.assertEqual(output, expected_output_weird_underlines) @@ -189,14 +201,14 @@ def test_issue_format(self): definitions = OrderedDict([("misc", {"name": "Misc", "showcontent": False})]) - expected_output = ( - u""" + expected_output = u"""MyProject 1.0 (never) +===================== + Misc ---- - xxbar, xx1, xx9, xx142 """ - ) template = pkg_resources.resource_string( "towncrier", "templates/template.rst" @@ -204,7 +216,13 @@ def test_issue_format(self): fragments = split_fragments(fragments, definitions) output = render_fragments( - template, u"xx{issue}", fragments, definitions, ["-", "~"], wrap=True + template, + u"xx{issue}", + fragments, + definitions, + ["-", "~"], + wrap=True, + versiondata={"name": "MyProject", "version": "1.0", "date": "never"}, ) self.assertEqual(output, expected_output) @@ -233,8 +251,9 @@ def test_line_wrapping(self): [("feature", {"name": "Features", "showcontent": True})] ) - expected_output = ( - u""" + expected_output = u"""MyProject 1.0 (never) +===================== + Features -------- @@ -248,7 +267,6 @@ def test_line_wrapping(self): a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a (#3) """ - ) template = pkg_resources.resource_string( "towncrier", "templates/template.rst" @@ -256,7 +274,13 @@ def test_line_wrapping(self): fragments = split_fragments(fragments, definitions) output = render_fragments( - template, None, fragments, definitions, ["-", "~"], wrap=True + template, + None, + fragments, + definitions, + ["-", "~"], + wrap=True, + versiondata={"name": "MyProject", "version": "1.0", "date": "never"}, ) self.assertEqual(output, expected_output) @@ -271,7 +295,7 @@ def test_line_wrapping_disabled(self): ( "1", "feature", - 0 + 0, ): u""" asdf asdf asdf asdf looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong newsfragment. """, # NOQA @@ -284,8 +308,9 @@ def test_line_wrapping_disabled(self): [("feature", {"name": "Features", "showcontent": True})] ) - expected_output = ( - u""" + expected_output = u"""MyProject 1.0 (never) +===================== + Features -------- @@ -293,7 +318,6 @@ def test_line_wrapping_disabled(self): - https://google.com/q=?---------------------------------------------------------------------------------------------------- (#2) - a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a (#3) """ # NOQA - ) template = pkg_resources.resource_string( "towncrier", "templates/template.rst" @@ -301,6 +325,12 @@ def test_line_wrapping_disabled(self): fragments = split_fragments(fragments, definitions) output = render_fragments( - template, None, fragments, definitions, ["-", "~"], wrap=False + template, + None, + fragments, + definitions, + ["-", "~"], + wrap=False, + versiondata={"name": "MyProject", "version": "1.0", "date": "never"}, ) self.assertEqual(output, expected_output) diff --git a/src/towncrier/test/test_write.py b/src/towncrier/test/test_write.py index 372bf0a1..cdad7423 100644 --- a/src/towncrier/test/test_write.py +++ b/src/towncrier/test/test_write.py @@ -43,8 +43,8 @@ def test_append_at_top(self): ] ) - expected_output = """MyProject 1.0 -============= + expected_output = """MyProject 1.0 (never) +===================== Features -------- @@ -94,9 +94,15 @@ def test_append_at_top(self): tempdir, "NEWS.rst", ".. towncrier release notes start\n", - "MyProject 1.0\n=============\n", + "", render_fragments( - template, None, fragments, definitions, ["-", "~"], wrap=True + template, + None, + fragments, + definitions, + ["-", "~"], + wrap=True, + versiondata={"name": "MyProject", "version": "1.0", "date": "never"}, ), ) @@ -140,8 +146,8 @@ def test_append_at_top_with_hint(self): .. towncrier release notes start -MyProject 1.0 -============= +MyProject 1.0 (never) +===================== Features -------- @@ -202,9 +208,15 @@ def test_append_at_top_with_hint(self): tempdir, "NEWS.rst", ".. towncrier release notes start\n", - "MyProject 1.0\n=============\n", + "", render_fragments( - template, None, fragments, definitions, ["-", "~"], wrap=True + template, + None, + fragments, + definitions, + ["-", "~"], + wrap=True, + versiondata={"name": "MyProject", "version": "1.0", "date": "never"}, ), ) From 99a0087b276ee9a71953d6bb7be52226bbab299b Mon Sep 17 00:00:00 2001 From: Amber Brown Date: Mon, 6 May 2019 15:29:07 -0400 Subject: [PATCH 2/4] fix --- src/towncrier/__init__.py | 2 +- src/towncrier/_settings.py | 7 ++++--- src/towncrier/_writer.py | 2 +- src/towncrier/templates/template.rst | 5 +++++ src/towncrier/test/test_cli.py | 1 - 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/towncrier/__init__.py b/src/towncrier/__init__.py index d0fa4ad8..bbb5ccc5 100644 --- a/src/towncrier/__init__.py +++ b/src/towncrier/__init__.py @@ -64,7 +64,7 @@ def __main(draft, directory, project_name, project_version, project_date, answer to_err = draft click.echo("Loading template...", err=to_err) - if config["template"] is None: + if config.get("template") is None: template = pkg_resources.resource_string( __name__, "templates/template.rst" ).decode("utf8") diff --git a/src/towncrier/_settings.py b/src/towncrier/_settings.py index 4e1794d9..83d88b73 100644 --- a/src/towncrier/_settings.py +++ b/src/towncrier/_settings.py @@ -28,9 +28,10 @@ def load_config(directory): def load_config_from_file(from_file): if not os.path.exists(from_file): - return None - with open(from_file, "r") as conffile: - config = toml.load(conffile) + config = {"tool": {"towncrier": {}}} + else: + with open(from_file, "r") as conffile: + config = toml.load(conffile) return parse_toml(config) diff --git a/src/towncrier/_writer.py b/src/towncrier/_writer.py index 7d2644b6..d0da0317 100644 --- a/src/towncrier/_writer.py +++ b/src/towncrier/_writer.py @@ -23,7 +23,7 @@ def append_to_newsfile(directory, filename, start_line, top_line, content): existing_content = existing_content.split(start_line, 1) - if top_line in existing_content: + if top_line and top_line in existing_content: raise ValueError("It seems you've already produced newsfiles for this version?") with open(os.path.join(directory, filename), "wb") as f: diff --git a/src/towncrier/templates/template.rst b/src/towncrier/templates/template.rst index e6f10836..362d8e17 100644 --- a/src/towncrier/templates/template.rst +++ b/src/towncrier/templates/template.rst @@ -1,5 +1,10 @@ +{% 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)}} +{% endif %} {% for section, _ in sections.items() %} {% set underline = underlines[0] %}{% if section %}{{section}} {{ underline * section|length }}{% set underline = underlines[1] %} diff --git a/src/towncrier/test/test_cli.py b/src/towncrier/test/test_cli.py index c820038e..b08c173c 100644 --- a/src/towncrier/test/test_cli.py +++ b/src/towncrier/test/test_cli.py @@ -321,7 +321,6 @@ def test_no_package_changelog(self): _main, ["--version", "7.8.9", "--date", "01-01-2001", "--draft"] ) - print(result.stderr) self.assertEqual(0, result.exit_code) self.assertEqual( result.output, From 02f6e5d33ba9b24c4a323b1588e222f1e0f9a771 Mon Sep 17 00:00:00 2001 From: "Amber H. Brown" Date: Mon, 12 Aug 2019 02:01:05 +1000 Subject: [PATCH 3/4] fix --- src/towncrier/test/test_cli.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/towncrier/test/test_cli.py b/src/towncrier/test/test_cli.py index 3e418269..cfbee479 100644 --- a/src/towncrier/test/test_cli.py +++ b/src/towncrier/test/test_cli.py @@ -61,7 +61,6 @@ def test_happy_path(self): Foo 1.2.3 (01-01-2001) ====================== - Features -------- From bbb4035fc4be6aeff7a5039faf1989997a1638a7 Mon Sep 17 00:00:00 2001 From: "Amber H. Brown" Date: Mon, 12 Aug 2019 02:04:18 +1000 Subject: [PATCH 4/4] changelog --- src/towncrier/newsfragments/147.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/towncrier/newsfragments/147.feature diff --git a/src/towncrier/newsfragments/147.feature b/src/towncrier/newsfragments/147.feature new file mode 100644 index 00000000..8655cab7 --- /dev/null +++ b/src/towncrier/newsfragments/147.feature @@ -0,0 +1 @@ +Towncrier's templating now allows configuration of the version header. \ No newline at end of file