Skip to content

Commit cf490db

Browse files
authored
Merge branch 'master' into scm-tagging-workflow
2 parents 2690b83 + 05bdead commit cf490db

15 files changed

+317
-70
lines changed

.github/workflows/pythonpackage.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
shell: bash
3232
- name: Upload coverage to Codecov
3333
if: runner.os == 'Linux'
34-
uses: codecov/codecov-action@v3
34+
uses: codecov/codecov-action@v4
3535
with:
3636
token: ${{secrets.CODECOV_TOKEN}}
3737
file: ./coverage.xml

.pre-commit-config.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ repos:
4646
exclude: "poetry.lock"
4747

4848
- repo: https://github.com/commitizen-tools/commitizen
49-
rev: v3.13.0 # automatically updated by Commitizen
49+
rev: v3.14.0 # automatically updated by Commitizen
5050
hooks:
5151
- id: commitizen
5252
- id: commitizen-branch

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11

2+
## v3.14.0 (2024-02-01)
3+
4+
### Feat
5+
6+
- properly bump versions between prereleases (#799)
7+
28
## v3.13.0 (2023-12-03)
39

410
### Feat

commitizen/__version__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "3.13.0"
1+
__version__ = "3.14.0"

commitizen/commands/bump.py

+35-6
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@
2424
)
2525
from commitizen.changelog_formats import get_changelog_format
2626
from commitizen.providers import get_provider
27-
from commitizen.version_schemes import InvalidVersion, get_version_scheme
27+
from commitizen.version_schemes import (
28+
get_version_scheme,
29+
InvalidVersion,
30+
VersionProtocol,
31+
)
2832

2933
logger = getLogger("commitizen")
3034

@@ -226,11 +230,6 @@ def __call__(self): # noqa: C901
226230
"To avoid this error, manually specify the type of increment with `--increment`"
227231
)
228232

229-
# Increment is removed when current and next version
230-
# are expected to be prereleases.
231-
if prerelease and current_version.is_prerelease:
232-
increment = None
233-
234233
new_version = current_version.bump(
235234
increment,
236235
prerelease=prerelease,
@@ -398,3 +397,33 @@ def _get_commit_args(self):
398397
if self.no_verify:
399398
commit_args.append("--no-verify")
400399
return " ".join(commit_args)
400+
401+
def find_previous_final_version(
402+
self, current_version: VersionProtocol
403+
) -> VersionProtocol | None:
404+
tag_format: str = self.bump_settings["tag_format"]
405+
current = bump.normalize_tag(
406+
current_version,
407+
tag_format=tag_format,
408+
scheme=self.scheme,
409+
)
410+
411+
final_versions = []
412+
for tag in git.get_tag_names():
413+
assert tag
414+
try:
415+
version = self.scheme(tag)
416+
if not version.is_prerelease or tag == current:
417+
final_versions.append(version)
418+
except InvalidVersion:
419+
continue
420+
421+
if not final_versions:
422+
return None
423+
424+
final_versions = sorted(final_versions) # type: ignore [type-var]
425+
current_index = final_versions.index(current_version)
426+
previous_index = current_index - 1
427+
if previous_index < 0:
428+
return None
429+
return final_versions[previous_index]

commitizen/version_schemes.py

+44-16
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ def bump(
118118
prerelease_offset: int = 0,
119119
devrelease: int | None = None,
120120
is_local_version: bool = False,
121+
force_bump: bool = False,
121122
) -> Self:
122123
"""
123124
Based on the given increment, generate the next bumped version according to the version scheme
@@ -164,6 +165,12 @@ def generate_prerelease(
164165
if not prerelease:
165166
return ""
166167

168+
# prevent down-bumping the pre-release phase, e.g. from 'b1' to 'a2'
169+
# https://packaging.python.org/en/latest/specifications/version-specifiers/#pre-releases
170+
# https://semver.org/#spec-item-11
171+
if self.is_prerelease and self.pre:
172+
prerelease = max(prerelease, self.pre[0])
173+
167174
# version.pre is needed for mypy check
168175
if self.is_prerelease and self.pre and prerelease.startswith(self.pre[0]):
169176
prev_prerelease: int = self.pre[1]
@@ -189,20 +196,15 @@ def increment_base(self, increment: str | None = None) -> str:
189196
increments = [MAJOR, MINOR, PATCH]
190197
base = dict(zip_longest(increments, prev_release, fillvalue=0))
191198

192-
# This flag means that current version
193-
# must remove its prerelease tag,
194-
# so it doesn't matter the increment.
195-
# Example: 1.0.0a0 with PATCH/MINOR -> 1.0.0
196-
if not self.is_prerelease:
197-
if increment == MAJOR:
198-
base[MAJOR] += 1
199-
base[MINOR] = 0
200-
base[PATCH] = 0
201-
elif increment == MINOR:
202-
base[MINOR] += 1
203-
base[PATCH] = 0
204-
elif increment == PATCH:
205-
base[PATCH] += 1
199+
if increment == MAJOR:
200+
base[MAJOR] += 1
201+
base[MINOR] = 0
202+
base[PATCH] = 0
203+
elif increment == MINOR:
204+
base[MINOR] += 1
205+
base[PATCH] = 0
206+
elif increment == PATCH:
207+
base[PATCH] += 1
206208

207209
return f"{base[MAJOR]}.{base[MINOR]}.{base[PATCH]}"
208210

@@ -213,6 +215,7 @@ def bump(
213215
prerelease_offset: int = 0,
214216
devrelease: int | None = None,
215217
is_local_version: bool = False,
218+
force_bump: bool = False,
216219
) -> Self:
217220
"""Based on the given increment a proper semver will be generated.
218221
@@ -230,9 +233,34 @@ def bump(
230233
local_version = self.scheme(self.local).bump(increment)
231234
return self.scheme(f"{self.public}+{local_version}") # type: ignore
232235
else:
233-
base = self.increment_base(increment)
236+
if not self.is_prerelease:
237+
base = self.increment_base(increment)
238+
elif force_bump:
239+
base = self.increment_base(increment)
240+
else:
241+
base = f"{self.major}.{self.minor}.{self.micro}"
242+
if increment == PATCH:
243+
pass
244+
elif increment == MINOR:
245+
if self.micro != 0:
246+
base = self.increment_base(increment)
247+
elif increment == MAJOR:
248+
if self.minor != 0 or self.micro != 0:
249+
base = self.increment_base(increment)
234250
dev_version = self.generate_devrelease(devrelease)
235-
pre_version = self.generate_prerelease(prerelease, offset=prerelease_offset)
251+
release = list(self.release)
252+
if len(release) < 3:
253+
release += [0] * (3 - len(release))
254+
current_base = ".".join(str(part) for part in release)
255+
if base == current_base:
256+
pre_version = self.generate_prerelease(
257+
prerelease, offset=prerelease_offset
258+
)
259+
else:
260+
base_version = cast(BaseVersion, self.scheme(base))
261+
pre_version = base_version.generate_prerelease(
262+
prerelease, offset=prerelease_offset
263+
)
236264
# TODO: post version
237265
return self.scheme(f"{base}{pre_version}{dev_version}") # type: ignore
238266

docs/bump.md

+28
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,34 @@ Generate a **changelog** along with the new version and tag when bumping.
113113
cz bump --changelog
114114
```
115115
116+
### `--prerelease`
117+
118+
The bump is a pre-release bump, meaning that in addition to a possible version bump the new version receives a
119+
pre-release segment compatible with the bump’s version scheme, where the segment consist of a _phase_ and a
120+
non-negative number. Supported options for `--prerelease` are the following phase names `alpha`, `beta`, or
121+
`rc` (release candidate). For more details, refer to the
122+
[Python Packaging User Guide](https://packaging.python.org/en/latest/specifications/version-specifiers/#pre-releases).
123+
124+
Note that as per [semantic versioning spec](https://semver.org/#spec-item-9)
125+
126+
> Pre-release versions have a lower precedence than the associated normal version. A pre-release version
127+
> indicates that the version is unstable and might not satisfy the intended compatibility requirements
128+
> as denoted by its associated normal version.
129+
130+
For example, the following versions (using the [PEP 440](https://peps.python.org/pep-0440/) scheme) are ordered
131+
by their precedence and showcase how a release might flow through a development cycle:
132+
133+
- `1.0.0` is the current published version
134+
- `1.0.1a0` after committing a `fix:` for pre-release
135+
- `1.1.0a1` after committing an additional `feat:` for pre-release
136+
- `1.1.0b0` after bumping a beta release
137+
- `1.1.0rc0` after bumping the release candidate
138+
- `1.1.0` next feature release
139+
140+
Also note that bumping pre-releases _maintains linearity_: bumping of a pre-release with lower precedence than
141+
the current pre-release phase maintains the current phase of higher precedence. For example, if the current
142+
version is `1.0.0b1` then bumping with `--prerelease alpha` will continue to bump the “beta” phase.
143+
116144
### `--check-consistency`
117145
118146
Check whether the versions defined in `version_files` and the version in commitizen

poetry.lock

+27-27
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[tool.commitizen]
2-
version = "3.13.0"
2+
version = "3.14.0"
33
tag_format = "v$version"
44
version_files = [
55
"pyproject.toml:version",
@@ -9,7 +9,7 @@ version_files = [
99

1010
[tool.poetry]
1111
name = "commitizen"
12-
version = "3.13.0"
12+
version = "3.14.0"
1313
description = "Python commitizen client tool"
1414
authors = ["Santiago Fraire <santiwilly@gmail.com>"]
1515
license = "MIT"
@@ -29,6 +29,7 @@ classifiers = [
2929
"Programming Language :: Python :: 3.9",
3030
"Programming Language :: Python :: 3.10",
3131
"Programming Language :: Python :: 3.11",
32+
"Programming Language :: Python :: 3.12",
3233
"Programming Language :: Python :: Implementation :: CPython",
3334
]
3435

@@ -52,7 +53,7 @@ importlib_metadata = { version = ">=4.13,<8"}
5253
# dev tool
5354
ipython = "^8.0"
5455
# test
55-
pytest = "^7.2.0"
56+
pytest = ">=7.2,<9.0"
5657
pytest-cov = "^4.0"
5758
pytest-mock = "^3.10"
5859
pytest-regressions = "^2.4.0"

0 commit comments

Comments
 (0)