From d3361521b6f16b4c714277988a5101bac81c8229 Mon Sep 17 00:00:00 2001 From: Chris Beaven Date: Tue, 11 Jun 2024 08:33:52 +1200 Subject: [PATCH] Default section --- docs/cli.rst | 2 +- src/towncrier/create.py | 65 ++++++++++++++----------------- src/towncrier/test/test_create.py | 27 ++++++------- 3 files changed, 42 insertions(+), 52 deletions(-) diff --git a/docs/cli.rst b/docs/cli.rst index 108a5429..6adbb94d 100644 --- a/docs/cli.rst +++ b/docs/cli.rst @@ -101,7 +101,7 @@ If that is the entire fragment name, a random hash will be added for you:: .. option:: --section SECTION The section to use for the news fragment. - Default: the first section with no path. + Default: the section with no path, or if all sections have a path then the first defined section. ``towncrier check`` diff --git a/src/towncrier/create.py b/src/towncrier/create.py index fca96c00..acb3f96c 100644 --- a/src/towncrier/create.py +++ b/src/towncrier/create.py @@ -105,40 +105,43 @@ def __main( if ext.lower() in (".rst", ".md"): filename_ext = ext - # Get the default section. - default_section = None - if len(config.sections) == 1: - default_section = next(iter(config.sections)) - else: - # If there are mulitple sections then the first without a path is the default - # section, otherwise there's no default. - for section_name, section_dir in config.sections.items(): - if not section_dir: - default_section = section_name - break - - if section is not None: - if section not in config.sections: - section_param = None - for p in ctx.command.params: # pragma: no branch - if p.name == "section": - section_param = p + section_provided = section is not None + if not section_provided: + # Get the default section. + if len(config.sections) == 1: + section = next(iter(config.sections)) + else: + # If there are multiple sections then the first without a path is the default + # section, otherwise it's the first defined section. + for section_name, section_dir in config.sections.items(): + if not section_dir: + section = section_name break - expected_sections = ", ".join(f"'{s}'" for s in config.sections) - raise click.BadParameter( - f"expected one of {expected_sections}", - param=section_param, - ) + if section is None: + section = list(config.sections.keys())[0] + + if section not in config.sections: + # Raise a click exception with the correct parameter. + section_param = None + for p in ctx.command.params: # pragma: no branch + if p.name == "section": + section_param = p + break + expected_sections = ", ".join(f"'{s}'" for s in config.sections) + raise click.BadParameter( + f"expected one of {expected_sections}", + param=section_param, + ) if not filename: - if section is None: + if not section_provided: sections = list(config.sections) if len(sections) > 1: click.echo("Pick a section:") default_section_index = None - for i, section in enumerate(sections): - click.echo(f" {i+1}: {section or '(primary)'}") - if not default_section_index and section == default_section: + for i, s in enumerate(sections): + click.echo(f" {i+1}: {s or '(primary)'}") + if not default_section_index and s == section: default_section_index = str(i + 1) section_index = click.prompt( "Section", @@ -182,14 +185,6 @@ def __main( if filename_parts[-1] in config.types and filename_ext: filename += filename_ext - if not section: - if default_section is None: - raise click.UsageError( - "Multiple sections defined in configuration file, all with paths." - " Please define a section with `--section`." - ) - section = default_section - get_fragments_path = FragmentsPath(base_directory, config) fragments_directory = get_fragments_path(section_directory=config.sections[section]) diff --git a/src/towncrier/test/test_create.py b/src/towncrier/test/test_create.py index 3ec00c46..79b883fe 100644 --- a/src/towncrier/test/test_create.py +++ b/src/towncrier/test/test_create.py @@ -419,7 +419,10 @@ def test_without_filename_no_orphan_config(self, runner: CliRunner): def test_sections(self, runner: CliRunner): """ When creating a new fragment, the user can specify the section from the command - line (and if non is provided, the default section will be used). + line (and if none is provided, the default section will be used). + + The default section is either the section with a blank path, or else the first + section defined in the configuration file. """ setup_simple_project( extra_config=""" @@ -428,21 +431,14 @@ def test_sections(self, runner: CliRunner): path = "backend" [[tool.towncrier.section]] name = "Frontend" -path = "frontend" +path = "" """ ) result = runner.invoke(_main, ["123.feature.rst"]) - self.assertTrue(result.exception, result.output) - self.assertEqual( - result.output, - """\ -Usage: create [OPTIONS] [FILENAME] -Try 'create --help' for help. - -Error: Multiple sections defined in configuration file, all with paths.\ - Please define a section with `--section`. -""", - ) + self.assertFalse(result.exception, result.output) + frag_path = Path("foo", "newsfragments") + fragments = [f.name for f in frag_path.iterdir()] + self.assertEqual(fragments, ["123.feature.rst"]) result = runner.invoke(_main, ["123.feature.rst", "--section", "invalid"]) self.assertTrue(result.exception, result.output) @@ -451,10 +447,9 @@ def test_sections(self, runner: CliRunner): result.output, ) - result = runner.invoke(_main, ["123.feature.rst", "--section", "Frontend"]) + result = runner.invoke(_main, ["123.feature.rst", "--section", "Backend"]) self.assertFalse(result.exception, result.output) - frag_path = Path("foo", "frontend", "newsfragments") - + frag_path = Path("foo", "backend", "newsfragments") fragments = [f.name for f in frag_path.iterdir()] self.assertEqual(fragments, ["123.feature.rst"])