Skip to content

Commit 5702bfe

Browse files
committed
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 52057ac commit 5702bfe

File tree

9 files changed

+142
-77
lines changed

9 files changed

+142
-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: Optional[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
},
@@ -103,6 +104,7 @@ def __call__(self): # noqa: C901
103104
bump_commit_message: str = self.bump_settings["bump_message"]
104105
version_files: List[str] = self.bump_settings["version_files"]
105106
major_version_zero: bool = self.bump_settings["major_version_zero"]
107+
prerelease_offset: int = self.bump_settings["prerelease_offset"]
106108

107109
dry_run: bool = self.arguments["dry_run"]
108110
is_yes: bool = self.arguments["yes"]
@@ -133,6 +135,11 @@ def __call__(self): # noqa: C901
133135
"--major-version-zero cannot be combined with MANUAL_VERSION"
134136
)
135137

138+
if prerelease_offset:
139+
raise NotAllowed(
140+
"--prerelease-offset cannot be combined with MANUAL_VERSION"
141+
)
142+
136143
if major_version_zero:
137144
if not current_version.startswith("0."):
138145
raise NotAllowed(
@@ -196,6 +203,7 @@ def __call__(self): # noqa: C901
196203
current_version,
197204
increment,
198205
prerelease=prerelease,
206+
prerelease_offset=prerelease_offset,
199207
devrelease=devrelease,
200208
is_local_version=is_local_version,
201209
)

commitizen/defaults.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class Settings(TypedDict, total=False):
4040
style: Optional[List[Tuple[str, str]]]
4141
customize: CzSettings
4242
major_version_zero: bool
43+
prerelease_offset: int
4344

4445

4546
name: str = "cz_conventional_commits"
@@ -65,6 +66,7 @@ class Settings(TypedDict, total=False):
6566
"update_changelog_on_bump": False,
6667
"use_shortcuts": False,
6768
"major_version_zero": False,
69+
"prerelease_offset": 0,
6870
}
6971

7072
MAJOR = "MAJOR"

docs/bump.md

Lines changed: 13 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 |
@@ -411,6 +412,17 @@ Defaults to: `false`
411412
major_version_zero = true
412413
```
413414
415+
### `prerelease_offset`
416+
417+
Offset with which to start counting prereleses.
418+
419+
Defaults to: `0`
420+
421+
```toml
422+
[tool.commitizen]
423+
prerelease_offset = 1
424+
```
425+
414426
## Custom bump
415427
416428
Read the [customizing section](./customization.md).

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: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,3 +759,19 @@ def test_bump_manual_version_disallows_major_version_zero(mocker):
759759
"--major-version-zero cannot be combined with MANUAL_VERSION"
760760
)
761761
assert expected_error_message in str(excinfo.value)
762+
763+
@pytest.mark.usefixtures("tmp_commitizen_project")
764+
def test_bump_manual_version_disallows_prerelease_offset(mocker):
765+
create_file_and_commit("feat: new file")
766+
767+
manual_version = "0.2.0"
768+
testargs = ["cz", "bump", "--yes", "--prerelease-offset", "42", manual_version]
769+
mocker.patch.object(sys, "argv", testargs)
770+
771+
with pytest.raises(NotAllowed) as excinfo:
772+
cli.main()
773+
774+
expected_error_message = (
775+
"--prerelease-offset cannot be combined with MANUAL_VERSION"
776+
)
777+
assert expected_error_message in str(excinfo.value)

0 commit comments

Comments
 (0)