From 08fa4acb12bb181670d8339fb0287451a79d183f Mon Sep 17 00:00:00 2001 From: Colin-b Date: Thu, 22 Dec 2022 15:51:14 +0100 Subject: [PATCH 1/3] Add more documentation on CLI --- README.md | 103 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 68 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index d4dfdee..edf2d56 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Number of downloads

+* [Command line utility](#usage-from-command-line) * [Convert to dict](#convert-changelog-to-dict) * [Convert from dict](#convert-dict-to-changelog) * [Release a new version](#release) @@ -156,6 +157,16 @@ Note that `release_date` metadata will be set to None in such as case. ### Retrieving the raw content +#### Using CLI + +```shell +keepachangelog show 1.0.0 --raw +``` + +For details on what is actually performed, refer to the section below as it is what is used underneath the hood. + +#### Using python module + If for some reason you would like to retrieve the raw content of a release you can use `to_raw_dict` instead. ```python @@ -239,6 +250,16 @@ content = keepachangelog.from_dict(changes) ## Release +### Using CLI + +```shell +keepachangelog release +``` + +For details on what is actually performed, refer to the section below as it is what is used underneath the hood. + +### Using python module + You can create a new release by using `keepachangelog.release` function. ```python @@ -257,6 +278,52 @@ This will: * `[Unreleased]` link will be updated. * New link will be created corresponding to the new section (based on the format of the Unreleased link). +## Usage from command line + +`keepachangelog` can be used directly via command line. + +The main usage is within your CI to be able to [Release a new version](#release) and then [Create the appropriate release body](#retrieving-the-raw-content). +As in the following sample: +```shell +NEW_VERSION=$(keepachangelog release) +GITHUB_RELEASE_BODY=$(keepachangelog show ${GIT_TAG} --raw) +``` + +You can use it as a python module: +```sh +python -m keepachangelog --help +``` + +Or as a shell command: +```sh +keepachangelog --help +``` + +```sh +# usage: keepachangelog [-h] [-v] {show,release} ... +# +# Manipulate keep a changelog files +# +# options: +# -h, --help show this help message and exit +# -v, --version show program's version number and exit +# +# commands: +# {show,release} +# show Show the content of a release from the changelog +# release Create a new release in the changelog +# +# Examples: +# +# keepachangelog show 1.0.0 +# keepachangelog show 1.0.0 --raw +# keepachangelog show 1.0.0 path/to/CHANGELOG.md +# +# keepachangelog release +# keepachangelog release 1.0.1 +# keepachangelog release 1.0.1 -f path/to/CHANGELOG.md +``` + ## Endpoint ### Starlette @@ -298,38 +365,4 @@ Note: [flask-restx](https://pypi.python.org/pypi/flask-restx) module must be ins 2. Use pip to install module: ```sh python -m pip install keepachangelog -``` - -## Usage from command line - -`keepachangelog` can be used directly via command line: - -```sh -# Run it as a Python module -python -m keepachangelog --help -# or as a shell command -keepachangelog --help - -# usage: keepachangelog [-h] [-v] {show,release} ... -# -# Manipulate keep a changelog files -# -# options: -# -h, --help show this help message and exit -# -v, --version show program's version number and exit -# -# commands: -# {show,release} -# show Show the content of a release from the changelog -# release Create a new release in the changelog -# -# Examples: -# -# keepachangelog show 1.0.0 -# keepachangelog show 1.0.0 --raw -# keepachangelog show 1.0.0 path/to/CHANGELOG.md -# -# keepachangelog release -# keepachangelog release 1.0.1 -# keepachangelog release 1.0.1 -f path/to/CHANGELOG.md -``` +``` \ No newline at end of file From a6f25d791e000070117cb87d95cb7aa9764480b8 Mon Sep 17 00:00:00 2001 From: Colin-b Date: Thu, 22 Dec 2022 15:55:09 +0100 Subject: [PATCH 2/3] Add more type hinting --- keepachangelog/__main__.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/keepachangelog/__main__.py b/keepachangelog/__main__.py index 834b2e9..b9ba7a5 100644 --- a/keepachangelog/__main__.py +++ b/keepachangelog/__main__.py @@ -5,16 +5,14 @@ from keepachangelog.version import __version__ -def _format_change_section(change_type: str, changes: List[str]): +def _format_change_section(change_type: str, changes: List[str]) -> str: body = "".join([f" - {change}\r\n" for change in changes]) return f"""{change_type.capitalize()} {body}""" -def _command_show(args): - output = None - +def _command_show(args: argparse.Namespace) -> None: if args.raw: changelog = keepachangelog.to_raw_dict(args.file) else: @@ -36,14 +34,14 @@ def _command_show(args): print(output) -def _command_release(args): +def _command_release(args: argparse.Namespace) -> None: new_version = keepachangelog.release(args.file, args.release) if new_version: print(new_version) -def _parse_args(cmdline: List[str]): +def _parse_args(command_line: List[str]) -> argparse.Namespace: class CustomFormatter( argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter ): @@ -119,11 +117,11 @@ class CustomFormatter( "-v", "--version", action="version", version=f"%(prog)s {__version__}" ) - return parser.parse_args(cmdline) + return parser.parse_args(command_line) -def main(cmdline: List[str] = None): - args = _parse_args(cmdline) +def main(command_line: List[str] = None) -> None: + args = _parse_args(command_line) args.func(args) From da7e1f60261557ea65d121df0d6adc1cb23c6dbd Mon Sep 17 00:00:00 2001 From: Colin-b Date: Tue, 3 Jan 2023 16:00:00 +0100 Subject: [PATCH 3/3] Fail if there is nothing to release --- CHANGELOG.md | 11 ++++++++- README.md | 5 ++-- keepachangelog/__main__.py | 39 +++++++----------------------- keepachangelog/version.py | 2 +- tests/test_cli.py | 49 ++++++++++++++++++++++++++++---------- 5 files changed, 57 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2f71f4..beb61fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.0.0.dev5] - 2023-01-03 +### Changed +- `keepachangelog show` does not support `--raw` option anymore. It will always be the raw markdown output. +- `keepachangelog release` will now fail if there is nothing to release. + +### Removed +- `keepachangelog show` does not support `--raw` option anymore. + ## [2.0.0.dev4] - 2022-12-22 ### Added - Add a CLI to interact with `keepachangelog` API. (Thanks [Luca Faggianelli](https://github.com/lucafaggianelli)) @@ -99,7 +107,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Initial release. -[Unreleased]: https://github.com/Colin-b/keepachangelog/compare/v2.0.0.dev4...HEAD +[Unreleased]: https://github.com/Colin-b/keepachangelog/compare/v2.0.0.dev5...HEAD +[2.0.0.dev5]: https://github.com/Colin-b/keepachangelog/compare/v2.0.0.dev4...v2.0.0.dev5 [2.0.0.dev4]: https://github.com/Colin-b/keepachangelog/compare/v2.0.0.dev3...v2.0.0.dev4 [2.0.0.dev3]: https://github.com/Colin-b/keepachangelog/compare/v2.0.0.dev2...v2.0.0.dev3 [2.0.0.dev2]: https://github.com/Colin-b/keepachangelog/compare/v2.0.0.dev1...v2.0.0.dev2 diff --git a/README.md b/README.md index edf2d56..069a076 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ Note that `release_date` metadata will be set to None in such as case. #### Using CLI ```shell -keepachangelog show 1.0.0 --raw +keepachangelog show 1.0.0 ``` For details on what is actually performed, refer to the section below as it is what is used underneath the hood. @@ -286,7 +286,7 @@ The main usage is within your CI to be able to [Release a new version](#release) As in the following sample: ```shell NEW_VERSION=$(keepachangelog release) -GITHUB_RELEASE_BODY=$(keepachangelog show ${GIT_TAG} --raw) +GITHUB_RELEASE_BODY=$(keepachangelog show ${NEW_VERSION}) ``` You can use it as a python module: @@ -316,7 +316,6 @@ keepachangelog --help # Examples: # # keepachangelog show 1.0.0 -# keepachangelog show 1.0.0 --raw # keepachangelog show 1.0.0 path/to/CHANGELOG.md # # keepachangelog release diff --git a/keepachangelog/__main__.py b/keepachangelog/__main__.py index b9ba7a5..da3d8f4 100644 --- a/keepachangelog/__main__.py +++ b/keepachangelog/__main__.py @@ -1,3 +1,4 @@ +import sys from typing import List import argparse @@ -5,40 +6,20 @@ from keepachangelog.version import __version__ -def _format_change_section(change_type: str, changes: List[str]) -> str: - body = "".join([f" - {change}\r\n" for change in changes]) - - return f"""{change_type.capitalize()} -{body}""" - - def _command_show(args: argparse.Namespace) -> None: - if args.raw: - changelog = keepachangelog.to_raw_dict(args.file) - else: - changelog = keepachangelog.to_dict(args.file) - + changelog = keepachangelog.to_raw_dict(args.file) content = changelog.get(args.release) - - if args.raw: - output = content["raw"] - else: - output = "\n".join( - [ - _format_change_section(change_type, changes) - for change_type, changes in content.items() - if change_type != "metadata" - ] - ) - - print(output) + print(content["raw"]) def _command_release(args: argparse.Namespace) -> None: new_version = keepachangelog.release(args.file, args.release) - if new_version: - print(new_version) + if not new_version: + sys.stderr.write(f"{args.file} must contains a description of the release content (within Unreleased section).") + exit(2) + + print(new_version) def _parse_args(command_line: List[str]) -> argparse.Namespace: @@ -54,7 +35,6 @@ class CustomFormatter( Examples: keepachangelog show 1.0.0 - keepachangelog show 1.0.0 --raw keepachangelog show 1.0.0 path/to/CHANGELOG.md keepachangelog release @@ -83,9 +63,6 @@ class CustomFormatter( default="CHANGELOG.md", help="The path to the changelog file", ) - parser_show.add_argument( - "-r", "--raw", action="store_true", help="Show the raw markdown body" - ) parser_show.set_defaults(func=_command_show) diff --git a/keepachangelog/version.py b/keepachangelog/version.py index 89c4624..e38d355 100644 --- a/keepachangelog/version.py +++ b/keepachangelog/version.py @@ -3,4 +3,4 @@ # Major should be incremented in case there is a breaking change. (eg: 2.5.8 -> 3.0.0) # Minor should be incremented in case there is an enhancement. (eg: 2.5.8 -> 2.6.0) # Patch should be incremented in case there is a bug fix. (eg: 2.5.8 -> 2.5.9) -__version__ = "2.0.0.dev4" +__version__ = "2.0.0.dev5" diff --git a/tests/test_cli.py b/tests/test_cli.py index e707a28..f464579 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -69,6 +69,28 @@ def changelog(tmpdir): return changelog_file_path +@pytest.fixture +def changelog_without_unreleased(tmpdir): + changelog_file_path = os.path.join(tmpdir, "CHANGELOG_without_unreleased.md") + with open(changelog_file_path, mode="wt", encoding="utf-8") as file: + file.write( + """# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [1.0.0] - 2017-04-10 +### Deprecated +- Known issue 1 (1.0.0) 漢字 +- Known issue 2 (1.0.0) +""" + ) + return changelog_file_path + + def test_print_help(changelog: str, capsys: pytest.CaptureFixture): with pytest.raises(SystemExit) as exc: cli(["--help"]) @@ -93,20 +115,8 @@ def test_print_version(changelog: str, capsys: pytest.CaptureFixture): assert captured.out.strip() == f"keepachangelog {__version__}" -def test_show_release_pretty(changelog: str, capsys: pytest.CaptureFixture): - cli(["show", "1.0.0", changelog]) - - captured = capsys.readouterr() - - assert captured.err == "" - assert ( - captured.out.strip() - == "Deprecated\n - Known issue 1 (1.0.0) 漢字\r\n - Known issue 2 (1.0.0)" - ) - - def test_show_release_raw(changelog: str, capsys: pytest.CaptureFixture): - cli(["show", "1.0.0", changelog, "--raw"]) + cli(["show", "1.0.0", changelog]) captured = capsys.readouterr() @@ -130,6 +140,19 @@ def test_create_release_automatic_version( assert captured.out.strip() == "2.0.0" +def test_create_release_nothing_to_release( + changelog_without_unreleased: str, capsys: pytest.CaptureFixture +): + with pytest.raises(SystemExit) as cm: + cli(["release", "-f", changelog_without_unreleased]) + assert cm.value.code == 2 + + captured = capsys.readouterr() + + assert captured.err == f"{changelog_without_unreleased} must contains a description of the release content (within Unreleased section)." + assert captured.out == "" + + def test_create_release_specific_version(changelog: str, capsys: pytest.CaptureFixture): cli(["release", "3.2.1", "-f", changelog])