-
Notifications
You must be signed in to change notification settings - Fork 122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Config location separate from directory containing news file and fragments #548
Changes from all commits
55debb9
0da67ff
e6a6c8b
e83df6a
0625734
f2e9f6f
b5917d3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ Narrative | |
|
||
tutorial | ||
markdown | ||
monorepo | ||
|
||
|
||
Reference | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
Multiple Projects Share One Config (Monorepo) | ||
============================================= | ||
|
||
Several projects may have independent release notes with the same format. | ||
For instance packages in a monorepo. | ||
Here's how you can use towncrier to set this up. | ||
|
||
Below is a minimal example: | ||
|
||
.. code-block:: text | ||
|
||
repo | ||
├── project_a | ||
│ ├── newsfragments | ||
│ │ └── 123.added | ||
│ ├── project_a | ||
│ │ └── __init__.py | ||
│ └── NEWS.rst | ||
├── project_b | ||
│ ├── newsfragments | ||
│ │ └── 120.bugfix | ||
│ ├── project_b | ||
│ │ └── __init__.py | ||
│ └── NEWS.rst | ||
└── towncrier.toml | ||
|
||
The ``towncrier.toml`` looks like this: | ||
|
||
.. code-block:: toml | ||
|
||
[tool.towncrier] | ||
# It's important to keep these config fields empty | ||
# because we have more than one package/name to manage. | ||
package = "" | ||
name = "" | ||
|
||
Now to add a fragment: | ||
|
||
.. code-block:: console | ||
|
||
towncrier create --config towncrier.toml --dir project_a 124.added | ||
|
||
This should create a file at ``project_a/newsfragments/124.added``. | ||
|
||
To build the news file for the same project: | ||
|
||
.. code-block:: console | ||
|
||
towncrier build --config towncrier.toml --dir project_a --version 1.5 | ||
|
||
Note that we must explicitly pass ``--version``, there is no other way to get the version number. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe create a GitHub issue for this. I don't know how to do it... as we are missing the package name info... so it's not easy to know for which package to extract the version. But maybe it's best to just have the issue created and linked from here. The sentence from below, reads like a bug description :) |
||
The ``towncrier.toml`` can only contain one version number and the ``package`` field is of no use for the same reason. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
Initial support was added for monorepo-style setup. | ||
One project with multiple independent news files stored in separate sub-directories, that share the same towncrier config. |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -145,6 +145,33 @@ def test_in_different_dir_config_option(self, runner): | |||||
self.assertEqual(0, result.exit_code) | ||||||
self.assertTrue((project_dir / "NEWS.rst").exists()) | ||||||
|
||||||
@with_isolated_runner | ||||||
def test_in_different_dir_with_nondefault_newsfragments_directory(self, runner): | ||||||
""" | ||||||
Using the `--dir` CLI argument, the NEWS file can | ||||||
be generated in a sub-directory from fragments | ||||||
that are relatives to that sub-directory. | ||||||
|
||||||
The path passed to `--dir` becomes the | ||||||
working directory. | ||||||
""" | ||||||
Path("pyproject.toml").write_text( | ||||||
"[tool.towncrier]\n" + 'directory = "changelog.d"\n' | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe also add an explicit empty |
||||||
) | ||||||
Path("foo/foo").mkdir(parents=True) | ||||||
Path("foo/foo/__init__.py").write_text("") | ||||||
Path("foo/changelog.d").mkdir() | ||||||
Path("foo/changelog.d/123.feature").write_text("Adds levitation") | ||||||
self.assertFalse(Path("foo/NEWS.rst").exists()) | ||||||
|
||||||
result = runner.invoke( | ||||||
cli, | ||||||
("--yes", "--config", "pyproject.toml", "--dir", "foo", "--version", "1.0"), | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see normpath was previously used. Maybe for the test, we can go wild, and add something like this, to make sure
Suggested change
also, do we need to pass There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for "wild" suggestion, I'll try it out! We must explicitly pass |
||||||
) | ||||||
|
||||||
self.assertEqual(0, result.exit_code) | ||||||
self.assertTrue(Path("foo/NEWS.rst").exists()) | ||||||
|
||||||
@with_isolated_runner | ||||||
def test_no_newsfragment_directory(self, runner): | ||||||
""" | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -297,3 +297,101 @@ def test_get_default_compare_branch_fallback(self): | |
|
||
self.assertEqual("origin/master", branch) | ||
self.assertTrue(w[0].message.args[0].startswith('Using "origin/master')) | ||
|
||
@with_isolated_runner | ||
def test_in_different_dir_with_nondefault_newsfragments_directory(self, runner): | ||
""" | ||
It can check the fragments located in a sub-directory | ||
that is specified using the `--dir` CLI argument. | ||
""" | ||
main_branch = "main" | ||
Path("pyproject.toml").write_text( | ||
# Important to customize `config.directory` because the default | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand this comment. Maybe something like For monorepos, the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yea, hmm, this must really be complicated cuz we're having to go over it a 3rd time now (I mentioned this in the PR description and in a comment about bug vs feature criteria). Let me know if the following is clearer.
Longer-term I think it makes sense to figure out how to merge these implementations for ease of maintenance. I didn't have time to do so for this PR. |
||
# already supports this scenario. | ||
"[tool.towncrier]\n" | ||
+ 'directory = "changelog.d"\n' | ||
) | ||
subproject1 = Path("foo") | ||
(subproject1 / "foo").mkdir(parents=True) | ||
(subproject1 / "foo/__init__.py").write_text("") | ||
(subproject1 / "changelog.d").mkdir(parents=True) | ||
(subproject1 / "changelog.d/123.feature").write_text("Adds levitation") | ||
initial_commit(branch=main_branch) | ||
call(["git", "checkout", "-b", "otherbranch"]) | ||
|
||
# We add a code change but forget to add a news fragment. | ||
write(subproject1 / "foo/somefile.py", "import os") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe also write a file like I think that the main goal of this tests it to make sure that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do I understand correctly that we don't want |
||
commit("add a file") | ||
result = runner.invoke( | ||
towncrier_check, | ||
( | ||
"--config", | ||
"pyproject.toml", | ||
"--dir", | ||
str(subproject1), | ||
"--compare-with", | ||
"main", | ||
), | ||
) | ||
|
||
self.assertEqual(1, result.exit_code) | ||
self.assertTrue( | ||
result.output.endswith("No new newsfragments found on this branch.\n") | ||
) | ||
|
||
# We add the news fragment. | ||
fragment_path = (subproject1 / "changelog.d/124.feature").absolute() | ||
write(fragment_path, "Adds gravity back") | ||
commit("add a newsfragment") | ||
result = runner.invoke( | ||
towncrier_check, | ||
("--config", "pyproject.toml", "--dir", "foo", "--compare-with", "main"), | ||
) | ||
|
||
self.assertEqual(0, result.exit_code, result.output) | ||
self.assertTrue( | ||
result.output.endswith("Found:\n1. " + str(fragment_path) + "\n"), | ||
(result.output, str(fragment_path)), | ||
) | ||
|
||
# We add a change in a different subproject without a news fragment. | ||
# Checking subproject1 should pass. | ||
subproject2 = Path("bar") | ||
(subproject2 / "bar").mkdir(parents=True) | ||
(subproject2 / "changelog.d").mkdir(parents=True) | ||
write(subproject2 / "bar/somefile.py", "import os") | ||
commit("add a file") | ||
result = runner.invoke( | ||
towncrier_check, | ||
( | ||
"--config", | ||
"pyproject.toml", | ||
"--dir", | ||
subproject1, | ||
"--compare-with", | ||
"main", | ||
), | ||
) | ||
|
||
self.assertEqual(0, result.exit_code, result.output) | ||
self.assertTrue( | ||
result.output.endswith("Found:\n1. " + str(fragment_path) + "\n"), | ||
(result.output, str(fragment_path)), | ||
) | ||
|
||
# Checking subproject2 should result in an error. | ||
result = runner.invoke( | ||
towncrier_check, | ||
( | ||
"--config", | ||
"pyproject.toml", | ||
"--dir", | ||
subproject2, | ||
"--compare-with", | ||
"main", | ||
), | ||
) | ||
self.assertEqual(1, result.exit_code) | ||
self.assertTrue( | ||
result.output.endswith("No new newsfragments found on this branch.\n") | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -249,3 +249,37 @@ def test_create_orphan_fragment_custom_prefix(self, runner: CliRunner): | |
self.assertEqual(len(change.stem), 11) | ||
# Check the remainder are all hex characters. | ||
self.assertTrue(all(c in string.hexdigits for c in change.stem[3:])) | ||
|
||
@with_isolated_runner | ||
def test_in_different_dir_with_nondefault_newsfragments_directory(self, runner): | ||
""" | ||
When the `--dir` CLI argument is passed, | ||
it will create a new file in directory that is | ||
created by combining the `--dir` value | ||
with the `directory` option from the configuration | ||
file. | ||
""" | ||
Path("pyproject.toml").write_text( | ||
# Important to customize `config.directory` because the default | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand this comment here. Maybe, it's important to note that this is a configured using a sub-directory that is later combined with the CLI argument. Also, maybe it's also important to pass an empty |
||
# already supports this scenario. | ||
"[tool.towncrier]\n" | ||
+ 'directory = "changelog.d"\n' | ||
) | ||
Path("foo/foo").mkdir(parents=True) | ||
Path("foo/foo/__init__.py").write_text("") | ||
|
||
result = runner.invoke( | ||
_main, | ||
( | ||
"--config", | ||
"pyproject.toml", | ||
"--dir", | ||
"foo", | ||
"--content", | ||
"Adds levitation.", | ||
"123.feature", | ||
), | ||
) | ||
|
||
self.assertEqual(0, result.exit_code) | ||
self.assertTrue(Path("foo/changelog.d/123.feature").exists()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we also have this information as part of the built-in CLI help system ?
this would need updating the
@click.options
help text for build.https://github.com/twisted/towncrier/pull/548/files#diff-3576f35f5faa5ded14cd2b3db52e19829e34270f7957ebdf765870dc6f305903R68-R74
In an ideal case, we would only write the docs for
click
and have it automatically exported in RST format.Same comment is valid for
create
andcheck
sub-commandsThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add this to the options. Have you looked into using this sphinx plugin to extract the documentation automatically?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's the plan. It just needs someone to implement it into the current build system :)