Skip to content
This repository has been archived by the owner on Mar 8, 2024. It is now read-only.

Commit

Permalink
feat: Add verbose logging to commands, and pass through to bumpversio…
Browse files Browse the repository at this point in the history
…n. (#96)

Support `-v`, `-vv`, `-vvv` flags for commands, and expose verbose logs
for debugging.

Refs: #95
  • Loading branch information
EdgyEdgemond authored Mar 2, 2024
1 parent 7916f6a commit c30bd1e
Show file tree
Hide file tree
Showing 20 changed files with 821 additions and 408 deletions.
21 changes: 20 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Test/Lint
name: Test

on:
push:
Expand Down Expand Up @@ -59,6 +59,25 @@ jobs:
run: |
pytest -m "backwards_compat"
test-legacy:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v1
- name: Set up Python 3.9
uses: actions/setup-python@v1
with:
python-version: 3.9.18
- name: Install dependencies
run: |
python -m pip install --upgrade pip poetry
poetry config virtualenvs.create false
poetry install --extras=bump2version
- name: Generate coverage report
run: |
pytest -m "backwards_compat"
test-python-versions:

runs-on: ${{ matrix.os }}
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ and how to customize them.
[optional footer(s)]
```

`description` allows typical `[a-zA-Z ]` sentences, as well as `[.,/]`
punctuation, and ``[`]`` for highlighting words.

i.e.
```
fix: This is a valid description, with punctuation and a `highlighted` word.
```

Optional footers that are parsed by `changelog-gen` are:

* `BREAKING CHANGE:`
Expand Down
124 changes: 89 additions & 35 deletions changelog_gen/cli/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@

import importlib.metadata
import json
import logging
import logging.config
from datetime import datetime, timezone
from pathlib import Path
from typing import Optional
from warnings import warn

import click
import rtoml
import typer
from rich.logging import RichHandler

from changelog_gen import (
config,
Expand All @@ -21,6 +26,37 @@
from changelog_gen.vcs import Git
from changelog_gen.version import BumpVersion

logger = logging.getLogger(__name__)

VERBOSITY = {
0: logging.ERROR,
1: logging.WARNING,
2: logging.INFO,
3: logging.DEBUG,
}


def setup_logging(verbose: int = 0) -> None:
"""Configure the logging."""
logging.basicConfig(
level=VERBOSITY.get(verbose, logging.DEBUG),
format="%(message)s",
datefmt="[%X]",
handlers=[
RichHandler(
rich_tracebacks=True,
show_level=False,
show_path=False,
show_time=False,
tracebacks_suppress=[click],
),
],
)
httpx_logger = logging.getLogger("httpx")
httpx_logger.disabled = True
root_logger = logging.getLogger("")
root_logger.setLevel(VERBOSITY.get(verbose, logging.DEBUG))


def _version_callback(*, value: bool) -> None:
"""Get current cli version."""
Expand Down Expand Up @@ -52,47 +88,53 @@ def process_info(info: dict, cfg: config.Config, *, dry_run: bool) -> None:
return

if info["dirty"] and not cfg.allow_dirty:
typer.echo("Working directory is not clean. Use `allow_dirty` configuration to ignore.")
logger.error("Working directory is not clean. Use `allow_dirty` configuration to ignore.")
raise typer.Exit(code=1)

allowed_branches = cfg.allowed_branches
if allowed_branches and info["branch"] not in allowed_branches:
typer.echo("Current branch not in allowed generation branches.")
logger.error("Current branch not in allowed generation branches.")
raise typer.Exit(code=1)


@init_app.command("init")
@init_app.command("changelog-init")
@app.command("init")
def init(
ctx: typer.Context,
file_format: writer.Extension = typer.Option("md", help="File format to generate."),
_version: Optional[bool] = typer.Option(
None,
"-v",
"--version",
callback=_version_callback,
help="Print version and exit.",
),
verbose: int = typer.Option(0, "-v", "--verbose", help="Set output verbosity.", count=True, max=3),
) -> None:
"""Generate an empty CHANGELOG file.
Detect and raise if a CHANGELOG already exists, if not create a new file.
"""
if ctx.command.name == "changelog-init":
warn(
"`changelog-init` has been deprecated, please use `changelog init`",
FutureWarning,
stacklevel=2,
)
setup_logging(verbose)
cfg = config.Config()
extension = util.detect_extension()
if extension is not None:
typer.echo(f"CHANGELOG.{extension.value} detected.")
logger.error("CHANGELOG.%s detected.", extension.value)
raise typer.Exit(code=1)

w = writer.new_writer(file_format)
w = writer.new_writer(file_format, cfg)
w.write()


@app.command("migrate")
def migrate() -> None:
def migrate(
verbose: int = typer.Option(0, "-v", "--verbose", help="Set output verbosity.", count=True, max=3),
) -> None:
"""Generate toml configuration from setup.cfg."""
setup_logging(verbose)
setup = Path("setup.cfg")

if not setup.exists():
typer.echo("setup.cfg not found.")
logger.error("setup.cfg not found.")
raise typer.Exit(code=1)

cfg = config._process_setup_cfg(setup) # noqa: SLF001
Expand All @@ -102,9 +144,10 @@ def migrate() -> None:
typer.echo(rtoml.dumps({"tool": {"changelog_gen": cfg}}))


@gen_app.command("generate")
@gen_app.command("changelog-gen")
@app.command("generate")
def gen( # noqa: PLR0913
ctx: typer.Context,
version_tag: Optional[str] = typer.Option(None, help="Provide the desired version tag, skip auto generation."),
version_part: Optional[str] = typer.Option(None, help="Provide the desired version part, skip auto generation."),
post_process_url: Optional[str] = typer.Option(
Expand All @@ -122,9 +165,9 @@ def gen( # noqa: PLR0913
release: Optional[bool] = typer.Option(None, help="Use bumpversion to tag the release."),
commit: Optional[bool] = typer.Option(None, help="Commit changes made to changelog after writing."),
reject_empty: Optional[bool] = typer.Option(None, help="Don't accept changes if there are no release notes."),
verbose: int = typer.Option(0, "-v", "--verbose", help="Set output verbosity.", count=True, max=3),
_version: Optional[bool] = typer.Option(
None,
"-v",
"--version",
callback=_version_callback,
help="Print version and exit.",
Expand All @@ -134,6 +177,13 @@ def gen( # noqa: PLR0913
Read release notes and generate a new CHANGELOG entry for the current version.
"""
if ctx.command.name == "changelog-gen":
warn(
"`changelog-gen` has been deprecated, please use `changelog generate`",
FutureWarning,
stacklevel=2,
)
setup_logging(verbose)
cfg = config.read(
release=release,
allow_dirty=allow_dirty,
Expand All @@ -142,12 +192,13 @@ def gen( # noqa: PLR0913
date_format=date_format,
post_process_url=post_process_url,
post_process_auth_env=post_process_auth_env,
verbose=verbose,
)

try:
_gen(cfg, version_part, version_tag, dry_run=dry_run)
except errors.ChangelogException as ex:
typer.echo(ex)
logger.error("%s", ex) # noqa: TRY400
raise typer.Exit(code=1) from ex


Expand All @@ -158,41 +209,44 @@ def _gen(
*,
dry_run: bool = False,
) -> None:
bv = BumpVersion(verbose=cfg.verbose, dry_run=dry_run)
git = Git(dry_run=dry_run)

extension = util.detect_extension()

if extension is None:
typer.echo("No CHANGELOG file detected, run `changelog init`")
logger.error("No CHANGELOG file detected, run `changelog init`")
raise typer.Exit(code=1)

process_info(Git.get_latest_tag_info(), cfg, dry_run=dry_run)
process_info(git.get_latest_tag_info(), cfg, dry_run=dry_run)

e = extractor.ReleaseNoteExtractor(dry_run=dry_run, type_headers=cfg.type_headers)
e = extractor.ReleaseNoteExtractor(cfg=cfg, git=git, dry_run=dry_run)
sections = e.extract()

unique_issues = e.unique_issues(sections)
if not unique_issues and cfg.reject_empty:
typer.echo("No changes present and reject_empty configured.")
logger.error("No changes present and reject_empty configured.")
raise typer.Exit(code=0)

if version_part is not None:
version_info_ = BumpVersion.get_version_info(version_part)
version_info_ = bv.get_version_info(version_part)
version_tag = version_info_["new"]

if version_tag is None:
version_tag = extract_version_tag(sections, cfg.semver_mapping)
version_tag = extract_version_tag(sections, cfg, bv)

version_string = cfg.version_string.format(new_version=version_tag)

date_fmt = cfg.date_format
if date_fmt:
version_string += f" {datetime.now(timezone.utc).strftime(date_fmt)}"

w = writer.new_writer(extension, dry_run=dry_run, issue_link=cfg.issue_link, commit_link=cfg.commit_link)
w = writer.new_writer(extension, cfg, dry_run=dry_run)

w.add_version(version_string)
w.consume(cfg.type_headers, sections)

typer.echo(w)
logger.error(str(w))

processed = _finalise(w, e, version_tag, extension, cfg, dry_run=dry_run)

Expand All @@ -211,26 +265,26 @@ def _finalise( # noqa: PLR0913
*,
dry_run: bool,
) -> bool:
bv = BumpVersion(verbose=cfg.verbose, dry_run=dry_run, allow_dirty=cfg.allow_dirty)
git = Git(dry_run=dry_run, commit=cfg.commit)

if dry_run or typer.confirm(
f"Write CHANGELOG for suggested version {version_tag}",
):
writer.write()
extractor.clean()

if dry_run or not cfg.commit:
return False

Git.add_path(f"CHANGELOG.{extension.value}")
paths = [f"CHANGELOG.{extension.value}"]
if Path("release_notes").exists():
Git.add_path("release_notes")
Git.commit(version_tag)
paths.append("release_notes")
git.commit(version_tag, paths)

if cfg.release:
if cfg.commit and cfg.release:
try:
BumpVersion.release(version_tag)
bv.release(version_tag)
except Exception as e: # noqa: BLE001
Git.revert()
typer.echo("Error creating release: {e}")
git.revert()
logger.error("Error creating release: %s", str(e)) # noqa: TRY400
raise typer.Exit(code=1) from e
return True

Expand Down
Loading

0 comments on commit c30bd1e

Please sign in to comment.