Skip to content

feat(bump): support prereleases with a start offset #614

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 11, 2023
Merged
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
15 changes: 11 additions & 4 deletions commitizen/bump.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ def find_increment(
return increment


def prerelease_generator(current_version: str, prerelease: Optional[str] = None) -> str:
def prerelease_generator(
current_version: str, prerelease: Optional[str] = None, offset: int = 0
) -> str:
"""Generate prerelease

X.YaN # Alpha release
Expand All @@ -65,7 +67,7 @@ def prerelease_generator(current_version: str, prerelease: Optional[str] = None)
prev_prerelease: int = version.pre[1]
new_prerelease_number = prev_prerelease + 1
else:
new_prerelease_number = 0
new_prerelease_number = offset
pre_version = f"{prerelease}{new_prerelease_number}"
return pre_version

Expand Down Expand Up @@ -115,6 +117,7 @@ def generate_version(
current_version: str,
increment: str,
prerelease: Optional[str] = None,
prerelease_offset: int = 0,
devrelease: Optional[int] = None,
is_local_version: bool = False,
) -> Version:
Expand All @@ -132,13 +135,17 @@ def generate_version(
if is_local_version:
version = Version(current_version)
dev_version = devrelease_generator(devrelease=devrelease)
pre_version = prerelease_generator(str(version.local), prerelease=prerelease)
pre_version = prerelease_generator(
str(version.local), prerelease=prerelease, offset=prerelease_offset
)
semver = semver_generator(str(version.local), increment=increment)

return Version(f"{version.public}+{semver}{pre_version}{dev_version}")
else:
dev_version = devrelease_generator(devrelease=devrelease)
pre_version = prerelease_generator(current_version, prerelease=prerelease)
pre_version = prerelease_generator(
current_version, prerelease=prerelease, offset=prerelease_offset
)
semver = semver_generator(current_version, increment=increment)

# TODO: post version
Expand Down
6 changes: 6 additions & 0 deletions commitizen/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,12 @@
"default": None,
"help": "keep major version at zero, even for breaking changes",
},
{
"name": ["--prerelease-offset"],
"type": int,
"default": None,
"help": "start pre-releases with this offset",
},
{
"name": "manual_version",
"type": str,
Expand Down
8 changes: 8 additions & 0 deletions commitizen/commands/bump.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def __init__(self, config: BaseConfig, arguments: dict):
"gpg_sign",
"annotated_tag",
"major_version_zero",
"prerelease_offset",
]
if arguments[key] is not None
},
Expand Down Expand Up @@ -105,6 +106,7 @@ def __call__(self): # noqa: C901
bump_commit_message: str = self.bump_settings["bump_message"]
version_files: List[str] = self.bump_settings["version_files"]
major_version_zero: bool = self.bump_settings["major_version_zero"]
prerelease_offset: int = self.bump_settings["prerelease_offset"]

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

if prerelease_offset:
raise NotAllowed(
"--prerelease-offset cannot be combined with MANUAL_VERSION"
)

if major_version_zero:
if not current_version.startswith("0."):
raise NotAllowed(
Expand Down Expand Up @@ -198,6 +205,7 @@ def __call__(self): # noqa: C901
current_version,
increment,
prerelease=prerelease,
prerelease_offset=prerelease_offset,
devrelease=devrelease,
is_local_version=is_local_version,
)
Expand Down
2 changes: 2 additions & 0 deletions commitizen/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class Settings(TypedDict, total=False):
major_version_zero: bool
pre_bump_hooks: Optional[List[str]]
post_bump_hooks: Optional[List[str]]
prerelease_offset: int


name: str = "cz_conventional_commits"
Expand Down Expand Up @@ -69,6 +70,7 @@ class Settings(TypedDict, total=False):
"major_version_zero": False,
"pre_bump_hooks": [],
"post_bump_hooks": [],
"prerelease_offset": 0,
}

MAJOR = "MAJOR"
Expand Down
12 changes: 11 additions & 1 deletion docs/bump.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ options:
Output changelog to the stdout
--retry retry commit if it fails the 1st time
--major-version-zero keep major version at zero, even for breaking changes
--prerelease-offset start pre-releases with this offset
```

### `--files-only`
Expand Down Expand Up @@ -304,7 +305,7 @@ The variables must be preceded by a `$` sign.
Supported variables:

| Variable | Description |
| ------------- | --------------------------------------------|
| ------------- | ------------------------------------------- |
| `$version` | full generated version |
| `$major` | MAJOR increment |
| `$minor` | MINOR increment |
Expand Down Expand Up @@ -464,6 +465,15 @@ release. During execution of the script, some environment variables are availabl
post_bump_hooks = [
"scripts/slack_notification.sh"
]
### `prerelease_offset`

Offset with which to start counting prereleses.

Defaults to: `0`

```toml
[tool.commitizen]
prerelease_offset = 1
```

## Custom bump
Expand Down
38 changes: 20 additions & 18 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,25 @@

## Settings

| Variable | Type | Default | Description |
| -------------------------- | ------ | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | `str` | `"cz_conventional_commits"` | Name of the committing rules to use |
| `version` | `str` | `None` | Current version. Example: "0.1.2" |
| `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] |
| `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] |
| `update_changelog_on_bump` | `bool` | `false` | Create changelog when running `cz bump` |
| `gpg_sign` | `bool` | `false` | Use gpg signed tags instead of lightweight tags. |
| `annotated_tag` | `bool` | `false` | Use annotated tags instead of lightweight tags. [See difference][annotated-tags-vs-lightweight] |
| `bump_message` | `str` | `None` | Create custom commit message, useful to skip ci. [See more][bump_message] |
| `allow_abort` | `bool` | `false` | Disallow empty commit messages, useful in ci. [See more][allow_abort] |
| `changelog_file` | `str` | `CHANGELOG.md` | filename of exported changelog |
| `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` |
| `changelog_start_rev` | `str` | `None` | Start from a given git rev to generate the changelog |
| `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] |
| `customize` | `dict` | `None` | **This is only supported when config through `toml`.** Custom rules for committing and bumping. [See more][customization] |
| `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] |
| `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] |
| Variable | Type | Default | Description |
| -------------------------- | ------ | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | `str` | `"cz_conventional_commits"` | Name of the committing rules to use |
| `version` | `str` | `None` | Current version. Example: "0.1.2" |
| `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] |
| `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] |
| `update_changelog_on_bump` | `bool` | `false` | Create changelog when running `cz bump` |
| `gpg_sign` | `bool` | `false` | Use gpg signed tags instead of lightweight tags. |
| `annotated_tag` | `bool` | `false` | Use annotated tags instead of lightweight tags. [See difference][annotated-tags-vs-lightweight] |
| `bump_message` | `str` | `None` | Create custom commit message, useful to skip ci. [See more][bump_message] |
| `allow_abort` | `bool` | `false` | Disallow empty commit messages, useful in ci. [See more][allow_abort] |
| `changelog_file` | `str` | `CHANGELOG.md` | filename of exported changelog |
| `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` |
| `changelog_start_rev` | `str` | `None` | Start from a given git rev to generate the changelog |
| `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] |
| `customize` | `dict` | `None` | **This is only supported when config through `toml`.** Custom rules for committing and bumping. [See more][customization] |
| `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] |
| `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] |
| `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] |

## pyproject.toml or .cz.toml

Expand Down Expand Up @@ -115,6 +116,7 @@ commitizen:
[tag_format]: bump.md#tag_format
[bump_message]: bump.md#bump_message
[major-version-zero]: bump.md#-major-version-zero
[prerelease-offset]: bump.md#-prerelease_offset
[allow_abort]: check.md#allow-abort
[additional-features]: https://github.com/tmbo/questionary#additional-features
[customization]: customization.md
Expand Down
17 changes: 17 additions & 0 deletions tests/commands/test_bump_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -814,3 +814,20 @@ def test_bump_with_pre_bump_hooks(
),
]
)


@pytest.mark.usefixtures("tmp_commitizen_project")
def test_bump_manual_version_disallows_prerelease_offset(mocker):
create_file_and_commit("feat: new file")

manual_version = "0.2.0"
testargs = ["cz", "bump", "--yes", "--prerelease-offset", "42", manual_version]
mocker.patch.object(sys, "argv", testargs)

with pytest.raises(NotAllowed) as excinfo:
cli.main()

expected_error_message = (
"--prerelease-offset cannot be combined with MANUAL_VERSION"
)
assert expected_error_message in str(excinfo.value)
Loading