1658 lines
52 KiB
Python
1658 lines
52 KiB
Python
from __future__ import annotations
|
|
|
|
import inspect
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
from textwrap import dedent
|
|
from unittest.mock import MagicMock, call
|
|
|
|
import py
|
|
import pytest
|
|
from pytest_mock import MockFixture
|
|
|
|
import commitizen.commands.bump as bump
|
|
from commitizen import cli, cmd, git, hooks
|
|
from commitizen.changelog_formats import ChangelogFormat
|
|
from commitizen.cz.base import BaseCommitizen
|
|
from commitizen.exceptions import (
|
|
BumpTagFailedError,
|
|
CommitizenException,
|
|
CurrentVersionNotFoundError,
|
|
DryRunExit,
|
|
ExitCode,
|
|
ExpectedExit,
|
|
GetNextExit,
|
|
InvalidManualVersion,
|
|
NoCommitsFoundError,
|
|
NoneIncrementExit,
|
|
NoPatternMapError,
|
|
NotAGitProjectError,
|
|
NotAllowed,
|
|
NoVersionSpecifiedError,
|
|
)
|
|
from tests.utils import create_file_and_commit, create_tag, skip_below_py_3_13
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"commit_msg",
|
|
(
|
|
"fix: username exception",
|
|
"fix(user): username exception",
|
|
"refactor: remove ini configuration support",
|
|
"refactor(config): remove ini configuration support",
|
|
"perf: update to use multiproess",
|
|
"perf(worker): update to use multiproess",
|
|
),
|
|
)
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_patch_increment(commit_msg, mocker: MockFixture):
|
|
create_file_and_commit(commit_msg)
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
tag_exists = git.tag_exist("0.1.1")
|
|
assert tag_exists is True
|
|
|
|
|
|
@pytest.mark.parametrize("commit_msg", ("feat: new file", "feat(user): new file"))
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_minor_increment(commit_msg, mocker: MockFixture):
|
|
create_file_and_commit(commit_msg)
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
cmd_res = cmd.run('git for-each-ref refs/tags --format "%(objecttype):%(refname)"')
|
|
assert tag_exists is True and "commit:refs/tags/0.2.0\n" in cmd_res.out
|
|
|
|
|
|
@pytest.mark.parametrize("commit_msg", ("feat: new file", "feat(user): new file"))
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_minor_increment_annotated(commit_msg, mocker: MockFixture):
|
|
create_file_and_commit(commit_msg)
|
|
testargs = ["cz", "bump", "--yes", "--annotated-tag"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
cmd_res = cmd.run('git for-each-ref refs/tags --format "%(objecttype):%(refname)"')
|
|
assert tag_exists is True and "tag:refs/tags/0.2.0\n" in cmd_res.out
|
|
|
|
_is_signed = git.is_signed_tag("0.2.0")
|
|
assert _is_signed is False
|
|
|
|
|
|
@pytest.mark.parametrize("commit_msg", ("feat: new file", "feat(user): new file"))
|
|
@pytest.mark.usefixtures("tmp_commitizen_project_with_gpg")
|
|
def test_bump_minor_increment_signed(commit_msg, mocker: MockFixture):
|
|
create_file_and_commit(commit_msg)
|
|
testargs = ["cz", "bump", "--yes", "--gpg-sign"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
cmd_res = cmd.run('git for-each-ref refs/tags --format "%(objecttype):%(refname)"')
|
|
assert tag_exists is True and "tag:refs/tags/0.2.0\n" in cmd_res.out
|
|
|
|
_is_signed = git.is_signed_tag("0.2.0")
|
|
assert _is_signed is True
|
|
|
|
|
|
@pytest.mark.parametrize("commit_msg", ("feat: new file", "feat(user): new file"))
|
|
def test_bump_minor_increment_annotated_config_file(
|
|
commit_msg, mocker: MockFixture, tmp_commitizen_project
|
|
):
|
|
tmp_commitizen_cfg_file = tmp_commitizen_project.join("pyproject.toml")
|
|
tmp_commitizen_cfg_file.write(
|
|
f"{tmp_commitizen_cfg_file.read()}\nannotated_tag = 1"
|
|
)
|
|
create_file_and_commit(commit_msg)
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
cmd_res = cmd.run('git for-each-ref refs/tags --format "%(objecttype):%(refname)"')
|
|
assert tag_exists is True and "tag:refs/tags/0.2.0\n" in cmd_res.out
|
|
|
|
_is_signed = git.is_signed_tag("0.2.0")
|
|
assert _is_signed is False
|
|
|
|
|
|
@pytest.mark.parametrize("commit_msg", ("feat: new file", "feat(user): new file"))
|
|
def test_bump_minor_increment_signed_config_file(
|
|
commit_msg, mocker: MockFixture, tmp_commitizen_project_with_gpg
|
|
):
|
|
tmp_commitizen_cfg_file = tmp_commitizen_project_with_gpg.join("pyproject.toml")
|
|
tmp_commitizen_cfg_file.write(f"{tmp_commitizen_cfg_file.read()}\ngpg_sign = 1")
|
|
create_file_and_commit(commit_msg)
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
cmd_res = cmd.run('git for-each-ref refs/tags --format "%(objecttype):%(refname)"')
|
|
assert tag_exists is True and "tag:refs/tags/0.2.0\n" in cmd_res.out
|
|
|
|
_is_signed = git.is_signed_tag("0.2.0")
|
|
assert _is_signed is True
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
@pytest.mark.parametrize(
|
|
"commit_msg",
|
|
(
|
|
"feat: new user interface\n\nBREAKING CHANGE: age is no longer supported",
|
|
"feat!: new user interface\n\nBREAKING CHANGE: age is no longer supported",
|
|
"feat!: new user interface",
|
|
"feat(user): new user interface\n\nBREAKING CHANGE: age is no longer supported",
|
|
"feat(user)!: new user interface\n\nBREAKING CHANGE: age is no longer supported",
|
|
"feat(user)!: new user interface",
|
|
"BREAKING CHANGE: age is no longer supported",
|
|
"BREAKING-CHANGE: age is no longer supported",
|
|
),
|
|
)
|
|
def test_bump_major_increment(commit_msg, mocker: MockFixture):
|
|
create_file_and_commit(commit_msg)
|
|
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("1.0.0")
|
|
assert tag_exists is True
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
@pytest.mark.parametrize(
|
|
"commit_msg",
|
|
(
|
|
"feat: new user interface\n\nBREAKING CHANGE: age is no longer supported",
|
|
"feat!: new user interface\n\nBREAKING CHANGE: age is no longer supported",
|
|
"feat!: new user interface",
|
|
"feat(user): new user interface\n\nBREAKING CHANGE: age is no longer supported",
|
|
"feat(user)!: new user interface\n\nBREAKING CHANGE: age is no longer supported",
|
|
"feat(user)!: new user interface",
|
|
"BREAKING CHANGE: age is no longer supported",
|
|
"BREAKING-CHANGE: age is no longer supported",
|
|
),
|
|
)
|
|
def test_bump_major_increment_major_version_zero(commit_msg, mocker):
|
|
create_file_and_commit(commit_msg)
|
|
|
|
testargs = ["cz", "bump", "--yes", "--major-version-zero"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
assert tag_exists is True
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
@pytest.mark.parametrize(
|
|
"commit_msg,increment,expected_tag",
|
|
[
|
|
("feat: new file", "PATCH", "0.1.1"),
|
|
("fix: username exception", "major", "1.0.0"),
|
|
("refactor: remove ini configuration support", "patch", "0.1.1"),
|
|
("BREAKING CHANGE: age is no longer supported", "minor", "0.2.0"),
|
|
],
|
|
)
|
|
def test_bump_command_increment_option(
|
|
commit_msg, increment, expected_tag, mocker: MockFixture
|
|
):
|
|
create_file_and_commit(commit_msg)
|
|
|
|
testargs = ["cz", "bump", "--increment", increment, "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist(expected_tag)
|
|
assert tag_exists is True
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_command_prelease(mocker: MockFixture):
|
|
create_file_and_commit("feat: location")
|
|
|
|
# Create an alpha pre-release.
|
|
testargs = ["cz", "bump", "--prerelease", "alpha", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.2.0a0")
|
|
assert tag_exists is True
|
|
|
|
# Create a beta pre-release.
|
|
testargs = ["cz", "bump", "--prerelease", "beta", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.2.0b0")
|
|
assert tag_exists is True
|
|
|
|
# With a current beta pre-release, bumping alpha must bump beta
|
|
# because we can't bump "backwards".
|
|
testargs = ["cz", "bump", "--prerelease", "alpha", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.2.0a1")
|
|
assert tag_exists is False
|
|
tag_exists = git.tag_exist("0.2.0b1")
|
|
assert tag_exists is True
|
|
|
|
# Create a rc pre-release.
|
|
testargs = ["cz", "bump", "--prerelease", "rc", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.2.0rc0")
|
|
assert tag_exists is True
|
|
|
|
# With a current rc pre-release, bumping alpha must bump rc.
|
|
testargs = ["cz", "bump", "--prerelease", "alpha", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.2.0a1")
|
|
assert tag_exists is False
|
|
tag_exists = git.tag_exist("0.2.0b2")
|
|
assert tag_exists is False
|
|
tag_exists = git.tag_exist("0.2.0rc1")
|
|
assert tag_exists is True
|
|
|
|
# With a current rc pre-release, bumping beta must bump rc.
|
|
testargs = ["cz", "bump", "--prerelease", "beta", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.2.0a2")
|
|
assert tag_exists is False
|
|
tag_exists = git.tag_exist("0.2.0b2")
|
|
assert tag_exists is False
|
|
tag_exists = git.tag_exist("0.2.0rc2")
|
|
assert tag_exists is True
|
|
|
|
# Create a final release from the current pre-release.
|
|
testargs = ["cz", "bump"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
assert tag_exists is True
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_command_prelease_increment(mocker: MockFixture):
|
|
# FINAL RELEASE
|
|
create_file_and_commit("fix: location")
|
|
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
assert git.tag_exist("0.1.1")
|
|
|
|
# PRERELEASE
|
|
create_file_and_commit("fix: location")
|
|
|
|
testargs = ["cz", "bump", "--prerelease", "alpha", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
assert git.tag_exist("0.1.2a0")
|
|
|
|
create_file_and_commit("feat: location")
|
|
|
|
testargs = ["cz", "bump", "--prerelease", "alpha", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
assert git.tag_exist("0.2.0a0")
|
|
|
|
create_file_and_commit("feat!: breaking")
|
|
|
|
testargs = ["cz", "bump", "--prerelease", "alpha", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
assert git.tag_exist("1.0.0a0")
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_command_prelease_exact_mode(mocker: MockFixture):
|
|
# PRERELEASE
|
|
create_file_and_commit("feat: location")
|
|
|
|
testargs = ["cz", "bump", "--prerelease", "alpha", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.2.0a0")
|
|
assert tag_exists is True
|
|
|
|
# PRERELEASE + PATCH BUMP
|
|
testargs = [
|
|
"cz",
|
|
"bump",
|
|
"--prerelease",
|
|
"alpha",
|
|
"--yes",
|
|
"--increment-mode=exact",
|
|
]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.2.0a1")
|
|
assert tag_exists is True
|
|
|
|
# PRERELEASE + MINOR BUMP
|
|
# --increment-mode allows the minor version to bump, and restart the prerelease
|
|
create_file_and_commit("feat: location")
|
|
|
|
testargs = [
|
|
"cz",
|
|
"bump",
|
|
"--prerelease",
|
|
"alpha",
|
|
"--yes",
|
|
"--increment-mode=exact",
|
|
]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.3.0a0")
|
|
assert tag_exists is True
|
|
|
|
# PRERELEASE + MAJOR BUMP
|
|
# --increment-mode=exact allows the major version to bump, and restart the prerelease
|
|
testargs = [
|
|
"cz",
|
|
"bump",
|
|
"--prerelease",
|
|
"alpha",
|
|
"--yes",
|
|
"--increment=MAJOR",
|
|
"--increment-mode=exact",
|
|
]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("1.0.0a0")
|
|
assert tag_exists is True
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_on_git_with_hooks_no_verify_disabled(mocker: MockFixture):
|
|
"""Bump commit without --no-verify"""
|
|
cmd.run("mkdir .git/hooks")
|
|
with open(".git/hooks/pre-commit", "w", encoding="utf-8") as f:
|
|
f.write('#!/usr/bin/env bash\necho "0.1.0"')
|
|
cmd.run("chmod +x .git/hooks/pre-commit")
|
|
|
|
# MINOR
|
|
create_file_and_commit("feat: new file")
|
|
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
assert tag_exists is True
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_tag_exists_raises_exception(mocker: MockFixture):
|
|
cmd.run("mkdir .git/hooks")
|
|
with open(".git/hooks/post-commit", "w", encoding="utf-8") as f:
|
|
f.write("#!/usr/bin/env bash\nexit 9")
|
|
cmd.run("chmod +x .git/hooks/post-commit")
|
|
|
|
# MINOR
|
|
create_file_and_commit("feat: new file")
|
|
git.tag("0.2.0")
|
|
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
|
|
with pytest.raises(BumpTagFailedError) as excinfo:
|
|
cli.main()
|
|
assert "0.2.0" in str(excinfo.value) # This should be a fatal error
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_on_git_with_hooks_no_verify_enabled(mocker: MockFixture):
|
|
cmd.run("mkdir .git/hooks")
|
|
with open(".git/hooks/pre-commit", "w", encoding="utf-8") as f:
|
|
f.write('#!/usr/bin/env bash\necho "0.1.0"')
|
|
cmd.run("chmod +x .git/hooks/pre-commit")
|
|
|
|
# MINOR
|
|
create_file_and_commit("feat: new file")
|
|
|
|
testargs = ["cz", "bump", "--yes", "--no-verify"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
assert tag_exists is True
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_when_bumpping_is_not_support(mocker: MockFixture):
|
|
create_file_and_commit(
|
|
"feat: new user interface\n\nBREAKING CHANGE: age is no longer supported"
|
|
)
|
|
|
|
testargs = ["cz", "-n", "cz_jira", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
|
|
with pytest.raises(NoPatternMapError) as excinfo:
|
|
cli.main()
|
|
|
|
assert "'cz_jira' rule does not support bump" in str(excinfo.value)
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_git_project")
|
|
def test_bump_when_version_is_not_specify(mocker: MockFixture):
|
|
mocker.patch.object(sys, "argv", ["cz", "bump"])
|
|
|
|
with pytest.raises(NoVersionSpecifiedError) as excinfo:
|
|
cli.main()
|
|
|
|
assert NoVersionSpecifiedError.message in str(excinfo.value)
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_when_no_new_commit(mocker: MockFixture):
|
|
"""bump without any commits since the last bump."""
|
|
# We need this first commit otherwise the revision is invalid.
|
|
create_file_and_commit("feat: initial")
|
|
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
|
|
# First bump.
|
|
# The next bump should fail since
|
|
# there is not a commit between the two bumps.
|
|
cli.main()
|
|
|
|
# bump without a new commit.
|
|
with pytest.raises(NoCommitsFoundError) as excinfo:
|
|
cli.main()
|
|
|
|
expected_error_message = "[NO_COMMITS_FOUND]\nNo new commits found."
|
|
assert expected_error_message in str(excinfo.value)
|
|
|
|
|
|
def test_bump_when_version_inconsistent_in_version_files(
|
|
tmp_commitizen_project, mocker: MockFixture
|
|
):
|
|
tmp_version_file = tmp_commitizen_project.join("__version__.py")
|
|
tmp_version_file.write("100.999.10000")
|
|
tmp_commitizen_cfg_file = tmp_commitizen_project.join("pyproject.toml")
|
|
tmp_version_file_string = str(tmp_version_file).replace("\\", "/")
|
|
tmp_commitizen_cfg_file.write(
|
|
f"{tmp_commitizen_cfg_file.read()}\n"
|
|
f'version_files = ["{tmp_version_file_string}"]'
|
|
)
|
|
|
|
create_file_and_commit("feat: new file")
|
|
|
|
testargs = ["cz", "bump", "--yes", "--check-consistency"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
|
|
with pytest.raises(CurrentVersionNotFoundError) as excinfo:
|
|
cli.main()
|
|
|
|
partial_expected_error_message = "Current version 0.1.0 is not found in"
|
|
assert partial_expected_error_message in str(excinfo.value)
|
|
|
|
|
|
def test_bump_major_version_zero_when_major_is_not_zero(mocker, tmp_commitizen_project):
|
|
tmp_version_file = tmp_commitizen_project.join("__version__.py")
|
|
tmp_version_file.write("1.0.0")
|
|
tmp_version_file_string = str(tmp_version_file).replace("\\", "/")
|
|
tmp_commitizen_cfg_file = tmp_commitizen_project.join("pyproject.toml")
|
|
tmp_commitizen_cfg_file.write(
|
|
f"[tool.commitizen]\n"
|
|
'version="1.0.0"\n'
|
|
f'version_files = ["{str(tmp_version_file_string)}"]'
|
|
)
|
|
tmp_changelog_file = tmp_commitizen_project.join("CHANGELOG.md")
|
|
tmp_changelog_file.write("## v1.0.0")
|
|
|
|
create_file_and_commit("feat(user): new file")
|
|
create_tag("v1.0.0")
|
|
create_file_and_commit("feat(user)!: new file")
|
|
|
|
testargs = ["cz", "bump", "--yes", "--major-version-zero"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
|
|
with pytest.raises(NotAllowed) as excinfo:
|
|
cli.main()
|
|
|
|
expected_error_message = (
|
|
"--major-version-zero is meaningless for current version 1.0.0"
|
|
)
|
|
assert expected_error_message in str(excinfo.value)
|
|
|
|
|
|
def test_bump_files_only(mocker: MockFixture, tmp_commitizen_project):
|
|
tmp_version_file = tmp_commitizen_project.join("__version__.py")
|
|
tmp_version_file.write("0.1.0")
|
|
tmp_commitizen_cfg_file = tmp_commitizen_project.join("pyproject.toml")
|
|
tmp_version_file_string = str(tmp_version_file).replace("\\", "/")
|
|
tmp_commitizen_cfg_file.write(
|
|
f"{tmp_commitizen_cfg_file.read()}\n"
|
|
f'version_files = ["{tmp_version_file_string}"]'
|
|
)
|
|
|
|
create_file_and_commit("feat: new user interface")
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
assert tag_exists is True
|
|
|
|
create_file_and_commit("feat: another new feature")
|
|
testargs = ["cz", "bump", "--yes", "--files-only"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
with pytest.raises(ExpectedExit):
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.3.0")
|
|
assert tag_exists is False
|
|
|
|
with open(tmp_version_file, encoding="utf-8") as f:
|
|
assert "0.3.0" in f.read()
|
|
|
|
with open(tmp_commitizen_cfg_file, encoding="utf-8") as f:
|
|
assert "0.3.0" in f.read()
|
|
|
|
|
|
def test_bump_local_version(mocker: MockFixture, tmp_commitizen_project):
|
|
tmp_version_file = tmp_commitizen_project.join("__version__.py")
|
|
tmp_version_file.write("4.5.1+0.1.0")
|
|
tmp_commitizen_cfg_file = tmp_commitizen_project.join("pyproject.toml")
|
|
tmp_version_file_string = str(tmp_version_file).replace("\\", "/")
|
|
tmp_commitizen_cfg_file.write(
|
|
f"[tool.commitizen]\n"
|
|
'version="4.5.1+0.1.0"\n'
|
|
f'version_files = ["{tmp_version_file_string}"]'
|
|
)
|
|
|
|
create_file_and_commit("feat: new user interface")
|
|
testargs = ["cz", "bump", "--yes", "--local-version"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
tag_exists = git.tag_exist("4.5.1+0.2.0")
|
|
assert tag_exists is True
|
|
|
|
with open(tmp_version_file, encoding="utf-8") as f:
|
|
assert "4.5.1+0.2.0" in f.read()
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_dry_run(mocker: MockFixture, capsys):
|
|
create_file_and_commit("feat: new file")
|
|
|
|
testargs = ["cz", "bump", "--yes", "--dry-run"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
with pytest.raises(DryRunExit):
|
|
cli.main()
|
|
|
|
out, _ = capsys.readouterr()
|
|
assert "0.2.0" in out
|
|
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
assert tag_exists is False
|
|
|
|
|
|
def test_bump_in_non_git_project(tmpdir, config, mocker: MockFixture):
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
|
|
with tmpdir.as_cwd():
|
|
with pytest.raises(NotAGitProjectError):
|
|
with pytest.raises(ExpectedExit):
|
|
cli.main()
|
|
|
|
|
|
def test_none_increment_exit_should_be_a_class():
|
|
assert inspect.isclass(NoneIncrementExit)
|
|
|
|
|
|
def test_none_increment_exit_should_be_expected_exit_subclass():
|
|
assert issubclass(NoneIncrementExit, CommitizenException)
|
|
|
|
|
|
def test_none_increment_exit_should_exist_in_bump():
|
|
assert hasattr(bump, "NoneIncrementExit")
|
|
|
|
|
|
def test_none_increment_exit_is_exception():
|
|
assert bump.NoneIncrementExit == NoneIncrementExit
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_none_increment_should_not_call_git_tag_and_error_code_is_not_zero(
|
|
mocker: MockFixture,
|
|
):
|
|
create_file_and_commit("test(test_get_all_droplets): fix bad comparison test")
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
|
|
# stash git.tag for later restore
|
|
stashed_git_tag = git.tag
|
|
dummy_value = git.tag("0.0.2")
|
|
git.tag = MagicMock(return_value=dummy_value)
|
|
|
|
with pytest.raises(NoneIncrementExit):
|
|
try:
|
|
cli.main()
|
|
except NoneIncrementExit as e:
|
|
git.tag.assert_not_called()
|
|
assert e.exit_code == ExitCode.NO_INCREMENT
|
|
raise e
|
|
|
|
# restore pop stashed
|
|
git.tag = stashed_git_tag
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_with_changelog_arg(mocker: MockFixture, changelog_path):
|
|
create_file_and_commit("feat(user): new file")
|
|
testargs = ["cz", "bump", "--yes", "--changelog"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
assert tag_exists is True
|
|
|
|
with open(changelog_path, encoding="utf-8") as f:
|
|
out = f.read()
|
|
assert out.startswith("#")
|
|
assert "0.2.0" in out
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_with_changelog_config(mocker: MockFixture, changelog_path, config_path):
|
|
create_file_and_commit("feat(user): new file")
|
|
with open(config_path, "a", encoding="utf-8") as fp:
|
|
fp.write("update_changelog_on_bump = true\n")
|
|
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
assert tag_exists is True
|
|
|
|
with open(changelog_path, encoding="utf-8") as f:
|
|
out = f.read()
|
|
assert out.startswith("#")
|
|
assert "0.2.0" in out
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_prevent_prerelease_when_no_increment_detected(mocker: MockFixture, capsys):
|
|
create_file_and_commit("feat: new file")
|
|
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
|
|
cli.main()
|
|
out, _ = capsys.readouterr()
|
|
|
|
assert "0.2.0" in out
|
|
|
|
create_file_and_commit("test: new file")
|
|
testargs = ["cz", "bump", "-pr", "beta"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
|
|
with pytest.raises(NoCommitsFoundError) as excinfo:
|
|
cli.main()
|
|
|
|
expected_error_message = (
|
|
"[NO_COMMITS_FOUND]\nNo commits found to generate a pre-release."
|
|
)
|
|
assert expected_error_message in str(excinfo.value)
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_with_changelog_to_stdout_arg(mocker: MockFixture, capsys, changelog_path):
|
|
create_file_and_commit("feat(user): this should appear in stdout")
|
|
testargs = ["cz", "bump", "--yes", "--changelog-to-stdout"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
out, _ = capsys.readouterr()
|
|
|
|
assert "this should appear in stdout" in out
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
assert tag_exists is True
|
|
|
|
with open(changelog_path, encoding="utf-8") as f:
|
|
out = f.read()
|
|
assert out.startswith("#")
|
|
assert "0.2.0" in out
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_with_changelog_to_stdout_dry_run_arg(
|
|
mocker: MockFixture, capsys, changelog_path
|
|
):
|
|
create_file_and_commit(
|
|
"feat(user): this should appear in stdout with dry-run enabled"
|
|
)
|
|
testargs = ["cz", "bump", "--yes", "--changelog-to-stdout", "--dry-run"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
with pytest.raises(DryRunExit):
|
|
cli.main()
|
|
out, _ = capsys.readouterr()
|
|
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
assert tag_exists is False
|
|
assert out.startswith("#")
|
|
assert "this should appear in stdout with dry-run enabled" in out
|
|
assert "0.2.0" in out
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_without_git_to_stdout_arg(mocker: MockFixture, capsys, changelog_path):
|
|
create_file_and_commit("feat(user): this should appear in stdout")
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
out, _ = capsys.readouterr()
|
|
|
|
assert (
|
|
re.search(r"^\[master \w+] bump: version 0.1.0 → 0.2.0", out, re.MULTILINE)
|
|
is not None
|
|
)
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_with_git_to_stdout_arg(mocker: MockFixture, capsys, changelog_path):
|
|
create_file_and_commit("feat(user): this should appear in stdout")
|
|
testargs = ["cz", "bump", "--yes", "--git-output-to-stderr"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
out, _ = capsys.readouterr()
|
|
|
|
assert (
|
|
re.search(r"^\[master \w+] bump: version 0.1.0 → 0.2.0", out, re.MULTILINE)
|
|
is None
|
|
)
|
|
|
|
|
|
@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.param(
|
|
"pyproject.toml",
|
|
"*.toml:^version",
|
|
"""
|
|
[tool.poetry]
|
|
name = "my_package"
|
|
version = "0.1.0"
|
|
""",
|
|
id="version in pyproject.toml with glob and regex",
|
|
),
|
|
],
|
|
)
|
|
@pytest.mark.parametrize(
|
|
"cli_bump_changelog_args",
|
|
[
|
|
("cz", "bump", "--changelog", "--yes"),
|
|
(
|
|
"cz",
|
|
"bump",
|
|
"--changelog",
|
|
"--changelog-to-stdout",
|
|
"--annotated-tag",
|
|
"--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",
|
|
encoding="utf-8",
|
|
) as commitizen_config:
|
|
commitizen_config.write(f"version_files = [\n'{version_regex}'\n]")
|
|
|
|
with tmp_commitizen_project.join(version_filepath).open(
|
|
mode="a+", encoding="utf-8"
|
|
) 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
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"testargs",
|
|
[
|
|
["cz", "bump", "--local-version", "1.2.3"],
|
|
["cz", "bump", "--prerelease", "rc", "1.2.3"],
|
|
["cz", "bump", "--devrelease", "0", "1.2.3"],
|
|
["cz", "bump", "--devrelease", "1", "1.2.3"],
|
|
["cz", "bump", "--increment", "PATCH", "1.2.3"],
|
|
["cz", "bump", "--build-metadata=a.b.c", "1.2.3"],
|
|
["cz", "bump", "--local-version", "--build-metadata=a.b.c"],
|
|
],
|
|
)
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_invalid_manual_args_raises_exception(mocker, testargs):
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
|
|
with pytest.raises(NotAllowed):
|
|
cli.main()
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
@pytest.mark.parametrize(
|
|
"manual_version",
|
|
[
|
|
"noversion",
|
|
"1.2..3",
|
|
],
|
|
)
|
|
def test_bump_invalid_manual_version_raises_exception(mocker, manual_version):
|
|
create_file_and_commit("feat: new file")
|
|
|
|
testargs = ["cz", "bump", "--yes", manual_version]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
|
|
with pytest.raises(InvalidManualVersion) as excinfo:
|
|
cli.main()
|
|
|
|
expected_error_message = (
|
|
f"[INVALID_MANUAL_VERSION]\nInvalid manual version: '{manual_version}'"
|
|
)
|
|
assert expected_error_message in str(excinfo.value)
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
@pytest.mark.parametrize(
|
|
"manual_version",
|
|
[
|
|
"0.0.1",
|
|
"0.1.0rc2",
|
|
"0.1.0.dev2",
|
|
"0.1.0+1.0.0",
|
|
"0.1.0rc2.dev2+1.0.0",
|
|
"0.1.1",
|
|
"0.2.0",
|
|
"1.0.0",
|
|
],
|
|
)
|
|
def test_bump_manual_version(mocker, manual_version):
|
|
create_file_and_commit("feat: new file")
|
|
|
|
testargs = ["cz", "bump", "--yes", manual_version]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
tag_exists = git.tag_exist(manual_version)
|
|
assert tag_exists is True
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_manual_version_disallows_major_version_zero(mocker):
|
|
create_file_and_commit("feat: new file")
|
|
|
|
manual_version = "0.2.0"
|
|
testargs = ["cz", "bump", "--yes", "--major-version-zero", manual_version]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
|
|
with pytest.raises(NotAllowed) as excinfo:
|
|
cli.main()
|
|
|
|
expected_error_message = (
|
|
"--major-version-zero cannot be combined with MANUAL_VERSION"
|
|
)
|
|
assert expected_error_message in str(excinfo.value)
|
|
|
|
|
|
@pytest.mark.parametrize("commit_msg", ("feat: new file", "feat(user): new file"))
|
|
def test_bump_with_pre_bump_hooks(
|
|
commit_msg, mocker: MockFixture, tmp_commitizen_project
|
|
):
|
|
pre_bump_hook = "scripts/pre_bump_hook.sh"
|
|
post_bump_hook = "scripts/post_bump_hook.sh"
|
|
|
|
tmp_commitizen_cfg_file = tmp_commitizen_project.join("pyproject.toml")
|
|
tmp_commitizen_cfg_file.write(
|
|
f"{tmp_commitizen_cfg_file.read()}\n"
|
|
f'pre_bump_hooks = ["{pre_bump_hook}"]\n'
|
|
f'post_bump_hooks = ["{post_bump_hook}"]\n'
|
|
)
|
|
|
|
run_mock = mocker.Mock()
|
|
mocker.patch.object(hooks, "run", run_mock)
|
|
|
|
create_file_and_commit(commit_msg)
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
assert tag_exists is True
|
|
|
|
run_mock.assert_has_calls(
|
|
[
|
|
call(
|
|
[pre_bump_hook],
|
|
_env_prefix="CZ_PRE_",
|
|
is_initial=True,
|
|
current_version="0.1.0",
|
|
current_tag_version="0.1.0",
|
|
new_version="0.2.0",
|
|
new_tag_version="0.2.0",
|
|
message="bump: version 0.1.0 → 0.2.0",
|
|
increment="MINOR",
|
|
changelog_file_name=None,
|
|
),
|
|
call(
|
|
[post_bump_hook],
|
|
_env_prefix="CZ_POST_",
|
|
was_initial=True,
|
|
previous_version="0.1.0",
|
|
previous_tag_version="0.1.0",
|
|
current_version="0.2.0",
|
|
current_tag_version="0.2.0",
|
|
message="bump: version 0.1.0 → 0.2.0",
|
|
increment="MINOR",
|
|
changelog_file_name=None,
|
|
),
|
|
]
|
|
)
|
|
|
|
|
|
def test_bump_with_hooks_and_increment(mocker: MockFixture, tmp_commitizen_project):
|
|
pre_bump_hook = "scripts/pre_bump_hook.sh"
|
|
post_bump_hook = "scripts/post_bump_hook.sh"
|
|
|
|
tmp_commitizen_cfg_file = tmp_commitizen_project.join("pyproject.toml")
|
|
tmp_commitizen_cfg_file.write(
|
|
f"{tmp_commitizen_cfg_file.read()}\n"
|
|
f'pre_bump_hooks = ["{pre_bump_hook}"]\n'
|
|
f'post_bump_hooks = ["{post_bump_hook}"]\n'
|
|
)
|
|
|
|
run_mock = mocker.Mock()
|
|
mocker.patch.object(hooks, "run", run_mock)
|
|
|
|
create_file_and_commit("test: some test")
|
|
testargs = ["cz", "bump", "--yes", "--increment", "MINOR"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
assert tag_exists is True
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_git_project")
|
|
def test_bump_use_version_provider(mocker: MockFixture):
|
|
mock = mocker.MagicMock(name="provider")
|
|
mock.get_version.return_value = "0.0.0"
|
|
get_provider = mocker.patch(
|
|
"commitizen.commands.bump.get_provider", return_value=mock
|
|
)
|
|
|
|
create_file_and_commit("fix: fake commit")
|
|
testargs = ["cz", "bump", "--yes", "--changelog"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
|
|
cli.main()
|
|
|
|
assert git.tag_exist("0.0.1")
|
|
get_provider.assert_called_once()
|
|
mock.get_version.assert_called_once()
|
|
mock.set_version.assert_called_once_with("0.0.1")
|
|
|
|
|
|
def test_bump_command_prelease_scheme_via_cli(
|
|
tmp_commitizen_project_initial, mocker: MockFixture
|
|
):
|
|
tmp_commitizen_project = tmp_commitizen_project_initial()
|
|
tmp_version_file = tmp_commitizen_project.join("__version__.py")
|
|
tmp_commitizen_cfg_file = tmp_commitizen_project.join("pyproject.toml")
|
|
|
|
testargs = [
|
|
"cz",
|
|
"bump",
|
|
"--prerelease",
|
|
"alpha",
|
|
"--yes",
|
|
"--version-scheme",
|
|
"semver",
|
|
]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.2.0-a0")
|
|
assert tag_exists is True
|
|
|
|
for version_file in [tmp_version_file, tmp_commitizen_cfg_file]:
|
|
with open(version_file) as f:
|
|
assert "0.2.0-a0" in f.read()
|
|
|
|
# PRERELEASE BUMP CREATES VERSION WITHOUT PRERELEASE
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
assert tag_exists is True
|
|
|
|
for version_file in [tmp_version_file, tmp_commitizen_cfg_file]:
|
|
with open(version_file) as f:
|
|
assert "0.2.0" in f.read()
|
|
|
|
|
|
def test_bump_command_prelease_scheme_via_config(
|
|
tmp_commitizen_project_initial, mocker: MockFixture
|
|
):
|
|
tmp_commitizen_project = tmp_commitizen_project_initial(
|
|
config_extra='version_scheme = "semver"\n',
|
|
)
|
|
tmp_version_file = tmp_commitizen_project.join("__version__.py")
|
|
tmp_commitizen_cfg_file = tmp_commitizen_project.join("pyproject.toml")
|
|
|
|
testargs = ["cz", "bump", "--prerelease", "alpha", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.2.0-a0")
|
|
assert tag_exists is True
|
|
|
|
for version_file in [tmp_version_file, tmp_commitizen_cfg_file]:
|
|
with open(version_file) as f:
|
|
assert "0.2.0-a0" in f.read()
|
|
|
|
testargs = ["cz", "bump", "--prerelease", "alpha", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.2.0-a1")
|
|
assert tag_exists is True
|
|
|
|
for version_file in [tmp_version_file, tmp_commitizen_cfg_file]:
|
|
with open(version_file) as f:
|
|
assert "0.2.0-a1" in f.read()
|
|
|
|
# PRERELEASE BUMP CREATES VERSION WITHOUT PRERELEASE
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
assert tag_exists is True
|
|
|
|
for version_file in [tmp_version_file, tmp_commitizen_cfg_file]:
|
|
with open(version_file) as f:
|
|
assert "0.2.0" in f.read()
|
|
|
|
|
|
def test_bump_command_prelease_scheme_check_old_tags(
|
|
tmp_commitizen_project_initial, mocker: MockFixture
|
|
):
|
|
tmp_commitizen_project = tmp_commitizen_project_initial(
|
|
config_extra=('tag_format = "v$version"\nversion_scheme = "semver"\n'),
|
|
)
|
|
tmp_version_file = tmp_commitizen_project.join("__version__.py")
|
|
tmp_commitizen_cfg_file = tmp_commitizen_project.join("pyproject.toml")
|
|
|
|
testargs = ["cz", "bump", "--prerelease", "alpha", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("v0.2.0-a0")
|
|
assert tag_exists is True
|
|
|
|
for version_file in [tmp_version_file, tmp_commitizen_cfg_file]:
|
|
with open(version_file) as f:
|
|
assert "0.2.0-a0" in f.read()
|
|
|
|
testargs = ["cz", "bump", "--prerelease", "alpha"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("v0.2.0-a1")
|
|
assert tag_exists is True
|
|
|
|
for version_file in [tmp_version_file, tmp_commitizen_cfg_file]:
|
|
with open(version_file) as f:
|
|
assert "0.2.0-a1" in f.read()
|
|
|
|
# PRERELEASE BUMP CREATES VERSION WITHOUT PRERELEASE
|
|
testargs = ["cz", "bump"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist("v0.2.0")
|
|
assert tag_exists is True
|
|
|
|
for version_file in [tmp_version_file, tmp_commitizen_cfg_file]:
|
|
with open(version_file) as f:
|
|
assert "0.2.0" in f.read()
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
@pytest.mark.usefixtures("use_cz_semver")
|
|
@pytest.mark.parametrize(
|
|
"message, expected_tag",
|
|
[
|
|
("minor: add users", "0.2.0"),
|
|
("patch: bug affecting users", "0.1.1"),
|
|
("major: bug affecting users", "1.0.0"),
|
|
],
|
|
)
|
|
def test_bump_with_plugin(mocker: MockFixture, message: str, expected_tag: str):
|
|
create_file_and_commit(message)
|
|
|
|
testargs = ["cz", "--name", "cz_semver", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist(expected_tag)
|
|
assert tag_exists is True
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
@pytest.mark.usefixtures("use_cz_semver")
|
|
@pytest.mark.parametrize(
|
|
"message, expected_tag",
|
|
[
|
|
("minor: add users", "0.2.0"),
|
|
("patch: bug affecting users", "0.1.1"),
|
|
("major: bug affecting users", "0.2.0"),
|
|
],
|
|
)
|
|
def test_bump_with_major_version_zero_with_plugin(
|
|
mocker: MockFixture, message: str, expected_tag: str
|
|
):
|
|
create_file_and_commit(message)
|
|
|
|
testargs = ["cz", "--name", "cz_semver", "bump", "--yes", "--major-version-zero"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
tag_exists = git.tag_exist(expected_tag)
|
|
assert tag_exists is True
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_command_version_type_deprecation(mocker: MockFixture):
|
|
create_file_and_commit("feat: check deprecation on --version-type")
|
|
|
|
testargs = [
|
|
"cz",
|
|
"bump",
|
|
"--prerelease",
|
|
"alpha",
|
|
"--yes",
|
|
"--version-type",
|
|
"semver",
|
|
]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
with pytest.warns(DeprecationWarning):
|
|
cli.main()
|
|
|
|
assert git.tag_exist("0.2.0-a0")
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_command_version_scheme_priority_over_version_type(mocker: MockFixture):
|
|
create_file_and_commit("feat: check deprecation on --version-type")
|
|
|
|
testargs = [
|
|
"cz",
|
|
"bump",
|
|
"--prerelease",
|
|
"alpha",
|
|
"--yes",
|
|
"--version-type",
|
|
"semver",
|
|
"--version-scheme",
|
|
"pep440",
|
|
]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
with pytest.warns(DeprecationWarning):
|
|
cli.main()
|
|
|
|
assert git.tag_exist("0.2.0a0")
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"arg, cfg, expected",
|
|
(
|
|
pytest.param("", "", "default", id="default"),
|
|
pytest.param("", "changelog.cfg", "from config", id="from-config"),
|
|
pytest.param(
|
|
"--template=changelog.cmd", "changelog.cfg", "from cmd", id="from-command"
|
|
),
|
|
),
|
|
)
|
|
def test_bump_template_option_precedance(
|
|
mocker: MockFixture,
|
|
tmp_commitizen_project: Path,
|
|
any_changelog_format: ChangelogFormat,
|
|
arg: str,
|
|
cfg: str,
|
|
expected: str,
|
|
):
|
|
project_root = Path(tmp_commitizen_project)
|
|
cfg_template = project_root / "changelog.cfg"
|
|
cmd_template = project_root / "changelog.cmd"
|
|
default_template = project_root / any_changelog_format.template
|
|
changelog = project_root / any_changelog_format.default_changelog_file
|
|
|
|
cfg_template.write_text("from config")
|
|
cmd_template.write_text("from cmd")
|
|
default_template.write_text("default")
|
|
|
|
create_file_and_commit("feat: new file")
|
|
|
|
if cfg:
|
|
pyproject = project_root / "pyproject.toml"
|
|
pyproject.write_text(
|
|
dedent(
|
|
f"""\
|
|
[tool.commitizen]
|
|
version = "0.1.0"
|
|
template = "{cfg}"
|
|
"""
|
|
)
|
|
)
|
|
|
|
testargs = ["cz", "bump", "--yes", "--changelog"]
|
|
if arg:
|
|
testargs.append(arg)
|
|
mocker.patch.object(sys, "argv", testargs + ["0.1.1"])
|
|
cli.main()
|
|
|
|
out = changelog.read_text()
|
|
assert out == expected
|
|
|
|
|
|
def test_bump_template_extras_precedance(
|
|
mocker: MockFixture,
|
|
tmp_commitizen_project: Path,
|
|
any_changelog_format: ChangelogFormat,
|
|
mock_plugin: BaseCommitizen,
|
|
):
|
|
project_root = Path(tmp_commitizen_project)
|
|
changelog_tpl = project_root / any_changelog_format.template
|
|
changelog_tpl.write_text("{{first}} - {{second}} - {{third}}")
|
|
|
|
mock_plugin.template_extras = dict(
|
|
first="from-plugin", second="from-plugin", third="from-plugin"
|
|
)
|
|
|
|
pyproject = project_root / "pyproject.toml"
|
|
pyproject.write_text(
|
|
dedent(
|
|
"""\
|
|
[tool.commitizen]
|
|
version = "0.1.0"
|
|
[tool.commitizen.extras]
|
|
first = "from-config"
|
|
second = "from-config"
|
|
"""
|
|
)
|
|
)
|
|
|
|
create_file_and_commit("feat: new file")
|
|
|
|
testargs = [
|
|
"cz",
|
|
"bump",
|
|
"--yes",
|
|
"--changelog",
|
|
"--extra",
|
|
"first=from-command",
|
|
"0.1.1",
|
|
]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
changelog = project_root / any_changelog_format.default_changelog_file
|
|
assert changelog.read_text() == "from-command - from-config - from-plugin"
|
|
|
|
|
|
def test_bump_template_extra_quotes(
|
|
mocker: MockFixture,
|
|
tmp_commitizen_project: Path,
|
|
any_changelog_format: ChangelogFormat,
|
|
):
|
|
project_root = Path(tmp_commitizen_project)
|
|
changelog_tpl = project_root / any_changelog_format.template
|
|
changelog_tpl.write_text("{{first}} - {{second}} - {{third}}")
|
|
|
|
create_file_and_commit("feat: new file")
|
|
|
|
testargs = [
|
|
"cz",
|
|
"bump",
|
|
"--changelog",
|
|
"--yes",
|
|
"-e",
|
|
"first=no-quote",
|
|
"-e",
|
|
"second='single quotes'",
|
|
"-e",
|
|
'third="double quotes"',
|
|
"0.1.1",
|
|
]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
changelog = project_root / any_changelog_format.default_changelog_file
|
|
assert changelog.read_text() == "no-quote - single quotes - double quotes"
|
|
|
|
|
|
def test_bump_changelog_contains_increment_only(mocker, tmp_commitizen_project, capsys):
|
|
"""Issue 1024"""
|
|
# Initialize commitizen up to v1.0.0
|
|
project_root = Path(tmp_commitizen_project)
|
|
tmp_commitizen_cfg_file = project_root / "pyproject.toml"
|
|
tmp_commitizen_cfg_file.write_text(
|
|
'[tool.commitizen]\nversion="1.0.0"\nupdate_changelog_on_bump = true\n'
|
|
)
|
|
tmp_changelog_file = project_root / "CHANGELOG.md"
|
|
tmp_changelog_file.write_text("## v1.0.0")
|
|
create_file_and_commit("feat(user): new file")
|
|
create_tag("v1.0.0")
|
|
|
|
# Add a commit and bump to v2.0.0
|
|
create_file_and_commit("feat(user)!: new file")
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
_ = capsys.readouterr()
|
|
|
|
# Add a commit and create the incremental changelog to v3.0.0
|
|
# it should only include v3 changes
|
|
create_file_and_commit("feat(next)!: next version")
|
|
testargs = ["cz", "bump", "--yes", "--files-only", "--changelog-to-stdout"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
with pytest.raises(ExpectedExit):
|
|
cli.main()
|
|
out, _ = capsys.readouterr()
|
|
|
|
assert "3.0.0" in out
|
|
assert "2.0.0" not in out
|
|
|
|
|
|
@skip_below_py_3_13
|
|
def test_bump_command_shows_description_when_use_help_option(
|
|
mocker: MockFixture, capsys, file_regression
|
|
):
|
|
testargs = ["cz", "bump", "--help"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
with pytest.raises(SystemExit):
|
|
cli.main()
|
|
|
|
out, _ = capsys.readouterr()
|
|
file_regression.check(out, extension=".txt")
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_get_next(mocker: MockFixture, capsys):
|
|
create_file_and_commit("feat: new file")
|
|
|
|
testargs = ["cz", "bump", "--yes", "--get-next"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
with pytest.raises(GetNextExit):
|
|
cli.main()
|
|
|
|
out, _ = capsys.readouterr()
|
|
assert "0.2.0" in out
|
|
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
assert tag_exists is False
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_get_next_update_changelog_on_bump(
|
|
mocker: MockFixture, capsys, config_path
|
|
):
|
|
create_file_and_commit("feat: new file")
|
|
with open(config_path, "a", encoding="utf-8") as fp:
|
|
fp.write("update_changelog_on_bump = true\n")
|
|
|
|
testargs = ["cz", "bump", "--yes", "--get-next"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
with pytest.raises(GetNextExit):
|
|
cli.main()
|
|
|
|
out, _ = capsys.readouterr()
|
|
assert "0.2.0" in out
|
|
|
|
tag_exists = git.tag_exist("0.2.0")
|
|
assert tag_exists is False
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_get_next__changelog_is_not_allowed(mocker: MockFixture):
|
|
create_file_and_commit("feat: new file")
|
|
|
|
testargs = ["cz", "bump", "--yes", "--get-next", "--changelog"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
|
|
with pytest.raises(NotAllowed):
|
|
cli.main()
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_get_next__changelog_to_stdout_is_not_allowed(mocker: MockFixture):
|
|
create_file_and_commit("feat: new file")
|
|
|
|
testargs = ["cz", "bump", "--yes", "--get-next", "--changelog-to-stdout"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
|
|
with pytest.raises(NotAllowed):
|
|
cli.main()
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_get_next__manual_version_is_not_allowed(mocker: MockFixture):
|
|
create_file_and_commit("feat: new file")
|
|
|
|
testargs = ["cz", "bump", "--yes", "--get-next", "0.2.1"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
|
|
with pytest.raises(NotAllowed):
|
|
cli.main()
|
|
|
|
|
|
@pytest.mark.usefixtures("tmp_commitizen_project")
|
|
def test_bump_get_next__no_eligible_commits_raises(mocker: MockFixture):
|
|
create_file_and_commit("chore: new commit")
|
|
|
|
testargs = ["cz", "bump", "--yes", "--get-next"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
|
|
with pytest.raises(NoneIncrementExit):
|
|
cli.main()
|
|
|
|
|
|
def test_bump_allow_no_commit_with_no_commit(mocker, tmp_commitizen_project, capsys):
|
|
with tmp_commitizen_project.as_cwd():
|
|
# Create the first commit and bump to 1.0.0
|
|
create_file_and_commit("feat(user)!: new file")
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
# Verify NoCommitsFoundError should be raised
|
|
# when there's no new commit and "--allow-no-commit" is not set
|
|
with pytest.raises(NoCommitsFoundError):
|
|
testargs = ["cz", "bump"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
# bump to 1.0.1 with new commit when "--allow-no-commit" is set
|
|
testargs = ["cz", "bump", "--allow-no-commit"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
out, _ = capsys.readouterr()
|
|
assert "bump: version 1.0.0 → 1.0.1" in out
|
|
|
|
|
|
def test_bump_allow_no_commit_with_no_eligible_commit(
|
|
mocker, tmp_commitizen_project, capsys
|
|
):
|
|
with tmp_commitizen_project.as_cwd():
|
|
# Create the first commit and bump to 1.0.0
|
|
create_file_and_commit("feat(user)!: new file")
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
# Create a commit that is ineligible to bump
|
|
create_file_and_commit("docs(bump): add description for allow no commit")
|
|
|
|
# Verify NoneIncrementExit should be raised
|
|
# when there's no eligible bumping commit and "--allow-no-commit" is not set
|
|
with pytest.raises(NoneIncrementExit):
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
# bump to 1.0.1 with ineligible commit when "--allow-no-commit" is set
|
|
testargs = ["cz", "bump", "--allow-no-commit"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
out, _ = capsys.readouterr()
|
|
assert "bump: version 1.0.0 → 1.0.1" in out
|
|
|
|
|
|
def test_bump_allow_no_commit_with_increment(mocker, tmp_commitizen_project, capsys):
|
|
with tmp_commitizen_project.as_cwd():
|
|
# # Create the first commit and bump to 1.0.0
|
|
create_file_and_commit("feat(user)!: new file")
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
# Verify NoCommitsFoundError should be raised
|
|
# when there's no new commit and "--allow-no-commit" is not set
|
|
with pytest.raises(NoCommitsFoundError):
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
# bump to 1.1.0 with no new commit when "--allow-no-commit" is set
|
|
# and increment is specified
|
|
testargs = ["cz", "bump", "--yes", "--allow-no-commit", "--increment", "MINOR"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
out, _ = capsys.readouterr()
|
|
assert "bump: version 1.0.0 → 1.1.0" in out
|
|
|
|
|
|
def test_bump_allow_no_commit_with_manual_version(
|
|
mocker, tmp_commitizen_project, capsys
|
|
):
|
|
with tmp_commitizen_project.as_cwd():
|
|
# # Create the first commit and bump to 1.0.0
|
|
create_file_and_commit("feat(user)!: new file")
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
# Verify NoCommitsFoundError should be raised
|
|
# when there's no new commit and "--allow-no-commit" is not set
|
|
with pytest.raises(NoCommitsFoundError):
|
|
testargs = ["cz", "bump", "--yes"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
# bump to 1.1.0 with no new commit when "--allow-no-commit" is set
|
|
# and increment is specified
|
|
testargs = ["cz", "bump", "--yes", "--allow-no-commit", "2.0.0"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
out, _ = capsys.readouterr()
|
|
assert "bump: version 1.0.0 → 2.0.0" in out
|
|
|
|
|
|
def test_bump_detect_legacy_tags_from_scm(
|
|
tmp_commitizen_project: py.path.local, mocker: MockFixture
|
|
):
|
|
project_root = Path(tmp_commitizen_project)
|
|
tmp_commitizen_cfg_file = project_root / "pyproject.toml"
|
|
tmp_commitizen_cfg_file.write_text(
|
|
"\n".join(
|
|
[
|
|
"[tool.commitizen]",
|
|
'version_provider = "scm"',
|
|
'tag_format = "v$version"',
|
|
"legacy_tag_formats = [",
|
|
' "legacy-${version}"',
|
|
"]",
|
|
]
|
|
),
|
|
)
|
|
create_file_and_commit("feat: new file")
|
|
create_tag("legacy-0.4.2")
|
|
create_file_and_commit("feat: new file")
|
|
|
|
testargs = ["cz", "bump", "--increment", "patch", "--changelog"]
|
|
mocker.patch.object(sys, "argv", testargs)
|
|
cli.main()
|
|
|
|
assert git.tag_exist("v0.4.3")
|