Skip to content

Commit

Permalink
Merge pull request #44 from Colin-b/develop
Browse files Browse the repository at this point in the history
Release 2.0.0.dev4
  • Loading branch information
Colin-b committed Dec 22, 2022
2 parents 9d79410 + be4de9d commit 8013d12
Show file tree
Hide file tree
Showing 12 changed files with 339 additions and 24 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.7', '3.8', '3.9', '3.10']
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11']

steps:
- uses: actions/checkout@v2
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.7', '3.8', '3.9', '3.10']
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11']

steps:
- uses: actions/checkout@v2
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
repos:
- repo: https://github.com/psf/black
rev: 22.10.0
rev: 22.12.0
hooks:
- id: black
13 changes: 11 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [2.0.0.dev4] - 2022-12-22
### Added
- Add a CLI to interact with `keepachangelog` API. (Thanks [Luca Faggianelli](https://github.com/lucafaggianelli))

### Changed
- Changelog file is now expected to be `utf-8` encoded when read. (Thanks [0x55aa](https://github.com/665465))
- Changelog file is now `utf-8` encoded when written.

## [2.0.0.dev3] - 2022-10-19
### Fixed
- `keepachangelog.from_dict` now returns a single new line at end of file in case no url could be found. (Thanks [rockstarr-programmerr](https://github.com/rockstarr-programmerr))
Expand Down Expand Up @@ -51,7 +59,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `keepachangelog.release` is now allowing to provide a custom new version thanks to the new `new_version` parameter.

### Fixed
- `keepachangelog.release` now allows `pre-release` and `build metadata` information as part of valid semantic version. As per [semantic versioning specifications](https://semver.org).
- `keepachangelog.release` now allows `pre-release` and `build metadata` information as part of valid semantic version. As per [semantic versioning specifications](https://semver.org).
To ensure compatibility with some python specific versioning, `pre-release` is also handled as not being prefixed with `-`, or prefixed with `.`.
- `keepachangelog.release` will now bump a pre-release version to a stable version. It was previously failing.

Expand Down Expand Up @@ -91,7 +99,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.dev3...HEAD
[Unreleased]: https://github.com/Colin-b/keepachangelog/compare/v2.0.0.dev4...HEAD
[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
[2.0.0.dev1]: https://github.com/Colin-b/keepachangelog/compare/v2.0.0.dev0...v2.0.0.dev1
Expand Down
36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<a href="https://github.com/Colin-b/keepachangelog/actions"><img alt="Build status" src="https://github.com/Colin-b/keepachangelog/workflows/Release/badge.svg"></a>
<a href="https://github.com/Colin-b/keepachangelog/actions"><img alt="Coverage" src="https://img.shields.io/badge/coverage-100%25-brightgreen"></a>
<a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
<a href="https://github.com/Colin-b/keepachangelog/actions"><img alt="Number of tests" src="https://img.shields.io/badge/tests-41 passed-blue"></a>
<a href="https://github.com/Colin-b/keepachangelog/actions"><img alt="Number of tests" src="https://img.shields.io/badge/tests-47 passed-blue"></a>
<a href="https://pypi.org/project/keepachangelog/"><img alt="Number of downloads" src="https://img.shields.io/pypi/dm/keepachangelog"></a>
</p>

Expand Down Expand Up @@ -299,3 +299,37 @@ Note: [flask-restx](https://pypi.python.org/pypi/flask-restx) module must be ins
```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
```
131 changes: 131 additions & 0 deletions keepachangelog/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
from typing import List
import argparse

import keepachangelog
from keepachangelog.version import __version__


def _format_change_section(change_type: str, changes: List[str]):
body = "".join([f" - {change}\r\n" for change in changes])

return f"""{change_type.capitalize()}
{body}"""


def _command_show(args):
output = None

if args.raw:
changelog = keepachangelog.to_raw_dict(args.file)
else:
changelog = keepachangelog.to_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)


def _command_release(args):
new_version = keepachangelog.release(args.file, args.release)

if new_version:
print(new_version)


def _parse_args(cmdline: List[str]):
class CustomFormatter(
argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter
):
pass

parser = argparse.ArgumentParser(
prog="keepachangelog",
description="Manipulate keep a changelog files",
epilog="""
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
""",
formatter_class=CustomFormatter,
)

subparser = parser.add_subparsers(title="commands")

# keepachangelog show
parser_show_help = "Show the content of a release from the changelog"
parser_show: argparse.ArgumentParser = subparser.add_parser(
"show", description=parser_show_help, help=parser_show_help
)
parser_show.formatter_class = CustomFormatter

parser_show.add_argument(
"release", type=str, help="The version to search in the changelog"
)
parser_show.add_argument(
"file",
type=str,
nargs="?",
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)

# keepachangelog release
parser_release_help = "Create a new release in the changelog"
parser_release: argparse.ArgumentParser = subparser.add_parser(
"release", description=parser_release_help, help=parser_release_help
)
parser_release.formatter_class = CustomFormatter

parser_release.add_argument(
"release",
type=str,
nargs="?",
help="The version to add to the changelog. If not provided, a new version will be automatically generated based on the changes in the Unreleased section",
)
parser_release.add_argument(
"-f",
"--file",
type=str,
required=False,
default="CHANGELOG.md",
help="The path to the changelog file",
)

parser_release.set_defaults(func=_command_release)

parser.add_argument(
"-v", "--version", action="version", version=f"%(prog)s {__version__}"
)

return parser.parse_args(cmdline)


def main(cmdline: List[str] = None):
args = _parse_args(cmdline)
args.func(args)


if __name__ == "__main__":
main() # pragma: no cover
8 changes: 4 additions & 4 deletions keepachangelog/_changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def to_dict(
"""
# Allow for changelog as a file path or as a context manager providing content
try:
with open(changelog_path) as change_log:
with open(changelog_path, encoding="utf-8") as change_log:
return _to_dict(change_log, show_unreleased)
except TypeError:
return _to_dict(changelog_path, show_unreleased)
Expand Down Expand Up @@ -177,7 +177,7 @@ def to_raw_dict(changelog_path: str) -> Dict[str, dict]:
changes = {}
# As URLs can be defined before actual usage, maintain a separate dict
urls = {}
with open(changelog_path) as change_log:
with open(changelog_path, encoding="utf-8") as change_log:
current_release = {}
for line in change_log:
clean_line = line.strip(" \n")
Expand Down Expand Up @@ -230,7 +230,7 @@ def release_version(
):
unreleased_link_pattern = re.compile(r"^\[Unreleased\]: (.*)$", re.DOTALL)
lines = []
with open(changelog_path) as change_log:
with open(changelog_path, encoding="utf-8") as change_log:
for line in change_log.readlines():
# Move Unreleased section to new version
if re.fullmatch(r"^## \[Unreleased\].*$", line, re.DOTALL):
Expand Down Expand Up @@ -263,5 +263,5 @@ def release_version(
else:
lines.append(line)

with open(changelog_path, "wt") as change_log:
with open(changelog_path, mode="wt", encoding="utf-8") as change_log:
change_log.writelines(lines)
2 changes: 1 addition & 1 deletion keepachangelog/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.dev3"
__version__ = "2.0.0.dev4"
10 changes: 6 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Topic :: Software Development :: Build Tools",
],
keywords=["changelog", "CHANGELOG.md", "markdown"],
Expand All @@ -40,11 +41,9 @@
"testing": [
# Used to check starlette endpoint
"httpx==0.23.*",
"starlette==0.21.*",
# Flask-Restx is buggy for now
"werkzeug==2.1.2",
"starlette==0.23.*",
# Used to check flask-restx endpoint
"flask-restx==0.5.*",
"flask-restx==1.*",
# Used to check coverage
"pytest-cov==4.*",
]
Expand All @@ -56,4 +55,7 @@
"Issues": "https://github.com/Colin-b/keepachangelog/issues",
},
platforms=["Windows", "Linux"],
entry_points={
"console_scripts": ["keepachangelog=keepachangelog.__main__:main"],
},
)
10 changes: 5 additions & 5 deletions tests/test_changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
@pytest.fixture
def changelog(tmpdir):
changelog_file_path = os.path.join(tmpdir, "CHANGELOG.md")
with open(changelog_file_path, "wt") as file:
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.
Expand All @@ -26,7 +26,7 @@ def changelog(tmpdir):
- Release note 2.
### Added
- Enhancement 1
- Enhancement 1 漢字
- sub enhancement 1
- sub enhancement 2
- Enhancement 2
Expand Down Expand Up @@ -81,7 +81,7 @@ def changelog(tmpdir):
changelog_as_dict = {
"1.2.0": {
"added": [
"Enhancement 1",
"Enhancement 1 漢字",
"sub enhancement 1",
"sub enhancement 2",
"Enhancement 2",
Expand Down Expand Up @@ -172,7 +172,7 @@ def test_changelog_with_versions_and_all_categories(changelog):


def test_changelog_with_versions_and_all_categories_as_file_reader(changelog):
with io.StringIO(open(changelog).read()) as file_reader:
with io.StringIO(open(changelog, encoding="utf-8").read()) as file_reader:
assert keepachangelog.to_dict(file_reader) == changelog_as_dict

# Assert that file reader is not closed
Expand All @@ -187,7 +187,7 @@ def test_raw_changelog_with_versions_and_all_categories(changelog):
- Release note 1.
- Release note 2.
### Added
- Enhancement 1
- Enhancement 1 漢字
- sub enhancement 1
- sub enhancement 2
- Enhancement 2
Expand Down
8 changes: 4 additions & 4 deletions tests/test_changelog_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def mock_date(monkeypatch):
@pytest.fixture
def major_changelog(tmpdir):
changelog_file_path = os.path.join(tmpdir, "MAJOR_CHANGELOG.md")
with open(changelog_file_path, "wt") as file:
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.
Expand All @@ -49,7 +49,7 @@ def major_changelog(tmpdir):
* Release note 2.
### Added
- Enhancement 1
- Enhancement 1 漢字
- sub enhancement 1
* sub enhancement 2
- Enhancement 2
Expand Down Expand Up @@ -500,7 +500,7 @@ def patch_digit_changelog(tmpdir):

def test_major_release(major_changelog, mock_date):
assert keepachangelog.release(major_changelog) == "2.0.0"
with open(major_changelog) as file:
with open(major_changelog, encoding="utf-8") as file:
assert (
file.read()
== """# Changelog
Expand All @@ -517,7 +517,7 @@ def test_major_release(major_changelog, mock_date):
* Release note 2.
### Added
- Enhancement 1
- Enhancement 1 漢字
- sub enhancement 1
* sub enhancement 2
- Enhancement 2
Expand Down
Loading

0 comments on commit 8013d12

Please sign in to comment.