Add command line parameters for VCS configuration

- Add the following flags to the 'bumpver update' command:
    * --commit / --no-commit
    * --tag-commit / --no-tag-commit
    * --push / --no-push
- Add test cases for these flags including checks for incorrect usage
- Document new flags in README
This commit is contained in:
Timo Ludwig 2021-11-06 15:06:15 +01:00 committed by mbarkhau
parent c8138d89ef
commit b4cf3a5f32
3 changed files with 273 additions and 29 deletions

View file

@ -564,30 +564,29 @@ Usage: bumpver update [OPTIONS]
Update project files with the incremented version string. Update project files with the incremented version string.
Options: Options:
-d, --dry Display diff of changes, don't rewrite files. -d, --dry Display diff of changes, don't rewrite files.
-f, --fetch / -n, --no-fetch Sync tags from remote origin. -f, --fetch / -n, --no-fetch Sync tags from remote origin.
-v, --verbose Control log level. -vv for debug level. -v, --verbose Control log level. -vv for debug level.
--allow-dirty Commit even when working directory is has --allow-dirty Commit even when working directory is has
uncomitted changes. (WARNING: The commit will uncomitted changes. (WARNING: The commit will
still be aborted if there are uncomitted to still be aborted if there are uncomitted to
files with version strings. files with version strings.
--set-version <VERSION> Set version explicitly.
--set-version <VERSION> Set version explicitly. --date <ISODATE> Set explicit date in format YYYY-0M-0D (e.g.
--date <ISODATE> Set explicit date in format YYYY-0M-0D (e.g. 2021-05-13).
2021-05-13). --pin-date Leave date components unchanged.
--tag-num Increment release tag number (rc1, rc2,
--pin-date Leave date components unchanged. rc3..).
--tag-num Increment release tag number (rc1, rc2, -t, --tag <NAME> Override release tag of current_version. Valid
rc3..). options are: alpha, beta, rc, post, final.
-p, --patch Increment PATCH component.
-t, --tag <NAME> Override release tag of current_version. Valid -m, --minor Increment MINOR component.
options are: alpha, beta, rc, post, final. --major Increment MAJOR component.
-c, --commit-message <TMPL> Set commit message template.
-p, --patch Increment PATCH component. --commit / --no-commit Create a commit with all updated files.
-m, --minor Increment MINOR component. --tag-commit / --no-tag-commit Tag the newly created commit.
--major Increment MAJOR component. --push / --no-push Push to the default remote.
-c, --commit-message <TMPL> Set commit message template. --help Show this message and exit.
--help Show this message and exit.
``` ```
<!-- END bumpver update --help --> <!-- END bumpver update --help -->
@ -1016,6 +1015,17 @@ INFO - git tag --annotate 2020.1006 --message 2020.1006
INFO - git push origin --follow-tags 2020.1006 HEAD INFO - git push origin --follow-tags 2020.1006 HEAD
``` ```
It's also possible to override the config values by passing the following command line flags to `bumpver update`:
| Flag | Override config |
|-------------------|-------------------------------------------------|
| `--commit` | `commit = True` |
| `--no-commit` | `commit = False`, `tag = False`, `push = False` |
| `--tag-commit` | `tag = True` |
| `--no-tag-commit` | `tag = False` |
| `--push` | `push = True` |
| `--no-push` | `push = False` |
### Custom Commit Message ### Custom Commit Message
In addition to the `commit_message` configuration, you can also override the string used as the the commit message template with the `-c/--commit-message=<TMPL>` parameter: In addition to the `commit_message` configuration, you can also override the string used as the the commit message template with the `-c/--commit-message=<TMPL>` parameter:

View file

@ -677,6 +677,32 @@ def _update_cfg_from_vcs(cfg: config.Config, fetch: bool) -> config.Config:
) )
def _parse_vcs_options(
cfg : config.Config,
commit: typ.Optional[bool] = None,
tag : typ.Optional[bool] = None,
push : typ.Optional[bool] = None,
) -> config.Config:
if commit is not None:
if not commit:
if tag:
raise ValueError("--no-commit and --tag-commit cannot be used at the same time")
if push:
raise ValueError("--no-commit and --push cannot be used at the same time")
cfg = cfg._replace(commit=commit)
if tag is not None:
if tag and not cfg.commit:
raise ValueError(
"--tag-commit requires the --commit flag if commit=False in the config file"
)
cfg = cfg._replace(tag=tag)
if push is not None:
if push and not cfg.commit:
raise ValueError("--push requires the --commit flag if commit=False in the config file")
cfg = cfg._replace(push=push)
return cfg
@cli.command() @cli.command()
@dry_option @dry_option
@fetch_option @fetch_option
@ -699,6 +725,21 @@ def _update_cfg_from_vcs(cfg: config.Config, fetch: bool) -> config.Config:
metavar="<TMPL>", metavar="<TMPL>",
help="Set commit message template.", help="Set commit message template.",
) )
@click.option(
"--commit/--no-commit",
default=None,
help="Create a commit with all updated files.",
)
@click.option(
"--tag-commit/--no-tag-commit",
default=None,
help="Tag the newly created commit.",
)
@click.option(
"--push/--no-push",
default=None,
help="Push to the default remote.",
)
def update( def update(
dry : bool = False, dry : bool = False,
allow_dirty : bool = False, allow_dirty : bool = False,
@ -713,6 +754,9 @@ def update(
date : typ.Optional[str] = None, date : typ.Optional[str] = None,
set_version : typ.Optional[str] = None, set_version : typ.Optional[str] = None,
commit_message: typ.Optional[str] = None, commit_message: typ.Optional[str] = None,
commit : typ.Optional[bool] = None,
tag_commit : typ.Optional[bool] = None,
push : typ.Optional[bool] = None,
) -> None: ) -> None:
"""Update project files with the incremented version string.""" """Update project files with the incremented version string."""
verbose = max(_VERBOSE, verbose) verbose = max(_VERBOSE, verbose)
@ -726,6 +770,12 @@ def update(
logger.error("Could not parse configuration.") logger.error("Could not parse configuration.")
sys.exit(1) sys.exit(1)
try:
cfg = _parse_vcs_options(cfg, commit, tag_commit, push)
except ValueError as ex:
logger.warning(f"Invalid argument: {ex}")
sys.exit(1)
cfg = _update_cfg_from_vcs(cfg, fetch) cfg = _update_cfg_from_vcs(cfg, fetch)
old_version = cfg.current_version old_version = cfg.current_version

View file

@ -640,6 +640,190 @@ def test_empty_hg_bump(runner, caplog):
assert any(("setup.cfg" in r.message) for r in caplog.records) assert any(("setup.cfg" in r.message) for r in caplog.records)
def test_incorrect_vcs_option_no_commit_tag(runner, caplog):
_add_project_files("README.md")
_vcs_init("git")
result = runner.invoke(cli.cli, ['init', "-vv"])
assert result.exit_code == 0
result = runner.invoke(cli.cli, ['update', "-vv", "--no-commit", "--tag-commit"])
assert result.exit_code == 1
assert len(caplog.records) == 1
assert (
"Invalid argument: --no-commit and --tag-commit cannot be used at the same time"
in caplog.records[0].message
)
def test_incorrect_vcs_option_no_commit_push(runner, caplog):
_add_project_files("README.md")
_vcs_init("git")
result = runner.invoke(cli.cli, ['init', "-vv"])
assert result.exit_code == 0
_update_config_val(
"bumpver.toml",
tag="false",
)
result = runner.invoke(cli.cli, ['update', "-vv", "--no-commit", "--push"])
assert result.exit_code == 1
assert len(caplog.records) == 1
assert (
"Invalid argument: --no-commit and --push cannot be used at the same time"
in caplog.records[0].message
)
def test_incorrect_vcs_option_tag_push(runner, caplog):
_add_project_files("README.md")
_vcs_init("git")
result = runner.invoke(cli.cli, ['init', "-vv"])
assert result.exit_code == 0
_update_config_val(
"bumpver.toml",
commit="false",
tag="false",
push="false",
)
result = runner.invoke(cli.cli, ['update', "-vv", "--tag-commit"])
assert result.exit_code == 1
assert len(caplog.records) == 1
assert (
"Invalid argument: --tag-commit requires the --commit flag if commit=False in the config file"
in caplog.records[0].message
)
result = runner.invoke(cli.cli, ['update', "-vv", "--push"])
assert result.exit_code == 1
assert len(caplog.records) == 2
assert (
"Invalid argument: --push requires the --commit flag if commit=False in the config file"
in caplog.records[1].message
)
@pytest.mark.parametrize("version_pattern, cur_version, cur_pep440", DEFAULT_VERSION_PATTERNS)
def test_vcs_option_no_commit(runner, caplog, version_pattern, cur_version, cur_pep440):
_add_project_files("README.md")
_vcs_init("git")
result = runner.invoke(cli.cli, ['init', "-vv"])
assert result.exit_code == 0
_update_config_val(
"bumpver.toml",
version_pattern=version_pattern,
current_version=f'"{cur_version}"',
)
shell("git", "add", "bumpver.toml")
shell("git", "commit", "-m", "update bumpver.toml")
prev_commit_count = shell("git", "rev-list", "HEAD", "--count").decode("utf-8")
result = runner.invoke(cli.cli, ['update', "-vv", "--no-commit"])
assert result.exit_code == 0
tags = shell("git", "tag", "--list").decode("utf-8")
assert not tags
commit_count = shell("git", "rev-list", "HEAD", "--count").decode("utf-8")
assert prev_commit_count == commit_count
@pytest.mark.parametrize("version_pattern, cur_version, cur_pep440", DEFAULT_VERSION_PATTERNS)
def test_vcs_option_commit(runner, caplog, version_pattern, cur_version, cur_pep440):
_add_project_files("README.md")
_vcs_init("git")
result = runner.invoke(cli.cli, ['init', "-vv"])
assert result.exit_code == 0
_update_config_val(
"bumpver.toml",
version_pattern=version_pattern,
current_version=f'"{cur_version}"',
commit="false",
tag="false",
push="false",
)
shell("git", "add", "bumpver.toml")
shell("git", "commit", "-m", "update bumpver.toml")
result = runner.invoke(cli.cli, ['update', "-vv", "--commit"])
assert result.exit_code == 0
calver = cur_version.split(".")[0]
tags = shell("git", "tag", "--list").decode("utf-8")
assert not tags
last_commit = shell("git", "log", "-1").decode("utf-8")
expected = f"bump version {calver}.1001-alpha -> {calver}.1002-alpha"
assert expected in last_commit
@pytest.mark.parametrize("version_pattern, cur_version, cur_pep440", DEFAULT_VERSION_PATTERNS)
def test_vcs_option_no_tag(runner, caplog, version_pattern, cur_version, cur_pep440):
_add_project_files("README.md")
_vcs_init("git")
result = runner.invoke(cli.cli, ['init', "-vv"])
assert result.exit_code == 0
_update_config_val(
"bumpver.toml",
version_pattern=version_pattern,
current_version=f'"{cur_version}"',
)
shell("git", "add", "bumpver.toml")
shell("git", "commit", "-m", "update bumpver.toml")
result = runner.invoke(cli.cli, ['update', "-vv", "--no-tag-commit"])
assert result.exit_code == 0
calver = cur_version.split(".")[0]
tags = shell("git", "tag", "--list").decode("utf-8")
assert not tags
last_commit = shell("git", "log", "-1").decode("utf-8")
expected = f"bump version {calver}.1001-alpha -> {calver}.1002-alpha"
assert expected in last_commit
@pytest.mark.parametrize("version_pattern, cur_version, cur_pep440", DEFAULT_VERSION_PATTERNS)
def test_vcs_option_tag(runner, caplog, version_pattern, cur_version, cur_pep440):
_add_project_files("README.md")
_vcs_init("git")
result = runner.invoke(cli.cli, ['init', "-vv"])
assert result.exit_code == 0
_update_config_val(
"bumpver.toml",
version_pattern=version_pattern,
current_version=f'"{cur_version}"',
tag="false",
)
shell("git", "add", "bumpver.toml")
shell("git", "commit", "-m", "update bumpver.toml")
result = runner.invoke(cli.cli, ['update', "-vv", "--tag-commit"])
assert result.exit_code == 0
calver = cur_version.split(".")[0]
tags = shell("git", "tag", "--list").decode("utf-8")
assert f"{calver}.1002-alpha" in tags
last_commit = shell("git", "log", "-1").decode("utf-8")
expected = f"bump version {calver}.1001-alpha -> {calver}.1002-alpha"
assert expected in last_commit
SETUP_CFG_SEMVER_FIXTURE = """ SETUP_CFG_SEMVER_FIXTURE = """
[metadata] [metadata]
license_file = LICENSE license_file = LICENSE
@ -1028,13 +1212,13 @@ ROLLOVER_TEST_CASES = [
["{year}.{month}.{MINOR}", "2020.10.3", "2020.11.4", _kwargs(2020, 11, True)], ["{year}.{month}.{MINOR}", "2020.10.3", "2020.11.4", _kwargs(2020, 11, True)],
["{year}.{month}.{MINOR}", "2020.10.3", "2020.11.3", _kwargs(2020, 11, False)], ["{year}.{month}.{MINOR}", "2020.10.3", "2020.11.3", _kwargs(2020, 11, False)],
# v2 cases # v2 cases
["YYYY.MM.MINOR" , "2020.10.3", "2020.10.4", _kwargs(2020, 10, True)], ["YYYY.MM.MINOR", "2020.10.3", "2020.10.4", _kwargs(2020, 10, True)],
["YYYY.MM.MINOR" , "2020.10.3", None, _kwargs(2020, 10, False)], ["YYYY.MM.MINOR", "2020.10.3", None, _kwargs(2020, 10, False)],
["YYYY.MM.MINOR" , "2020.10.3", "2020.11.0", _kwargs(2020, 11, True)], ["YYYY.MM.MINOR", "2020.10.3", "2020.11.0", _kwargs(2020, 11, True)],
["YYYY.MM.MINOR" , "2020.10.3", "2020.11.0", _kwargs(2020, 11, False)], ["YYYY.MM.MINOR", "2020.10.3", "2020.11.0", _kwargs(2020, 11, False)],
["YYYY.MM[.MINOR]", "2020.10.3", "2020.10.4", _kwargs(2020, 10, True)], ["YYYY.MM[.MINOR]", "2020.10.3", "2020.10.4", _kwargs(2020, 10, True)],
["YYYY.MM[.MINOR]", "2020.10.3", "2020.11", _kwargs(2020, 11, False)], ["YYYY.MM[.MINOR]", "2020.10.3", "2020.11", _kwargs(2020, 11, False)],
["YYYY.MM.MINOR" , "2020.10.3", "2021.10.0", _kwargs(2021, 10, False)], ["YYYY.MM.MINOR", "2020.10.3", "2021.10.0", _kwargs(2021, 10, False)],
# incr0/incr1 part # incr0/incr1 part
["YYYY.MM.INC0", "2020.10.3", "2020.10.4", _kwargs(2020, 10)], ["YYYY.MM.INC0", "2020.10.3", "2020.10.4", _kwargs(2020, 10)],
["YYYY.MM.INC0", "2020.10.3", "2020.11.0", _kwargs(2020, 11)], ["YYYY.MM.INC0", "2020.10.3", "2020.11.0", _kwargs(2020, 11)],