Repository: twisted/towncrier

Issue:
FileNotFoundError, Failed to list the news fragment files
After [adopting towncrier](https://github.com/jaraco/skeleton/pull/84) for the hundreds of projects that depend on [jaraco/skeleton](/jaraco/skeleton), I've been pleased to say that it has helped streamline the changelog generation.

I've tried as much as possible to minimize the amount of config required (relying on towncrier to provide best practices by default). Unfortunately, if I try to cut a release when there are no newsfragments, the "[finalize](https://github.com/jaraco/jaraco.develop/blob/9061f3bfc77c39fa2c3b1e06ea0c7695edb753ef/jaraco/develop/finalize.py#L9-L13)" step fails:

```
 pytest-checkdocs main @ tox -e finalize
finalize: commands[0]> python -m jaraco.develop.finalize
Loading template...
Finding news fragments...
Failed to list the news fragment files.
FileNotFoundError: [Errno 2] No such file or directory: '/Users/jaraco/code/jaraco/pytest-checkdocs/newsfragments'
```

I can work around the issue by first running `mkdir -p newsfragments`, but I'd rather not have to add that step. I know I can create a permanent `newsfragments` directory in every project, but that requires adding a sentinel file to keep it present. And given that towncrier already works well to create that directory when it doesn't exist, I'd like it to fall back to the degenerate behavior when running `build`.

Can you update towncrier build to treat a missing fragments directory as the same as an empty directory, same as towcrier create?

Comments:

Patch:
diff --git a/docs/cli.rst b/docs/cli.rst
index 90b5c89..7af5a3a 100644
--- a/docs/cli.rst
+++ b/docs/cli.rst
@@ -24,6 +24,13 @@ The following options can be passed to all of the commands that explained below:
 Build the combined news file from news fragments.
 ``build`` is also assumed if no command is passed.
 
+If there are no news fragments (including an empty fragments directory or a
+non-existent directory), a notice of "no significant changes" will be added to
+the news file.
+
+By default, the processed news fragments are removed using ``git``, which will
+also remove the fragments directory if now empty.
+
 .. option:: --draft
 
    Only render news fragments to standard output.
@@ -67,6 +74,8 @@ Create a news fragment in the directory that ``towncrier`` is configured to look
 
 ``towncrier create`` will enforce that the passed type (e.g. ``bugfix``) is valid.
 
+If the fragments directory does not exist, it will be created.
+
 If the filename exists already, ``towncrier create`` will add (and then increment) a number after the fragment type until it finds a filename that does not exist yet.
 In the above example, it will generate ``123.bugfix.1.rst`` if ``123.bugfix.rst`` already exists.
 
diff --git a/src/towncrier/_builder.py b/src/towncrier/_builder.py
index 6f8f166..3f72f1f 100644
--- a/src/towncrier/_builder.py
+++ b/src/towncrier/_builder.py
@@ -6,15 +6,12 @@ from __future__ import annotations
 
 import os
 import textwrap
-import traceback
 
 from collections import defaultdict
 from typing import Any, DefaultDict, Iterable, Iterator, Mapping, Sequence
 
 from jinja2 import Template
 
-from ._settings import ConfigError
-
 
 def strip_if_integer_string(s: str) -> str:
     try:
@@ -102,11 +99,8 @@ def find_fragments(
 
         try:
             files = os.listdir(section_dir)
-        except FileNotFoundError as e:
-            message = "Failed to list the news fragment files.\n{}".format(
-                "".join(traceback.format_exception_only(type(e), e)),
-            )
-            raise ConfigError(message)
+        except FileNotFoundError:
+            files = []
 
         file_content = {}
 
diff --git a/src/towncrier/newsfragments/538.bugfix b/src/towncrier/newsfragments/538.bugfix
new file mode 100644
index 0000000..3a6fbf3
--- /dev/null
+++ b/src/towncrier/newsfragments/538.bugfix
@@ -0,0 +1,1 @@
+``build`` now treats a missing fragments directory the same as an empty one, consistent with other operations.


Test patch:
diff --git a/src/towncrier/test/test_build.py b/src/towncrier/test/test_build.py
index f15cd9a..780a3c8 100644
--- a/src/towncrier/test/test_build.py
+++ b/src/towncrier/test/test_build.py
@@ -182,8 +182,8 @@ class TestCli(TestCase):
 
         result = runner.invoke(_main, ["--draft", "--date", "01-01-2001"])
 
-        self.assertEqual(1, result.exit_code, result.output)
-        self.assertIn("Failed to list the news fragment files.\n", result.output)
+        self.assertEqual(0, result.exit_code)
+        self.assertIn("No significant changes.\n", result.output)
 
     def test_no_newsfragments_draft(self):
         """