Skip to content

Commit

Permalink
feat: Add provider CLI option
Browse files Browse the repository at this point in the history
Issue pawamoy#37: pawamoy#37
PR pawamoy#40: pawamoy#40
Co-authored-by: Théo Goudout <theo.goudout@gmail.com>
Co-authored-by: Timothée Mazzucotelli <pawamoy@pm.me>
  • Loading branch information
TheoGoudout authored Aug 21, 2023
1 parent b3c90af commit 908531b
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 42 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,11 @@ options:
missing from changelog). If two marker lines are
present in the changelog, the contents between those
two lines will be overwritten (useful to update an
'Unreleased' entry for example). Default: <!--
insertion marker -->.
'Unreleased' entry for example). Default:
<!-- insertion marker -->.
-o, --output OUTPUT Output to given file. Default: stdout.
-p {github,gitlab}, --provider {github,gitlab}
Explicitly specify the repository provider.
-r, --parse-refs Parse provider-specific references in commit messages
(GitHub/GitLab/Bitbucket issues, PRs, etc.). Default: False.
-R, --release-notes Output release notes to stdout based on the last entry
Expand Down
7 changes: 7 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ and parsing provider-specific references (GitHub/GitLab/Bitbucket):
git-changelog -rt path:./templates/changelog.md.jinja
```

Generate a changelog using a specific provider (GitHub/GitLab/BitBucket):

```bash
git-changelog --provider github
```

Author's favorite, from Python:

```python
Expand All @@ -58,6 +64,7 @@ build_and_render(
repository=".",
output="CHANGELOG.md",
convention="angular",
provider="github",
template="keepachangelog",
parse_trailers=True,
parse_refs=False,
Expand Down
12 changes: 8 additions & 4 deletions src/git_changelog/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import re
import sys
from contextlib import suppress
from subprocess import check_output # (we trust the commands we run)
from subprocess import check_output
from typing import TYPE_CHECKING, ClassVar, Type, Union

from semver import VersionInfo
Expand Down Expand Up @@ -163,7 +163,7 @@ def __init__(
self,
repository: str | Path,
*,
provider: ProviderRefParser | None = None,
provider: ProviderRefParser | type[ProviderRefParser] | None = None,
convention: ConventionType | None = None,
parse_provider_refs: bool = False,
parse_trailers: bool = False,
Expand All @@ -186,17 +186,21 @@ def __init__(
self.parse_trailers: bool = parse_trailers

# set provider
if not provider:
if not isinstance(provider, ProviderRefParser):
remote_url = self.get_remote_url()
split = remote_url.split("/")
provider_url = "/".join(split[:3])
namespace, project = "/".join(split[3:-1]), split[-1]
if "github" in provider_url:
if callable(provider):
provider = provider(namespace, project, url=provider_url)
elif "github" in provider_url:
provider = GitHub(namespace, project, url=provider_url)
elif "gitlab" in provider_url:
provider = GitLab(namespace, project, url=provider_url)
elif "bitbucket" in provider_url:
provider = Bitbucket(namespace, project, url=provider_url)
else:
provider = None
self.remote_url: str = remote_url
self.provider = provider

Expand Down
23 changes: 23 additions & 0 deletions src/git_changelog/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
CommitConvention,
ConventionalCommitConvention,
)
from git_changelog.providers import Bitbucket, GitHub, GitLab, ProviderRefParser

if TYPE_CHECKING:
from pathlib import Path
Expand Down Expand Up @@ -63,6 +64,13 @@ def _comma_separated_list(value: str) -> list[str]:
return value.split(",")


providers: dict[str, type[ProviderRefParser]] = {
"github": GitHub,
"gitlab": GitLab,
"bitbucket": Bitbucket,
}


def get_parser() -> argparse.ArgumentParser:
"""Return the CLI argument parser.
Expand Down Expand Up @@ -165,6 +173,14 @@ def get_parser() -> argparse.ArgumentParser:
default=sys.stdout,
help="Output to given file. Default: stdout.",
)
parser.add_argument(
"-p",
"--provider",
dest="provider",
default=None,
choices=providers.keys(),
help="Explicitly specify the repository provider. Default: %(default)s.",
)
parser.add_argument(
"-r",
"--parse-refs",
Expand Down Expand Up @@ -272,6 +288,7 @@ def build_and_render(
marker_line: str = DEFAULT_MARKER_LINE,
bump_latest: bool = False, # noqa: FBT001,FBT002
omit_empty_versions: bool = False, # noqa: FBT001,FBT002
provider: str | None = None,
) -> tuple[Changelog, str]:
"""Build a changelog and render it.
Expand All @@ -291,6 +308,7 @@ def build_and_render(
marker_line: Marker line used to insert contents in an existing changelog.
bump_latest: Whether to try and bump the latest version to guess the new one.
omit_empty_versions: Whether to omit empty versions from the output.
provider: Provider class used by this repository.
Raises:
ValueError: When some arguments are incompatible or missing.
Expand All @@ -315,9 +333,13 @@ def build_and_render(
if in_place and output is sys.stdout:
raise ValueError("Cannot write in-place to stdout")

# get provider
provider_class = providers[provider] if provider else None

# build data
changelog = Changelog(
repository,
provider=provider_class,
convention=convention,
parse_provider_refs=parse_refs,
parse_trailers=parse_trailers,
Expand Down Expand Up @@ -484,6 +506,7 @@ def main(args: list[str] | None = None) -> int:
convention=opts.convention,
parse_refs=opts.parse_refs,
parse_trailers=opts.parse_trailers,
provider=opts.provider,
sections=opts.sections,
in_place=opts.in_place,
output=opts.output,
Expand Down
48 changes: 12 additions & 36 deletions src/git_changelog/providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ class ProviderRefParser(ABC):
project: str
REF: ClassVar[dict[str, RefDef]] = {}

def __init__(self, namespace: str, project: str, url: str | None = None):
"""Initialization method.
Arguments:
namespace: The Bitbucket namespace.
project: The Bitbucket project.
url: The Bitbucket URL.
"""
self.namespace: str = namespace
self.project: str = project
self.url: str = url or self.url

def get_refs(self, ref_type: str, text: str) -> list[Ref]:
"""Find all references in the given text.
Expand Down Expand Up @@ -169,18 +181,6 @@ class GitHub(ProviderRefParser):
"mentions": RefDef(regex=re.compile(RefRe.BB + RefRe.MENTION, re.I), url_string="{base_url}/{ref}"),
}

def __init__(self, namespace: str, project: str, url: str = url):
"""Initialization method.
Arguments:
namespace: The GitHub namespace.
project: The GitHub project.
url: The GitHub URL.
"""
self.namespace: str = namespace
self.project: str = project
self.url: str = url # (shadowing but uses class' as default)

def build_ref_url(self, ref_type: str, match_dict: dict[str, str]) -> str: # noqa: D102 (use parent docstring)
match_dict["base_url"] = self.url
if not match_dict.get("namespace"):
Expand Down Expand Up @@ -275,18 +275,6 @@ class GitLab(ProviderRefParser):
"mentions": RefDef(regex=re.compile(RefRe.BB + RefRe.MENTION, re.I), url_string="{base_url}/{ref}"),
}

def __init__(self, namespace: str, project: str, url: str = url):
"""Initialization method.
Arguments:
namespace: The GitLab namespace.
project: The GitLab project.
url: The GitLab URL.
"""
self.namespace: str = namespace
self.project: str = project
self.url: str = url # (shadowing but uses class' as default)

def build_ref_url(self, ref_type: str, match_dict: dict[str, str]) -> str: # noqa: D102 (use parent docstring)
match_dict["base_url"] = self.url
if not match_dict.get("namespace"):
Expand Down Expand Up @@ -352,18 +340,6 @@ class Bitbucket(ProviderRefParser):
),
}

def __init__(self, namespace: str, project: str, url: str = url):
"""Initialization method.
Arguments:
namespace: The Bitbucket namespace.
project: The Bitbucket project.
url: The Bitbucket URL.
"""
self.namespace: str = namespace
self.project: str = project
self.url: str = url # (shadowing but uses class' as default)

def build_ref_url(self, ref_type: str, match_dict: dict[str, str]) -> str: # noqa: D102 (use parent docstring)
match_dict["base_url"] = self.url
if not match_dict.get("namespace"):
Expand Down

0 comments on commit 908531b

Please sign in to comment.