yaclog show and yaclog format commands

This commit is contained in:
Andrew Cassidy 2021-04-22 22:48:48 -07:00
parent 6e75e15526
commit 157f49839f
3 changed files with 67 additions and 21 deletions

View File

@ -1,6 +1,16 @@
# Changelog # Changelog
All notable changes to this project will be documented in this file All notable changes to this project will be documented in this file
## Unreleased
### Added
- `yaclog` tool for manipulating changelogs from the command line
- `init` command to make a new changelog
- `format` command to reformat the changelog
- `show` command to show changes from the changelog
## 0.2.0 - 2021-04-19 ## 0.2.0 - 2021-04-19
### Added ### Added
@ -12,8 +22,7 @@ All notable changes to this project will be documented in this file
- Updated package metadata - Updated package metadata
- Rewrote parser to use a 2-step method that is more flexible. - Rewrote parser to use a 2-step method that is more flexible.
- Parser can now handle code blocks. - Parser can now handle code blocks.
- Parser can now handle setext-style headers and H2s not conforming to the - Parser can now handle setext-style headers and H2s not conforming to the schema.
schema.
## 0.1.0 - 2021-04-16 ## 0.1.0 - 2021-04-16

View File

@ -48,7 +48,7 @@ def _join_markdown(segments: List[str]) -> str:
text: List[str] = [] text: List[str] = []
last_bullet = False last_bullet = False
for segment in segments: for segment in segments:
is_bullet = bullet_regex.match(segment) and '\n' not in segment is_bullet = bullet_regex.match(segment)
if not is_bullet or not last_bullet: if not is_bullet or not last_bullet:
text.append('') text.append('')
@ -76,7 +76,7 @@ class VersionEntry:
for section, entries in self.sections.items(): for section, entries in self.sections.items():
if section: if section:
if md: if md:
segments.append(f'## {section.title()}') segments.append(f'### {section.title()}')
else: else:
segments.append(f'{section.upper()}:') segments.append(f'{section.upper()}:')
@ -107,7 +107,7 @@ class VersionEntry:
return ' '.join(segments) return ' '.join(segments)
def text(self, md: bool = True) -> str: def text(self, md: bool = True) -> str:
return self.body(md) + '\n\n' + self.header(md) return self.header(md) + '\n\n' + self.body(md)
def __str__(self) -> str: def __str__(self) -> str:
return self.header(False) return self.header(False)
@ -115,9 +115,9 @@ class VersionEntry:
class Changelog: class Changelog:
def __init__(self, path: os.PathLike = None): def __init__(self, path: os.PathLike = None):
self.path = path self.path: os.PathLike = path
self.header = '' self.header: str = ''
self.versions = [] self.versions: List[VersionEntry] = []
self.links = {} self.links = {}
if not os.path.exists(path): if not os.path.exists(path):
@ -256,7 +256,6 @@ class Changelog:
# strip whitespace from header # strip whitespace from header
self.header = _join_markdown(header_segments) self.header = _join_markdown(header_segments)
self.links = self.links
def write(self, path: os.PathLike = None): def write(self, path: os.PathLike = None):
if path is None: if path is None:
@ -274,7 +273,10 @@ class Changelog:
v_links[version.name] = version.link v_links[version.name] = version.link
fp.write(version.text()) fp.write(version.text())
fp.write('\n\n') fp.write('\n')
if version != self.versions[-1] or len(v_links) > 0:
fp.write('\n')
for link_id, link in v_links.items(): for link_id, link in v_links.items():
fp.write(f'[{link_id.lower()}]: {link}\n') fp.write(f'[{link_id.lower()}]: {link}\n')

View File

@ -20,33 +20,68 @@ import os.path
@click.group() @click.group()
@click.option('--path', envvar='YACLOG_PATH', default='CHANGELOG.md', @click.option('--path', envvar='YACLOG_PATH', default='CHANGELOG.md', show_default=True,
type=click.Path(dir_okay=False, writable=True, readable=True)) type=click.Path(dir_okay=False, writable=True, readable=True),
help='Location for the changelog file')
@click.version_option() @click.version_option()
@click.pass_context @click.pass_context
def cli(ctx, path): def cli(ctx, path):
ctx.obj = path """Manipulate markdown changelog files"""
if not (ctx.invoked_subcommand == 'init' or os.path.exists(path)): if not (ctx.invoked_subcommand == 'init' or os.path.exists(path)):
# if the path doesnt exist, then ask if we can create it # if the path doesnt exist, then ask if we can create it
if click.confirm(f'Changelog file {path} does not exist. Would you like to create it?'): if click.confirm(f'Changelog file {path} does not exist. Would you like to create it?', abort=True):
ctx.invoke('init') ctx.invoke('init')
else:
return ctx.obj = yaclog.read(path)
@cli.command('init') @cli.command()
@click.pass_context @click.pass_context
def init(ctx): def init(ctx):
"""Create a new changelog file"""
path = ctx.parent.params['path'] path = ctx.parent.params['path']
if os.path.exists(path) and not click.confirm( if os.path.exists(path):
f'Changelog file {path} already exists. Would you like to overwrite it?'): click.confirm(f'Changelog file {path} already exists. Would you like to overwrite it?', abort=True)
return
yaclog.Changelog(path).write() yaclog.Changelog(path).write()
print(f'Created new changelog file at {path}') print(f'Created new changelog file at {path}')
@cli.command('format')
@click.pass_obj
def reformat(obj: yaclog.Changelog):
"""Reformat the changelog file"""
obj.write()
print(f'Reformatted changelog file at {obj.path}')
@cli.command(short_help='Show changes from the changelog file')
@click.option('--all', '-a', 'all_versions', is_flag=True, help='show all versions')
@click.argument('versions', type=str, nargs=-1)
@click.pass_obj
def show(obj: yaclog.Changelog, all_versions, versions):
"""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
else:
v_list = [obj.versions[0]]
for v in v_list:
click.echo(v.text())
if __name__ == '__main__': if __name__ == '__main__':
cli() cli()