Skip to content

Commit 583c7dd

Browse files
ckagererLee-W
authored andcommitted
feat(bump): support prereleases with start offset
In special cases, it may be necessary for prereleases not to start with a 0, because the individual characters are encoded in bytes. Here, a 0 in the byte is interpreted as a release version, consistent with the location of bugfixes. Therefore, this commit introduces a generic option to change the start of the prerelease to accommodate such circumstances. EXAMPLES Before: 0.3.0 -> PATCH beta-> 0.3.1b0 Now (with offset 0 == default) 0.3.0 -> PATCH beta-> 0.3.1b0 Now (with offset 1) 0.3.0 -> PATCH beta-> 0.3.1b1
1 parent 32c4f3e commit 583c7dd

File tree

9 files changed

+141
-77
lines changed

9 files changed

+141
-77
lines changed

commitizen/bump.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ def find_increment(
4545
return increment
4646

4747

48-
def prerelease_generator(current_version: str, prerelease: Optional[str] = None) -> str:
48+
def prerelease_generator(
49+
current_version: str, prerelease: Optional[str] = None, offset: int = 0
50+
) -> str:
4951
"""Generate prerelease
5052
5153
X.YaN # Alpha release
@@ -65,7 +67,7 @@ def prerelease_generator(current_version: str, prerelease: Optional[str] = None)
6567
prev_prerelease: int = version.pre[1]
6668
new_prerelease_number = prev_prerelease + 1
6769
else:
68-
new_prerelease_number = 0
70+
new_prerelease_number = offset
6971
pre_version = f"{prerelease}{new_prerelease_number}"
7072
return pre_version
7173

@@ -115,6 +117,7 @@ def generate_version(
115117
current_version: str,
116118
increment: str,
117119
prerelease: Optional[str] = None,
120+
prerelease_offset: int = 0,
118121
devrelease: Optional[int] = None,
119122
is_local_version: bool = False,
120123
) -> Version:
@@ -132,13 +135,17 @@ def generate_version(
132135
if is_local_version:
133136
version = Version(current_version)
134137
dev_version = devrelease_generator(devrelease=devrelease)
135-
pre_version = prerelease_generator(str(version.local), prerelease=prerelease)
138+
pre_version = prerelease_generator(
139+
str(version.local), prerelease=prerelease, offset=prerelease_offset
140+
)
136141
semver = semver_generator(str(version.local), increment=increment)
137142

138143
return Version(f"{version.public}+{semver}{pre_version}{dev_version}")
139144
else:
140145
dev_version = devrelease_generator(devrelease=devrelease)
141-
pre_version = prerelease_generator(current_version, prerelease=prerelease)
146+
pre_version = prerelease_generator(
147+
current_version, prerelease=prerelease, offset=prerelease_offset
148+
)
142149
semver = semver_generator(current_version, increment=increment)
143150

144151
# TODO: post version

commitizen/cli.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,12 @@
189189
"default": None,
190190
"help": "keep major version at zero, even for breaking changes",
191191
},
192+
{
193+
"name": ["--prerelease-offset"],
194+
"type": int,
195+
"default": None,
196+
"help": "start pre-releases with this offset",
197+
},
192198
{
193199
"name": "manual_version",
194200
"type": str,

commitizen/commands/bump.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ def __init__(self, config: BaseConfig, arguments: dict):
4646
"gpg_sign",
4747
"annotated_tag",
4848
"major_version_zero",
49+
"prerelease_offset",
4950
]
5051
if arguments[key] is not None
5152
},
@@ -105,6 +106,7 @@ def __call__(self): # noqa: C901
105106
bump_commit_message: str = self.bump_settings["bump_message"]
106107
version_files: List[str] = self.bump_settings["version_files"]
107108
major_version_zero: bool = self.bump_settings["major_version_zero"]
109+
prerelease_offset: int = self.bump_settings["prerelease_offset"]
108110

109111
dry_run: bool = self.arguments["dry_run"]
110112
is_yes: bool = self.arguments["yes"]
@@ -135,6 +137,11 @@ def __call__(self): # noqa: C901
135137
"--major-version-zero cannot be combined with MANUAL_VERSION"
136138
)
137139

140+
if prerelease_offset:
141+
raise NotAllowed(
142+
"--prerelease-offset cannot be combined with MANUAL_VERSION"
143+
)
144+
138145
if major_version_zero:
139146
if not current_version.startswith("0."):
140147
raise NotAllowed(
@@ -198,6 +205,7 @@ def __call__(self): # noqa: C901
198205
current_version,
199206
increment,
200207
prerelease=prerelease,
208+
prerelease_offset=prerelease_offset,
201209
devrelease=devrelease,
202210
is_local_version=is_local_version,
203211
)

commitizen/defaults.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class Settings(TypedDict, total=False):
4242
major_version_zero: bool
4343
pre_bump_hooks: Optional[List[str]]
4444
post_bump_hooks: Optional[List[str]]
45+
prerelease_offset: int
4546

4647

4748
name: str = "cz_conventional_commits"
@@ -69,6 +70,7 @@ class Settings(TypedDict, total=False):
6970
"major_version_zero": False,
7071
"pre_bump_hooks": [],
7172
"post_bump_hooks": [],
73+
"prerelease_offset": 0,
7274
}
7375

7476
MAJOR = "MAJOR"

docs/bump.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ options:
9595
Output changelog to the stdout
9696
--retry retry commit if it fails the 1st time
9797
--major-version-zero keep major version at zero, even for breaking changes
98+
--prerelease-offset start pre-releases with this offset
9899
```
99100
100101
### `--files-only`
@@ -304,7 +305,7 @@ The variables must be preceded by a `$` sign.
304305
Supported variables:
305306
306307
| Variable | Description |
307-
| ------------- | --------------------------------------------|
308+
| ------------- | ------------------------------------------- |
308309
| `$version` | full generated version |
309310
| `$major` | MAJOR increment |
310311
| `$minor` | MINOR increment |
@@ -464,6 +465,15 @@ release. During execution of the script, some environment variables are availabl
464465
post_bump_hooks = [
465466
"scripts/slack_notification.sh"
466467
]
468+
### `prerelease_offset`
469+
470+
Offset with which to start counting prereleses.
471+
472+
Defaults to: `0`
473+
474+
```toml
475+
[tool.commitizen]
476+
prerelease_offset = 1
467477
```
468478
469479
## Custom bump

docs/config.md

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,25 @@
22

33
## Settings
44

5-
| Variable | Type | Default | Description |
6-
| -------------------------- | ------ | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
7-
| `name` | `str` | `"cz_conventional_commits"` | Name of the committing rules to use |
8-
| `version` | `str` | `None` | Current version. Example: "0.1.2" |
9-
| `version_files` | `list` | `[ ]` | Files were the version will be updated. A pattern to match a line, can also be specified, separated by `:` [See more][version_files] |
10-
| `tag_format` | `str` | `None` | Format for the git tag, useful for old projects, that use a convention like `"v1.2.1"`. [See more][tag_format] |
11-
| `update_changelog_on_bump` | `bool` | `false` | Create changelog when running `cz bump` |
12-
| `gpg_sign` | `bool` | `false` | Use gpg signed tags instead of lightweight tags. |
13-
| `annotated_tag` | `bool` | `false` | Use annotated tags instead of lightweight tags. [See difference][annotated-tags-vs-lightweight] |
14-
| `bump_message` | `str` | `None` | Create custom commit message, useful to skip ci. [See more][bump_message] |
15-
| `allow_abort` | `bool` | `false` | Disallow empty commit messages, useful in ci. [See more][allow_abort] |
16-
| `changelog_file` | `str` | `CHANGELOG.md` | filename of exported changelog |
17-
| `changelog_incremental` | `bool` | `false` | Update changelog with the missing versions. This is good if you don't want to replace previous versions in the file. Note: when doing `cz bump --changelog` this is automatically set to `true` |
18-
| `changelog_start_rev` | `str` | `None` | Start from a given git rev to generate the changelog |
19-
| `style` | `list` | see above | Style for the prompts (It will merge this value with default style.) [See More (Styling your prompts with your favorite colors)][additional-features] |
20-
| `customize` | `dict` | `None` | **This is only supported when config through `toml`.** Custom rules for committing and bumping. [See more][customization] |
21-
| `use_shortcuts` | `bool` | `false` | If enabled, commitizen will show keyboard shortcuts when selecting from a list. Define a `key` for each of your choices to set the key. [See more][shortcuts] |
22-
| `major_version_zero` | `bool` | `false` | When true, breaking changes on a `0.x` will remain as a `0.x` version. On `false`, a breaking change will bump a `0.x` version to `1.0`. [major-version-zero] |
5+
| Variable | Type | Default | Description |
6+
| -------------------------- | ------ | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
7+
| `name` | `str` | `"cz_conventional_commits"` | Name of the committing rules to use |
8+
| `version` | `str` | `None` | Current version. Example: "0.1.2" |
9+
| `version_files` | `list` | `[ ]` | Files were the version will be updated. A pattern to match a line, can also be specified, separated by `:` [See more][version_files] |
10+
| `tag_format` | `str` | `None` | Format for the git tag, useful for old projects, that use a convention like `"v1.2.1"`. [See more][tag_format] |
11+
| `update_changelog_on_bump` | `bool` | `false` | Create changelog when running `cz bump` |
12+
| `gpg_sign` | `bool` | `false` | Use gpg signed tags instead of lightweight tags. |
13+
| `annotated_tag` | `bool` | `false` | Use annotated tags instead of lightweight tags. [See difference][annotated-tags-vs-lightweight] |
14+
| `bump_message` | `str` | `None` | Create custom commit message, useful to skip ci. [See more][bump_message] |
15+
| `allow_abort` | `bool` | `false` | Disallow empty commit messages, useful in ci. [See more][allow_abort] |
16+
| `changelog_file` | `str` | `CHANGELOG.md` | filename of exported changelog |
17+
| `changelog_incremental` | `bool` | `false` | Update changelog with the missing versions. This is good if you don't want to replace previous versions in the file. Note: when doing `cz bump --changelog` this is automatically set to `true` |
18+
| `changelog_start_rev` | `str` | `None` | Start from a given git rev to generate the changelog |
19+
| `style` | `list` | see above | Style for the prompts (It will merge this value with default style.) [See More (Styling your prompts with your favorite colors)][additional-features] |
20+
| `customize` | `dict` | `None` | **This is only supported when config through `toml`.** Custom rules for committing and bumping. [See more][customization] |
21+
| `use_shortcuts` | `bool` | `false` | If enabled, commitizen will show keyboard shortcuts when selecting from a list. Define a `key` for each of your choices to set the key. [See more][shortcuts] |
22+
| `major_version_zero` | `bool` | `false` | When true, breaking changes on a `0.x` will remain as a `0.x` version. On `false`, a breaking change will bump a `0.x` version to `1.0`. [major-version-zero] |
23+
| `prerelease_offset` | `int` | `0` | In special cases it may be necessary that a prerelease cannot start with a 0, e.g. in an embedded project the individual characters are encoded in bytes. This can be done by specifying an offset from which to start counting. [prerelease-offset] |
2324

2425
## pyproject.toml or .cz.toml
2526

@@ -115,6 +116,7 @@ commitizen:
115116
[tag_format]: bump.md#tag_format
116117
[bump_message]: bump.md#bump_message
117118
[major-version-zero]: bump.md#-major-version-zero
119+
[prerelease-offset]: bump.md#-prerelease_offset
118120
[allow_abort]: check.md#allow-abort
119121
[additional-features]: https://github.com/tmbo/questionary#additional-features
120122
[customization]: customization.md

tests/commands/test_bump_command.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,3 +814,20 @@ def test_bump_with_pre_bump_hooks(
814814
),
815815
]
816816
)
817+
818+
819+
@pytest.mark.usefixtures("tmp_commitizen_project")
820+
def test_bump_manual_version_disallows_prerelease_offset(mocker):
821+
create_file_and_commit("feat: new file")
822+
823+
manual_version = "0.2.0"
824+
testargs = ["cz", "bump", "--yes", "--prerelease-offset", "42", manual_version]
825+
mocker.patch.object(sys, "argv", testargs)
826+
827+
with pytest.raises(NotAllowed) as excinfo:
828+
cli.main()
829+
830+
expected_error_message = (
831+
"--prerelease-offset cannot be combined with MANUAL_VERSION"
832+
)
833+
assert expected_error_message in str(excinfo.value)

0 commit comments

Comments
 (0)