Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat 451 add commit args #621

Merged
merged 8 commits into from
Oct 17, 2023
27 changes: 25 additions & 2 deletions commitizen/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
CommitizenException,
ExitCode,
ExpectedExit,
InvalidCommandArgumentError,
NoCommandFoundError,
)

Expand Down Expand Up @@ -441,7 +442,7 @@

# This is for the command required constraint in 2.0
try:
args = parser.parse_args()
args, unknown_args = parser.parse_known_args()
except (TypeError, SystemExit) as e:
# https://github.com/commitizen-tools/commitizen/issues/429
# argparse raises TypeError when non exist command is provided on Python < 3.9
Expand All @@ -450,6 +451,28 @@
raise NoCommandFoundError()
raise e

arguments = vars(args)
if unknown_args:
# Raise error for extra-args without -- separation
if "--" not in unknown_args:
raise InvalidCommandArgumentError(
f"Invalid commitizen arguments were found: `{' '.join(unknown_args)}`. "
"Please use -- separator for extra git args"
)
# Raise error for extra-args before --
elif unknown_args[0] != "--":
pos = unknown_args.index("--")
raise InvalidCommandArgumentError(
f"Invalid commitizen arguments were found before -- separator: `{' '.join(unknown_args[:pos])}`. "
)
# Log warning for -- without any extra args
elif len(unknown_args) == 1:
logger.warning(

Check warning on line 470 in commitizen/cli.py

View check run for this annotation

Codecov / codecov/patch

commitizen/cli.py#L469-L470

Added lines #L469 - L470 were not covered by tests
"\nWARN: Incomplete commit command: received -- separator without any following git arguments\n"
)
extra_args = " ".join(unknown_args[1:])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might need to handle the case that the user use -- without actually providing an argument. e.g., cz commit --

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, how should we deal with it?

Warning or error?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning should be enough in this case 👍

arguments["extra_cli_args"] = extra_args

Check warning on line 474 in commitizen/cli.py

View check run for this annotation

Codecov / codecov/patch

commitizen/cli.py#L473-L474

Added lines #L473 - L474 were not covered by tests

if args.name:
conf.update({"name": args.name})
elif not args.name and not conf.path:
Expand All @@ -465,7 +488,7 @@
)
sys.excepthook = no_raise_debug_excepthook

args.func(conf, vars(args))()
args.func(conf, arguments)()


if __name__ == "__main__":
Expand Down
9 changes: 7 additions & 2 deletions commitizen/commands/commit.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,14 @@ def __call__(self):
)

if signoff:
c = git.commit(m, "-s")
out.warn(
"signoff mechanic is deprecated, please use `cz commit -- -s` instead."
)
extra_args = self.arguments.get("extra_cli_args", "--") + " -s"
else:
c = git.commit(m)
extra_args = self.arguments.get("extra_cli_args", "")

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

if c.return_code != 0:
out.error(c.err)
Expand Down
4 changes: 3 additions & 1 deletion commitizen/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,14 @@


def add(args: str = "") -> cmd.Command:
c = cmd.run(f"git add {args}")
return c

Check warning on line 97 in commitizen/git.py

View check run for this annotation

Codecov / codecov/patch

commitizen/git.py#L96-L97

Added lines #L96 - L97 were not covered by tests


def commit(
message: str, args: str = "", committer_date: str | None = None
message: str,
args: str = "",
committer_date: str | None = None,
) -> cmd.Command:
f = NamedTemporaryFile("wb", delete=False)
f.write(message.encode("utf-8"))
Expand Down
2 changes: 1 addition & 1 deletion docs/bump.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ These are used in:

* `cz bump`: Find previous release tag (exact match) and generate new tag.
* Find previous release tags in `cz changelog`.
* If `--incremental`: Using latest version found in the changelog, scan existing Git tags with 89\% similarity match.
* If `--incremental`: Using latest version found in the changelog, scan existing Git tags with 89\% similarity match.
* `--rev-range` is converted to Git tag names with `tag_format` before searching Git history.
* If the `scm` `version_provider` is used, it uses different regexes to find the previous version tags:
* If `tag_format` is set to `$version` (default): `VersionProtocol.parser` (allows `v` prefix)
Expand Down
28 changes: 14 additions & 14 deletions docs/commit.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,28 @@

In your terminal run `cz commit` or the shortcut `cz c` to generate a guided git commit.

A commit can be signed off using `cz commit --signoff` or the shortcut `cz commit -s`.

You can run `cz commit --write-message-to-file COMMIT_MSG_FILE` to additionally save the
generated message to a file. This can be combined with the `--dry-run` flag to only
write the message to a file and not modify files and create a commit. A possible use
case for this is to [automatically prepare a commit message](./tutorials/auto_prepare_commit_message.md).

!!! note
To maintain platform compatibility, the `commit` command disables ANSI escaping in its output.
In particular, pre-commit hooks coloring will be deactivated as discussed in [commitizen-tools/commitizen#417](https://github.com/commitizen-tools/commitizen/issues/417).

## Configuration

### `always_signoff`
!!! note
To maintain platform compatibility, the `commit` command disable ANSI escaping in its output.
In particular pre-commit hooks coloring will be deactivated as discussed in [commitizen-tools/commitizen#417](https://github.com/commitizen-tools/commitizen/issues/417).

When set to `true`, each commit message created by `cz commit` will be signed off.

Defaults to: `false`.
### git options

In your `pyproject.toml` or `.cz.toml`:
`git` command options that are not implemented by commitizen can be use via the `--` syntax for the `commit` command.
The syntax separates commitizen arguments from `git commit` arguments by a double dash. This is the resulting syntax:
```sh
cz commit <commitizen-args> -- <git-cli-args>

```toml
[tool.commitizen]
always_signoff = true
# e.g., cz commit --dry-run -- -a -S
```
For example, using the `-S` option on `git commit` to sign a commit is now commitizen compatible: `cz c -- -S`

!!! note
Deprecation warning: A commit can be signed off using `cz commit --signoff` or the shortcut `cz commit -s`.
This syntax is now deprecated in favor of the new `cz commit -- -s` syntax.
26 changes: 23 additions & 3 deletions tests/commands/test_commit_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def test_commit_retry_works(config, mocker: MockFixture):

commands.Commit(config, {"retry": True})()

commit_mock.assert_called_with("feat: user created\n\ncloses #21")
commit_mock.assert_called_with("feat: user created\n\ncloses #21", args="")
prompt_mock.assert_called_once()
success_mock.assert_called_once()
assert not os.path.isfile(temp_file)
Expand Down Expand Up @@ -174,7 +174,7 @@ def test_commit_command_with_signoff_option(config, mocker: MockFixture):

commands.Commit(config, {"signoff": True})()

commit_mock.assert_called_once_with(ANY, "-s")
commit_mock.assert_called_once_with(ANY, args="-- -s")
success_mock.assert_called_once()


Expand All @@ -197,7 +197,7 @@ def test_commit_command_with_always_signoff_enabled(config, mocker: MockFixture)
config.settings["always_signoff"] = True
commands.Commit(config, {})()

commit_mock.assert_called_once_with(ANY, "-s")
commit_mock.assert_called_once_with(ANY, args="-- -s")
success_mock.assert_called_once()


Expand Down Expand Up @@ -276,3 +276,23 @@ def test_commit_command_with_all_option(config, mocker: MockFixture):
commands.Commit(config, {"all": True})()
add_mock.assert_called()
success_mock.assert_called_once()


@pytest.mark.usefixtures("staging_is_clean")
def test_commit_command_with_extra_args(config, mocker: MockFixture):
prompt_mock = mocker.patch("questionary.prompt")
prompt_mock.return_value = {
"prefix": "feat",
"subject": "user created",
"scope": "",
"is_breaking_change": False,
"body": "",
"footer": "",
}

commit_mock = mocker.patch("commitizen.git.commit")
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
success_mock = mocker.patch("commitizen.out.success")
commands.Commit(config, {"extra_cli_args": "-- -extra-args1 -extra-arg2"})()
commit_mock.assert_called_once_with(ANY, args="-- -extra-args1 -extra-arg2")
success_mock.assert_called_once()
25 changes: 24 additions & 1 deletion tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
from pytest_mock import MockFixture

from commitizen import cli
from commitizen.exceptions import ExpectedExit, NoCommandFoundError, NotAGitProjectError
from commitizen.exceptions import (
ExpectedExit,
NoCommandFoundError,
NotAGitProjectError,
InvalidCommandArgumentError,
)


def test_sysexit_no_argv(mocker: MockFixture, capsys):
Expand Down Expand Up @@ -149,3 +154,21 @@ def test_parse_no_raise_mix_invalid_arg_is_skipped():
input_str = "NO_COMMITIZEN_FOUND,2,nothing,4"
result = cli.parse_no_raise(input_str)
assert result == [1, 2, 4]


def test_unknown_args_raises(mocker: MockFixture):
testargs = ["cz", "c", "-this_arg_is_not_supported"]
mocker.patch.object(sys, "argv", testargs)
with pytest.raises(InvalidCommandArgumentError) as excinfo:
cli.main()
assert "Invalid commitizen arguments were found" in str(excinfo.value)


def test_unknown_args_before_double_dash_raises(mocker: MockFixture):
testargs = ["cz", "c", "-this_arg_is_not_supported", "--"]
mocker.patch.object(sys, "argv", testargs)
with pytest.raises(InvalidCommandArgumentError) as excinfo:
cli.main()
assert "Invalid commitizen arguments were found before -- separator" in str(
excinfo.value
)
Loading