From c43fc25eaeda8fd36f09fb25d166384b7cb2343d Mon Sep 17 00:00:00 2001 From: drewcassidy Date: Thu, 29 Apr 2021 22:59:09 -0700 Subject: [PATCH] use API in command line tools --- tests/test_changelog.py | 2 +- tests/test_cli.py | 17 +++----- yaclog/changelog.py | 24 ++++++----- yaclog/cli/__main__.py | 93 ++++++++++++++++++++++------------------- 4 files changed, 71 insertions(+), 65 deletions(-) diff --git a/tests/test_changelog.py b/tests/test_changelog.py index 18a6fe3..99a75e2 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -4,8 +4,8 @@ import tempfile import unittest import yaclog -from yaclog.changelog import Changelog, VersionEntry from tests.common import log, log_segments, log_text +from yaclog.changelog import VersionEntry class TestParser(unittest.TestCase): diff --git a/tests/test_cli.py b/tests/test_cli.py index abba431..31d8b4b 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -8,8 +8,8 @@ import yaclog.changelog from yaclog.cli.__main__ import cli -def check_result(runner, result, expected=0): - runner.assertEqual(result.exit_code, expected, f'output: {result.output}\ntraceback: {result.exc_info}') +def check_result(runner, result, success: bool = True): + runner.assertEqual((result.exit_code == 0), success, f'output: {result.output}\ntraceback: {result.exc_info}') class TestCreation(unittest.TestCase): @@ -53,7 +53,7 @@ class TestCreation(unittest.TestCase): with runner.isolated_filesystem(): result = runner.invoke(cli, ['show']) - check_result(self, result, 1) + check_result(self, result, False) self.assertIn('does not exist', result.output) @@ -82,8 +82,7 @@ class TestTagging(unittest.TestCase): self.assertEqual(out_log.versions[1].tags, ['TAG2']) result = runner.invoke(cli, ['tag', 'tag3', '0.8.0']) - check_result(self, result, 2) - self.assertIn('not found in changelog', result.output) + check_result(self, result, False) def test_tag_deletion(self): """Test deleting tags from versions""" @@ -103,15 +102,12 @@ class TestTagging(unittest.TestCase): in_log.write() result = runner.invoke(cli, ['tag', '-d', 'tag2', '0.8.0']) - check_result(self, result, 2) - self.assertIn('not found in changelog', result.output) + check_result(self, result, False) result = runner.invoke(cli, ['tag', '-d', 'tag3', '0.9.0']) - check_result(self, result, 2) - self.assertIn('not found in version', result.output) + check_result(self, result, False) result = runner.invoke(cli, ['tag', '-d', 'tag1']) - self.assertNotIn('not found in version', result.output) check_result(self, result) out_log = yaclog.read(location) @@ -119,7 +115,6 @@ class TestTagging(unittest.TestCase): self.assertEqual(out_log.versions[1].tags, ['TAG2']) result = runner.invoke(cli, ['tag', '-d', 'tag2', '0.9.0']) - self.assertNotIn('not found in version', result.output) check_result(self, result) out_log = yaclog.read(location) diff --git a/yaclog/changelog.py b/yaclog/changelog.py index d201fa6..22e1db4 100644 --- a/yaclog/changelog.py +++ b/yaclog/changelog.py @@ -298,17 +298,18 @@ class Changelog: self.versions.insert(index, version := VersionEntry(*args, **kwargs)) return version - def current_version(self, released: Optional[bool] = None, - new_version_name: str = 'Unreleased') -> Optional[VersionEntry]: + def current_version(self, released: Optional[bool] = None, new_version: bool = False, + new_version_name: str = 'Unreleased') -> VersionEntry: """ Get the current version entry from the changelog :param released: if the returned version should be a released version, an unreleased version, or ``None`` to return the most recent - :param new_version_name: if unreleased versions are allowed, the name of - the version to create if there are no matches - :return: The current version matching the criteria, or None if only - release versions are allowed and none are found. + :param new_version: if a new version should be created if none exist. + :param new_version_name: The name of the version to create if there + are no matches and ``new_version`` is True. + :return: The current version matching the criteria, + or None if ``new_version`` is disabled and none are found. """ # return the first version that matches `released` @@ -317,10 +318,13 @@ class Changelog: return version # fallback if none are found - if released: - return None - else: + if new_version: return self.add_version(name=new_version_name) + else: + if released is not None: + raise ValueError(f'Changelog has no current version matching released={released}') + else: + raise ValueError('Changelog has no current version') def get_version(self, name: Optional[str] = None) -> VersionEntry: """ @@ -333,7 +337,7 @@ class Changelog: for version in self.versions: if version.name == name or name is None: return version - raise IndexError() + raise KeyError(f'Version {name} not found in changelog') def __getitem__(self, item: str) -> VersionEntry: return self.get_version(item) diff --git a/yaclog/cli/__main__.py b/yaclog/cli/__main__.py index 3646076..28dc020 100644 --- a/yaclog/cli/__main__.py +++ b/yaclog/cli/__main__.py @@ -14,14 +14,14 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import click -import os.path import datetime +import os.path + +import click import git import yaclog.version -import yaclog.changelog -from yaclog import Changelog +from yaclog.changelog import Changelog @click.group() @@ -61,35 +61,44 @@ def reformat(obj: Changelog): @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.argument('versions', type=str, nargs=-1) +@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, + 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.header(**k), 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, versions): +def show(obj: Changelog, all_versions, markdown, str_func, version_names): """Show the changes for VERSIONS. VERSIONS is a list of versions to print. If not given, the most recent version is used. """ - if all_versions: - with open(obj.path, 'r') as fp: - click.echo_via_pager(fp.read()) - else: - if len(versions): - v_list = [] - for v_name in versions: - matches = [v for v in obj.versions if v.name == v_name] - if len(matches) == 0: - raise click.BadArgumentUsage(f'Version "{v_name}" not found in changelog.') - v_list += matches + + try: + if all_versions: + versions = obj.versions + elif len(version_names) == 0: + versions = [obj.current_version()] else: - v_list = [obj.versions[0]] + versions = [obj.get_version(name) for name in version_names] + except KeyError as k: + raise click.BadArgumentUsage(k) + except ValueError as v: + raise click.ClickException(v) + + kwargs = {'md': markdown} - for v in v_list: - click.echo(v.text(False)) + for v in versions: + text = str_func(v, kwargs) + click.echo(text) + click.echo('\n') @cli.command(short_help='Modify version tags') @click.option('--add/--delete', '-a/-d', default=True, is_flag=True, help='Add or delete tags') @click.argument('tag_name', metavar='tag', type=str) -@click.argument('version_name', metavar='version', type=str, required=False) +@click.argument('version_name', metavar='VERSION', type=str, required=False) @click.pass_obj def tag(obj: Changelog, add, tag_name: str, version_name: str): """Modify TAG on VERSION. @@ -97,13 +106,15 @@ def tag(obj: Changelog, add, tag_name: str, version_name: str): VERSION is the name of a version to add tags to. If not given, the most recent version is used. """ tag_name = tag_name.upper() - if version_name: - matches = [v for v in obj.versions if v.name == version_name] - if len(matches) == 0: - raise click.BadArgumentUsage(f'Version "{version_name}" not found in changelog.') - version = matches[0] - else: - version = obj.versions[0] + try: + if version_name: + version = obj.get_version(version_name) + else: + version = obj.current_version() + except KeyError as k: + raise click.BadArgumentUsage(k) + except ValueError as v: + raise click.ClickException(v) if add: version.tags.append(tag_name) @@ -111,7 +122,7 @@ def tag(obj: Changelog, add, tag_name: str, version_name: str): try: version.tags.remove(tag_name) except ValueError: - raise click.BadArgumentUsage(f'Tag "{tag_name}" not found in version "{version.name}".') + raise click.BadArgumentUsage(f'Tag {tag_name} not found in version {version.name}.') obj.write() @@ -135,24 +146,19 @@ def entry(obj: Changelog, bullets, paragraphs, section_name, version_name): """ section_name = section_name.title() - if version_name: - matches = [v for v in obj.versions if v.name == version_name] - if len(matches) == 0: - raise click.BadArgumentUsage(f'Version "{version_name}" not found in changelog.') - version = matches[0] - else: - matches = [v for v in obj.versions if v.name.lower() == 'unreleased'] - if len(matches) == 0: - version = yaclog.changelog.VersionEntry() - obj.versions.insert(0, version) + try: + if version_name: + version = obj.get_version(version_name) else: - version = matches[0] + version = obj.current_version(released=False, new_version=True) + except KeyError as k: + raise click.BadArgumentUsage(k) if section_name not in version.sections.keys(): version.sections[section_name] = [] - section = version.sections[section_name] - section += paragraphs + for p in paragraphs: + version.add_entry(p, section_name) sub_bullet = False bullet_str = '' @@ -166,7 +172,8 @@ def entry(obj: Changelog, bullets, paragraphs, section_name, version_name): bullet_str += bullet sub_bullet = True - section.append(bullet_str) + + version.add_entry(bullet_str, section_name) obj.write()