commitizen 4.14.0__tar.gz → 4.15.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {commitizen-4.14.0 → commitizen-4.15.1}/PKG-INFO +1 -1
- commitizen-4.15.1/commitizen/__version__.py +1 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/bump.py +3 -3
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/cli.py +37 -3
- commitizen-4.15.1/commitizen/cmd.py +105 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/commands/bump.py +2 -2
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/commands/changelog.py +1 -1
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/commands/commit.py +3 -3
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/commands/init.py +12 -7
- commitizen-4.15.1/commitizen/commands/version.py +141 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/git.py +53 -36
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/hooks.py +1 -1
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/out.py +11 -11
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/tags.py +6 -8
- commitizen-4.15.1/commitizen/version_increment.py +33 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/version_schemes.py +13 -4
- {commitizen-4.14.0 → commitizen-4.15.1}/pyproject.toml +1 -1
- commitizen-4.14.0/commitizen/__version__.py +0 -1
- commitizen-4.14.0/commitizen/cmd.py +0 -57
- commitizen-4.14.0/commitizen/commands/version.py +0 -86
- {commitizen-4.14.0 → commitizen-4.15.1}/LICENSE +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/__init__.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/__main__.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/changelog.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/changelog_formats/__init__.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/changelog_formats/asciidoc.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/changelog_formats/base.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/changelog_formats/markdown.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/changelog_formats/restructuredtext.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/changelog_formats/textile.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/commands/__init__.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/commands/check.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/commands/example.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/commands/info.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/commands/list_cz.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/commands/schema.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/config/__init__.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/config/base_config.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/config/factory.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/config/json_config.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/config/toml_config.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/config/yaml_config.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/cz/__init__.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/cz/base.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/cz/conventional_commits/__init__.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/cz/conventional_commits/conventional_commits.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/cz/conventional_commits/conventional_commits_info.txt +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/cz/customize/__init__.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/cz/customize/customize.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/cz/customize/customize_info.txt +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/cz/exceptions.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/cz/jira/__init__.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/cz/jira/jira.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/cz/jira/jira_info.txt +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/cz/utils.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/defaults.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/exceptions.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/factory.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/project_info.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/providers/__init__.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/providers/base_provider.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/providers/cargo_provider.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/providers/commitizen_provider.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/providers/composer_provider.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/providers/npm_provider.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/providers/pep621_provider.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/providers/poetry_provider.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/providers/scm_provider.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/providers/uv_provider.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/py.typed +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/question.py +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/templates/CHANGELOG.adoc.j2 +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/templates/CHANGELOG.md.j2 +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/templates/CHANGELOG.rst.j2 +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/commitizen/templates/CHANGELOG.textile.j2 +0 -0
- {commitizen-4.14.0 → commitizen-4.15.1}/docs/README.md +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "4.15.1"
|
|
@@ -15,7 +15,7 @@ from commitizen.git import GitCommit, smart_open
|
|
|
15
15
|
if TYPE_CHECKING:
|
|
16
16
|
from collections.abc import Generator, Iterable
|
|
17
17
|
|
|
18
|
-
from commitizen.version_schemes import Increment,
|
|
18
|
+
from commitizen.version_schemes import Increment, VersionProtocol
|
|
19
19
|
|
|
20
20
|
VERSION_TYPES = [None, PATCH, MINOR, MAJOR]
|
|
21
21
|
|
|
@@ -131,8 +131,8 @@ def _resolve_files_and_regexes(
|
|
|
131
131
|
|
|
132
132
|
|
|
133
133
|
def create_commit_message(
|
|
134
|
-
current_version:
|
|
135
|
-
new_version:
|
|
134
|
+
current_version: VersionProtocol | str,
|
|
135
|
+
new_version: VersionProtocol | str,
|
|
136
136
|
message_template: str | None = None,
|
|
137
137
|
) -> str:
|
|
138
138
|
if message_template is None:
|
|
@@ -21,6 +21,7 @@ from commitizen.exceptions import (
|
|
|
21
21
|
InvalidCommandArgumentError,
|
|
22
22
|
NoCommandFoundError,
|
|
23
23
|
)
|
|
24
|
+
from commitizen.version_increment import VersionIncrement
|
|
24
25
|
|
|
25
26
|
logger = logging.getLogger(__name__)
|
|
26
27
|
|
|
@@ -542,13 +543,19 @@ data = {
|
|
|
542
543
|
},
|
|
543
544
|
{
|
|
544
545
|
"name": ["--major"],
|
|
545
|
-
"help":
|
|
546
|
+
"help": (
|
|
547
|
+
"Output just the major version. Must be used with MANUAL_VERSION, "
|
|
548
|
+
"--project, or --verbose."
|
|
549
|
+
),
|
|
546
550
|
"action": "store_true",
|
|
547
551
|
"exclusive_group": "group2",
|
|
548
552
|
},
|
|
549
553
|
{
|
|
550
554
|
"name": ["--minor"],
|
|
551
|
-
"help":
|
|
555
|
+
"help": (
|
|
556
|
+
"Output just the minor version. Must be used with MANUAL_VERSION, "
|
|
557
|
+
"--project, or --verbose."
|
|
558
|
+
),
|
|
552
559
|
"action": "store_true",
|
|
553
560
|
"exclusive_group": "group2",
|
|
554
561
|
},
|
|
@@ -558,6 +565,33 @@ data = {
|
|
|
558
565
|
"action": "store_true",
|
|
559
566
|
"exclusive_group": "group2",
|
|
560
567
|
},
|
|
568
|
+
{
|
|
569
|
+
"name": ["--patch"],
|
|
570
|
+
"help": (
|
|
571
|
+
"Output the patch version only. Must be used with MANUAL_VERSION, "
|
|
572
|
+
"--project, or --verbose."
|
|
573
|
+
),
|
|
574
|
+
"action": "store_true",
|
|
575
|
+
"exclusive_group": "group2",
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
"name": ["--next"],
|
|
579
|
+
"help": "Output the next version.",
|
|
580
|
+
"type": str,
|
|
581
|
+
"nargs": "?",
|
|
582
|
+
"default": None,
|
|
583
|
+
"const": "USE_GIT_COMMITS",
|
|
584
|
+
"choices": ["USE_GIT_COMMITS"]
|
|
585
|
+
+ [str(increment) for increment in VersionIncrement],
|
|
586
|
+
"exclusive_group": "group2",
|
|
587
|
+
},
|
|
588
|
+
{
|
|
589
|
+
"name": "manual_version",
|
|
590
|
+
"type": str,
|
|
591
|
+
"nargs": "?",
|
|
592
|
+
"help": "Use the version provided instead of the version from the project. Can be used to test the selected version scheme.",
|
|
593
|
+
"metavar": "MANUAL_VERSION",
|
|
594
|
+
},
|
|
561
595
|
],
|
|
562
596
|
},
|
|
563
597
|
],
|
|
@@ -670,7 +704,7 @@ def main() -> None:
|
|
|
670
704
|
logger.warning(
|
|
671
705
|
"\nWARN: Incomplete commit command: received -- separator without any following git arguments\n"
|
|
672
706
|
)
|
|
673
|
-
extra_args =
|
|
707
|
+
extra_args = unknown_args[1:]
|
|
674
708
|
arguments["extra_cli_args"] = extra_args
|
|
675
709
|
|
|
676
710
|
conf = config.read_cfg(args.config)
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import subprocess
|
|
5
|
+
import warnings
|
|
6
|
+
from typing import TYPE_CHECKING, NamedTuple, overload
|
|
7
|
+
|
|
8
|
+
from charset_normalizer import from_bytes
|
|
9
|
+
|
|
10
|
+
from commitizen.exceptions import CharacterSetDecodeError
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from collections.abc import Mapping, Sequence
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Command(NamedTuple):
|
|
17
|
+
out: str
|
|
18
|
+
err: str
|
|
19
|
+
stdout: bytes
|
|
20
|
+
stderr: bytes
|
|
21
|
+
return_code: int
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _try_decode(bytes_: bytes) -> str:
|
|
25
|
+
try:
|
|
26
|
+
return bytes_.decode("utf-8")
|
|
27
|
+
except UnicodeDecodeError:
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
charset_match = from_bytes(bytes_).best()
|
|
31
|
+
if charset_match is None:
|
|
32
|
+
raise CharacterSetDecodeError()
|
|
33
|
+
try:
|
|
34
|
+
return bytes_.decode(charset_match.encoding)
|
|
35
|
+
except UnicodeDecodeError as e:
|
|
36
|
+
raise CharacterSetDecodeError() from e
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _popen(
|
|
40
|
+
cmd: str | Sequence[str],
|
|
41
|
+
*,
|
|
42
|
+
shell: bool,
|
|
43
|
+
env: Mapping[str, str] | None = None,
|
|
44
|
+
) -> Command:
|
|
45
|
+
if env is not None:
|
|
46
|
+
env = {**os.environ, **env}
|
|
47
|
+
|
|
48
|
+
process = subprocess.Popen(
|
|
49
|
+
cmd,
|
|
50
|
+
shell=shell,
|
|
51
|
+
stdout=subprocess.PIPE,
|
|
52
|
+
stderr=subprocess.PIPE,
|
|
53
|
+
stdin=subprocess.PIPE,
|
|
54
|
+
env=env,
|
|
55
|
+
)
|
|
56
|
+
stdout, stderr = process.communicate()
|
|
57
|
+
return_code = process.returncode
|
|
58
|
+
return Command(
|
|
59
|
+
_try_decode(stdout),
|
|
60
|
+
_try_decode(stderr),
|
|
61
|
+
stdout,
|
|
62
|
+
stderr,
|
|
63
|
+
return_code,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@overload
|
|
68
|
+
def run(cmd: str, env: Mapping[str, str] | None = None) -> Command: ...
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@overload
|
|
72
|
+
def run(cmd: Sequence[str], env: Mapping[str, str] | None = None) -> Command: ...
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def run(cmd: str | Sequence[str], env: Mapping[str, str] | None = None) -> Command:
|
|
76
|
+
"""Run a command safely without shell interpretation (shell=False).
|
|
77
|
+
|
|
78
|
+
Arguments are passed directly to the OS, preventing shell-injection
|
|
79
|
+
vulnerabilities (CWE-78).
|
|
80
|
+
|
|
81
|
+
Passing a string is deprecated and will be removed in a future version.
|
|
82
|
+
Use a list of arguments instead, or use run_shell() for shell features.
|
|
83
|
+
"""
|
|
84
|
+
if isinstance(cmd, str):
|
|
85
|
+
warnings.warn(
|
|
86
|
+
"Passing a string to cmd.run() is deprecated and will be removed in v5. "
|
|
87
|
+
"Use a list of arguments instead, or use cmd.run_shell() explicitly.",
|
|
88
|
+
DeprecationWarning,
|
|
89
|
+
stacklevel=2,
|
|
90
|
+
)
|
|
91
|
+
return _popen(cmd, shell=True, env=env)
|
|
92
|
+
return _popen(cmd, shell=False, env=env)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def run_shell(cmd: str, env: Mapping[str, str] | None = None) -> Command:
|
|
96
|
+
"""Run a command string via the system shell (shell=True).
|
|
97
|
+
|
|
98
|
+
Only use this for cases that intentionally require shell features
|
|
99
|
+
(e.g., user-defined hooks with pipes/redirects). Never pass
|
|
100
|
+
untrusted/user-controlled values into *cmd*.
|
|
101
|
+
|
|
102
|
+
Related: CWE-78 (OS Command Injection),
|
|
103
|
+
https://github.com/commitizen-tools/commitizen/issues/1918
|
|
104
|
+
"""
|
|
105
|
+
return _popen(cmd, shell=True, env=env)
|
|
@@ -439,8 +439,8 @@ class Bump:
|
|
|
439
439
|
else:
|
|
440
440
|
out.success("Done!")
|
|
441
441
|
|
|
442
|
-
def _get_commit_args(self) -> str:
|
|
442
|
+
def _get_commit_args(self) -> list[str]:
|
|
443
443
|
commit_args = ["-a"]
|
|
444
444
|
if self.no_verify:
|
|
445
445
|
commit_args.append("--no-verify")
|
|
446
|
-
return
|
|
446
|
+
return commit_args
|
|
@@ -257,7 +257,7 @@ class Changelog:
|
|
|
257
257
|
changelog_meta.latest_version_position = None
|
|
258
258
|
changelog_meta.unreleased_end = latest_full_release_info.index + 1
|
|
259
259
|
|
|
260
|
-
commits = git.get_commits(start=start_rev, end=end_rev, args="--topo-order")
|
|
260
|
+
commits = git.get_commits(start=start_rev, end=end_rev, args=["--topo-order"])
|
|
261
261
|
if (
|
|
262
262
|
not self.allow_no_commit
|
|
263
263
|
and not commits
|
|
@@ -34,7 +34,7 @@ class CommitArgs(TypedDict, total=False):
|
|
|
34
34
|
all: bool
|
|
35
35
|
dry_run: bool
|
|
36
36
|
edit: bool
|
|
37
|
-
extra_cli_args: str
|
|
37
|
+
extra_cli_args: list[str]
|
|
38
38
|
message_length_limit: int
|
|
39
39
|
no_retry: bool
|
|
40
40
|
signoff: bool
|
|
@@ -132,7 +132,7 @@ class Commit:
|
|
|
132
132
|
return self._get_message_by_prompt_commit_questions()
|
|
133
133
|
|
|
134
134
|
def __call__(self) -> None:
|
|
135
|
-
extra_args = self.arguments.get("extra_cli_args",
|
|
135
|
+
extra_args: list[str] = self.arguments.get("extra_cli_args", [])
|
|
136
136
|
dry_run = bool(self.arguments.get("dry_run"))
|
|
137
137
|
write_message_to_file = self.arguments.get("write_message_to_file")
|
|
138
138
|
signoff = bool(self.arguments.get("signoff"))
|
|
@@ -167,7 +167,7 @@ class Commit:
|
|
|
167
167
|
raise DryRunExit()
|
|
168
168
|
|
|
169
169
|
if self.config.settings["always_signoff"] or signoff:
|
|
170
|
-
extra_args =
|
|
170
|
+
extra_args = [*extra_args, "-s"]
|
|
171
171
|
|
|
172
172
|
c = git.commit(commit_message, args=extra_args)
|
|
173
173
|
if c.return_code != 0:
|
|
@@ -17,7 +17,11 @@ from commitizen.exceptions import (
|
|
|
17
17
|
NoAnswersError,
|
|
18
18
|
)
|
|
19
19
|
from commitizen.git import get_latest_tag_name, get_tag_names, smart_open
|
|
20
|
-
from commitizen.version_schemes import
|
|
20
|
+
from commitizen.version_schemes import (
|
|
21
|
+
KNOWN_SCHEMES,
|
|
22
|
+
VersionProtocol,
|
|
23
|
+
get_version_scheme,
|
|
24
|
+
)
|
|
21
25
|
|
|
22
26
|
if TYPE_CHECKING:
|
|
23
27
|
from commitizen.config import (
|
|
@@ -130,11 +134,12 @@ class Init:
|
|
|
130
134
|
"pre-commit is not installed in current environment."
|
|
131
135
|
)
|
|
132
136
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
c = cmd.run(
|
|
137
|
+
cmd_args = ["pre-commit", "install"]
|
|
138
|
+
for ty in hook_types:
|
|
139
|
+
cmd_args.extend(["--hook-type", ty])
|
|
140
|
+
c = cmd.run(cmd_args)
|
|
137
141
|
if c.return_code != 0:
|
|
142
|
+
cmd_str = " ".join(cmd_args)
|
|
138
143
|
raise InitFailedError(
|
|
139
144
|
"Failed to install pre-commit hook.\n"
|
|
140
145
|
f"Error running {cmd_str}."
|
|
@@ -265,7 +270,7 @@ class Init:
|
|
|
265
270
|
).unsafe_ask()
|
|
266
271
|
return scheme
|
|
267
272
|
|
|
268
|
-
def _ask_major_version_zero(self, version:
|
|
273
|
+
def _ask_major_version_zero(self, version: VersionProtocol) -> bool:
|
|
269
274
|
"""Ask for setting: major_version_zero"""
|
|
270
275
|
if version.major > 0:
|
|
271
276
|
return False
|
|
@@ -323,7 +328,7 @@ def _write_config_to_file(
|
|
|
323
328
|
cz_name: str,
|
|
324
329
|
version_provider: str,
|
|
325
330
|
version_scheme: str,
|
|
326
|
-
version:
|
|
331
|
+
version: VersionProtocol,
|
|
327
332
|
tag_format: str,
|
|
328
333
|
update_changelog_on_bump: bool,
|
|
329
334
|
major_version_zero: bool,
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import platform
|
|
2
|
+
import sys
|
|
3
|
+
from typing import TypedDict
|
|
4
|
+
|
|
5
|
+
from packaging.version import InvalidVersion
|
|
6
|
+
|
|
7
|
+
from commitizen import out
|
|
8
|
+
from commitizen.__version__ import __version__
|
|
9
|
+
from commitizen.config import BaseConfig
|
|
10
|
+
from commitizen.exceptions import NoVersionSpecifiedError, VersionSchemeUnknown
|
|
11
|
+
from commitizen.providers import get_provider
|
|
12
|
+
from commitizen.tags import TagRules
|
|
13
|
+
from commitizen.version_increment import VersionIncrement
|
|
14
|
+
from commitizen.version_schemes import Increment, get_version_scheme
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class VersionArgs(TypedDict, total=False):
|
|
18
|
+
manual_version: str | None
|
|
19
|
+
next: str | None
|
|
20
|
+
|
|
21
|
+
# Exclusive groups 1
|
|
22
|
+
commitizen: bool
|
|
23
|
+
report: bool
|
|
24
|
+
project: bool
|
|
25
|
+
verbose: bool
|
|
26
|
+
|
|
27
|
+
# Exclusive groups 2
|
|
28
|
+
major: bool
|
|
29
|
+
minor: bool
|
|
30
|
+
patch: bool
|
|
31
|
+
tag: bool
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class Version:
|
|
35
|
+
"""Get the version of the installed commitizen or the current project.
|
|
36
|
+
Precedence:
|
|
37
|
+
1. report
|
|
38
|
+
2. commitizen
|
|
39
|
+
3. verbose, project
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def __init__(self, config: BaseConfig, arguments: VersionArgs) -> None:
|
|
43
|
+
self.config: BaseConfig = config
|
|
44
|
+
self.arguments = arguments
|
|
45
|
+
|
|
46
|
+
def __call__(self) -> None:
|
|
47
|
+
if self.arguments.get("report"):
|
|
48
|
+
out.write(f"Commitizen Version: {__version__}")
|
|
49
|
+
out.write(f"Python Version: {sys.version}")
|
|
50
|
+
out.write(f"Operating System: {platform.system()}")
|
|
51
|
+
return
|
|
52
|
+
|
|
53
|
+
if self.arguments.get("verbose"):
|
|
54
|
+
out.write(f"Installed Commitizen Version: {__version__}")
|
|
55
|
+
|
|
56
|
+
if self.arguments.get("commitizen"):
|
|
57
|
+
out.write(__version__)
|
|
58
|
+
return
|
|
59
|
+
|
|
60
|
+
if (
|
|
61
|
+
self.arguments.get("project")
|
|
62
|
+
or self.arguments.get("verbose")
|
|
63
|
+
or self.arguments.get("next")
|
|
64
|
+
or self.arguments.get("manual_version")
|
|
65
|
+
):
|
|
66
|
+
version_str = self.arguments.get("manual_version")
|
|
67
|
+
if version_str is None:
|
|
68
|
+
try:
|
|
69
|
+
version_str = get_provider(self.config).get_version()
|
|
70
|
+
except NoVersionSpecifiedError:
|
|
71
|
+
out.error("No project information in this project.")
|
|
72
|
+
return
|
|
73
|
+
try:
|
|
74
|
+
scheme_factory = get_version_scheme(self.config.settings)
|
|
75
|
+
except VersionSchemeUnknown:
|
|
76
|
+
out.error("Unknown version scheme.")
|
|
77
|
+
return
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
version = scheme_factory(version_str)
|
|
81
|
+
except InvalidVersion:
|
|
82
|
+
out.error(f"Invalid version: '{version_str}'")
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
if next_increment_str := self.arguments.get("next"):
|
|
86
|
+
if next_increment_str == "USE_GIT_COMMITS":
|
|
87
|
+
# TODO: implement USE_GIT_COMMITS by deriving the increment from
|
|
88
|
+
# git history. This requires refactoring the bump logic out of
|
|
89
|
+
# `commitizen/commands/bump.py` so it can be reused here. See #1678.
|
|
90
|
+
out.error("--next USE_GIT_COMMITS is not implemented yet.")
|
|
91
|
+
return
|
|
92
|
+
|
|
93
|
+
next_increment = VersionIncrement.from_value(next_increment_str)
|
|
94
|
+
increment: Increment | None
|
|
95
|
+
if next_increment == VersionIncrement.NONE:
|
|
96
|
+
increment = None
|
|
97
|
+
elif next_increment == VersionIncrement.PATCH:
|
|
98
|
+
increment = "PATCH"
|
|
99
|
+
elif next_increment == VersionIncrement.MINOR:
|
|
100
|
+
increment = "MINOR"
|
|
101
|
+
else:
|
|
102
|
+
increment = "MAJOR"
|
|
103
|
+
version = version.bump(increment=increment)
|
|
104
|
+
|
|
105
|
+
if self.arguments.get("major"):
|
|
106
|
+
out.write(version.major)
|
|
107
|
+
return
|
|
108
|
+
if self.arguments.get("minor"):
|
|
109
|
+
out.write(version.minor)
|
|
110
|
+
return
|
|
111
|
+
if self.arguments.get("patch"):
|
|
112
|
+
out.write(version.micro)
|
|
113
|
+
return
|
|
114
|
+
|
|
115
|
+
display_version: str
|
|
116
|
+
if self.arguments.get("tag"):
|
|
117
|
+
tag_rules = TagRules.from_settings(self.config.settings)
|
|
118
|
+
display_version = tag_rules.normalize_tag(version)
|
|
119
|
+
else:
|
|
120
|
+
display_version = str(version)
|
|
121
|
+
|
|
122
|
+
out.write(
|
|
123
|
+
f"Project Version: {display_version}"
|
|
124
|
+
if self.arguments.get("verbose")
|
|
125
|
+
else display_version
|
|
126
|
+
)
|
|
127
|
+
return
|
|
128
|
+
|
|
129
|
+
for argument in ("major", "minor", "patch"):
|
|
130
|
+
if self.arguments.get(argument):
|
|
131
|
+
out.error(
|
|
132
|
+
f"{argument} can only be used with MANUAL_VERSION, --project or --verbose."
|
|
133
|
+
)
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
if self.arguments.get("tag"):
|
|
137
|
+
out.error("Tag can only be used with --project or --verbose.")
|
|
138
|
+
return
|
|
139
|
+
|
|
140
|
+
# If no arguments are provided, just show the installed commitizen version
|
|
141
|
+
out.write(__version__)
|
|
@@ -5,10 +5,14 @@ from enum import Enum
|
|
|
5
5
|
from functools import lru_cache
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from tempfile import NamedTemporaryFile
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
8
9
|
|
|
9
10
|
from commitizen import cmd, out
|
|
10
11
|
from commitizen.exceptions import GitCommandError
|
|
11
12
|
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from collections.abc import Sequence
|
|
15
|
+
|
|
12
16
|
|
|
13
17
|
class EOLType(Enum):
|
|
14
18
|
"""The EOL type from `git config core.eol`."""
|
|
@@ -19,7 +23,7 @@ class EOLType(Enum):
|
|
|
19
23
|
|
|
20
24
|
@classmethod
|
|
21
25
|
def for_open(cls) -> str:
|
|
22
|
-
c = cmd.run("git config core.eol")
|
|
26
|
+
c = cmd.run(["git", "config", "core.eol"])
|
|
23
27
|
eol = c.out.strip().upper()
|
|
24
28
|
return cls._char_for_open()[cls._safe_cast(eol)]
|
|
25
29
|
|
|
@@ -164,49 +168,47 @@ def tag(
|
|
|
164
168
|
tag: str, annotated: bool = False, signed: bool = False, msg: str | None = None
|
|
165
169
|
) -> cmd.Command:
|
|
166
170
|
if not annotated and not signed:
|
|
167
|
-
return cmd.run(
|
|
171
|
+
return cmd.run(["git", "tag", tag])
|
|
168
172
|
|
|
169
173
|
# according to https://git-scm.com/book/en/v2/Git-Basics-Tagging,
|
|
170
174
|
# we're not able to create lightweight tag with message.
|
|
171
175
|
# by adding message, we make it a annotated tags
|
|
172
176
|
option = "-s" if signed else "-a" # The else case is for annotated tags
|
|
173
|
-
return cmd.run(
|
|
177
|
+
return cmd.run(["git", "tag", option, tag, "-m", msg or tag])
|
|
174
178
|
|
|
175
179
|
|
|
176
180
|
def add(*args: str) -> cmd.Command:
|
|
177
|
-
return cmd.run(
|
|
181
|
+
return cmd.run(["git", "add", *args])
|
|
178
182
|
|
|
179
183
|
|
|
180
184
|
def commit(
|
|
181
185
|
message: str,
|
|
182
|
-
args: str =
|
|
186
|
+
args: Sequence[str] = (),
|
|
183
187
|
committer_date: str | None = None,
|
|
184
188
|
) -> cmd.Command:
|
|
185
189
|
f = NamedTemporaryFile("wb", delete=False)
|
|
186
190
|
f.write(message.encode("utf-8"))
|
|
187
191
|
f.close()
|
|
188
192
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
+
cmd_args = ["git", "commit"]
|
|
194
|
+
if args:
|
|
195
|
+
cmd_args.extend(args)
|
|
196
|
+
cmd_args.extend(["-F", f.name])
|
|
193
197
|
|
|
198
|
+
env: dict[str, str] | None = None
|
|
199
|
+
if committer_date:
|
|
200
|
+
env = {"GIT_COMMITTER_DATE": committer_date}
|
|
194
201
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
return command
|
|
199
|
-
if os.name != "nt":
|
|
200
|
-
return f"GIT_COMMITTER_DATE={committer_date} {command}"
|
|
201
|
-
# Using `cmd /v /c "{command}"` sets environment variables only for that command
|
|
202
|
-
return f'cmd /v /c "set GIT_COMMITTER_DATE={committer_date}&& {command}"'
|
|
202
|
+
c = cmd.run(cmd_args, env=env)
|
|
203
|
+
os.unlink(f.name)
|
|
204
|
+
return c
|
|
203
205
|
|
|
204
206
|
|
|
205
207
|
def get_commits(
|
|
206
208
|
start: str | None = None,
|
|
207
209
|
end: str | None = None,
|
|
208
210
|
*,
|
|
209
|
-
args: str =
|
|
211
|
+
args: Sequence[str] = (),
|
|
210
212
|
) -> list[GitCommit]:
|
|
211
213
|
"""Get the commits between start and end."""
|
|
212
214
|
if end is None:
|
|
@@ -226,7 +228,10 @@ def get_filenames_in_commit(git_reference: str = "") -> list[str]:
|
|
|
226
228
|
|
|
227
229
|
:returns: file names committed in the last commit by default or inside the passed git reference
|
|
228
230
|
"""
|
|
229
|
-
|
|
231
|
+
cmd_args = ["git", "show", "--name-only", "--pretty=format:"]
|
|
232
|
+
if git_reference:
|
|
233
|
+
cmd_args.append(git_reference)
|
|
234
|
+
c = cmd.run(cmd_args)
|
|
230
235
|
if c.return_code == 0:
|
|
231
236
|
return c.out.strip().split("\n")
|
|
232
237
|
raise GitCommandError(c.err)
|
|
@@ -237,15 +242,17 @@ def get_tags(
|
|
|
237
242
|
) -> list[GitTag]:
|
|
238
243
|
inner_delimiter = "---inner_delimiter---"
|
|
239
244
|
formatter = (
|
|
240
|
-
f
|
|
245
|
+
f"%(refname:strip=2){inner_delimiter}"
|
|
241
246
|
f"%(objectname){inner_delimiter}"
|
|
242
247
|
f"%(creatordate:format:{dateformat}){inner_delimiter}"
|
|
243
|
-
f
|
|
248
|
+
f"%(object)"
|
|
244
249
|
)
|
|
245
|
-
|
|
250
|
+
cmd_args = ["git", "tag", f"--format={formatter}", "--sort=-creatordate"]
|
|
251
|
+
if reachable_only:
|
|
252
|
+
cmd_args.append("--merged")
|
|
246
253
|
# Force the default language for parsing
|
|
247
254
|
env = {"LC_ALL": "C", "LANG": "C", "LANGUAGE": "C"}
|
|
248
|
-
c = cmd.run(
|
|
255
|
+
c = cmd.run(cmd_args, env=env)
|
|
249
256
|
if c.return_code != 0:
|
|
250
257
|
if reachable_only and c.err == "fatal: malformed object name HEAD\n":
|
|
251
258
|
# this can happen if there are no commits in the repo yet
|
|
@@ -262,37 +269,37 @@ def get_tags(
|
|
|
262
269
|
|
|
263
270
|
|
|
264
271
|
def tag_exist(tag: str) -> bool:
|
|
265
|
-
c = cmd.run(
|
|
272
|
+
c = cmd.run(["git", "tag", "--list", tag])
|
|
266
273
|
return tag in c.out
|
|
267
274
|
|
|
268
275
|
|
|
269
276
|
def is_signed_tag(tag: str) -> bool:
|
|
270
|
-
return cmd.run(
|
|
277
|
+
return cmd.run(["git", "tag", "-v", tag]).return_code == 0
|
|
271
278
|
|
|
272
279
|
|
|
273
280
|
def get_latest_tag_name() -> str | None:
|
|
274
|
-
c = cmd.run("git describe --abbrev=0 --tags")
|
|
281
|
+
c = cmd.run(["git", "describe", "--abbrev=0", "--tags"])
|
|
275
282
|
if c.err:
|
|
276
283
|
return None
|
|
277
284
|
return c.out.strip()
|
|
278
285
|
|
|
279
286
|
|
|
280
287
|
def get_tag_message(tag: str) -> str | None:
|
|
281
|
-
c = cmd.run(
|
|
288
|
+
c = cmd.run(["git", "tag", "-l", "--format=%(contents:subject)", tag])
|
|
282
289
|
if c.err:
|
|
283
290
|
return None
|
|
284
291
|
return c.out.strip()
|
|
285
292
|
|
|
286
293
|
|
|
287
294
|
def get_tag_names() -> list[str]:
|
|
288
|
-
c = cmd.run("git tag --list")
|
|
295
|
+
c = cmd.run(["git", "tag", "--list"])
|
|
289
296
|
if c.err:
|
|
290
297
|
return []
|
|
291
298
|
return [tag for raw in c.out.split("\n") if (tag := raw.strip())]
|
|
292
299
|
|
|
293
300
|
|
|
294
301
|
def find_git_project_root() -> Path | None:
|
|
295
|
-
c = cmd.run("git rev-parse --show-toplevel")
|
|
302
|
+
c = cmd.run(["git", "rev-parse", "--show-toplevel"])
|
|
296
303
|
if c.err:
|
|
297
304
|
return None
|
|
298
305
|
return Path(c.out.strip())
|
|
@@ -300,17 +307,17 @@ def find_git_project_root() -> Path | None:
|
|
|
300
307
|
|
|
301
308
|
def is_staging_clean() -> bool:
|
|
302
309
|
"""Check if staging is clean."""
|
|
303
|
-
c = cmd.run("git diff --no-ext-diff --cached --name-only")
|
|
310
|
+
c = cmd.run(["git", "diff", "--no-ext-diff", "--cached", "--name-only"])
|
|
304
311
|
return not bool(c.out)
|
|
305
312
|
|
|
306
313
|
|
|
307
314
|
def is_git_project() -> bool:
|
|
308
|
-
c = cmd.run("git rev-parse --is-inside-work-tree")
|
|
315
|
+
c = cmd.run(["git", "rev-parse", "--is-inside-work-tree"])
|
|
309
316
|
return c.out.strip() == "true"
|
|
310
317
|
|
|
311
318
|
|
|
312
319
|
def get_core_editor() -> str | None:
|
|
313
|
-
c = cmd.run("git var GIT_EDITOR")
|
|
320
|
+
c = cmd.run(["git", "var", "GIT_EDITOR"])
|
|
314
321
|
if c.out:
|
|
315
322
|
return c.out.strip()
|
|
316
323
|
return None
|
|
@@ -321,21 +328,31 @@ def smart_open(*args, **kwargs): # type: ignore[no-untyped-def,unused-ignore] #
|
|
|
321
328
|
return open(*args, newline=EOLType.for_open(), **kwargs)
|
|
322
329
|
|
|
323
330
|
|
|
324
|
-
def _get_log_as_str_list(start: str | None, end: str, args: str) -> list[str]:
|
|
331
|
+
def _get_log_as_str_list(start: str | None, end: str, args: Sequence[str]) -> list[str]:
|
|
325
332
|
"""Get string representation of each log entry"""
|
|
326
333
|
delimiter = "----------commit-delimiter----------"
|
|
327
334
|
log_format: str = "%H%n%P%n%s%n%an%n%ae%n%b"
|
|
328
335
|
command_range = f"{start}..{end}" if start else end
|
|
329
|
-
|
|
336
|
+
cmd_args = [
|
|
337
|
+
"git",
|
|
338
|
+
"-c",
|
|
339
|
+
"log.showSignature=False",
|
|
340
|
+
"log",
|
|
341
|
+
f"--pretty={log_format}{delimiter}",
|
|
342
|
+
]
|
|
343
|
+
if args:
|
|
344
|
+
cmd_args.extend(args)
|
|
345
|
+
if command_range:
|
|
346
|
+
cmd_args.append(command_range)
|
|
330
347
|
|
|
331
|
-
c = cmd.run(
|
|
348
|
+
c = cmd.run(cmd_args)
|
|
332
349
|
if c.return_code != 0:
|
|
333
350
|
raise GitCommandError(c.err)
|
|
334
351
|
return c.out.split(f"{delimiter}\n")
|
|
335
352
|
|
|
336
353
|
|
|
337
354
|
def get_default_branch() -> str:
|
|
338
|
-
c = cmd.run("git symbolic-ref refs/remotes/origin/HEAD")
|
|
355
|
+
c = cmd.run(["git", "symbolic-ref", "refs/remotes/origin/HEAD"])
|
|
339
356
|
if c.return_code != 0:
|
|
340
357
|
raise GitCommandError(c.err)
|
|
341
358
|
return c.out.strip()
|
|
@@ -17,7 +17,7 @@ def run(hooks: str | list[str], _env_prefix: str = "CZ_", **env: object) -> None
|
|
|
17
17
|
for hook in hooks:
|
|
18
18
|
out.info(f"Running hook '{hook}'")
|
|
19
19
|
|
|
20
|
-
c = cmd.
|
|
20
|
+
c = cmd.run_shell(hook, env=_format_env(_env_prefix, env))
|
|
21
21
|
|
|
22
22
|
if c.out:
|
|
23
23
|
out.write(c.out)
|
|
@@ -9,35 +9,35 @@ if sys.platform == "win32":
|
|
|
9
9
|
sys.stdout.reconfigure(encoding="utf-8")
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
def write(value:
|
|
12
|
+
def write(value: object, *args: object) -> None:
|
|
13
13
|
"""Intended to be used when value is multiline."""
|
|
14
14
|
print(value, *args)
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
def line(value:
|
|
17
|
+
def line(value: object, *args: object, **kwargs: Any) -> None:
|
|
18
18
|
"""Wrapper in case I want to do something different later."""
|
|
19
19
|
print(value, *args, **kwargs)
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
def error(value:
|
|
23
|
-
message = colored(value, "red")
|
|
22
|
+
def error(value: object) -> None:
|
|
23
|
+
message = colored(str(value), "red")
|
|
24
24
|
line(message, file=sys.stderr)
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
def success(value:
|
|
28
|
-
message = colored(value, "green")
|
|
27
|
+
def success(value: object) -> None:
|
|
28
|
+
message = colored(str(value), "green")
|
|
29
29
|
line(message)
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
def info(value:
|
|
33
|
-
message = colored(value, "blue")
|
|
32
|
+
def info(value: object) -> None:
|
|
33
|
+
message = colored(str(value), "blue")
|
|
34
34
|
line(message)
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
def diagnostic(value:
|
|
37
|
+
def diagnostic(value: object) -> None:
|
|
38
38
|
line(value, file=sys.stderr)
|
|
39
39
|
|
|
40
40
|
|
|
41
|
-
def warn(value:
|
|
42
|
-
message = colored(value, "magenta")
|
|
41
|
+
def warn(value: object) -> None:
|
|
42
|
+
message = colored(str(value), "magenta")
|
|
43
43
|
line(message, file=sys.stderr)
|
|
@@ -14,7 +14,7 @@ from commitizen.git import GitTag
|
|
|
14
14
|
from commitizen.version_schemes import (
|
|
15
15
|
DEFAULT_SCHEME,
|
|
16
16
|
InvalidVersion,
|
|
17
|
-
|
|
17
|
+
VersionProtocol,
|
|
18
18
|
VersionScheme,
|
|
19
19
|
get_version_scheme,
|
|
20
20
|
)
|
|
@@ -23,8 +23,6 @@ if TYPE_CHECKING:
|
|
|
23
23
|
import sys
|
|
24
24
|
from collections.abc import Iterable, Sequence
|
|
25
25
|
|
|
26
|
-
from commitizen.version_schemes import VersionScheme
|
|
27
|
-
|
|
28
26
|
# Self is Python 3.11+ but backported in typing-extensions
|
|
29
27
|
if sys.version_info < (3, 11):
|
|
30
28
|
from typing_extensions import Self
|
|
@@ -75,7 +73,7 @@ class TagRules:
|
|
|
75
73
|
assert not rules.is_version_tag("warn1.0.0", warn=True) # Does warn
|
|
76
74
|
|
|
77
75
|
assert rules.search_version("# My v1.0.0 version").version == "1.0.0"
|
|
78
|
-
assert rules.extract_version("v1.0.0") ==
|
|
76
|
+
assert rules.extract_version("v1.0.0") == rules.scheme("1.0.0")
|
|
79
77
|
try:
|
|
80
78
|
assert rules.extract_version("not-a-v1.0.0")
|
|
81
79
|
except InvalidVersion:
|
|
@@ -145,7 +143,7 @@ class TagRules:
|
|
|
145
143
|
"""Filter in version tags and warn on unexpected tags"""
|
|
146
144
|
return [tag for tag in tags if self.is_version_tag(tag, warn)]
|
|
147
145
|
|
|
148
|
-
def extract_version(self, tag: GitTag) ->
|
|
146
|
+
def extract_version(self, tag: GitTag) -> VersionProtocol:
|
|
149
147
|
"""
|
|
150
148
|
Extract a version from the tag as defined in tag formats.
|
|
151
149
|
|
|
@@ -195,7 +193,7 @@ class TagRules:
|
|
|
195
193
|
return VersionTag(version, match.group(0))
|
|
196
194
|
|
|
197
195
|
def normalize_tag(
|
|
198
|
-
self, version:
|
|
196
|
+
self, version: VersionProtocol | str, tag_format: str | None = None
|
|
199
197
|
) -> str:
|
|
200
198
|
"""
|
|
201
199
|
The tag and the software version might be different.
|
|
@@ -225,7 +223,7 @@ class TagRules:
|
|
|
225
223
|
)
|
|
226
224
|
|
|
227
225
|
def find_tag_for(
|
|
228
|
-
self, tags: Iterable[GitTag], version:
|
|
226
|
+
self, tags: Iterable[GitTag], version: VersionProtocol | str
|
|
229
227
|
) -> GitTag | None:
|
|
230
228
|
"""Find the first matching tag for a given version."""
|
|
231
229
|
version = self.scheme(version) if isinstance(version, str) else version
|
|
@@ -234,7 +232,7 @@ class TagRules:
|
|
|
234
232
|
# If the requested version is incomplete (e.g., "1.2"), try to find the latest
|
|
235
233
|
# matching tag that shares the provided prefix.
|
|
236
234
|
if len(release) < 3:
|
|
237
|
-
matching_versions: list[tuple[
|
|
235
|
+
matching_versions: list[tuple[VersionProtocol, GitTag]] = []
|
|
238
236
|
for tag in tags:
|
|
239
237
|
try:
|
|
240
238
|
tag_version = self.extract_version(tag)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from enum import IntEnum
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class VersionIncrement(IntEnum):
|
|
7
|
+
"""Semantic versioning bump increments.
|
|
8
|
+
|
|
9
|
+
IntEnum keeps a total order compatible with NONE < PATCH < MINOR < MAJOR
|
|
10
|
+
for comparisons across the codebase.
|
|
11
|
+
|
|
12
|
+
- NONE: no bump (docs-only / style commits, etc.)
|
|
13
|
+
- PATCH: backwards-compatible bug fixes
|
|
14
|
+
- MINOR: backwards-compatible features
|
|
15
|
+
- MAJOR: incompatible API changes
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
NONE = 0
|
|
19
|
+
PATCH = 1
|
|
20
|
+
MINOR = 2
|
|
21
|
+
MAJOR = 3
|
|
22
|
+
|
|
23
|
+
def __str__(self) -> str:
|
|
24
|
+
return self.name
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
def from_value(cls, value: object) -> VersionIncrement:
|
|
28
|
+
if not isinstance(value, str):
|
|
29
|
+
return VersionIncrement.NONE
|
|
30
|
+
try:
|
|
31
|
+
return cls[value]
|
|
32
|
+
except KeyError:
|
|
33
|
+
return VersionIncrement.NONE
|
|
@@ -10,6 +10,7 @@ from typing import (
|
|
|
10
10
|
ClassVar,
|
|
11
11
|
Literal,
|
|
12
12
|
Protocol,
|
|
13
|
+
TypeAlias,
|
|
13
14
|
cast,
|
|
14
15
|
runtime_checkable,
|
|
15
16
|
)
|
|
@@ -22,7 +23,6 @@ from commitizen.exceptions import VersionSchemeUnknown
|
|
|
22
23
|
|
|
23
24
|
if TYPE_CHECKING:
|
|
24
25
|
import sys
|
|
25
|
-
from typing import TypeAlias
|
|
26
26
|
|
|
27
27
|
# Self is Python 3.11+ but backported in typing-extensions
|
|
28
28
|
if sys.version_info < (3, 11):
|
|
@@ -31,7 +31,7 @@ if TYPE_CHECKING:
|
|
|
31
31
|
from typing import Self
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
Increment: TypeAlias = Literal["MAJOR", "MINOR", "PATCH"]
|
|
34
|
+
Increment: TypeAlias = Literal["MAJOR", "MINOR", "PATCH"] # TODO: deprecate
|
|
35
35
|
Prerelease: TypeAlias = Literal["alpha", "beta", "rc"]
|
|
36
36
|
_DEFAULT_VERSION_PARSER = re.compile(
|
|
37
37
|
r"v?(?P<version>([0-9]+)\.([0-9]+)(?:\.([0-9]+))?(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z.]+)?(\w+)?)"
|
|
@@ -140,7 +140,7 @@ class VersionProtocol(Protocol):
|
|
|
140
140
|
"""
|
|
141
141
|
|
|
142
142
|
|
|
143
|
-
# With PEP 440 and SemVer
|
|
143
|
+
# With PEP 440 and SemVer semantics, a scheme is the class; a version is an instance.
|
|
144
144
|
Version: TypeAlias = VersionProtocol
|
|
145
145
|
VersionScheme: TypeAlias = type[VersionProtocol]
|
|
146
146
|
|
|
@@ -422,7 +422,16 @@ def get_version_scheme(settings: Settings, name: str | None = None) -> VersionSc
|
|
|
422
422
|
raise VersionSchemeUnknown(f'Version scheme "{name}" unknown.')
|
|
423
423
|
scheme = cast("VersionScheme", ep.load())
|
|
424
424
|
|
|
425
|
-
|
|
425
|
+
# `VersionProtocol` is a `@runtime_checkable` Protocol, but `issubclass()` is not
|
|
426
|
+
# supported for Protocols with non-method members. We check an instance instead by
|
|
427
|
+
# verifying the loaded object is a class with the expected interface.
|
|
428
|
+
if isinstance(scheme, type):
|
|
429
|
+
# Check for a key method/attribute that VersionProtocol requires
|
|
430
|
+
if not hasattr(scheme, "bump"):
|
|
431
|
+
warnings.warn(
|
|
432
|
+
f"Version scheme {name} does not implement the VersionProtocol"
|
|
433
|
+
)
|
|
434
|
+
else:
|
|
426
435
|
warnings.warn(f"Version scheme {name} does not implement the VersionProtocol")
|
|
427
436
|
|
|
428
437
|
return scheme
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "4.14.0"
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
import subprocess
|
|
5
|
-
from typing import TYPE_CHECKING, NamedTuple
|
|
6
|
-
|
|
7
|
-
from charset_normalizer import from_bytes
|
|
8
|
-
|
|
9
|
-
from commitizen.exceptions import CharacterSetDecodeError
|
|
10
|
-
|
|
11
|
-
if TYPE_CHECKING:
|
|
12
|
-
from collections.abc import Mapping
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class Command(NamedTuple):
|
|
16
|
-
out: str
|
|
17
|
-
err: str
|
|
18
|
-
stdout: bytes
|
|
19
|
-
stderr: bytes
|
|
20
|
-
return_code: int
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def _try_decode(bytes_: bytes) -> str:
|
|
24
|
-
try:
|
|
25
|
-
return bytes_.decode("utf-8")
|
|
26
|
-
except UnicodeDecodeError:
|
|
27
|
-
pass
|
|
28
|
-
|
|
29
|
-
charset_match = from_bytes(bytes_).best()
|
|
30
|
-
if charset_match is None:
|
|
31
|
-
raise CharacterSetDecodeError()
|
|
32
|
-
try:
|
|
33
|
-
return bytes_.decode(charset_match.encoding)
|
|
34
|
-
except UnicodeDecodeError as e:
|
|
35
|
-
raise CharacterSetDecodeError() from e
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def run(cmd: str, env: Mapping[str, str] | None = None) -> Command:
|
|
39
|
-
if env is not None:
|
|
40
|
-
env = {**os.environ, **env}
|
|
41
|
-
process = subprocess.Popen(
|
|
42
|
-
cmd,
|
|
43
|
-
shell=True,
|
|
44
|
-
stdout=subprocess.PIPE,
|
|
45
|
-
stderr=subprocess.PIPE,
|
|
46
|
-
stdin=subprocess.PIPE,
|
|
47
|
-
env=env,
|
|
48
|
-
)
|
|
49
|
-
stdout, stderr = process.communicate()
|
|
50
|
-
return_code = process.returncode
|
|
51
|
-
return Command(
|
|
52
|
-
_try_decode(stdout),
|
|
53
|
-
_try_decode(stderr),
|
|
54
|
-
stdout,
|
|
55
|
-
stderr,
|
|
56
|
-
return_code,
|
|
57
|
-
)
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import platform
|
|
2
|
-
import sys
|
|
3
|
-
from typing import TypedDict
|
|
4
|
-
|
|
5
|
-
from commitizen import out
|
|
6
|
-
from commitizen.__version__ import __version__
|
|
7
|
-
from commitizen.config import BaseConfig
|
|
8
|
-
from commitizen.exceptions import NoVersionSpecifiedError, VersionSchemeUnknown
|
|
9
|
-
from commitizen.providers import get_provider
|
|
10
|
-
from commitizen.tags import TagRules
|
|
11
|
-
from commitizen.version_schemes import get_version_scheme
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class VersionArgs(TypedDict, total=False):
|
|
15
|
-
commitizen: bool
|
|
16
|
-
report: bool
|
|
17
|
-
project: bool
|
|
18
|
-
verbose: bool
|
|
19
|
-
major: bool
|
|
20
|
-
minor: bool
|
|
21
|
-
tag: bool
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class Version:
|
|
25
|
-
"""Get the version of the installed commitizen or the current project.
|
|
26
|
-
Precedence:
|
|
27
|
-
1. report
|
|
28
|
-
2. commitizen
|
|
29
|
-
3. verbose, project
|
|
30
|
-
"""
|
|
31
|
-
|
|
32
|
-
def __init__(self, config: BaseConfig, arguments: VersionArgs) -> None:
|
|
33
|
-
self.config: BaseConfig = config
|
|
34
|
-
self.arguments = arguments
|
|
35
|
-
|
|
36
|
-
def __call__(self) -> None:
|
|
37
|
-
if self.arguments.get("report"):
|
|
38
|
-
out.write(f"Commitizen Version: {__version__}")
|
|
39
|
-
out.write(f"Python Version: {sys.version}")
|
|
40
|
-
out.write(f"Operating System: {platform.system()}")
|
|
41
|
-
return
|
|
42
|
-
|
|
43
|
-
if self.arguments.get("verbose"):
|
|
44
|
-
out.write(f"Installed Commitizen Version: {__version__}")
|
|
45
|
-
|
|
46
|
-
if not self.arguments.get("commitizen") and (
|
|
47
|
-
self.arguments.get("project") or self.arguments.get("verbose")
|
|
48
|
-
):
|
|
49
|
-
try:
|
|
50
|
-
version = get_provider(self.config).get_version()
|
|
51
|
-
except NoVersionSpecifiedError:
|
|
52
|
-
out.error("No project information in this project.")
|
|
53
|
-
return
|
|
54
|
-
try:
|
|
55
|
-
version_scheme = get_version_scheme(self.config.settings)(version)
|
|
56
|
-
except VersionSchemeUnknown:
|
|
57
|
-
out.error("Unknown version scheme.")
|
|
58
|
-
return
|
|
59
|
-
|
|
60
|
-
if self.arguments.get("major"):
|
|
61
|
-
version = f"{version_scheme.major}"
|
|
62
|
-
elif self.arguments.get("minor"):
|
|
63
|
-
version = f"{version_scheme.minor}"
|
|
64
|
-
elif self.arguments.get("tag"):
|
|
65
|
-
tag_rules = TagRules.from_settings(self.config.settings)
|
|
66
|
-
version = tag_rules.normalize_tag(version_scheme)
|
|
67
|
-
|
|
68
|
-
out.write(
|
|
69
|
-
f"Project Version: {version}"
|
|
70
|
-
if self.arguments.get("verbose")
|
|
71
|
-
else version
|
|
72
|
-
)
|
|
73
|
-
return
|
|
74
|
-
|
|
75
|
-
if self.arguments.get("major") or self.arguments.get("minor"):
|
|
76
|
-
out.error(
|
|
77
|
-
"Major or minor version can only be used with --project or --verbose."
|
|
78
|
-
)
|
|
79
|
-
return
|
|
80
|
-
|
|
81
|
-
if self.arguments.get("tag"):
|
|
82
|
-
out.error("Tag can only be used with --project or --verbose.")
|
|
83
|
-
return
|
|
84
|
-
|
|
85
|
-
# If no arguments are provided, just show the installed commitizen version
|
|
86
|
-
out.write(__version__)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{commitizen-4.14.0 → commitizen-4.15.1}/commitizen/cz/conventional_commits/conventional_commits.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|