Skip to content

Commit

Permalink
Full documented support for sharing config between multiple projects
Browse files Browse the repository at this point in the history
  • Loading branch information
iliakur committed Oct 9, 2023
1 parent 0da67ff commit eacaa45
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 37 deletions.
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Narrative

tutorial
markdown
monorepo


Reference
Expand Down
52 changes: 52 additions & 0 deletions docs/monorepo.rst
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.
The ``towncrier.toml`` can only contain one version number and the ``package`` field is of no use for the same reason.
2 changes: 2 additions & 0 deletions src/towncrier/newsfragments/548.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Full support for monorepo-style setup.
One project with multiple independent news files that share the same towncrier config.
63 changes: 26 additions & 37 deletions src/towncrier/test/test_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,32 @@ 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):
"""
Config location differs from the base directory for news file and fragments.
This is useful when multiple projects share one towncrier configuration.
The default `newsfragments` setting already supports this scenario so here
we test that custom settings also do.
"""
Path("pyproject.toml").write_text(
"[tool.towncrier]\n" + 'directory = "changelog.d"\n'
)
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"),
)

self.assertEqual(0, result.exit_code)
self.assertTrue(Path("foo/NEWS.rst").exists())

@with_isolated_runner
def test_no_newsfragment_directory(self, runner):
"""
Expand Down Expand Up @@ -1344,40 +1370,3 @@ def test_with_topline_and_template_and_draft(self):

self.assertEqual(0, result.exit_code, result.output)
self.assertEqual(expected_output, result.output)

@with_isolated_runner
def test_projects_share_one_config_with_nondefault_directory(self, runner):
"""
Multiple projects with independent changelogs share one towncrier
configuration.
For this to work:
1. We need to leave `config.package` empty.
2. We need to pass `--dir` to `create` and `build` explicitly.
It must point to the project folder.
3. We need to pass `--config` pointing at the global configuration.
4. We need to make sure `config.directory` and `config.filename` are resolved
relative to what we passed as `--dir`.
"""
# We don't want to specify the package because we have multiple ones.
Path("pyproject.toml").write_text(
# Important to customize `config.directory` because the default
# already supports this scenario.
"[tool.towncrier]\n"
+ 'directory = "changelog.d"\n'
)
# Each subproject contains the source code...
Path("foo/foo").mkdir(parents=True)
Path("foo/foo/__init__.py").write_text("")
# ... and the changelog machinery.
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"),
)

self.assertEqual(0, result.exit_code)
self.assertTrue(Path("foo/NEWS.rst").exists())
32 changes: 32 additions & 0 deletions src/towncrier/test/test_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,3 +249,35 @@ 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):
"""
Config location differs from the base directory for news file and fragments.
This is useful when multiple projects share one towncrier configuration.
"""
Path("pyproject.toml").write_text(
# Important to customize `config.directory` because the default
# 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())

0 comments on commit eacaa45

Please sign in to comment.