Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 53a1d17

Browse files
jenstroegerLee-W
authored andcommitted
feat: add major-version-zero option to support initial package development
1 parent cb798dc commit 53a1d17

File tree

7 files changed

+145
-4
lines changed

7 files changed

+145
-4
lines changed

‎commitizen/cli.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,12 @@
183183
"default": False,
184184
"help": "retry commit if it fails the 1st time",
185185
},
186+
{
187+
"name": ["--major-version-zero"],
188+
"action": "store_true",
189+
"default": None,
190+
"help": "keep major version at zero, even for breaking changes",
191+
},
186192
{
187193
"name": "manual_version",
188194
"type": str,

‎commitizen/commands/bump.py‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import questionary
66
from packaging.version import InvalidVersion, Version
77

8-
from commitizen import bump, cmd, factory, git, out
8+
from commitizen import bump, cmd, defaults, factory, git, out
99
from commitizen.commands.changelog import Changelog
1010
from commitizen.config import BaseConfig
1111
from commitizen.exceptions import (
@@ -45,6 +45,7 @@ def __init__(self, config: BaseConfig, arguments: dict):
4545
"bump_message",
4646
"gpg_sign",
4747
"annotated_tag",
48+
"major_version_zero",
4849
]
4950
if arguments[key] is not None
5051
},
@@ -101,6 +102,7 @@ def __call__(self): # noqa: C901
101102
tag_format: str = self.bump_settings["tag_format"]
102103
bump_commit_message: str = self.bump_settings["bump_message"]
103104
version_files: List[str] = self.bump_settings["version_files"]
105+
major_version_zero: bool = self.bump_settings["major_version_zero"]
104106

105107
dry_run: bool = self.arguments["dry_run"]
106108
is_yes: bool = self.arguments["yes"]
@@ -126,6 +128,20 @@ def __call__(self): # noqa: C901
126128
"--local-version cannot be combined with MANUAL_VERSION"
127129
)
128130

131+
if major_version_zero:
132+
raise NotAllowed(
133+
"--major-version-zero cannot be combined with MANUAL_VERSION"
134+
)
135+
136+
if major_version_zero:
137+
if not current_version.startswith("0."):
138+
raise NotAllowed(
139+
f"--major-version-zero is meaningless for current version {current_version}"
140+
)
141+
142+
# Update the bump map to ensure major version doesn't increment.
143+
self.cz.bump_map = defaults.bump_map_major_version_zero
144+
129145
current_tag_version: str = bump.normalize_tag(
130146
current_version, tag_format=tag_format
131147
)

‎commitizen/defaults.py‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class Settings(TypedDict, total=False):
3939
use_shortcuts: bool
4040
style: Optional[List[Tuple[str, str]]]
4141
customize: CzSettings
42+
major_version_zero: bool
4243

4344

4445
name: str = "cz_conventional_commits"
@@ -63,6 +64,7 @@ class Settings(TypedDict, total=False):
6364
"changelog_start_rev": None,
6465
"update_changelog_on_bump": False,
6566
"use_shortcuts": False,
67+
"major_version_zero": False,
6668
}
6769

6870
MAJOR = "MAJOR"
@@ -80,6 +82,16 @@ class Settings(TypedDict, total=False):
8082
(r"^perf", PATCH),
8183
)
8284
)
85+
bump_map_major_version_zero = OrderedDict(
86+
(
87+
(r"^.+!$", MINOR),
88+
(r"^BREAKING[\-\ ]CHANGE", MINOR),
89+
(r"^feat", MINOR),
90+
(r"^fix", PATCH),
91+
(r"^refactor", PATCH),
92+
(r"^perf", PATCH),
93+
)
94+
)
8395
change_type_order = ["BREAKING CHANGE", "Feat", "Fix", "Refactor", "Perf"]
8496
bump_message = "bump: version $current_version → $new_version"
8597

‎docs/bump.md‎

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ usage: cz bump [-h] [--dry-run] [--files-only] [--local-version] [--changelog]
5959
[--bump-message BUMP_MESSAGE] [--prerelease {alpha,beta,rc}]
6060
[--devrelease DEVRELEASE] [--increment {MAJOR,MINOR,PATCH}]
6161
[--check-consistency] [--annotated-tag] [--gpg-sign]
62-
[--changelog-to-stdout] [--retry] [MANUAL_VERSION]
62+
[--changelog-to-stdout] [--retry] [--major-version-zero]
63+
[MANUAL_VERSION]
6364

6465
positional arguments:
6566
MANUAL_VERSION bump to the given version (e.g: 1.5.3)
@@ -93,6 +94,7 @@ options:
9394
--changelog-to-stdout
9495
Output changelog to the stdout
9596
--retry retry commit if it fails the 1st time
97+
--major-version-zero keep major version at zero, even for breaking changes
9698
```
9799
98100
### `--files-only`
@@ -199,6 +201,18 @@ It will retry the commit if it fails the 1st time.
199201
200202
Useful to combine with code formatters, like [Prettier](https://prettier.io/).
201203
204+
### `--major-version-zero`
205+
206+
A project in its initial development should have a major version zero, and even breaking changes
207+
should not bump that major version from zero. This command ensures that behavior.
208+
209+
If `--major-version-zero` is used for projects that have a version number greater than zero it fails.
210+
If used together with a manual version the command also fails.
211+
212+
We recommend setting `major_version_zero = true` in your configuration file while a project
213+
is in its initial development. Remove that configuration using a breaking-change commit to bump
214+
your project’s major version to `v1.0.0` once your project has reached maturity.
215+
202216
## Avoid raising errors
203217
204218
Some situations from commitizen rise an exit code different than 0.
@@ -369,6 +383,8 @@ When set to `true` commitizen will create annotated tags.
369383
370384
```toml
371385
[tool.commitizen]
386+
annotated_tag = true
387+
```
372388
373389
---
374390
@@ -379,7 +395,20 @@ When set to `true` commitizen will create gpg signed tags.
379395
```toml
380396
[tool.commitizen]
381397
gpg_sign = true
382-
annotated_tag = true
398+
```
399+
400+
---
401+
402+
### `major_version_zero`
403+
404+
When set to `true` commitizen will keep the major version at zero.
405+
Useful during the initial development stage of your project.
406+
407+
Defaults to: `false`
408+
409+
```toml
410+
[tool.commitizen]
411+
major_version_zero = true
383412
```
384413
385414
## Custom bump

‎tests/commands/test_bump_command.py‎

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
NotAllowed,
2323
NoVersionSpecifiedError,
2424
)
25-
from tests.utils import create_file_and_commit
25+
from tests.utils import create_file_and_commit, create_tag
2626

2727

2828
@pytest.mark.parametrize(
@@ -151,6 +151,31 @@ def test_bump_major_increment(commit_msg, mocker):
151151
assert tag_exists is True
152152

153153

154+
@pytest.mark.usefixtures("tmp_commitizen_project")
155+
@pytest.mark.parametrize(
156+
"commit_msg",
157+
(
158+
"feat: new user interface\n\nBREAKING CHANGE: age is no longer supported",
159+
"feat!: new user interface\n\nBREAKING CHANGE: age is no longer supported",
160+
"feat!: new user interface",
161+
"feat(user): new user interface\n\nBREAKING CHANGE: age is no longer supported",
162+
"feat(user)!: new user interface\n\nBREAKING CHANGE: age is no longer supported",
163+
"feat(user)!: new user interface",
164+
"BREAKING CHANGE: age is no longer supported",
165+
"BREAKING-CHANGE: age is no longer supported",
166+
),
167+
)
168+
def test_bump_major_increment_major_version_zero(commit_msg, mocker):
169+
create_file_and_commit(commit_msg)
170+
171+
testargs = ["cz", "bump", "--yes", "--major-version-zero"]
172+
mocker.patch.object(sys, "argv", testargs)
173+
cli.main()
174+
175+
tag_exists = git.tag_exist("0.2.0")
176+
assert tag_exists is True
177+
178+
154179
@pytest.mark.usefixtures("tmp_commitizen_project")
155180
@pytest.mark.parametrize(
156181
"commit_msg,increment,expected_tag",
@@ -320,6 +345,34 @@ def test_bump_when_version_inconsistent_in_version_files(
320345
assert partial_expected_error_message in str(excinfo.value)
321346

322347

348+
def test_bump_major_version_zero_when_major_is_not_zero(mocker, tmp_commitizen_project):
349+
tmp_version_file = tmp_commitizen_project.join("__version__.py")
350+
tmp_version_file.write("1.0.0")
351+
tmp_commitizen_cfg_file = tmp_commitizen_project.join("pyproject.toml")
352+
tmp_commitizen_cfg_file.write(
353+
f"[tool.commitizen]\n"
354+
'version="1.0.0"\n'
355+
f'version_files = ["{str(tmp_version_file)}"]'
356+
)
357+
tmp_changelog_file = tmp_commitizen_project.join("CHANGELOG.md")
358+
tmp_changelog_file.write("## v1.0.0")
359+
360+
create_file_and_commit("feat(user): new file")
361+
create_tag("v1.0.0")
362+
create_file_and_commit("feat(user)!: new file")
363+
364+
testargs = ["cz", "bump", "--yes", "--major-version-zero"]
365+
mocker.patch.object(sys, "argv", testargs)
366+
367+
with pytest.raises(NotAllowed) as excinfo:
368+
cli.main()
369+
370+
expected_error_message = (
371+
"--major-version-zero is meaningless for current version 1.0.0"
372+
)
373+
assert expected_error_message in str(excinfo.value)
374+
375+
323376
def test_bump_files_only(mocker, tmp_commitizen_project):
324377
tmp_version_file = tmp_commitizen_project.join("__version__.py")
325378
tmp_version_file.write("0.1.0")
@@ -683,3 +736,20 @@ def test_bump_manual_version(mocker, manual_version):
683736
cli.main()
684737
tag_exists = git.tag_exist(manual_version)
685738
assert tag_exists is True
739+
740+
741+
@pytest.mark.usefixtures("tmp_commitizen_project")
742+
def test_bump_manual_version_disallows_major_version_zero(mocker):
743+
create_file_and_commit("feat: new file")
744+
745+
manual_version = "0.2.0"
746+
testargs = ["cz", "bump", "--yes", "--major-version-zero", manual_version]
747+
mocker.patch.object(sys, "argv", testargs)
748+
749+
with pytest.raises(NotAllowed) as excinfo:
750+
cli.main()
751+
752+
expected_error_message = (
753+
"--major-version-zero cannot be combined with MANUAL_VERSION"
754+
)
755+
assert expected_error_message in str(excinfo.value)

‎tests/test_conf.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"changelog_start_rev": None,
4949
"update_changelog_on_bump": False,
5050
"use_shortcuts": False,
51+
"major_version_zero": False,
5152
}
5253

5354
_new_settings = {
@@ -63,6 +64,7 @@
6364
"changelog_start_rev": None,
6465
"update_changelog_on_bump": False,
6566
"use_shortcuts": False,
67+
"major_version_zero": False,
6668
}
6769

6870
_read_settings = {

‎tests/utils.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ def create_file_and_commit(message: str, filename: Optional[str] = None):
2626
raise exceptions.CommitError(c.err)
2727

2828

29+
def create_tag(tag: str):
30+
c = git.tag(tag)
31+
if c.return_code != 0:
32+
raise exceptions.CommitError(c.err)
33+
34+
2935
def wait_for_tag():
3036
"""Wait for tag.
3137

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /