Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions commitizen/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,12 @@ def __call__(
"help": "specify non-negative integer for dev. release",
"type": int,
},
{
"name": ["--postrelease"],
"action": "store_true",
"default": False,
"help": "mark as a post release",
},
{
"name": ["--increment"],
"help": "manually specify the desired increment",
Expand Down
6 changes: 6 additions & 0 deletions commitizen/commands/bump.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class BumpArgs(Settings, total=False):
changelog: bool
check_consistency: bool
devrelease: int | None
postrelease: bool
dry_run: bool
file_name: str
files_only: bool | None
Expand Down Expand Up @@ -166,6 +167,7 @@ def _validate_arguments(self, current_version: VersionProtocol) -> None:
(self.arguments["increment"], "--increment"),
(self.arguments["prerelease"], "--prerelease"),
(self.arguments["devrelease"] is not None, "--devrelease"),
(self.arguments["postrelease"], "--postrelease"),
(self.arguments["local_version"], "--local-version"),
(self.arguments["build_metadata"], "--build-metadata"),
(self.arguments["major_version_zero"], "--major-version-zero"),
Expand Down Expand Up @@ -227,11 +229,15 @@ def _resolve_increment_and_new_version(
if increment is None and self.arguments["allow_no_commit"]:
increment = "PATCH"

if self.arguments["postrelease"]:
increment = None

return increment, current_version.bump(
increment,
prerelease=self.arguments["prerelease"],
prerelease_offset=self.bump_settings["prerelease_offset"],
devrelease=self.arguments["devrelease"],
postrelease=self.arguments["postrelease"],
is_local_version=self.arguments["local_version"],
build_metadata=self.arguments["build_metadata"],
exact_increment=self.arguments["increment_mode"] == "exact",
Expand Down
1 change: 1 addition & 0 deletions commitizen/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ def get_tag_regexes(
"patch": r"(?P<patch>\d+)",
"prerelease": r"(?P<prerelease>\w+\d+)?",
"devrelease": r"(?P<devrelease>\.dev\d+)?",
"postrelease": r"(?P<postrelease>\.post\d+)?",
}
return {
**{f"${k}": v for k, v in regexes.items()},
Expand Down
37 changes: 35 additions & 2 deletions commitizen/version_schemes.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,16 @@ def prerelease(self) -> str | None:
"""The prerelease potion of the version is this is a prerelease."""
raise NotImplementedError("must be implemented")

@property
def is_postrelease(self) -> bool:
"""Whether this version is a post-release."""
raise NotImplementedError("must be implemented")

@property
def postrelease(self) -> str | None:
"""The postrelease potion of the version is this is a postrelease."""
raise NotImplementedError("must be implemented")

@property
def public(self) -> str:
"""The public portion of the version."""
Expand Down Expand Up @@ -124,6 +134,7 @@ def bump(
prerelease: Prerelease | None = None,
prerelease_offset: int = 0,
devrelease: int | None = None,
postrelease: bool = False,
is_local_version: bool = False,
build_metadata: str | None = None,
exact_increment: bool = False,
Expand Down Expand Up @@ -164,6 +175,13 @@ def prerelease(self) -> str | None:
return f"{self.pre[0]}{self.pre[1]}"
return None

@property
def postrelease(self) -> str | None:
# version.post is needed for mypy check
if self.is_postrelease and self.post is not None:
return f"post{self.post}"
return None

def generate_prerelease(
self, prerelease: str | None = None, offset: int = 0
) -> str:
Expand Down Expand Up @@ -206,6 +224,19 @@ def generate_devrelease(self, devrelease: int | None) -> str:

return f"dev{devrelease}"

def generate_postrelease(self, postrelease: bool = False) -> str:
"""Generate postrelease"""
if not postrelease:
return ""

# version.post is needed for mypy check
if self.is_postrelease and self.post is not None:
new_postrelease_number = self.post + 1
else:
new_postrelease_number = 0

return f"post{new_postrelease_number}"

def generate_build_metadata(self, build_metadata: str | None) -> str:
"""Generate build-metadata

Expand Down Expand Up @@ -240,6 +271,7 @@ def bump(
prerelease: Prerelease | None = None,
prerelease_offset: int = 0,
devrelease: int | None = None,
postrelease: bool = False,
is_local_version: bool = False,
build_metadata: str | None = None,
exact_increment: bool = False,
Expand Down Expand Up @@ -272,9 +304,10 @@ def bump(
self if base == current_base else cast("BaseVersion", self.scheme(base))
).generate_prerelease(prerelease, offset=prerelease_offset)

# TODO: post version
post_version = self.generate_postrelease(postrelease)

return self.scheme(
f"{base}{pre_version}{dev_version}{self.generate_build_metadata(build_metadata)}"
f"{base}{pre_version}{post_version}{dev_version}{self.generate_build_metadata(build_metadata)}"
) # type: ignore[return-value]

def _get_increment_base(
Expand Down
65 changes: 64 additions & 1 deletion docs/commands/bump.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,29 @@ Commitizen supports the [PEP 440][pep440] version format, which includes several
1.0.0b2.dev1 # Development release 1 of beta 2
```

> **Note**: `post` releases (e.g., `1.0.0.post1`) are not currently supported.
#### Post-releases
```text
1.0.0.post0 # Post-release 0
1.0.0.post1 # Post-release 1
```

#### Combined Pre-release and Post-release
```text
1.0.0a1.post0 # Alpha release 1 with a post-release
1.0.0rc1.post1 # Release candidate 1 with a post-release
```

#### Combined Post-release and Development
```text
1.0.0.post0.dev0 # Post-release 0 with development release 0
1.0.0.post1.dev1 # Post-release 1 with development release 1
```

#### Combined Post-release, Pre-release and Development
```text
1.0.0a1.post0.dev0 # Alpha release 1 Post-release 0 with development release 0
1.0.0rc1.post1.dev1 # Release candidate 1 Post-release 1 with development release 1
```

## Command line options

Expand Down Expand Up @@ -149,6 +171,47 @@ by their precedence and showcase how a release might flow through a development
- `1.1.0rc0` after bumping the release candidate
- `1.1.0` next feature release

### `--devrelease`

The bump is a development-release bump. A development release appends a `.devN` segment to the
current version where `N` is a non-negative integer. Use `--devrelease <N>` to explicitly set the
development release number. When combined with prereleases or post-releases the `.devN` segment is
placed after those segments (for example `1.0.0a1.dev0` or `1.0.0.post0.dev0`).

Examples:

```bash
# create a development release
cz bump --devrelease 0 --yes # 1.0.0 -> 1.0.0.dev0

# increment a development release (with new commits)
cz bump --devrelease 1 --yes # 1.0.0 -> 1.0.0.dev1

# combined with a prerelease
cz bump --prerelease alpha --devrelease 0 --yes # 1.1.0 -> 1.1.0a0.dev0
```

### `--postrelease`

A post-release preserves the current base version and appends a `.postN` segment. Use the
`--postrelease` boolean flag to create or increment a post-release. Post-releases start at
`.post0` and increment the post number on subsequent `--postrelease` bumps (new commits required
for subsequent increments). To promote a post-release to the next final version, run a normal bump
without `--postrelease`.

Examples:

```bash
# create post-release
cz bump --postrelease --yes # 0.1.0 -> 0.1.0.post0

# increment post-release (requires new commits)
cz bump --postrelease --yes # 0.1.0.post0 -> 0.1.0.post1

# finalize to next release (normal bump)
cz bump --yes # 0.1.0.post1 -> 0.1.1
```

### `--increment-mode`

#### `--increment-mode=linear` (default)
Expand Down
Loading