Skip to content

Commit

Permalink
Merge pull request #391 from mikesongming/patch-2
Browse files Browse the repository at this point in the history
The detection of duplicate release notes was fixed and recording changes of same version is no longer triggered.

Support for having the release notes for each version in a separate file is working again. This is regression introduced in VERSION 19.9.0rc1.
  • Loading branch information
adiroiban authored Jul 11, 2022
2 parents 57a72eb + 8a8e4e1 commit 9747174
Show file tree
Hide file tree
Showing 6 changed files with 270 additions and 55 deletions.
13 changes: 12 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,18 @@ Towncrier has the following global options, which can be specified in the toml f
wrap = false # Wrap text to 79 characters
all_bullets = true # make all fragments bullet points
If a single file is used, the content of that file gets overwritten each time.
If ``single_file`` is set to ``true`` or unspecified, all changes will be written to a single
fixed newsfile, whose name is literally fixed as the ``filename`` option. In each run of ``towncrier build``,
content of new changes will append at the top of old content, and after ``start_string`` if the
``start_string`` already appears in the newsfile. If the corresponding ``top_line``, which is formatted
as the option 'title_format', already exists in newsfile, ``ValueError`` will be raised to remind
you "already produced newsfiles for this version".

If ``single_file`` is set to ``false`` instead, each versioned ``towncrier build`` will generate a
separate newsfile, whose name is formatted as the patten given by option ``filename``.
For example, if ``filename="{version}-notes.rst"``, then the release note with version "7.8.9" will
be written to the file "7.8.9-notes.rst". If the newsfile already exists, its content
will be overwriten with new release note, without throwing a ``ValueError`` warning.

If ``title_format`` is unspecified or an empty string, the default format will be used.
If set to ``false``, no title will be created.
Expand Down
2 changes: 1 addition & 1 deletion src/towncrier/_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def append_to_newsfile(
else:
existing_content = [""]

if top_line and top_line in existing_content:
if top_line and top_line in existing_content[-1]:
raise ValueError("It seems you've already produced newsfiles for this version?")

with open(os.path.join(directory, filename), "wb") as f:
Expand Down
5 changes: 3 additions & 2 deletions src/towncrier/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,9 @@ def __main(
start_string = config["start_string"]
news_file = config["filename"]

if config["single_file"]:
# When single_file is enabled, the news file name changes based on the version.
if config["single_file"] is False:
# The release notes for each version are stored in a separate file.
# The name of that file is generated based on the current version and project.
news_file = news_file.format(
name=project_name, version=project_version, project_date=project_date
)
Expand Down
3 changes: 3 additions & 0 deletions src/towncrier/newsfragments/391.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The detection of duplicate release notes was fixed and recording changes of same version is no longer triggered.

Support for having the release notes for each version in a separate file is working again. This is regression introduced in VERSION 19.9.0rc1.
180 changes: 129 additions & 51 deletions src/towncrier/test/test_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import os

from pathlib import Path
from subprocess import call
from textwrap import dedent

Expand Down Expand Up @@ -500,54 +501,96 @@ def test_no_package_changelog(self):
).lstrip(),
)

def test_single_file(self):
def test_release_notes_in_separate_files(self):
"""
Enabling the single file mode will write the changelog to a filename
that is formatted from the filename args.
When `single_file = false` the release notes for each version are stored
in a separate file.
The name of the file is defined by the `filename` configuration value.
"""
runner = CliRunner()

with runner.isolated_filesystem():
with open("pyproject.toml", "w") as f:
f.write(
'[tool.towncrier]\n single_file=true\n filename="{version}-notes.rst"'
)
os.mkdir("newsfragments")
with open("newsfragments/123.feature", "w") as f:
f.write("Adds levitation")
def do_build_once_with(version, fragment_file, fragment):
with open(f"newsfragments/{fragment_file}", "w") as f:
f.write(fragment)

result = runner.invoke(
_main,
[
"--version",
"7.8.9",
version,
"--name",
"foo",
"--date",
"01-01-2001",
"--yes",
],
)
# not git repository, manually remove fragment file
Path(f"newsfragments/{fragment_file}").unlink()
return result

self.assertEqual(0, result.exit_code, result.output)
results = []
with runner.isolated_filesystem():
with open("pyproject.toml", "w") as f:
f.write(
"\n".join(
[
"[tool.towncrier]",
" single_file=false",
' filename="{version}-notes.rst"',
]
)
)
os.mkdir("newsfragments")
results.append(
do_build_once_with("7.8.9", "123.feature", "Adds levitation")
)
results.append(do_build_once_with("7.9.0", "456.bugfix", "Adds catapult"))

self.assertEqual(0, results[0].exit_code, results[0].output)
self.assertEqual(0, results[1].exit_code, results[1].output)
self.assertEqual(
2,
len(list(Path.cwd().glob("*-notes.rst"))),
"one newfile for each build",
)
self.assertTrue(os.path.exists("7.8.9-notes.rst"), os.listdir("."))
self.assertTrue(os.path.exists("7.9.0-notes.rst"), os.listdir("."))

outputs = []
with open("7.8.9-notes.rst") as f:
output = f.read()
outputs.append(f.read())
with open("7.9.0-notes.rst") as f:
outputs.append(f.read())

self.assertEqual(
output,
dedent(
self.assertEqual(
outputs[0],
dedent(
"""
foo 7.8.9 (01-01-2001)
======================
Features
--------
- Adds levitation (#123)
"""
foo 7.8.9 (01-01-2001)
======================
).lstrip(),
)
self.assertEqual(
outputs[1],
dedent(
"""
foo 7.9.0 (01-01-2001)
======================
Features
--------
Bugfixes
--------
- Adds levitation (#123)
"""
).lstrip(),
)
- Adds catapult (#456)
"""
).lstrip(),
)

def test_singlefile_errors_and_explains_cleanly(self):
"""
Expand All @@ -568,55 +611,90 @@ def test_singlefile_errors_and_explains_cleanly(self):
result.output,
)

def test_single_file_false(self):
def test_all_version_notes_in_a_single_file(self):
"""
If formatting arguments are given in the filename arg and single_file is
false, the filename will not be formatted.
When `single_file = true` the single file is used to store the notes
for multiple versions.
The name of the file is fixed as the literal option `filename` option
in the configuration file, instead of extrapolated with variables.
"""
runner = CliRunner()

with runner.isolated_filesystem():
with open("pyproject.toml", "w") as f:
f.write(
'[tool.towncrier]\n single_file=false\n filename="{version}-notes.rst"'
)
os.mkdir("newsfragments")
with open("newsfragments/123.feature", "w") as f:
f.write("Adds levitation")
def do_build_once_with(version, fragment_file, fragment):
with open(f"newsfragments/{fragment_file}", "w") as f:
f.write(fragment)

result = runner.invoke(
_main,
[
"--version",
"7.8.9",
version,
"--name",
"foo",
"--date",
"01-01-2001",
"--yes",
],
)
# not git repository, manually remove fragment file
Path(f"newsfragments/{fragment_file}").unlink()
return result

self.assertEqual(0, result.exit_code, result.output)
results = []
with runner.isolated_filesystem():
with open("pyproject.toml", "w") as f:
f.write(
"\n".join(
[
"[tool.towncrier]",
" single_file=true",
" # The `filename` variable is fixed and not formated in any way.",
' filename="{version}-notes.rst"',
]
)
)
os.mkdir("newsfragments")
results.append(
do_build_once_with("7.8.9", "123.feature", "Adds levitation")
)
results.append(do_build_once_with("7.9.0", "456.bugfix", "Adds catapult"))

self.assertEqual(0, results[0].exit_code, results[0].output)
self.assertEqual(0, results[1].exit_code, results[1].output)
self.assertEqual(
1,
len(list(Path.cwd().glob("*-notes.rst"))),
"single newfile for multiple builds",
)
self.assertTrue(os.path.exists("{version}-notes.rst"), os.listdir("."))
self.assertFalse(os.path.exists("7.8.9-notes.rst"), os.listdir("."))

with open("{version}-notes.rst") as f:
output = f.read()

self.assertEqual(
output,
dedent(
"""
foo 7.8.9 (01-01-2001)
======================
self.assertEqual(
output,
dedent(
"""
foo 7.9.0 (01-01-2001)
======================
Features
--------
Bugfixes
--------
- Adds levitation (#123)
"""
).lstrip(),
)
- Adds catapult (#456)
foo 7.8.9 (01-01-2001)
======================
Features
--------
- Adds levitation (#123)
"""
).lstrip(),
)

def test_bullet_points_false(self):
"""
Expand Down
Loading

0 comments on commit 9747174

Please sign in to comment.