diff --git a/tests/test_cli.py b/tests/test_cli.py index 541d0ef..e3d56d0 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -218,5 +218,70 @@ class TestRelease(unittest.TestCase): self.assertEqual(repo.tags[0].name, '1.0.0') +class TestShow(unittest.TestCase): + + # noinspection PyShadowingNames + def setUp(self): + self.runner = CliRunner() + self.location = 'CHANGELOG.md' + + self.log = yaclog.Changelog() + + self.log.add_version(name='1.0.0').add_entry('- entry number 1') + self.log.add_version(name='Version 2.0.0').add_entry('- entry number 2', 'Added') + self.log.add_version(name='Three Point Oh').add_entry('entry number 3') + v = self.log.add_version(name='4.0.0 "Euclid"') + v.add_entry('- entry number 4') + v.add_entry('- entry number 5') + v.tags.append('TAGGED') + + self.modes = { + 'full': ([], lambda v, k: v.text(**k), '\n\n'), + 'name': (['-n'], lambda v, k: v.name, '\n'), + 'body': (['-b'], lambda v, k: v.body(**k), '\n\n'), + 'header': (['-h'], lambda v, k: v.header(**k), '\n'), + } + + def test_show_all(self): + """Test showing all version information""" + + with self.runner.isolated_filesystem(): + self.log.write(self.location) + + for mode, t in self.modes.items(): + with self.subTest(mode, flags=t[0]): + check_result(self, result := self.runner.invoke(cli, ['show', '-a'] + t[0])) + self.assertEqual(t[2].join([t[1](v, {'md': False}) for v in self.log.versions]), + result.output.strip(), 'incorrect plaintext output') + + check_result(self, result := self.runner.invoke(cli, ['show', '-am'] + t[0])) + self.assertEqual(t[2].join([t[1](v, {'md': True}) for v in self.log.versions]), + result.output.strip(), 'incorrect markdown output') + + def test_show_version(self): + with self.runner.isolated_filesystem(): + self.log.write(self.location) + + for mode, t in self.modes.items(): + with self.subTest(mode, flags=t[0]): + + for version in self.log.versions: + check_result(self, result := self.runner.invoke(cli, ['show', version.name] + t[0])) + self.assertEqual(t[1](version, {'md': False}), + result.output.strip(), 'incorrect plaintext output') + + check_result(self, result := self.runner.invoke(cli, ['show', version.name[-5:]] + t[0])) + self.assertEqual(t[1](version, {'md': False}), + result.output.strip(), 'incorrect plaintext output') + + check_result(self, result := self.runner.invoke(cli, ['show', version.name, '-m'] + t[0])) + self.assertEqual(t[1](version, {'md': True}), + result.output.strip(), 'incorrect markdown output') + + check_result(self, result := self.runner.invoke(cli, ['show', version.name[-5:], '-m'] + t[0])) + self.assertEqual(t[1](version, {'md': True}), + result.output.strip(), 'incorrect markdown output') + + if __name__ == '__main__': unittest.main() diff --git a/yaclog/changelog.py b/yaclog/changelog.py index ea1b27e..2e14a0a 100644 --- a/yaclog/changelog.py +++ b/yaclog/changelog.py @@ -381,14 +381,15 @@ class Changelog: def get_version(self, name: Optional[str] = None) -> VersionEntry: """ - Get a version from the changelog by name + Get a version from the changelog by name. - :param name: The name of the version to get, or `None` to return the most recent + :param name: The name of the version to get, or `None` to return the most recent. + The first version with this value in its name is returned. :return: The first version with the selected name """ for version in self.versions: - if version.name == name or name is None: + if name in version.name or name is None: return version raise KeyError(f'Version {name} not found in changelog') diff --git a/yaclog/cli/__main__.py b/yaclog/cli/__main__.py index 08cd5da..f623254 100644 --- a/yaclog/cli/__main__.py +++ b/yaclog/cli/__main__.py @@ -59,24 +59,36 @@ def reformat(obj: Changelog): click.echo(f'Reformatted changelog file at {obj.path}') +# noinspection PyShadowingNames @cli.command(short_help='Show changes from the changelog file') @click.option('--all', '-a', 'all_versions', is_flag=True, help='Show the entire changelog.') @click.option('--markdown/--txt', '-m/-t', default=False, help='Display as markdown or plain text.') -@click.option('--full', '-f', 'str_func', flag_value=lambda v, k: v.text(**k), default=True, +@click.option('--full', '-f', 'mode', flag_value='full', default=True, help='Show version header and body.') -@click.option('--name', '-n', 'str_func', flag_value=lambda v, k: v.name, help='Show only the version name') -@click.option('--body', '-b', 'str_func', flag_value=lambda v, k: v.body(**k), help='Show only the version body.') -@click.option('--header', '-h', 'str_func', flag_value=lambda v, k: v.preamble(**k), +@click.option('--name', '-n', 'mode', flag_value='name', + help='Show only the version name') +@click.option('--body', '-b', 'mode', flag_value='body', + help='Show only the version body.') +@click.option('--header', '-h', 'mode', flag_value='header', help='Show only the version header.') @click.argument('version_names', metavar='VERSIONS', type=str, nargs=-1) @click.pass_obj -def show(obj: Changelog, all_versions, markdown, str_func, version_names): +def show(obj: Changelog, all_versions, markdown, mode, version_names): """ Show the changes for VERSIONS. VERSIONS is a list of versions to print. If not given, the most recent version is used. """ + functions = { + 'full': (lambda v, k: v.text(**k)), + 'name': (lambda v, k: v.name), + 'body': (lambda v, k: v.body(**k)), + 'header': (lambda v, k: v.header(**k)), + } + + str_func = functions[mode] + try: if all_versions: versions = obj.versions @@ -85,16 +97,14 @@ def show(obj: Changelog, all_versions, markdown, str_func, version_names): else: versions = [obj.get_version(name) for name in version_names] except KeyError as k: - raise click.BadArgumentUsage(k) + raise click.BadArgumentUsage(str(k)) except ValueError as v: - raise click.ClickException(v) + raise click.ClickException(str(v)) kwargs = {'md': markdown, 'color': True} - for v in versions: - text = str_func(v, kwargs) - click.echo(text) - click.echo('\n') + sep = '\n\n' if mode == 'body' or mode == 'full' else '\n' + click.echo(sep.join([str_func(v, kwargs) for v in versions])) @cli.command(short_help='Modify version tags') @@ -115,9 +125,9 @@ def tag(obj: Changelog, add, tag_name: str, version_name: str): else: version = obj.current_version() except KeyError as k: - raise click.BadArgumentUsage(k) + raise click.BadArgumentUsage(str(k)) except ValueError as v: - raise click.ClickException(v) + raise click.ClickException(str(v)) if add: version.tags.append(tag_name) @@ -153,7 +163,7 @@ def entry(obj: Changelog, bullets, paragraphs, section_name, version_name): else: version = obj.current_version(released=False, new_version=True) except KeyError as k: - raise click.BadArgumentUsage(k) + raise click.BadArgumentUsage(str(k)) for p in paragraphs: version.add_entry(p, section_name)