diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index ee63c8db77..abc329ea8c 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -205,7 +205,11 @@ def __call__(self): # noqa: C901 }, ) changelog_cmd() - c = cmd.run(f"git add {changelog_cmd.file_name} {' '.join(version_files)}") + git_add_changelog_and_version_files_command = ( + f"git add {changelog_cmd.file_name} " + f"{' '.join(file_name.partition(':')[0] for file_name in version_files)}" + ) + c = cmd.run(git_add_changelog_and_version_files_command) # Do not perform operations over files or git. if dry_run: @@ -228,7 +232,7 @@ def __call__(self): # noqa: C901 # Maybe pre-commit reformatted some files? Retry once logger.debug("1st git.commit error: %s", c.err) logger.info("1st commit attempt failed; retrying once") - cmd.run(f"git add {changelog_cmd.file_name} {' '.join(version_files)}") + cmd.run(git_add_changelog_and_version_files_command) c = git.commit(message, args=self._get_commit_args()) if c.return_code != 0: raise BumpCommitFailedError(f'2nd git.commit error: "{c.err.strip()}"') diff --git a/commitizen/git.py b/commitizen/git.py index babd41989b..2c2cb5b368 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -126,6 +126,20 @@ def get_commits( return git_commits +def get_filenames_in_commit(git_reference: str = ""): + """Get the list of files that were committed in the requested git reference. + + :param git_reference: a git reference as accepted by `git show`, default: the last commit + + :returns: file names committed in the last commit by default or inside the passed git reference + """ + c = cmd.run(f"git show --name-only --pretty=format: {git_reference}") + if c.return_code == 0: + return c.out.strip().split("\n") + else: + raise GitCommandError(c.err) + + def get_tags(dateformat: str = "%Y-%m-%d") -> List[GitTag]: inner_delimiter = "---inner_delimiter---" formatter = ( diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index 2c9ca36774..2eb1b1d2ed 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -1,5 +1,6 @@ import inspect import sys +from typing import Tuple from unittest.mock import MagicMock import pytest @@ -528,3 +529,88 @@ def test_bump_with_changelog_to_stdout_dry_run_arg(mocker, capsys, changelog_pat assert out.startswith("#") assert "this should appear in stdout with dry-run enabled" in out assert "0.2.0" in out + + +@pytest.mark.parametrize( + "version_filepath, version_regex, version_file_content", + [ + pytest.param( + "pyproject.toml", + "pyproject.toml:^version", + """ +[tool.poetry] +name = "my_package" +version = "0.1.0" +""", + id="version in pyproject.toml with regex", + ), + pytest.param( + "pyproject.toml", + "pyproject.toml", + """ +[tool.poetry] +name = "my_package" +version = "0.1.0" +""", + id="version in pyproject.toml without regex", + ), + pytest.param( + "__init__.py", + "__init__.py:^__version__", + """ +'''This is a test file.''' +__version__ = "0.1.0" +""", + id="version in __init__.py with regex", + ), + ], +) +@pytest.mark.parametrize( + "cli_bump_changelog_args", + [ + ("cz", "bump", "--changelog", "--yes"), + ( + "cz", + "bump", + "--changelog", + "--changelog-to-stdout", + "--annotated", + "--check-consistency", + "--yes", + ), + ], + ids=lambda cmd_tuple: " ".join(cmd_tuple), +) +def test_bump_changelog_command_commits_untracked_changelog_and_version_files( + tmp_commitizen_project, + mocker, + cli_bump_changelog_args: Tuple[str, ...], + version_filepath: str, + version_regex: str, + version_file_content: str, +): + """Ensure that changelog always gets committed, no matter what version file or cli options get passed. + + Steps: + - Append the version file's name and regex commitizen configuration lines to `pyproject.toml`. + - Append to or create the version file. + - Add a commit of type fix to be eligible for a version bump. + - Call commitizen main cli and assert that the `CHANGELOG.md` and the version file were committed. + """ + + with tmp_commitizen_project.join("pyproject.toml").open( + mode="a" + ) as commitizen_config: + commitizen_config.write(f"version_files = [\n" f"'{version_regex}'\n]") + + with tmp_commitizen_project.join(version_filepath).open(mode="a+") as version_file: + version_file.write(version_file_content) + + create_file_and_commit("fix: some test commit") + + mocker.patch.object(sys, "argv", cli_bump_changelog_args) + cli.main() + + commit_file_names = git.get_filenames_in_commit() + assert "CHANGELOG.md" in commit_file_names + assert version_filepath in commit_file_names