Skip to content

Commit 33a06e9

Browse files
Merge branch 'master' into feature/custom-validation
2 parents 904f200 + 3e21ac5 commit 33a06e9

27 files changed

+541
-293
lines changed

.github/workflows/homebrewpublish.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
run: |
2525
echo "project_version=$(cz version --project)" >> $GITHUB_ENV
2626
- name: Update Homebrew formula
27-
uses: dawidd6/action-homebrew-bump-formula@v3
27+
uses: dawidd6/action-homebrew-bump-formula@v4
2828
with:
2929
token: ${{secrets.PERSONAL_ACCESS_TOKEN}}
3030
formula: commitizen

.github/workflows/pythonpackage.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ jobs:
66
python-check:
77
strategy:
88
matrix:
9-
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13-dev"]
9+
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
1010
platform: [ubuntu-20.04, macos-latest, windows-latest]
1111
runs-on: ${{ matrix.platform }}
1212
steps:
@@ -30,7 +30,7 @@ jobs:
3030
shell: bash
3131
- name: Upload coverage to Codecov
3232
if: runner.os == 'Linux'
33-
uses: codecov/codecov-action@v4
33+
uses: codecov/codecov-action@v5
3434
with:
3535
token: ${{ secrets.CODECOV_TOKEN }}
3636
file: ./coverage.xml

.pre-commit-config.yaml

+5-5
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ default_install_hook_types:
44
- pre-push
55

66
default_stages:
7-
- commit
8-
- push
7+
- pre-commit
8+
- pre-push
99

1010
repos:
1111
- repo: meta
@@ -49,13 +49,13 @@ repos:
4949
- tomli
5050

5151
- repo: https://github.com/commitizen-tools/commitizen
52-
rev: v3.29.1 # automatically updated by Commitizen
52+
rev: v3.31.0 # automatically updated by Commitizen
5353
hooks:
5454
- id: commitizen
5555
- id: commitizen-branch
5656
stages:
5757
- post-commit
58-
- push
58+
- pre-push
5959

6060
- repo: local
6161
hooks:
@@ -70,6 +70,6 @@ repos:
7070
name: linter and test
7171
language: system
7272
pass_filenames: false
73-
stages: [ push ]
73+
stages: [ pre-push ]
7474
entry: ./scripts/test
7575
types: [ python ]

CHANGELOG.md

+29
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,32 @@
1+
## v3.31.0 (2024-11-16)
2+
3+
### Feat
4+
5+
- **commitizen**: document '--' double dash in '--help'
6+
7+
### Fix
8+
9+
- **commit**: avoid warnings with 'always_signoff' configuration
10+
- **commit**: resolve 'always_signoff' configuration and '-s' CLI issues
11+
12+
## v3.30.1 (2024-11-10)
13+
14+
### Refactor
15+
16+
- **cli**: replace magic number 0 with ExitCode.EXPECTED_EXIT
17+
- **defaults**: disallow style as None
18+
- **cz_customize**: return empty string for info, example, schema and schema_pattern if not provided
19+
20+
## v3.30.0 (2024-10-23)
21+
22+
### Feat
23+
24+
- **commands/commit**: add force-edit functionality after answering questions
25+
26+
### Refactor
27+
28+
- remove redundant return None
29+
130
## v3.29.1 (2024-09-26)
231

332
### Fix

commitizen/__version__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "3.29.1"
1+
__version__ = "3.31.0"

commitizen/cli.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,24 @@ def __call__(
156156
"action": "store_true",
157157
"help": "Tell the command to automatically stage files that have been modified and deleted, but new files you have not told Git about are not affected.",
158158
},
159+
{
160+
"name": ["-e", "--edit"],
161+
"action": "store_true",
162+
"default": False,
163+
"help": "edit the commit message before committing",
164+
},
159165
{
160166
"name": ["-l", "--message-length-limit"],
161167
"type": int,
162168
"default": 0,
163169
"help": "length limit of the commit message; 0 for no limit",
164170
},
171+
{
172+
"name": ["--"],
173+
"action": "store_true",
174+
"dest": "double_dash",
175+
"help": "Positional arguments separator (recommended)",
176+
},
165177
],
166178
},
167179
{
@@ -541,7 +553,7 @@ def commitizen_excepthook(
541553
original_excepthook(type, value, traceback)
542554
exit_code = value.exit_code
543555
if exit_code in no_raise:
544-
exit_code = 0
556+
exit_code = ExitCode.EXPECTED_EXIT
545557
sys.exit(exit_code)
546558
else:
547559
original_excepthook(type, value, traceback)

commitizen/commands/check.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def _valid_command_argument(self):
5353
for arg in (self.commit_msg_file, self.commit_msg, self.rev_range)
5454
)
5555
if num_exclusive_args_provided == 0 and not sys.stdin.isatty():
56-
self.commit_msg: str | None = sys.stdin.read()
56+
self.commit_msg = sys.stdin.read()
5757
elif num_exclusive_args_provided != 1:
5858
raise InvalidCommandArgumentError(
5959
"Only one of --rev-range, --message, and --commit-msg-file is permitted by check command! "
@@ -106,7 +106,9 @@ def _get_commits(self):
106106
return [git.GitCommit(rev="", title="", body=msg)]
107107

108108
# Get commit messages from git log (--rev-range)
109-
return git.get_commits(end=self.rev_range)
109+
if self.rev_range:
110+
return git.get_commits(end=self.rev_range)
111+
return git.get_commits()
110112

111113
@staticmethod
112114
def _filter_comments(msg: str) -> str:

commitizen/commands/commit.py

+31-6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
import contextlib
44
import os
5+
import shutil
6+
import subprocess
7+
import tempfile
58

69
import questionary
710

@@ -72,9 +75,27 @@ def prompt_commit_questions(self) -> str:
7275

7376
return message
7477

78+
def manual_edit(self, message: str) -> str:
79+
editor = git.get_core_editor()
80+
if editor is None:
81+
raise RuntimeError("No 'editor' value given and no default available.")
82+
exec_path = shutil.which(editor)
83+
if exec_path is None:
84+
raise RuntimeError(f"Editor '{editor}' not found.")
85+
with tempfile.NamedTemporaryFile(mode="w", delete=False) as file:
86+
file.write(message)
87+
file_path = file.name
88+
argv = [exec_path, file_path]
89+
subprocess.call(argv)
90+
with open(file_path) as temp_file:
91+
message = temp_file.read().strip()
92+
file.unlink()
93+
return message
94+
7595
def __call__(self):
7696
dry_run: bool = self.arguments.get("dry_run")
7797
write_message_to_file: bool = self.arguments.get("write_message_to_file")
98+
manual_edit: bool = self.arguments.get("edit")
7899

79100
is_all: bool = self.arguments.get("all")
80101
if is_all:
@@ -101,6 +122,9 @@ def __call__(self):
101122
else:
102123
m = self.prompt_commit_questions()
103124

125+
if manual_edit:
126+
m = self.manual_edit(m)
127+
104128
out.info(f"\n{m}\n")
105129

106130
if write_message_to_file:
@@ -110,17 +134,18 @@ def __call__(self):
110134
if dry_run:
111135
raise DryRunExit()
112136

113-
signoff: bool = (
114-
self.arguments.get("signoff") or self.config.settings["always_signoff"]
115-
)
137+
always_signoff: bool = self.config.settings["always_signoff"]
138+
signoff: bool = self.arguments.get("signoff")
139+
140+
extra_args = self.arguments.get("extra_cli_args", "")
116141

117142
if signoff:
118143
out.warn(
119144
"signoff mechanic is deprecated, please use `cz commit -- -s` instead."
120145
)
121-
extra_args = self.arguments.get("extra_cli_args", "--") + " -s"
122-
else:
123-
extra_args = self.arguments.get("extra_cli_args", "")
146+
147+
if always_signoff or signoff:
148+
extra_args = f"{extra_args} -s".strip()
124149

125150
c = git.commit(m, args=extra_args)
126151

commitizen/cz/base.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class BaseCommitizen(metaclass=ABCMeta):
6767
template_loader: BaseLoader = PackageLoader("commitizen", "templates")
6868
template_extras: dict[str, Any] = {}
6969

70-
def __init__(self, config: BaseConfig):
70+
def __init__(self, config: BaseConfig) -> None:
7171
self.config = config
7272
if not self.config.settings.get("style"):
7373
self.config.settings.update({"style": BaseCommitizen.default_style_config})
@@ -89,15 +89,15 @@ def style(self):
8989
]
9090
)
9191

92-
def example(self) -> str | None:
92+
def example(self) -> str:
9393
"""Example of the commit message."""
9494
raise NotImplementedError("Not Implemented yet")
9595

96-
def schema(self) -> str | None:
96+
def schema(self) -> str:
9797
"""Schema definition of the commit message."""
9898
raise NotImplementedError("Not Implemented yet")
9999

100-
def schema_pattern(self) -> str | None:
100+
def schema_pattern(self) -> str:
101101
"""Regex matching the schema used for message validation."""
102102
raise NotImplementedError("Not Implemented yet")
103103

@@ -142,7 +142,7 @@ def format_exception_message(
142142
f"pattern: {self.schema_pattern()}"
143143
)
144144

145-
def info(self) -> str | None:
145+
def info(self) -> str:
146146
"""Information about the standardized commit message."""
147147
raise NotImplementedError("Not Implemented yet")
148148

commitizen/cz/customize/customize.py

+16-11
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
from __future__ import annotations
22

3-
try:
3+
from typing import TYPE_CHECKING
4+
5+
if TYPE_CHECKING:
46
from jinja2 import Template
5-
except ImportError:
6-
from string import Template # type: ignore
7+
else:
8+
try:
9+
from jinja2 import Template
10+
except ImportError:
11+
from string import Template
712

813

914
from commitizen import defaults
@@ -68,16 +73,16 @@ def message(self, answers: dict) -> str:
6873
else:
6974
return message_template.render(**answers)
7075

71-
def example(self) -> str | None:
72-
return self.custom_settings.get("example")
76+
def example(self) -> str:
77+
return self.custom_settings.get("example") or ""
7378

74-
def schema_pattern(self) -> str | None:
75-
return self.custom_settings.get("schema_pattern")
79+
def schema_pattern(self) -> str:
80+
return self.custom_settings.get("schema_pattern") or ""
7681

77-
def schema(self) -> str | None:
78-
return self.custom_settings.get("schema")
82+
def schema(self) -> str:
83+
return self.custom_settings.get("schema") or ""
7984

80-
def info(self) -> str | None:
85+
def info(self) -> str:
8186
info_path = self.custom_settings.get("info_path")
8287
info = self.custom_settings.get("info")
8388
if info_path:
@@ -86,4 +91,4 @@ def info(self) -> str | None:
8691
return content
8792
elif info:
8893
return info
89-
return None
94+
return ""

commitizen/defaults.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class Settings(TypedDict, total=False):
4545
changelog_merge_prerelease: bool
4646
update_changelog_on_bump: bool
4747
use_shortcuts: bool
48-
style: list[tuple[str, str]] | None
48+
style: list[tuple[str, str]]
4949
customize: CzSettings
5050
major_version_zero: bool
5151
pre_bump_hooks: list[str] | None

commitizen/exceptions.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class ExitCode(enum.IntEnum):
4242
class CommitizenException(Exception):
4343
def __init__(self, *args, **kwargs):
4444
self.output_method = kwargs.get("output_method") or out.error
45-
self.exit_code = self.__class__.exit_code
45+
self.exit_code: ExitCode = self.__class__.exit_code
4646
if args:
4747
self.message = args[0]
4848
elif hasattr(self.__class__, "message"):

commitizen/git.py

+7
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,13 @@ def get_eol_style() -> EOLTypes:
271271
return map["native"]
272272

273273

274+
def get_core_editor() -> str | None:
275+
c = cmd.run("git var GIT_EDITOR")
276+
if c.out:
277+
return c.out.strip()
278+
return None
279+
280+
274281
def smart_open(*args, **kargs):
275282
"""Open a file with the EOL style determined from Git."""
276283
return open(*args, newline=get_eol_style().get_eol_for_open(), **kargs)

docs/README.md

+12-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
[![PyPI Package latest release](https://img.shields.io/pypi/v/commitizen.svg?style=flat-square)](https://pypi.org/project/commitizen/)
44
[![PyPI Package download count (per month)](https://img.shields.io/pypi/dm/commitizen?style=flat-square)](https://pypi.org/project/commitizen/)
55
[![Supported versions](https://img.shields.io/pypi/pyversions/commitizen.svg?style=flat-square)](https://pypi.org/project/commitizen/)
6+
[![Conda Version](https://img.shields.io/conda/vn/conda-forge/commitizen?style=flat-square)](https://anaconda.org/conda-forge/commitizen)
67
[![homebrew](https://img.shields.io/homebrew/v/commitizen?color=teal&style=flat-square)](https://formulae.brew.sh/formula/commitizen)
78
[![Codecov](https://img.shields.io/codecov/c/github/commitizen-tools/commitizen.svg?style=flat-square)](https://codecov.io/gh/commitizen-tools/commitizen)
89
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?style=flat-square&logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit)
@@ -62,19 +63,27 @@ pip install --user -U commitizen
6263

6364
### Python project
6465

65-
You can add it to your local project using one of these:
66+
You can add it to your local project using one of the following.
67+
68+
With `pip`:
6669

6770
```bash
6871
pip install -U commitizen
6972
```
7073

71-
for Poetry >= 1.2.0:
74+
With `conda`:
75+
76+
```bash
77+
conda install -c conda-forge commitizen
78+
```
79+
80+
With Poetry >= 1.2.0:
7281

7382
```bash
7483
poetry add commitizen --group dev
7584
```
7685

77-
for Poetry < 1.2.0:
86+
With Poetry < 1.2.0:
7887

7988
```bash
8089
poetry add commitizen --dev

docs/commands/check.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ permit them. Since `git commit` accepts an `--allow-empty-message` flag (primari
7070
### Allowed Prefixes
7171

7272
If the commit message starts by some specific prefixes, `cz check` returns `True` without checkign the regex.
73-
By default, the the following prefixes are allowed: `Merge`, `Revert`, `Pull Request`, `fixup!` and `squash!`.
73+
By default, the the following prefixes are allowed: `Merge`, `Revert`, `Pull request`, `fixup!` and `squash!`.
7474

7575
```bash
7676
cz check --message MESSAGE --allowed-prefixes 'Merge' 'Revert' 'Custom Prefix'

docs/contributing.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ If you're a first-time contributor, you can check the issues with [good first is
2222
(We use [CodeCov](https://codecov.io/) to ensure our test coverage does not drop.)
2323
7. Use [commitizen](https://github.com/commitizen-tools/commitizen) to do git commit. We follow [conventional commits](https://www.conventionalcommits.org/).
2424
8. Run `./scripts/format` and `./scripts/test` to ensure you follow the coding style and the tests pass.
25-
9. Optionally, update the `./docs/README.md`.
25+
9. Optionally, update the `./docs/README.md` or `docs/images/cli_help` (through running `scripts/gen_cli_help_screenshots.py`).
2626
9. **Do not** update the `CHANGELOG.md`, it will be automatically created after merging to `master`.
2727
10. **Do not** update the versions in the project, they will be automatically updated.
2828
10. If your changes are about documentation. Run `poetry run mkdocs serve` to serve documentation locally and check whether there is any warning or error.

0 commit comments

Comments
 (0)