-
-
Notifications
You must be signed in to change notification settings - Fork 339
Expand file tree
/
Copy path__init__.py
More file actions
110 lines (83 loc) · 3.29 KB
/
__init__.py
File metadata and controls
110 lines (83 loc) · 3.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
from __future__ import annotations
import warnings
from importlib import metadata
from typing import TYPE_CHECKING, ClassVar, Protocol
from commitizen.exceptions import ChangelogFormatUnknown
if TYPE_CHECKING:
from collections.abc import Callable
from commitizen.changelog import IncrementalMergeInfo, Metadata
from commitizen.config.base_config import BaseConfig
CHANGELOG_FORMAT_ENTRYPOINT = "commitizen.changelog_format"
TEMPLATE_EXTENSION = "j2"
class ChangelogFormat(Protocol):
extension: ClassVar[str]
"""Standard known extension associated with this format"""
alternative_extensions: ClassVar[set[str]]
"""Known alternatives extensions for this format"""
config: BaseConfig
def __init__(self, config: BaseConfig) -> None:
self.config = config
@property
def ext(self) -> str:
"""Dotted version of extensions, as in `pathlib` and `os` modules"""
return f".{self.extension}"
@property
def template(self) -> str:
"""Expected template name for this format"""
return f"CHANGELOG.{self.extension}.{TEMPLATE_EXTENSION}"
@property
def default_changelog_file(self) -> str:
return f"CHANGELOG.{self.extension}"
def get_metadata(self, filepath: str) -> Metadata:
"""
Extract the changelog metadata.
"""
raise NotImplementedError
def get_latest_full_release(self, filepath: str) -> IncrementalMergeInfo:
"""
Extract metadata for the last non-pre-release.
"""
raise NotImplementedError
KNOWN_CHANGELOG_FORMATS: dict[str, type[ChangelogFormat]] = {
ep.name: ep.load()
for ep in metadata.entry_points(group=CHANGELOG_FORMAT_ENTRYPOINT)
}
def get_changelog_format(
config: BaseConfig, filename: str | None = None
) -> ChangelogFormat:
"""
Get a format from its name
:raises FormatUnknown: if a non-empty name is provided but cannot be found in the known formats
"""
name: str | None = config.settings.get("changelog_format")
format = (
name and KNOWN_CHANGELOG_FORMATS.get(name) or _guess_changelog_format(filename)
)
if not format:
raise ChangelogFormatUnknown(f"Unknown changelog format '{name}'")
return format(config)
def _guess_changelog_format(filename: str | None) -> type[ChangelogFormat] | None:
"""
Try guessing the file format from the filename.
Algorithm is basic, extension-based, and won't work
for extension-less file names like `CHANGELOG` or `NEWS`.
"""
if not filename or not isinstance(filename, str):
return None
for format in KNOWN_CHANGELOG_FORMATS.values():
if filename.endswith(f".{format.extension}"):
return format
for alt_extension in format.alternative_extensions:
if filename.endswith(f".{alt_extension}"):
return format
return None
def __getattr__(name: str) -> Callable[[str], type[ChangelogFormat] | None]:
if name == "guess_changelog_format":
warnings.warn(
"guess_changelog_format is deprecated and will be removed in v5. "
"Use _guess_changelog_format instead.",
DeprecationWarning,
stacklevel=2,
)
return _guess_changelog_format
raise AttributeError(f"module {__name__} has no attribute {name}")