diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index cda2abcefd..6be8886e60 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -9,6 +9,7 @@ NO_ANSWERS = 5 COMMIT_ERROR = 6 NO_COMMIT_BACKUP = 7 +NOTHING_TO_COMMIT = 8 class Commit: @@ -21,6 +22,10 @@ def __init__(self, config: dict, arguments: dict): self.temp_file: str = os.path.join(tempfile.gettempdir(), "cz.commit.backup") def __call__(self): + if git.is_staging_clean(): + out.write("No files added to staging!") + raise SystemExit(NOTHING_TO_COMMIT) + retry: bool = self.arguments.get("retry") if retry: diff --git a/commitizen/git.py b/commitizen/git.py index c04206a906..db307d4510 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -33,3 +33,10 @@ def get_commits(start: str, end: str = "HEAD", from_beginning: bool = False) -> def tag_exist(tag: str) -> bool: c = cmd.run(f"git tag --list {tag}") return tag in c.out + + +def is_staging_clean() -> bool: + """Check if staing is clean""" + c = cmd.run("git diff --no-ext-diff --name-only") + c_cached = cmd.run("git diff --no-ext-diff --cached --name-only") + return not (bool(c.out) or bool(c_cached.out)) diff --git a/tests/test_commands.py b/tests/test_commands.py index 3dda7202f5..6c7434aa0d 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -8,6 +8,13 @@ config = {"name": defaults.name} +@pytest.fixture +def staging_is_clean(mocker): + is_staging_clean_mock = mocker.patch("commitizen.git.is_staging_clean") + is_staging_clean_mock.return_value = False + + +@pytest.mark.usefixtures("staging_is_clean") def test_commit(mocker): prompt_mock = mocker.patch("questionary.prompt") prompt_mock.return_value = { @@ -27,6 +34,7 @@ def test_commit(mocker): success_mock.assert_called_once() +@pytest.mark.usefixtures("staging_is_clean") def test_commit_retry_fails_no_backup(mocker): commit_mock = mocker.patch("commitizen.git.commit") commit_mock.return_value = cmd.Command("success", "", "", "") @@ -35,6 +43,7 @@ def test_commit_retry_fails_no_backup(mocker): commands.Commit(config, {"retry": True})() +@pytest.mark.usefixtures("staging_is_clean") def test_commit_retry_works(mocker): prompt_mock = mocker.patch("questionary.prompt") prompt_mock.return_value = { @@ -72,6 +81,17 @@ def test_commit_retry_works(mocker): assert not os.path.isfile(temp_file) +def test_commit_when_nothing_to_commit(mocker): + is_staging_clean_mock = mocker.patch("commitizen.git.is_staging_clean") + is_staging_clean_mock.return_value = True + + with pytest.raises(SystemExit) as err: + commit_cmd = commands.Commit(config, {}) + commit_cmd() + + assert err.value.code == commands.commit.NOTHING_TO_COMMIT + + def test_example(): with mock.patch("commitizen.out.write") as write_mock: commands.Example(config)()