diff --git a/.github/workflows/label_issues.yml b/.github/workflows/label_issues.yml index 359c50d65a..3c3ecb1594 100644 --- a/.github/workflows/label_issues.yml +++ b/.github/workflows/label_issues.yml @@ -12,7 +12,7 @@ jobs: issues: write runs-on: ubuntu-latest steps: - - uses: actions/github-script@v8 + - uses: actions/github-script@v9 with: script: | const issue = await github.rest.issues.get({ diff --git a/.github/workflows/label_pr.yml b/.github/workflows/label_pr.yml index 8e2d674f2b..168b322ff9 100644 --- a/.github/workflows/label_pr.yml +++ b/.github/workflows/label_pr.yml @@ -18,7 +18,7 @@ jobs: with: configuration-path: .github/labeler.yml - name: Label based on PR title - uses: actions/github-script@v8 + uses: actions/github-script@v9 with: script: | const title = context.payload.pull_request.title.toLowerCase(); diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 8bd275ffab..28345c4647 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -24,7 +24,7 @@ jobs: - name: Broken Links Report if: steps.lychee.outputs.exit_code != 0 && github.event_name == 'schedule' - uses: actions/github-script@v8 + uses: actions/github-script@v9 with: script: | const fs = require('fs'); diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0bc79ea90f..af46432389 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -56,7 +56,7 @@ repos: - tomli - repo: https://github.com/commitizen-tools/commitizen - rev: v4.13.10 # automatically updated by Commitizen + rev: v4.15.0 # automatically updated by Commitizen hooks: - id: commitizen - id: commitizen-branch diff --git a/AGENTS.md b/AGENTS.md index c2d0e98ae7..be39dfd536 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,45 +9,70 @@ Follow these instructions in addition to any higher-level system or tool rules. - **Project**: `commitizen` - a tool to help enforce and automate conventional commits, version bumps, and changelog generation. - **Primary language**: Python (library + CLI). +- **Cross-platform**: Tests run on Linux, macOS, and Windows. Avoid POSIX-only assumptions in code (paths, subprocesses, line endings). - **Key entrypoints**: - `commitizen/cli.py` - main CLI implementation. - `commitizen/commands/` - subcommands such as `bump`, `commit`, `changelog`, `check`, etc. - `commitizen/config/` - configuration discovery and loading. - `commitizen/providers/` - version providers (e.g., `pep621`, `poetry`, `npm`, `uv`). +- **Config sources**: `pyproject.toml` (project config, poe tasks, ruff, mypy), `.pre-commit-config.yaml` (hooks), `.github/workflows/` (CI). ## General Expectations -- **Preserve public behavior and CLI UX.** -- **Avoid breaking changes** (APIs, CLI flags, exit codes) unless explicitly requested. -- **Keep changes small and focused.** +- **Preserve public behavior and CLI UX** — no breaking changes to APIs, CLI flags, or exit codes unless explicitly requested. - **Update or add tests/docs** when you change user-facing behavior. +- **Commit messages** must follow [Conventional Commits](https://www.conventionalcommits.org/) (enforced by commitizen itself). -## How to Explore and Validate Changes +## Setup and Validation -- **Code entrypoints**: - - CLI behavior: `commitizen/cli.py` and `commitizen/commands/`. - - Config resolution: `commitizen/config/factory.py` and config modules. - - Bump/changelog/versioning: `commitizen/bump.py`, `commitizen/changelog.py`, `commitizen/version_schemes.py`, `commitizen/providers/`. -- **Docs to consult** (before larger changes): - - `docs/README.md` - - `docs/contributing.md` - - `docs/commands/` and `docs/config/` -- **Tests**: - - Prefer targeted runs, e.g. `uv run pytest tests/test_cli.py` or a specific `tests/commands/` file. +### Bootstrap -## Coding Guidelines (for AI tools) +```bash +uv sync --frozen --group base --group test --group linters +``` + +### Local commands + +- **Format**: `uv run poe format` (runs `ruff check --fix` then `ruff format`) +- **Lint**: `uv run poe lint` (runs `ruff check` then `mypy`) +- **Test**: `uv run poe test` (runs `pytest -n auto`) +- **CI-equivalent**: `uv run poe ci` (commit check + pre-commit hooks via `prek` + test with coverage) +- **Full local check**: `uv run poe all` (format + lint + check-commit + coverage) + +Always run at least `uv run ruff check --fix . && uv run ruff format .` before pushing. CI will fail if the formatter modifies any files. + +### CI pipeline + +- CI runs `poe ci` on a matrix of Python 3.10–3.14 × ubuntu/macos/windows. +- Pre-commit hooks are defined in `.pre-commit-config.yaml` and run via `prek`. +- The matrix is **fail-fast**: inspect the earliest failing job that completed; others are cancelled. + +### Common CI failure patterns + +- **"Format Python code...Failed"**: Run `uv run poe format` and commit the result. +- **mypy `[arg-type]` on TypedDict**: Dynamically-constructed dicts (e.g., from `pytest.mark.parametrize`) passed to TypedDict-typed params need `# type: ignore[arg-type]`. +- **"pathspec 'vX.Y.Z' did not match"**: `.pre-commit-config.yaml` pins a tag of this repo. Rebase onto master to pick up the tag. +- **`VersionProtocol` + `issubclass`**: This Protocol has non-method members (properties), so `issubclass()` raises `TypeError`. Use `hasattr` checks for runtime validation. + +## What to Read Before Changing + +| Changing... | Read first | +|---|---| +| CLI flags/arguments | `commitizen/cli.py`, `docs/commands/.md`, `tests/test_cli/` | +| Bump logic | `commitizen/bump.py`, `commitizen/commands/bump.py`, `docs/commands/bump.md` | +| Changelog generation | `commitizen/changelog.py`, `commitizen/changelog_formats/`, `docs/commands/changelog.md` | +| Version schemes | `commitizen/version_schemes.py`, `tests/test_version_schemes.py` | +| Version providers | `commitizen/providers/`, `tests/test_providers.py`, `docs/config/version_provider.md` | +| Config resolution | `commitizen/config/`, `tests/test_conf.py`, `docs/config/` | +| Tag handling | `commitizen/tags.py`, `tests/test_tags.py` | +| Pre-commit / CI | `.pre-commit-config.yaml`, `.github/workflows/`, `pyproject.toml` (poe tasks) | + +## Coding Guidelines -- **Style**: Follow patterns in nearby code; keep functions focused. - **Types**: Preserve or improve existing type hints. - **Errors**: Prefer `commitizen/exceptions.py` error types; keep messages clear for CLI users. - **Output**: Use `commitizen/out.py`; do not add noisy logging. -## Common Task Pointers - -- **CLI commands**: edit `commitizen/commands/.py`, wire via `commitizen/cli.py`, and adjust `tests/commands/` + `docs/commands/`. -- **Version bumps / changelog**: use `commitizen/bump.py`, `commitizen/changelog.py`, `commitizen/version_schemes.py`, and `commitizen/providers/` (+ matching tests). -- **Config resolution**: use `commitizen/config/factory.py` and config modules; update `tests/test_conf.py` and related tests. - ## When Unsure - Prefer **reading tests and documentation first** to understand the expected behavior. diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 66aba30d08..54ddc8fdd7 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "4.13.10" +__version__ = "4.15.0" diff --git a/commitizen/bump.py b/commitizen/bump.py index cb572d3612..030c8f1e5b 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -15,7 +15,7 @@ if TYPE_CHECKING: from collections.abc import Generator, Iterable - from commitizen.version_schemes import Increment, Version + from commitizen.version_schemes import Increment, VersionProtocol VERSION_TYPES = [None, PATCH, MINOR, MAJOR] @@ -131,8 +131,8 @@ def _resolve_files_and_regexes( def create_commit_message( - current_version: Version | str, - new_version: Version | str, + current_version: VersionProtocol | str, + new_version: VersionProtocol | str, message_template: str | None = None, ) -> str: if message_template is None: diff --git a/commitizen/cli.py b/commitizen/cli.py index 79988fb5cb..85674e8c4d 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -21,6 +21,7 @@ InvalidCommandArgumentError, NoCommandFoundError, ) +from commitizen.version_increment import VersionIncrement logger = logging.getLogger(__name__) @@ -542,13 +543,19 @@ def __call__( }, { "name": ["--major"], - "help": "Output just the major version. Must be used with --project or --verbose.", + "help": ( + "Output just the major version. Must be used with MANUAL_VERSION, " + "--project, or --verbose." + ), "action": "store_true", "exclusive_group": "group2", }, { "name": ["--minor"], - "help": "Output just the minor version. Must be used with --project or --verbose.", + "help": ( + "Output just the minor version. Must be used with MANUAL_VERSION, " + "--project, or --verbose." + ), "action": "store_true", "exclusive_group": "group2", }, @@ -558,6 +565,33 @@ def __call__( "action": "store_true", "exclusive_group": "group2", }, + { + "name": ["--patch"], + "help": ( + "Output the patch version only. Must be used with MANUAL_VERSION, " + "--project, or --verbose." + ), + "action": "store_true", + "exclusive_group": "group2", + }, + { + "name": ["--next"], + "help": "Output the next version.", + "type": str, + "nargs": "?", + "default": None, + "const": "USE_GIT_COMMITS", + "choices": ["USE_GIT_COMMITS"] + + [str(increment) for increment in VersionIncrement], + "exclusive_group": "group2", + }, + { + "name": "manual_version", + "type": str, + "nargs": "?", + "help": "Use the version provided instead of the version from the project. Can be used to test the selected version scheme.", + "metavar": "MANUAL_VERSION", + }, ], }, ], diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 6084c8c151..9e2ae81b1f 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -330,7 +330,11 @@ def __call__(self) -> None: changelog_cmd = Changelog( self.config, - {**changelog_args, "file_name": self.file_name}, # type: ignore[typeddict-item] + { + **changelog_args, # type: ignore[typeddict-item] + "file_name": self.file_name, + "allow_no_commit": bool(self.arguments["allow_no_commit"]), + }, ) changelog_cmd() changelog_file_name = changelog_cmd.file_name diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 5093ed9f29..8cef5d39f4 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -43,6 +43,7 @@ class ChangelogArgs(TypedDict, total=False): extras: dict[str, Any] export_template: str during_version_bump: bool | None + allow_no_commit: bool | None # Internal-only when invoked by bump. class Changelog: @@ -124,6 +125,8 @@ def __init__(self, config: BaseConfig, arguments: ChangelogArgs) -> None: self.export_template_to = arguments.get("export_template") self.during_version_bump: bool = arguments.get("during_version_bump") or False + # Internal flag used when changelog is invoked from `cz bump --allow-no-commit`. + self.allow_no_commit: bool = bool(arguments.get("allow_no_commit")) def _find_incremental_rev(self, latest_version: str, tags: Iterable[GitTag]) -> str: """Try to find the 'start_rev'. @@ -255,8 +258,10 @@ def __call__(self) -> None: changelog_meta.unreleased_end = latest_full_release_info.index + 1 commits = git.get_commits(start=start_rev, end=end_rev, args="--topo-order") - if not commits and ( - self.current_version is None or not self.current_version.is_prerelease + if ( + not self.allow_no_commit + and not commits + and (self.current_version is None or not self.current_version.is_prerelease) ): raise NoCommitsFoundError("No commits found") diff --git a/commitizen/commands/init.py b/commitizen/commands/init.py index d0f4b686ac..ad33d884bf 100644 --- a/commitizen/commands/init.py +++ b/commitizen/commands/init.py @@ -17,7 +17,11 @@ NoAnswersError, ) from commitizen.git import get_latest_tag_name, get_tag_names, smart_open -from commitizen.version_schemes import KNOWN_SCHEMES, Version, get_version_scheme +from commitizen.version_schemes import ( + KNOWN_SCHEMES, + VersionProtocol, + get_version_scheme, +) if TYPE_CHECKING: from commitizen.config import ( @@ -265,7 +269,7 @@ def _ask_version_scheme(self) -> str: ).unsafe_ask() return scheme - def _ask_major_version_zero(self, version: Version) -> bool: + def _ask_major_version_zero(self, version: VersionProtocol) -> bool: """Ask for setting: major_version_zero""" if version.major > 0: return False @@ -323,7 +327,7 @@ def _write_config_to_file( cz_name: str, version_provider: str, version_scheme: str, - version: Version, + version: VersionProtocol, tag_format: str, update_changelog_on_bump: bool, major_version_zero: bool, diff --git a/commitizen/commands/version.py b/commitizen/commands/version.py index c8a76fe27f..2a4bcea88a 100644 --- a/commitizen/commands/version.py +++ b/commitizen/commands/version.py @@ -2,22 +2,32 @@ import sys from typing import TypedDict +from packaging.version import InvalidVersion + from commitizen import out from commitizen.__version__ import __version__ from commitizen.config import BaseConfig from commitizen.exceptions import NoVersionSpecifiedError, VersionSchemeUnknown from commitizen.providers import get_provider from commitizen.tags import TagRules -from commitizen.version_schemes import get_version_scheme +from commitizen.version_increment import VersionIncrement +from commitizen.version_schemes import Increment, get_version_scheme class VersionArgs(TypedDict, total=False): + manual_version: str | None + next: str | None + + # Exclusive groups 1 commitizen: bool report: bool project: bool verbose: bool + + # Exclusive groups 2 major: bool minor: bool + patch: bool tag: bool @@ -43,40 +53,85 @@ def __call__(self) -> None: if self.arguments.get("verbose"): out.write(f"Installed Commitizen Version: {__version__}") - if not self.arguments.get("commitizen") and ( - self.arguments.get("project") or self.arguments.get("verbose") + if self.arguments.get("commitizen"): + out.write(__version__) + return + + if ( + self.arguments.get("project") + or self.arguments.get("verbose") + or self.arguments.get("next") + or self.arguments.get("manual_version") ): + version_str = self.arguments.get("manual_version") + if version_str is None: + try: + version_str = get_provider(self.config).get_version() + except NoVersionSpecifiedError: + out.error("No project information in this project.") + return try: - version = get_provider(self.config).get_version() - except NoVersionSpecifiedError: - out.error("No project information in this project.") - return - try: - version_scheme = get_version_scheme(self.config.settings)(version) + scheme_factory = get_version_scheme(self.config.settings) except VersionSchemeUnknown: out.error("Unknown version scheme.") return + try: + version = scheme_factory(version_str) + except InvalidVersion: + out.error(f"Invalid version: '{version_str}'") + return + + if next_increment_str := self.arguments.get("next"): + if next_increment_str == "USE_GIT_COMMITS": + # TODO: implement USE_GIT_COMMITS by deriving the increment from + # git history. This requires refactoring the bump logic out of + # `commitizen/commands/bump.py` so it can be reused here. See #1678. + out.error("--next USE_GIT_COMMITS is not implemented yet.") + return + + next_increment = VersionIncrement.from_value(next_increment_str) + increment: Increment | None + if next_increment == VersionIncrement.NONE: + increment = None + elif next_increment == VersionIncrement.PATCH: + increment = "PATCH" + elif next_increment == VersionIncrement.MINOR: + increment = "MINOR" + else: + increment = "MAJOR" + version = version.bump(increment=increment) + if self.arguments.get("major"): - version = f"{version_scheme.major}" - elif self.arguments.get("minor"): - version = f"{version_scheme.minor}" - elif self.arguments.get("tag"): + out.write(version.major) + return + if self.arguments.get("minor"): + out.write(version.minor) + return + if self.arguments.get("patch"): + out.write(version.micro) + return + + display_version: str + if self.arguments.get("tag"): tag_rules = TagRules.from_settings(self.config.settings) - version = tag_rules.normalize_tag(version_scheme) + display_version = tag_rules.normalize_tag(version) + else: + display_version = str(version) out.write( - f"Project Version: {version}" + f"Project Version: {display_version}" if self.arguments.get("verbose") - else version + else display_version ) return - if self.arguments.get("major") or self.arguments.get("minor"): - out.error( - "Major or minor version can only be used with --project or --verbose." - ) - return + for argument in ("major", "minor", "patch"): + if self.arguments.get(argument): + out.error( + f"{argument} can only be used with MANUAL_VERSION, --project or --verbose." + ) + return if self.arguments.get("tag"): out.error("Tag can only be used with --project or --verbose.") diff --git a/commitizen/out.py b/commitizen/out.py index 1bbfe4329d..cdc80cf521 100644 --- a/commitizen/out.py +++ b/commitizen/out.py @@ -9,35 +9,35 @@ sys.stdout.reconfigure(encoding="utf-8") -def write(value: str, *args: object) -> None: +def write(value: object, *args: object) -> None: """Intended to be used when value is multiline.""" print(value, *args) -def line(value: str, *args: object, **kwargs: Any) -> None: +def line(value: object, *args: object, **kwargs: Any) -> None: """Wrapper in case I want to do something different later.""" print(value, *args, **kwargs) -def error(value: str) -> None: - message = colored(value, "red") +def error(value: object) -> None: + message = colored(str(value), "red") line(message, file=sys.stderr) -def success(value: str) -> None: - message = colored(value, "green") +def success(value: object) -> None: + message = colored(str(value), "green") line(message) -def info(value: str) -> None: - message = colored(value, "blue") +def info(value: object) -> None: + message = colored(str(value), "blue") line(message) -def diagnostic(value: str) -> None: +def diagnostic(value: object) -> None: line(value, file=sys.stderr) -def warn(value: str) -> None: - message = colored(value, "magenta") +def warn(value: object) -> None: + message = colored(str(value), "magenta") line(message, file=sys.stderr) diff --git a/commitizen/tags.py b/commitizen/tags.py index 11b9899bed..b3bcbe7a07 100644 --- a/commitizen/tags.py +++ b/commitizen/tags.py @@ -14,7 +14,7 @@ from commitizen.version_schemes import ( DEFAULT_SCHEME, InvalidVersion, - Version, + VersionProtocol, VersionScheme, get_version_scheme, ) @@ -23,8 +23,6 @@ import sys from collections.abc import Iterable, Sequence - from commitizen.version_schemes import VersionScheme - # Self is Python 3.11+ but backported in typing-extensions if sys.version_info < (3, 11): from typing_extensions import Self @@ -75,7 +73,7 @@ class TagRules: assert not rules.is_version_tag("warn1.0.0", warn=True) # Does warn assert rules.search_version("# My v1.0.0 version").version == "1.0.0" - assert rules.extract_version("v1.0.0") == Version("1.0.0") + assert rules.extract_version("v1.0.0") == rules.scheme("1.0.0") try: assert rules.extract_version("not-a-v1.0.0") except InvalidVersion: @@ -145,7 +143,7 @@ def get_version_tags( """Filter in version tags and warn on unexpected tags""" return [tag for tag in tags if self.is_version_tag(tag, warn)] - def extract_version(self, tag: GitTag) -> Version: + def extract_version(self, tag: GitTag) -> VersionProtocol: """ Extract a version from the tag as defined in tag formats. @@ -195,7 +193,7 @@ def search_version(self, text: str, last: bool = False) -> VersionTag | None: return VersionTag(version, match.group(0)) def normalize_tag( - self, version: Version | str, tag_format: str | None = None + self, version: VersionProtocol | str, tag_format: str | None = None ) -> str: """ The tag and the software version might be different. @@ -225,7 +223,7 @@ def normalize_tag( ) def find_tag_for( - self, tags: Iterable[GitTag], version: Version | str + self, tags: Iterable[GitTag], version: VersionProtocol | str ) -> GitTag | None: """Find the first matching tag for a given version.""" version = self.scheme(version) if isinstance(version, str) else version @@ -234,7 +232,7 @@ def find_tag_for( # If the requested version is incomplete (e.g., "1.2"), try to find the latest # matching tag that shares the provided prefix. if len(release) < 3: - matching_versions: list[tuple[Version, GitTag]] = [] + matching_versions: list[tuple[VersionProtocol, GitTag]] = [] for tag in tags: try: tag_version = self.extract_version(tag) diff --git a/commitizen/version_increment.py b/commitizen/version_increment.py new file mode 100644 index 0000000000..9320fe8f90 --- /dev/null +++ b/commitizen/version_increment.py @@ -0,0 +1,33 @@ +from __future__ import annotations + +from enum import IntEnum + + +class VersionIncrement(IntEnum): + """Semantic versioning bump increments. + + IntEnum keeps a total order compatible with NONE < PATCH < MINOR < MAJOR + for comparisons across the codebase. + + - NONE: no bump (docs-only / style commits, etc.) + - PATCH: backwards-compatible bug fixes + - MINOR: backwards-compatible features + - MAJOR: incompatible API changes + """ + + NONE = 0 + PATCH = 1 + MINOR = 2 + MAJOR = 3 + + def __str__(self) -> str: + return self.name + + @classmethod + def from_value(cls, value: object) -> VersionIncrement: + if not isinstance(value, str): + return VersionIncrement.NONE + try: + return cls[value] + except KeyError: + return VersionIncrement.NONE diff --git a/commitizen/version_schemes.py b/commitizen/version_schemes.py index 1f17e90871..14a55d6554 100644 --- a/commitizen/version_schemes.py +++ b/commitizen/version_schemes.py @@ -10,6 +10,7 @@ ClassVar, Literal, Protocol, + TypeAlias, cast, runtime_checkable, ) @@ -22,7 +23,6 @@ if TYPE_CHECKING: import sys - from typing import TypeAlias # Self is Python 3.11+ but backported in typing-extensions if sys.version_info < (3, 11): @@ -31,7 +31,7 @@ from typing import Self -Increment: TypeAlias = Literal["MAJOR", "MINOR", "PATCH"] +Increment: TypeAlias = Literal["MAJOR", "MINOR", "PATCH"] # TODO: deprecate Prerelease: TypeAlias = Literal["alpha", "beta", "rc"] _DEFAULT_VERSION_PARSER = re.compile( r"v?(?P([0-9]+)\.([0-9]+)(?:\.([0-9]+))?(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z.]+)?(\w+)?)" @@ -140,7 +140,7 @@ def bump( """ -# With PEP 440 and SemVer semantic, Scheme is the type, Version is an instance +# With PEP 440 and SemVer semantics, a scheme is the class; a version is an instance. Version: TypeAlias = VersionProtocol VersionScheme: TypeAlias = type[VersionProtocol] @@ -422,7 +422,16 @@ def get_version_scheme(settings: Settings, name: str | None = None) -> VersionSc raise VersionSchemeUnknown(f'Version scheme "{name}" unknown.') scheme = cast("VersionScheme", ep.load()) - if not isinstance(scheme, VersionProtocol): + # `VersionProtocol` is a `@runtime_checkable` Protocol, but `issubclass()` is not + # supported for Protocols with non-method members. We check an instance instead by + # verifying the loaded object is a class with the expected interface. + if isinstance(scheme, type): + # Check for a key method/attribute that VersionProtocol requires + if not hasattr(scheme, "bump"): + warnings.warn( + f"Version scheme {name} does not implement the VersionProtocol" + ) + else: warnings.warn(f"Version scheme {name} does not implement the VersionProtocol") return scheme diff --git a/docs/commands/bump.md b/docs/commands/bump.md index 76ca00fc83..84666cbc66 100644 --- a/docs/commands/bump.md +++ b/docs/commands/bump.md @@ -385,6 +385,11 @@ cz bump --allow-no-commit 2.0.0 cz bump --allow-no-commit 2.0.0 ``` +!!! note "Behavior with changelog updates" + When `update_changelog_on_bump = true` (or `--changelog` is used), `cz bump --allow-no-commit` also generates a changelog entry even if there are no commits in the selected range. + + This makes the new release visible in the changelog while still showing that no commit-based changes were included. + ### `--tag-format` `tag_format` and [version_scheme][version_scheme] are combined to make Git tag names from versions. diff --git a/docs/commands/changelog.md b/docs/commands/changelog.md index 62f018ecfc..8b7a7a4d48 100644 --- a/docs/commands/changelog.md +++ b/docs/commands/changelog.md @@ -2,6 +2,8 @@ Generates a changelog following the committing rules established. +When changelog generation is triggered by `cz bump --allow-no-commit` (with `--changelog` or `update_changelog_on_bump = true`), Commitizen still creates a release entry even when no commits are found in the selected revision range. + !!! tip To create the changelog automatically on bump, add the setting [update_changelog_on_bump](../config/bump.md#update_changelog_on_bump) diff --git a/docs/commands/version.md b/docs/commands/version.md index 4d2e6a0323..198df5b480 100644 --- a/docs/commands/version.md +++ b/docs/commands/version.md @@ -1,5 +1,27 @@ -Get the version of the installed Commitizen or the current project (default: installed commitizen) +Get the version of the installed Commitizen or the current project (default: installed commitizen). ## Usage ![cz version --help](../images/cli_help/cz_version___help.svg) + +## Project version and scheme + +- **`cz version --project`** prints the version from your configured [version provider](../config/version_provider.md). +- **`cz version MANUAL_VERSION`** (optional positional) uses that string instead of the provider, so you can try how your configured scheme parses and formats it. + +## Components and next version + +- **`--major`**, **`--minor`**, **`--patch`**: print only that component of the (possibly manual) project version. Requires `--project`, `--verbose`, or a manual version. +- **`--next` `[MAJOR|MINOR|PATCH|NONE]`**: print the version after applying that bump to the current project or manual version. `NONE` leaves the version unchanged. +- **`--tag`**: print the version formatted with your `tag_format` (requires `--project` or `--verbose`). + +`--next USE_GIT_COMMITS` is reserved for a future feature (derive the bump from git history) and is not implemented yet. + +## Examples + +```bash +cz version --project +cz version 2.0.0 --next MAJOR +cz version --project --major +cz version --verbose +``` diff --git a/docs/images/bump.tape b/docs/images/bump.tape index 08003602e2..ef4a427c98 100644 --- a/docs/images/bump.tape +++ b/docs/images/bump.tape @@ -1,77 +1,17 @@ Output cli_interactive/bump.gif -Require cz - -# Use bash for cross-platform compatibility (macOS, Linux, Windows) -Set Shell bash - -Set FontSize 16 -Set Width 878 -Set Height 568 -Set Padding 20 -Set TypingSpeed 50ms - -Set Theme { - "name": "Commitizen", - "black": "#232628", - "red": "#fc4384", - "green": "#b3e33b", - "yellow": "#ffa727", - "blue": "#75dff2", - "magenta": "#ae89fe", - "cyan": "#708387", - "white": "#d5d5d0", - "brightBlack": "#626566", - "brightRed": "#ff7fac", - "brightGreen": "#c8ed71", - "brightYellow": "#ebdf86", - "brightBlue": "#75dff2", - "brightMagenta": "#ae89fe", - "brightCyan": "#b1c6ca", - "brightWhite": "#f9f9f4", - "background": "#1e1e2e", - "foreground": "#afafaf", - "cursor": "#c7c7c7" -} - -# Hide initial shell prompt -Hide - -# Wait for terminal to be ready -Sleep 1s - -# Set a clean, simple prompt (while hidden) -Type "PS1='$ '" -Enter -Sleep 300ms - -# Create a clean temporary directory for recording -Type "rm -rf /tmp/commitizen-example && mkdir -p /tmp/commitizen-example && cd /tmp/commitizen-example" -Enter -Sleep 500ms - -# Initialize git repository -Type "git init" -Enter -Type "git config user.email 'you@example.com'" -Enter -Type "git config user.name 'Your Name'" -Enter -Sleep 500ms +Source shared/base.tape +Source shared/git_init.tape # Initialize commitizen config with version 0.0.1 and changelog enabled Type `cat > pyproject.toml << 'EOF'` Enter -Sleep 100ms Type `[tool.commitizen]` Enter -Sleep 100ms Type `version = "0.0.1"` Enter -Sleep 100ms Type `update_changelog_on_bump = true` Enter -Sleep 100ms Type "EOF" Enter Sleep 300ms @@ -131,4 +71,6 @@ Enter Sleep 1s # Wait for final output -Sleep 3s +Sleep 1s + +Source shared/cleanup.tape diff --git a/docs/images/bump.yml b/docs/images/bump.yml deleted file mode 100644 index ea77a2f406..0000000000 --- a/docs/images/bump.yml +++ /dev/null @@ -1,195 +0,0 @@ -# The configurations that used for the recording, feel free to edit them -config: - - # Specify a command to be executed - # like `/bin/bash -l`, `ls`, or any other commands - # the default is bash for Linux - # or powershell.exe for Windows - command: bash -l - - # Specify the current working directory path - # the default is the current working directory path - cwd: ~/my-project - - # Export additional ENV variables - env: - recording: true - - # Explicitly set the number of columns - # or use `auto` to take the current - # number of columns of your shell - cols: 80 - - # Explicitly set the number of rows - # or use `auto` to take the current - # number of rows of your shell - rows: 20 - - # Amount of times to repeat GIF - # If value is -1, play once - # If value is 0, loop indefinitely - # If value is a positive number, loop n times - repeat: 0 - - # Quality - # 1 - 100 - quality: 85 - - # Delay between frames in ms - # If the value is `auto` use the actual recording delays - frameDelay: auto - - # Maximum delay between frames in ms - # Ignored if the `frameDelay` isn't set to `auto` - # Set to `auto` to prevent limiting the max idle time - maxIdleTime: 2000 - - # The surrounding frame box - # The `type` can be null, window, floating, or solid` - # To hide the title use the value null - # Don't forget to add a backgroundColor style with a null as type - frameBox: - type: floating - title: "Commitizen: bump" - style: - border: 0px black solid - # boxShadow: none - # margin: 0px - - # Add a watermark image to the rendered gif - # You need to specify an absolute path for - # the image on your machine or a URL, and you can also - # add your own CSS styles - watermark: - imagePath: null - style: - position: absolute - right: 15px - bottom: 15px - width: 100px - opacity: 0.9 - - # Cursor style can be one of - # `block`, `underline`, or `bar` - cursorStyle: block - - # Font family - # You can use any font that is installed on your machine - # in CSS-like syntax - fontFamily: "Monaco, Lucida Console, Ubuntu Mono, Monospace" - - # The size of the font - fontSize: 16 - - # The height of lines - lineHeight: 1 - - # The spacing between letters - letterSpacing: 0 - - # Theme - theme: - background: "transparent" - foreground: "#afafaf" - cursor: "#c7c7c7" - black: "#232628" - red: "#fc4384" - green: "#b3e33b" - yellow: "#ffa727" - blue: "#75dff2" - magenta: "#ae89fe" - cyan: "#708387" - white: "#d5d5d0" - brightBlack: "#626566" - brightRed: "#ff7fac" - brightGreen: "#c8ed71" - brightYellow: "#ebdf86" - brightBlue: "#75dff2" - brightMagenta: "#ae89fe" - brightCyan: "#b1c6ca" - brightWhite: "#f9f9f4" - -# Records, feel free to edit them -records: - - delay: 2295 - content: "\e[1;33m\e[0;32m\e[1;34m\e[1;32msantiago\e[1;34m@\e[1;31mhome\e[1;37m in \e[1;34m~/my-project\e[0;36m |master=|\e[1;32m $\r\r\n\e[1;32m$\e[00m " - - delay: 662 - content: c - - delay: 70 - content: z - - delay: 111 - content: ' ' - - delay: 253 - content: '-' - - delay: 112 - content: '-' - - delay: 112 - content: v - - delay: 122 - content: e - - delay: 280 - content: r - - delay: 202 - content: s - - delay: 106 - content: i - - delay: 55 - content: o - - delay: 298 - content: 'n' - - delay: 273 - content: "\r\n" - - delay: 1121 - content: "1.1.0\r\n\e[0m" - - delay: 161 - content: "\e[1;33m\e[0;32m\e[1;34m\e[1;32msantiago\e[1;34m@\e[1;31mhome\e[1;37m in \e[1;34m~/my-project\e[0;36m |master=|\e[1;32m $\r\r\n\e[1;32m$\e[00m " - - delay: 667 - content: c - - delay: 95 - content: z - - delay: 147 - content: ' ' - - delay: 150 - content: b - - delay: 114 - content: u - - delay: 180 - content: m - - delay: 132 - content: p - - delay: 239 - content: "\r\n" - - delay: 1176 - content: "bump: version 1.1.0 → 1.1.1\r\ntag to create: v1.1.1\r\nincrement detected: PATCH\r\n" - - delay: 75 - content: "\e[32mDone!\e[0m\r\n\e[0m" - - delay: 183 - content: "\e[1;33m\e[0;32m\e[1;34m\e[1;32msantiago\e[1;34m@\e[1;31mhome\e[1;37m in \e[1;34m~/my-project\e[0;36m |master>|\e[1;32m $\r\r\n\e[1;32m$\e[00m " - - delay: 1500 - content: c - - delay: 70 - content: z - - delay: 44 - content: ' ' - - delay: 161 - content: '-' - - delay: 119 - content: '-' - - delay: 87 - content: v - - delay: 133 - content: e - - delay: 92 - content: r - - delay: 89 - content: s - - delay: 87 - content: i - - delay: 45 - content: o - - delay: 200 - content: 'n' - - delay: 199 - content: "\r\n" - - delay: 1120 - content: "1.1.1\r\n\e[0m" diff --git a/docs/images/cli_help/cz_version___help.svg b/docs/images/cli_help/cz_version___help.svg index 20331e0972..e3b9d55763 100644 --- a/docs/images/cli_help/cz_version___help.svg +++ b/docs/images/cli_help/cz_version___help.svg @@ -1,4 +1,4 @@ - + - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - $ cz version --help -usage: cz version [-h][-r | -p | -c | -v][--major | --minor | --tag] - -Get the version of the installed commitizen or the current project (default: -installed commitizen) - -options: -  -h, --help        show this help message and exit -  -r, --report      Output the system information for reporting bugs. -  -p, --project     Output the version of the current project. -  -c, --commitizen  Output the version of the installed commitizen. -  -v, --verbose     Output the version of both the installed commitizen and -                    the current project. -  --major           Output just the major version. Must be used with --project -                    or --verbose. -  --minor           Output just the minor version. Must be used with --project -                    or --verbose. -  --tag             get the version with tag prefix. Need to be used with -                    --project or --verbose. - + + $ cz version --help + diff --git a/docs/images/cli_interactive/bump.gif b/docs/images/cli_interactive/bump.gif index 60ae97077e..9bc80069b9 100644 Binary files a/docs/images/cli_interactive/bump.gif and b/docs/images/cli_interactive/bump.gif differ diff --git a/docs/images/cli_interactive/commit.gif b/docs/images/cli_interactive/commit.gif index 98c55a014c..083f65f7dd 100644 Binary files a/docs/images/cli_interactive/commit.gif and b/docs/images/cli_interactive/commit.gif differ diff --git a/docs/images/cli_interactive/init.gif b/docs/images/cli_interactive/init.gif index a199d6e1aa..edd2122a76 100644 Binary files a/docs/images/cli_interactive/init.gif and b/docs/images/cli_interactive/init.gif differ diff --git a/docs/images/cli_interactive/shortcut_custom.gif b/docs/images/cli_interactive/shortcut_custom.gif index 6a32478238..12afb889ac 100644 Binary files a/docs/images/cli_interactive/shortcut_custom.gif and b/docs/images/cli_interactive/shortcut_custom.gif differ diff --git a/docs/images/cli_interactive/shortcut_default.gif b/docs/images/cli_interactive/shortcut_default.gif index 402570a05c..eeedd61cee 100644 Binary files a/docs/images/cli_interactive/shortcut_default.gif and b/docs/images/cli_interactive/shortcut_default.gif differ diff --git a/docs/images/commit.tape b/docs/images/commit.tape index f05a354e7b..e93a38ae67 100644 --- a/docs/images/commit.tape +++ b/docs/images/commit.tape @@ -1,63 +1,7 @@ Output cli_interactive/commit.gif -Require cz - -# Use bash for cross-platform compatibility (macOS, Linux, Windows) -Set Shell bash - -Set FontSize 16 -Set Width 878 -Set Height 568 -Set Padding 20 -Set TypingSpeed 50ms - -Set Theme { - "name": "Commitizen", - "black": "#232628", - "red": "#fc4384", - "green": "#b3e33b", - "yellow": "#ffa727", - "blue": "#75dff2", - "magenta": "#ae89fe", - "cyan": "#708387", - "white": "#d5d5d0", - "brightBlack": "#626566", - "brightRed": "#ff7fac", - "brightGreen": "#c8ed71", - "brightYellow": "#ebdf86", - "brightBlue": "#75dff2", - "brightMagenta": "#ae89fe", - "brightCyan": "#b1c6ca", - "brightWhite": "#f9f9f4", - "background": "#1e1e2e", - "foreground": "#afafaf", - "cursor": "#c7c7c7" -} - -# Hide initial shell prompt -Hide - -# Wait for terminal to be ready -Sleep 1s - -# Set a clean, simple prompt (while hidden) -Type "PS1='$ '" -Enter -Sleep 300ms - -# Create a clean temporary directory for recording -Type "rm -rf /tmp/commitizen-demo && mkdir -p /tmp/commitizen-demo && cd /tmp/commitizen-demo" -Enter -Sleep 500ms - -# Initialize git repository -Type "git init" -Enter -Type "git config user.email 'you@example.com'" -Enter -Type "git config user.name 'Your Name'" -Enter -Sleep 500ms +Source shared/base.tape +Source shared/git_init.tape Type "git checkout -b awesome-feature" Enter @@ -117,4 +61,6 @@ Enter Sleep 1s # Wait for commit success message -Sleep 2s +Sleep 1s + +Source shared/cleanup.tape diff --git a/docs/images/commit.yml b/docs/images/commit.yml deleted file mode 100644 index fd10ed777f..0000000000 --- a/docs/images/commit.yml +++ /dev/null @@ -1,187 +0,0 @@ -# The configurations that used for the recording, feel free to edit them -config: - - # Specify a command to be executed - # like `/bin/bash -l`, `ls`, or any other commands - # the default is bash for Linux - # or powershell.exe for Windows - command: bash -l - - # Specify the current working directory path - # the default is the current working directory path - cwd: ~/my-project - - # Export additional ENV variables - env: - recording: true - - # Explicitly set the number of columns - # or use `auto` to take the current - # number of columns of your shell - cols: 101 - - # Explicitly set the number of rows - # or use `auto` to take the current - # number of rows of your shell - rows: 22 - - # Amount of times to repeat GIF - # If value is -1, play once - # If value is 0, loop indefinitely - # If value is a positive number, loop n times - repeat: 0 - - # Quality - # 1 - 100 - quality: 85 - - # Delay between frames in ms - # If the value is `auto` use the actual recording delays - frameDelay: auto - - # Maximum delay between frames in ms - # Ignored if the `frameDelay` isn't set to `auto` - # Set to `auto` to prevent limiting the max idle time - maxIdleTime: 2000 - - # The surrounding frame box - # The `type` can be null, window, floating, or solid` - # To hide the title use the value null - # Don't forget to add a backgroundColor style with a null as type - frameBox: - type: floating - title: Commitizen - style: - border: 0px black solid - # boxShadow: none - # margin: 0px - - # Add a watermark image to the rendered gif - # You need to specify an absolute path for - # the image on your machine or a URL, and you can also - # add your own CSS styles - watermark: - imagePath: null - style: - position: absolute - right: 15px - bottom: 15px - width: 100px - opacity: 0.9 - - # Cursor style can be one of - # `block`, `underline`, or `bar` - cursorStyle: block - - # Font family - # You can use any font that is installed on your machine - # in CSS-like syntax - fontFamily: "Monaco, Lucida Console, Ubuntu Mono, Monospace" - - # The size of the font - fontSize: 12 - - # The height of lines - lineHeight: 1 - - # The spacing between letters - letterSpacing: 0 - - # Theme - theme: - background: "transparent" - foreground: "#afafaf" - cursor: "#c7c7c7" - black: "#232628" - red: "#fc4384" - green: "#b3e33b" - yellow: "#ffa727" - blue: "#75dff2" - magenta: "#ae89fe" - cyan: "#708387" - white: "#d5d5d0" - brightBlack: "#626566" - brightRed: "#ff7fac" - brightGreen: "#c8ed71" - brightYellow: "#ebdf86" - brightBlue: "#75dff2" - brightMagenta: "#ae89fe" - brightCyan: "#b1c6ca" - brightWhite: "#f9f9f4" - -# Records, feel free to edit them -records: - - delay: 987 - content: "\e[1;33m\e[0;32m\e[1;34m\e[1;32msantiago\e[1;34m@\e[1;31mhome\e[1;37m in \e[1;34m~/my-project\e[0;36m |master #|\e[1;32m\r\r\n\e[1;32m$\e[00m " - - delay: 731 - content: c - - delay: 345 - content: z - - delay: 135 - content: ' ' - - delay: 118 - content: c - - delay: 116 - content: o - - delay: 200 - content: m - - delay: 135 - content: m - - delay: 199 - content: i - - delay: 406 - content: t - - delay: 144 - content: "\r\n" - - delay: 209 - content: "\e[?1l\e[6n" - - delay: 7 - content: "\e[?2004h\e[?25l\e[0m\e[?7l\e[0m\e[J\e[0;38;5;67m?\e[0;1m Select the type of change you are committing \e[0m (Use arrow keys) \r\e[100C \e[0m\r\r\n\e[0m » fix: A bug fix. Correlates with PATCH in SemVer\e[0m\r\r\n\e[0m feat: A new feature. Correlates with MINOR in SemVer\e[0m\r\r\n\e[0m docs: Documentation only changes\e[0m\r\r\n\e[0m style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-\r\e[100Cc\e[0m\r\r\n\e[0m refactor: A code change that neither fixes a bug nor adds a feature\e[0m\r\r\n\e[0m perf: A code change that improves performance\e[0m\r\r\n\e[0m test: Adding missing or correcting existing tests\e[0m\r\r\n\e[0m build: Changes that affect the build system or external dependencies (example scopes: pip, docker\r\e[100C,\e[0m\r\r\n\e[0m ci: Changes to CI configuration files and scripts (example scopes: GitLabCI) \r\e[100C \r\e[9A\e[64C\e[?7h\e[0m\e[?12l\e[?25h" - - delay: 17 - content: "\e[?25l\e[?7l\e[0m\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\e[0m ci: Changes to CI configuration files and scripts (example scopes: GitLabCI)\e[0m\e[K\e[0m\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\e[0m \r\e[100C \r\e[19A\e[64C\e[?7h\e[0m\e[?12l\e[?25h" - - delay: 647 - content: "\e[?25l\e[?7l\e[0m\r\r\n\e[0m \e[0m\r\r\n\e[0m » \e[2A\e[61C\e[?7h\e[0m\e[?12l\e[?25h" - - delay: 574 - content: "\e[?25l\e[?7l\e[64D\e[0m\e[J\e[0;38;5;67m?\e[0;1m Select the type of change you are committing \e[0;38;5;214;1m feat: A new feature. Correlates with MINOR in SemVer\r\e[100C\e[0m \r\e[0m\r\r\n\e[J\e[?7h\e[0m\e[?12l\e[?25h\e[?2004l" - - delay: 20 - content: "\e[?1l\e[6n\e[?2004h\e[?25l\e[0m\e[?7l\e[0m\e[J\e[0;38;5;67m?\e[0;1m Scope. Could be anything specifying place of the commit change (users, db, poll):\e[0m \r\e[100C \e[0m\r\r\n\e[0;1m \e[0m \r\e[100C \r\e[C\e[?7h\e[0m\e[?12l\e[?25h" - - delay: 11 - content: "\e[?25l\e[?7l\b\e[0;1m \e[0m \e[0m\e[K\e[0m\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\e[0m \r\e[100C \r\e[17A\e[C\e[?7h\e[0m\e[?12l\e[?25h" - - delay: 1388 - content: "\e[?25l\e[?7l\e[A\b\e[0m\e[J\e[0;38;5;67m?\e[0;1m Scope. Could be anything specifying place of the commit change (users, db, poll):\e[0m \r\e[100C \e[0m\r\r\n\e[0;1m \e[0m \r\e[100C \r\e[0m\r\r\n\e[J\e[?7h\e[0m\e[?12l\e[?25h\e[?2004l" - - delay: 12 - content: "\e[?1l\e[6n" - - delay: 5 - content: "\e[?2004h\e[?25l\e[0m\e[?7l\e[0m\e[J\e[0;38;5;67m?\e[0;1m Subject. Concise description of the changes. Imperative, lower case and no final dot:\e[0m \r\e[100C \e[0m\r\r\n\e[0;1m \e[0m \r\e[100C \r\e[C\e[?7h\e[0m\e[?12l\e[?25h" - - delay: 24 - content: "\e[?25l\e[?7l\b\e[0;1m \e[0m \e[0m\e[K\e[0m\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\e[0m \r\e[100C \r\e[15A\e[C\e[?7h\e[0m\e[?12l\e[?25h" - - delay: 925 - content: "\e[?25l\e[?7l\e[0mallow provided config object to extend other configs \b\e[?7h\e[0m\e[?12l\e[?25h\e[?25l\e[?7l\e[?7h\e[0m\e[?12l\e[?25h" - - delay: 2880 - content: "\e[?25l\e[?7l\e[A\e[53D\e[0m\e[J\e[0;38;5;67m?\e[0;1m Subject. Concise description of the changes. Imperative, lower case and no final dot:\e[0m \r\e[100C \e[0m\r\r\n\e[0;1m \e[0mallow provided config object to extend other configs \r\e[100C \r\e[0m\r\r\n\e[J\e[?7h\e[0m\e[?12l\e[?25h\e[?2004l" - - delay: 13 - content: "\e[?1l\e[6n\e[?2004h\e[?25l\e[0m\e[?7l\e[0m\e[J\e[0;38;5;67m?\e[0;1m Is this a BREAKING CHANGE? Correlates with MAJOR in SemVer \e[0m (y/N) \r\e[100C \r\e[67C\e[?7h\e[0m\e[?12l\e[?25h" - - delay: 19 - content: "\e[?25l\e[?7l\e[67D\e[0;38;5;67m?\e[0;1m Is this a BREAKING CHANGE? Correlates with MAJOR in SemVer \e[0m (y/N) \e[0m\e[K\e[0m\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\e[0m \r\e[100C \r\e[14A\e[67C\e[?7h\e[0m\e[?12l\e[?25h" - - delay: 1521 - content: "\e[?25l\e[?7l\e[67D\e[0m\e[J\e[0;38;5;67m?\e[0;1m Is this a BREAKING CHANGE? Correlates with MAJOR in SemVer \e[0;38;5;214;1m Yes\e[0m \r\e[100C \r\e[0m\r\r\n\e[J\e[?7h\e[0m\e[?12l\e[?25h\e[?2004l" - - delay: 15 - content: "\e[?1l\e[6n\e[?2004h\e[?25l\e[0m\e[?7l\e[0m\e[J\e[0;38;5;67m?\e[0;1m Body. Motivation for the change and contrast this with previous behavior:\e[0m \r\e[100C \e[0m\r\r\n\e[0;1m \e[0m \r\e[100C \r\e[C\e[?7h\e[0m\e[?12l\e[?25h" - - delay: 16 - content: "\e[?25l\e[?7l\b\e[0;1m \e[0m \e[0m\e[K\e[0m\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\e[0m \r\e[100C \r\e[12A\e[C\e[?7h\e[0m\e[?12l\e[?25h" - - delay: 5659 - content: "\e[?25l\e[?7l\e[0mextends key in config file is now used for extending other config files \b\e[?7h\e[0m\e[?12l\e[?25h\e[?25l\e[?7l\e[?7h\e[0m\e[?12l\e[?25h" - - delay: 647 - content: "\e[?25l\e[?7l\e[A\e[72D\e[0m\e[J\e[0;38;5;67m?\e[0;1m Body. Motivation for the change and contrast this with previous behavior:\e[0m \r\e[100C \e[0m\r\r\n\e[0;1m \e[0mextends key in config file is now used for extending other config files \r\e[100C \r\e[0m\r\r\n\e[J\e[?7h\e[0m\e[?12l\e[?25h\e[?2004l" - - delay: 10 - content: "\e[?1l\e[6n" - - delay: 5 - content: "\e[?2004h\e[?25l\e[0m\e[?7l\e[0m\e[J\e[0;38;5;67m?\e[0;1m Footer. Information about Breaking Changes and reference issues that this commit closes:\e[0m \r\e[100C \e[0m\r\r\n\e[0;1m \e[0m \r\e[100C \r\e[C\e[?7h\e[0m\e[?12l\e[?25h" - - delay: 22 - content: "\e[?25l\e[?7l\b\e[0;1m \e[0m \e[0m\e[K\e[0m\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\e[0m \r\e[100C \r\e[10A\e[C\e[?7h\e[0m\e[?12l\e[?25h" - - delay: 1583 - content: "\e[?25l\e[?7l\e[A\b\e[0m\e[J\e[0;38;5;67m?\e[0;1m Footer. Information about Breaking Changes and reference issues that this commit closes:\e[0m \r\e[100C \e[0m\r\r\n\e[0;1m \e[0m \r\e[100C \r\e[0m\r\r\n\e[J\e[?7h\e[0m\e[?12l\e[?25h\e[?2004l" - - delay: 6 - content: "[master (root-commit) 76d9660] feat: allow provided config object to extend other configs\r\n 1 file changed, 0 insertions(+), 0 deletions(-)\r\n create mode 100644 fil.py\r\n\r\n\e[32mCommit successful!\e[0m\r\n\e[0m" - - delay: 102 - content: "\e[1;33m\e[0;32m\e[1;34m\e[1;32msantiago\e[1;34m@\e[1;31mhome\e[1;37m in \e[1;34m~/my-project\e[0;36m |master|\e[1;32m\r\r\n\e[1;32m$\e[00m " diff --git a/docs/images/init.tape b/docs/images/init.tape index cd115c6abb..aad8335303 100644 --- a/docs/images/init.tape +++ b/docs/images/init.tape @@ -1,55 +1,6 @@ Output cli_interactive/init.gif -Require cz - -# Use bash for cross-platform compatibility (macOS, Linux, Windows) -Set Shell bash - -Set FontSize 16 -Set Width 878 -Set Height 568 -Set Padding 20 -Set TypingSpeed 50ms - -Set Theme { - "name": "Commitizen", - "black": "#232628", - "red": "#fc4384", - "green": "#b3e33b", - "yellow": "#ffa727", - "blue": "#75dff2", - "magenta": "#ae89fe", - "cyan": "#708387", - "white": "#d5d5d0", - "brightBlack": "#626566", - "brightRed": "#ff7fac", - "brightGreen": "#c8ed71", - "brightYellow": "#ebdf86", - "brightBlue": "#75dff2", - "brightMagenta": "#ae89fe", - "brightCyan": "#b1c6ca", - "brightWhite": "#f9f9f4", - "background": "#1e1e2e", - "foreground": "#afafaf", - "cursor": "#c7c7c7" -} - -# Hide initial shell prompt -Hide - -# Wait for terminal to be ready -Sleep 1s - -# Set a clean, simple prompt -Type "PS1='$ '" -Enter -Sleep 300ms - - -# Create a clean temporary directory for recording -Type "rm -rf /tmp/commitizen-example && mkdir -p /tmp/commitizen-example && cd /tmp/commitizen-example" -Enter -Sleep 500ms +Source shared/base.tape # Clear the screen to start fresh Type "clear" @@ -67,6 +18,7 @@ Enter # Wait for welcome message and first prompt Sleep 500ms Sleep 1s + # Question 1: Please choose a supported config file # Default is .cz.toml, just press Enter Enter @@ -108,4 +60,6 @@ Enter Sleep 1s # Wait for completion message -Sleep 3s +Sleep 1s + +Source shared/cleanup.tape diff --git a/docs/images/shared/base.tape b/docs/images/shared/base.tape new file mode 100644 index 0000000000..08cf5f8849 --- /dev/null +++ b/docs/images/shared/base.tape @@ -0,0 +1,45 @@ +Require cz + +# Use bash for cross-platform compatibility (macOS, Linux, Windows) +Set Shell bash + +Set FontSize 16 +Set Width 878 +Set Height 568 +Set Padding 20 +Set TypingSpeed 50ms + +Set Theme { + "name": "Commitizen", + "black": "#232628", + "red": "#fc4384", + "green": "#b3e33b", + "yellow": "#ffa727", + "blue": "#75dff2", + "magenta": "#ae89fe", + "cyan": "#708387", + "white": "#d5d5d0", + "brightBlack": "#626566", + "brightRed": "#ff7fac", + "brightGreen": "#c8ed71", + "brightYellow": "#ebdf86", + "brightBlue": "#75dff2", + "brightMagenta": "#ae89fe", + "brightCyan": "#b1c6ca", + "brightWhite": "#f9f9f4", + "background": "#1e1e2e", + "foreground": "#afafaf", + "cursor": "#c7c7c7" +} + +Hide + +Sleep 1s + +Type "PS1='$ '" +Enter +Sleep 300ms + +Type "rm -rf /tmp/commitizen-example && mkdir -p /tmp/commitizen-example && cd /tmp/commitizen-example" +Enter +Sleep 500ms diff --git a/docs/images/shared/cleanup.tape b/docs/images/shared/cleanup.tape new file mode 100644 index 0000000000..1d7d3e74c6 --- /dev/null +++ b/docs/images/shared/cleanup.tape @@ -0,0 +1,4 @@ +Hide +Type "cd /tmp && rm -rf /tmp/commitizen-example" +Enter +Sleep 200ms diff --git a/docs/images/shared/git_init.tape b/docs/images/shared/git_init.tape new file mode 100644 index 0000000000..afd195d2e8 --- /dev/null +++ b/docs/images/shared/git_init.tape @@ -0,0 +1,7 @@ +Type "git init" +Enter +Type "git config user.email 'you@example.com'" +Enter +Type "git config user.name 'Your Name'" +Enter +Sleep 500ms diff --git a/docs/images/shortcut_custom.tape b/docs/images/shortcut_custom.tape index 39f1c5838f..54362b4bb1 100644 --- a/docs/images/shortcut_custom.tape +++ b/docs/images/shortcut_custom.tape @@ -1,63 +1,7 @@ Output cli_interactive/shortcut_custom.gif -Require cz - -# Use bash for cross-platform compatibility (macOS, Linux, Windows) -Set Shell bash - -Set FontSize 16 -Set Width 878 -Set Height 568 -Set Padding 20 -Set TypingSpeed 50ms - -Set Theme { - "name": "Commitizen", - "black": "#232628", - "red": "#fc4384", - "green": "#b3e33b", - "yellow": "#ffa727", - "blue": "#75dff2", - "magenta": "#ae89fe", - "cyan": "#708387", - "white": "#d5d5d0", - "brightBlack": "#626566", - "brightRed": "#ff7fac", - "brightGreen": "#c8ed71", - "brightYellow": "#ebdf86", - "brightBlue": "#75dff2", - "brightMagenta": "#ae89fe", - "brightCyan": "#b1c6ca", - "brightWhite": "#f9f9f4", - "background": "#1e1e2e", - "foreground": "#afafaf", - "cursor": "#c7c7c7" -} - -# Hide initial shell prompt -Hide - -# Wait for terminal to be ready -Sleep 1s - -# Set a clean, simple prompt (while hidden) -Type "PS1='$ '" -Enter -Sleep 300ms - -# Create a clean temporary directory for recording -Type "rm -rf /tmp/commitizen-example && mkdir -p /tmp/commitizen-example && cd /tmp/commitizen-example" -Enter -Sleep 500ms - -# Initialize git repository -Type "git init" -Enter -Type "git config user.email 'you@example.com'" -Enter -Type "git config user.name 'Your Name'" -Enter -Sleep 500ms +Source shared/base.tape +Source shared/git_init.tape Type "git checkout -b awesome-docs" Enter @@ -157,3 +101,5 @@ Sleep 500ms # Wait for commit success message Sleep 1s + +Source shared/cleanup.tape diff --git a/docs/images/shortcut_default.tape b/docs/images/shortcut_default.tape index 204a18a473..c7d12111c6 100644 --- a/docs/images/shortcut_default.tape +++ b/docs/images/shortcut_default.tape @@ -1,63 +1,7 @@ Output cli_interactive/shortcut_default.gif -Require cz - -# Use bash for cross-platform compatibility (macOS, Linux, Windows) -Set Shell bash - -Set FontSize 16 -Set Width 878 -Set Height 568 -Set Padding 20 -Set TypingSpeed 50ms - -Set Theme { - "name": "Commitizen", - "black": "#232628", - "red": "#fc4384", - "green": "#b3e33b", - "yellow": "#ffa727", - "blue": "#75dff2", - "magenta": "#ae89fe", - "cyan": "#708387", - "white": "#d5d5d0", - "brightBlack": "#626566", - "brightRed": "#ff7fac", - "brightGreen": "#c8ed71", - "brightYellow": "#ebdf86", - "brightBlue": "#75dff2", - "brightMagenta": "#ae89fe", - "brightCyan": "#b1c6ca", - "brightWhite": "#f9f9f4", - "background": "#1e1e2e", - "foreground": "#afafaf", - "cursor": "#c7c7c7" -} - -# Hide initial shell prompt -Hide - -# Wait for terminal to be ready -Sleep 1s - -# Set a clean, simple prompt (while hidden) -Type "PS1='$ '" -Enter -Sleep 300ms - -# Create a clean temporary directory for recording -Type "rm -rf /tmp/commitizen-example && mkdir -p /tmp/commitizen-example && cd /tmp/commitizen-example" -Enter -Sleep 500ms - -# Initialize git repository -Type "git init" -Enter -Type "git config user.email 'you@example.com'" -Enter -Type "git config user.name 'Your Name'" -Enter -Sleep 500ms +Source shared/base.tape +Source shared/git_init.tape Type "git checkout -b awesome-docs" Enter @@ -66,16 +10,12 @@ Sleep 500ms # Initialize commitizen config with shortcuts enabled Type `cat > pyproject.toml << 'EOF'` Enter -Sleep 100ms Type `[tool.commitizen]` Enter -Sleep 100ms Type `name = "cz_conventional_commits"` Enter -Sleep 100ms Type `use_shortcuts = true` Enter -Sleep 100ms Type "EOF" Enter Sleep 300ms @@ -136,3 +76,5 @@ Sleep 500ms # Wait for commit success message Sleep 1s + +Source shared/cleanup.tape diff --git a/pyproject.toml b/pyproject.toml index 9d08ffac0e..314ecc9eaf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "commitizen" -version = "4.13.10" +version = "4.15.0" description = "Python commitizen client tool" authors = [{ name = "Santiago Fraire", email = "santiwilly@gmail.com" }] maintainers = [ diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index 951565d05a..021e242913 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -1537,3 +1537,18 @@ def test_changelog_merge_preserves_header( out = changelog_path.read_text() file_regression.check(out, extension=".md") + + +@pytest.mark.freeze_time("2025-01-01") +def test_bump_allow_no_commit_issue( + tmp_commitizen_project_initial, + util: UtilFixture, +) -> None: + """Issue #1866: bump command called changelog command with allow_no_commit=True, but changelog command raised NoCommitsFoundError""" + tmp_commitizen_project_initial( + version="1.0.0", config_extra="update_changelog_on_bump = true\n" + ) + util.run_cli("bump", "--yes", "--allow-no-commit", "--prerelease", "beta") + util.run_cli( + "bump", "--allow-no-commit", "--prerelease", "rc" + ) # Should not fail when changelog generation runs with no new commits diff --git a/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_10_version_.txt b/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_10_version_.txt index 5085d0fd3c..824f6e9fcb 100644 --- a/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_10_version_.txt +++ b/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_10_version_.txt @@ -1,18 +1,29 @@ -usage: cz version [-h] [-r | -p | -c | -v] [--major | --minor | --tag] +usage: cz version [-h] [-r | -p | -c | -v] + [--major | --minor | --tag | --patch | --next [{USE_GIT_COMMITS,NONE,PATCH,MINOR,MAJOR}]] + [MANUAL_VERSION] Get the version of the installed commitizen or the current project (default: installed commitizen) +positional arguments: + MANUAL_VERSION Use the version provided instead of the version from + the project. Can be used to test the selected version + scheme. + options: - -h, --help show this help message and exit - -r, --report Output the system information for reporting bugs. - -p, --project Output the version of the current project. - -c, --commitizen Output the version of the installed commitizen. - -v, --verbose Output the version of both the installed commitizen and - the current project. - --major Output just the major version. Must be used with --project - or --verbose. - --minor Output just the minor version. Must be used with --project - or --verbose. - --tag get the version with tag prefix. Need to be used with - --project or --verbose. + -h, --help show this help message and exit + -r, --report Output the system information for reporting bugs. + -p, --project Output the version of the current project. + -c, --commitizen Output the version of the installed commitizen. + -v, --verbose Output the version of both the installed commitizen + and the current project. + --major Output just the major version. Must be used with + MANUAL_VERSION, --project, or --verbose. + --minor Output just the minor version. Must be used with + MANUAL_VERSION, --project, or --verbose. + --tag get the version with tag prefix. Need to be used with + --project or --verbose. + --patch Output the patch version only. Must be used with + MANUAL_VERSION, --project, or --verbose. + --next [{USE_GIT_COMMITS,NONE,PATCH,MINOR,MAJOR}] + Output the next version. diff --git a/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_11_version_.txt b/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_11_version_.txt index 5085d0fd3c..824f6e9fcb 100644 --- a/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_11_version_.txt +++ b/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_11_version_.txt @@ -1,18 +1,29 @@ -usage: cz version [-h] [-r | -p | -c | -v] [--major | --minor | --tag] +usage: cz version [-h] [-r | -p | -c | -v] + [--major | --minor | --tag | --patch | --next [{USE_GIT_COMMITS,NONE,PATCH,MINOR,MAJOR}]] + [MANUAL_VERSION] Get the version of the installed commitizen or the current project (default: installed commitizen) +positional arguments: + MANUAL_VERSION Use the version provided instead of the version from + the project. Can be used to test the selected version + scheme. + options: - -h, --help show this help message and exit - -r, --report Output the system information for reporting bugs. - -p, --project Output the version of the current project. - -c, --commitizen Output the version of the installed commitizen. - -v, --verbose Output the version of both the installed commitizen and - the current project. - --major Output just the major version. Must be used with --project - or --verbose. - --minor Output just the minor version. Must be used with --project - or --verbose. - --tag get the version with tag prefix. Need to be used with - --project or --verbose. + -h, --help show this help message and exit + -r, --report Output the system information for reporting bugs. + -p, --project Output the version of the current project. + -c, --commitizen Output the version of the installed commitizen. + -v, --verbose Output the version of both the installed commitizen + and the current project. + --major Output just the major version. Must be used with + MANUAL_VERSION, --project, or --verbose. + --minor Output just the minor version. Must be used with + MANUAL_VERSION, --project, or --verbose. + --tag get the version with tag prefix. Need to be used with + --project or --verbose. + --patch Output the patch version only. Must be used with + MANUAL_VERSION, --project, or --verbose. + --next [{USE_GIT_COMMITS,NONE,PATCH,MINOR,MAJOR}] + Output the next version. diff --git a/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_12_version_.txt b/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_12_version_.txt index 5085d0fd3c..824f6e9fcb 100644 --- a/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_12_version_.txt +++ b/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_12_version_.txt @@ -1,18 +1,29 @@ -usage: cz version [-h] [-r | -p | -c | -v] [--major | --minor | --tag] +usage: cz version [-h] [-r | -p | -c | -v] + [--major | --minor | --tag | --patch | --next [{USE_GIT_COMMITS,NONE,PATCH,MINOR,MAJOR}]] + [MANUAL_VERSION] Get the version of the installed commitizen or the current project (default: installed commitizen) +positional arguments: + MANUAL_VERSION Use the version provided instead of the version from + the project. Can be used to test the selected version + scheme. + options: - -h, --help show this help message and exit - -r, --report Output the system information for reporting bugs. - -p, --project Output the version of the current project. - -c, --commitizen Output the version of the installed commitizen. - -v, --verbose Output the version of both the installed commitizen and - the current project. - --major Output just the major version. Must be used with --project - or --verbose. - --minor Output just the minor version. Must be used with --project - or --verbose. - --tag get the version with tag prefix. Need to be used with - --project or --verbose. + -h, --help show this help message and exit + -r, --report Output the system information for reporting bugs. + -p, --project Output the version of the current project. + -c, --commitizen Output the version of the installed commitizen. + -v, --verbose Output the version of both the installed commitizen + and the current project. + --major Output just the major version. Must be used with + MANUAL_VERSION, --project, or --verbose. + --minor Output just the minor version. Must be used with + MANUAL_VERSION, --project, or --verbose. + --tag get the version with tag prefix. Need to be used with + --project or --verbose. + --patch Output the patch version only. Must be used with + MANUAL_VERSION, --project, or --verbose. + --next [{USE_GIT_COMMITS,NONE,PATCH,MINOR,MAJOR}] + Output the next version. diff --git a/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_13_version_.txt b/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_13_version_.txt index 5085d0fd3c..51c985679f 100644 --- a/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_13_version_.txt +++ b/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_13_version_.txt @@ -1,18 +1,29 @@ -usage: cz version [-h] [-r | -p | -c | -v] [--major | --minor | --tag] +usage: cz version [-h] [-r | -p | -c | -v] [--major | --minor | --tag | + --patch | --next [{USE_GIT_COMMITS,NONE,PATCH,MINOR,MAJOR}]] + [MANUAL_VERSION] Get the version of the installed commitizen or the current project (default: installed commitizen) +positional arguments: + MANUAL_VERSION Use the version provided instead of the version from + the project. Can be used to test the selected version + scheme. + options: - -h, --help show this help message and exit - -r, --report Output the system information for reporting bugs. - -p, --project Output the version of the current project. - -c, --commitizen Output the version of the installed commitizen. - -v, --verbose Output the version of both the installed commitizen and - the current project. - --major Output just the major version. Must be used with --project - or --verbose. - --minor Output just the minor version. Must be used with --project - or --verbose. - --tag get the version with tag prefix. Need to be used with - --project or --verbose. + -h, --help show this help message and exit + -r, --report Output the system information for reporting bugs. + -p, --project Output the version of the current project. + -c, --commitizen Output the version of the installed commitizen. + -v, --verbose Output the version of both the installed commitizen + and the current project. + --major Output just the major version. Must be used with + MANUAL_VERSION, --project, or --verbose. + --minor Output just the minor version. Must be used with + MANUAL_VERSION, --project, or --verbose. + --tag get the version with tag prefix. Need to be used with + --project or --verbose. + --patch Output the patch version only. Must be used with + MANUAL_VERSION, --project, or --verbose. + --next [{USE_GIT_COMMITS,NONE,PATCH,MINOR,MAJOR}] + Output the next version. diff --git a/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_14_version_.txt b/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_14_version_.txt index 5085d0fd3c..51c985679f 100644 --- a/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_14_version_.txt +++ b/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_14_version_.txt @@ -1,18 +1,29 @@ -usage: cz version [-h] [-r | -p | -c | -v] [--major | --minor | --tag] +usage: cz version [-h] [-r | -p | -c | -v] [--major | --minor | --tag | + --patch | --next [{USE_GIT_COMMITS,NONE,PATCH,MINOR,MAJOR}]] + [MANUAL_VERSION] Get the version of the installed commitizen or the current project (default: installed commitizen) +positional arguments: + MANUAL_VERSION Use the version provided instead of the version from + the project. Can be used to test the selected version + scheme. + options: - -h, --help show this help message and exit - -r, --report Output the system information for reporting bugs. - -p, --project Output the version of the current project. - -c, --commitizen Output the version of the installed commitizen. - -v, --verbose Output the version of both the installed commitizen and - the current project. - --major Output just the major version. Must be used with --project - or --verbose. - --minor Output just the minor version. Must be used with --project - or --verbose. - --tag get the version with tag prefix. Need to be used with - --project or --verbose. + -h, --help show this help message and exit + -r, --report Output the system information for reporting bugs. + -p, --project Output the version of the current project. + -c, --commitizen Output the version of the installed commitizen. + -v, --verbose Output the version of both the installed commitizen + and the current project. + --major Output just the major version. Must be used with + MANUAL_VERSION, --project, or --verbose. + --minor Output just the minor version. Must be used with + MANUAL_VERSION, --project, or --verbose. + --tag get the version with tag prefix. Need to be used with + --project or --verbose. + --patch Output the patch version only. Must be used with + MANUAL_VERSION, --project, or --verbose. + --next [{USE_GIT_COMMITS,NONE,PATCH,MINOR,MAJOR}] + Output the next version. diff --git a/tests/commands/test_version_command.py b/tests/commands/test_version_command.py index dce710ac84..099e7110e7 100644 --- a/tests/commands/test_version_command.py +++ b/tests/commands/test_version_command.py @@ -20,13 +20,13 @@ def test_version_for_showing_project_version_error(config, capsys): def test_version_for_showing_project_version(config, capsys): - config.settings["version"] = "v0.0.1" + config.settings["version"] = "0.0.1" commands.Version( config, {"project": True}, )() captured = capsys.readouterr() - assert "v0.0.1" in captured.out + assert "0.0.1" in captured.out @pytest.mark.parametrize("project", [True, False]) @@ -50,14 +50,14 @@ def test_version_for_showing_both_versions_no_project(config, capsys): def test_version_for_showing_both_versions(config, capsys): - config.settings["version"] = "v0.0.1" + config.settings["version"] = "0.0.1" commands.Version( config, {"verbose": True}, )() captured = capsys.readouterr() expected_out = ( - f"Installed Commitizen Version: {__version__}\nProject Version: v0.0.1" + f"Installed Commitizen Version: {__version__}\nProject Version: 0.0.1" ) assert expected_out in captured.out @@ -147,20 +147,30 @@ def test_version_just_minor(config, capsys, version: str, expected_version: str) assert expected_version == captured.out -@pytest.mark.parametrize("argument", ["major", "minor"]) -def test_version_just_major_error_no_project(config, capsys, argument: str): - commands.Version( - config, - { - argument: True, # type: ignore[misc] - }, - )() +@pytest.mark.parametrize( + ("args", "expected_error"), + [ + ( + {"major": True}, + "can only be used with MANUAL_VERSION, --project or --verbose.", + ), + ( + {"minor": True}, + "can only be used with MANUAL_VERSION, --project or --verbose.", + ), + ( + {"patch": True}, + "can only be used with MANUAL_VERSION, --project or --verbose.", + ), + ({"tag": True}, "Tag can only be used with --project or --verbose."), + ], +) +def test_version_invalid_combinations(config, capsys, args: dict, expected_error: str): + """Test that certain flag combinations produce errors.""" + commands.Version(config, args)() # type: ignore[arg-type] captured = capsys.readouterr() assert not captured.out - assert ( - "Major or minor version can only be used with --project or --verbose." - in captured.err - ) + assert expected_error in captured.err @pytest.mark.parametrize( @@ -189,14 +199,100 @@ def test_version_with_tag_format( assert captured.out == expected_output -def test_version_tag_without_project_error(config, capsys): - """Test --tag requires --project or --verbose""" +@pytest.mark.parametrize( + ("next_increment", "current_version", "expected_version"), + [ + ("MAJOR", "1.1.0", "2.0.0"), + ("MAJOR", "1.0.0", "2.0.0"), + ("MAJOR", "0.0.1", "1.0.0"), + ("MINOR", "1.1.0", "1.2.0"), + ("MINOR", "1.0.0", "1.1.0"), + ("MINOR", "0.0.1", "0.1.0"), + ("PATCH", "1.1.0", "1.1.1"), + ("PATCH", "1.0.0", "1.0.1"), + ("PATCH", "0.0.1", "0.0.2"), + ("NONE", "1.0.0", "1.0.0"), + ], +) +def test_next_version( + config, capsys, next_increment: str, current_version: str, expected_version: str +): + config.settings["version"] = current_version + for project in (True, False): + commands.Version( + config, + { + "next": next_increment, + "project": project, + }, + )() + captured = capsys.readouterr() + assert expected_version in captured.out + + # Use the same settings to test the manual version + commands.Version( + config, + { + "manual_version": current_version, + "next": next_increment, + }, + )() + captured = capsys.readouterr() + assert expected_version in captured.out + + +def test_next_version_invalid_version(config, capsys): commands.Version( config, { - "tag": True, + "manual_version": "INVALID", }, )() captured = capsys.readouterr() - assert not captured.out - assert "Tag can only be used with --project or --verbose." in captured.err + assert "Invalid version: 'INVALID'" in captured.err + + +@pytest.mark.parametrize( + ("version", "expected_version"), + [ + ("1.0.0", "0\n"), + ("2.1.3", "3\n"), + ("0.0.1", "1\n"), + ("0.1.0", "0\n"), + ], +) +def test_version_just_patch(config, capsys, version: str, expected_version: str): + config.settings["version"] = version + commands.Version( + config, + { + "project": True, + "patch": True, + }, + )() + captured = capsys.readouterr() + assert expected_version == captured.out + + +def test_version_unknown_scheme(config, capsys): + config.settings["version"] = "1.0.0" + config.settings["version_scheme"] = "not_a_registered_scheme_name_xyz" + commands.Version(config, {"project": True})() + captured = capsys.readouterr() + assert "Unknown version scheme." in captured.err + + +def test_version_use_git_commits_not_implemented(config, capsys): + config.settings["version"] = "1.0.0" + commands.Version( + config, + {"project": True, "next": "USE_GIT_COMMITS"}, + )() + captured = capsys.readouterr() + assert "USE_GIT_COMMITS is not implemented" in captured.err + + +def test_version_no_arguments_shows_commitizen_version(config, capsys): + commands.Version(config, {})() + captured = capsys.readouterr() + assert captured.out.strip() == __version__ diff --git a/tests/test_version_increment.py b/tests/test_version_increment.py new file mode 100644 index 0000000000..5832140a81 --- /dev/null +++ b/tests/test_version_increment.py @@ -0,0 +1,25 @@ +import pytest + +from commitizen.version_increment import VersionIncrement + + +@pytest.mark.parametrize( + ("value", "expected"), + [ + ("MAJOR", VersionIncrement.MAJOR), + ("MINOR", VersionIncrement.MINOR), + ("PATCH", VersionIncrement.PATCH), + ("NONE", VersionIncrement.NONE), + ("not_a_valid_name", VersionIncrement.NONE), + (None, VersionIncrement.NONE), + (123, VersionIncrement.NONE), + ], +) +def test_version_increment_from_value( + value: object, expected: VersionIncrement +) -> None: + assert VersionIncrement.from_value(value) == expected + + +def test_version_increment_str() -> None: + assert str(VersionIncrement.PATCH) == "PATCH" diff --git a/uv.lock b/uv.lock index bcaf39df90..a72b30bad3 100644 --- a/uv.lock +++ b/uv.lock @@ -203,7 +203,7 @@ wheels = [ [[package]] name = "commitizen" -version = "4.13.10" +version = "4.15.0" source = { editable = "." } dependencies = [ { name = "argcomplete" }, @@ -589,14 +589,14 @@ wheels = [ [[package]] name = "gitpython" -version = "3.1.46" +version = "3.1.47" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "gitdb" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/df/b5/59d16470a1f0dfe8c793f9ef56fd3826093fc52b3bd96d6b9d6c26c7e27b/gitpython-3.1.46.tar.gz", hash = "sha256:400124c7d0ef4ea03f7310ac2fbf7151e09ff97f2a3288d64a440c584a29c37f", size = 215371, upload-time = "2026-01-01T15:37:32.073Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c1/bd/50db468e9b1310529a19fce651b3b0e753b5c07954d486cba31bbee9a5d5/gitpython-3.1.47.tar.gz", hash = "sha256:dba27f922bd2b42cb54c87a8ab3cb6beb6bf07f3d564e21ac848913a05a8a3cd", size = 216978, upload-time = "2026-04-22T02:44:44.059Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/09/e21df6aef1e1ffc0c816f0522ddc3f6dcded766c3261813131c78a704470/gitpython-3.1.46-py3-none-any.whl", hash = "sha256:79812ed143d9d25b6d176a10bb511de0f9c67b1fa641d82097b0ab90398a2058", size = 208620, upload-time = "2026-01-01T15:37:30.574Z" }, + { url = "https://files.pythonhosted.org/packages/f2/c5/a1bc0996af85757903cf2bf444a7824e68e0035ce63fb41d6f76f9def68b/gitpython-3.1.47-py3-none-any.whl", hash = "sha256:489f590edfd6d20571b2c0e72c6a6ac6915ee8b8cd04572330e3842207a78905", size = 209547, upload-time = "2026-04-22T02:44:41.271Z" }, ] [[package]] @@ -1313,7 +1313,7 @@ wheels = [ [[package]] name = "pytest" -version = "9.0.2" +version = "9.0.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -1324,9 +1324,9 @@ dependencies = [ { name = "pygments" }, { name = "tomli", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" }, + { url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" }, ] [[package]] @@ -1830,28 +1830,28 @@ wheels = [ [[package]] name = "uv" -version = "0.11.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/88/ed/f11c558e8d2e02fba6057dacd9e92a71557359a80bd5355452310b89f40f/uv-0.11.3.tar.gz", hash = "sha256:6a6fcaf1fec28bbbdf0dfc5a0a6e34be4cea08c6287334b08c24cf187300f20d", size = 4027684, upload-time = "2026-04-01T21:47:22.096Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/93/4f04c49fd6046a18293de341d795ded3b9cbd95db261d687e26db0f11d1e/uv-0.11.3-py3-none-linux_armv6l.whl", hash = "sha256:deb533e780e8181e0859c68c84f546620072cd1bd827b38058cb86ebfba9bb7d", size = 23337334, upload-time = "2026-04-01T21:46:47.545Z" }, - { url = "https://files.pythonhosted.org/packages/7a/4b/c44fd3fbc80ac2f81e2ad025d235c820aac95b228076da85be3f5d509781/uv-0.11.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d2b3b0fa1693880ca354755c216ae1c65dd938a4f1a24374d0c3f4b9538e0ee6", size = 22940169, upload-time = "2026-04-01T21:47:32.72Z" }, - { url = "https://files.pythonhosted.org/packages/ba/c7/7d01be259a47d42fa9e80adcb7a829d81e7c376aa8fa1b714f31d7dfc226/uv-0.11.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:71f5d0b9e73daa5d8a7e2db3fa2e22a4537d24bb4fe78130db797280280d4edc", size = 21473579, upload-time = "2026-04-01T21:47:25.063Z" }, - { url = "https://files.pythonhosted.org/packages/9a/71/fffcd890290a4639a3799cf3f3e87947c10d1b0de19eba3cf837cb418dd8/uv-0.11.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:55ba578752f29a3f2b22879b22a162edad1454e3216f3ca4694fdbd4093a6822", size = 23132691, upload-time = "2026-04-01T21:47:44.587Z" }, - { url = "https://files.pythonhosted.org/packages/d1/7b/1ac9e1f753a19b6252434f0bbe96efdcc335cd74677f4c6f431a7c916114/uv-0.11.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:3b1fe09d5e1d8e19459cd28d7825a3b66ef147b98328345bad6e17b87c4fea48", size = 22955764, upload-time = "2026-04-01T21:46:51.721Z" }, - { url = "https://files.pythonhosted.org/packages/ff/51/1a6010a681a3c3e0a8ec99737ba2d0452194dc372a5349a9267873261c02/uv-0.11.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:088165b9eed981d2c2a58566cc75dd052d613e47c65e2416842d07308f793a6f", size = 22966245, upload-time = "2026-04-01T21:47:07.403Z" }, - { url = "https://files.pythonhosted.org/packages/38/74/1a1b0712daead7e85f56d620afe96fe166a04b615524c14027b4edd39b82/uv-0.11.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef0ae8ee2988928092616401ec7f473612b8e9589fe1567452c45dbc56840f85", size = 24623370, upload-time = "2026-04-01T21:47:03.59Z" }, - { url = "https://files.pythonhosted.org/packages/b6/62/5c3aa5e7bd2744810e50ad72a5951386ec84a513e109b1b5cb7ec442f3b6/uv-0.11.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6708827ecb846d00c5512a7e4dc751c2e27b92e9bd55a0be390561ac68930c32", size = 25142735, upload-time = "2026-04-01T21:46:55.756Z" }, - { url = "https://files.pythonhosted.org/packages/88/ab/6266a04980e0877af5518762adfe23a0c1ab0b801ae3099a2e7b74e34411/uv-0.11.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8df030ea7563e99c09854e1bc82ab743dfa2d0ba18976e6861979cb40d04dba7", size = 24512083, upload-time = "2026-04-01T21:46:43.531Z" }, - { url = "https://files.pythonhosted.org/packages/4e/be/7c66d350f833eb437f9aa0875655cc05e07b441e3f4a770f8bced56133f7/uv-0.11.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fde893b5ab9f6997fe357138e794bac09d144328052519fbbe2e6f72145e457", size = 24589293, upload-time = "2026-04-01T21:47:11.379Z" }, - { url = "https://files.pythonhosted.org/packages/18/4f/22ada41564a8c8c36653fc86f89faae4c54a4cdd5817bda53764a3eb352d/uv-0.11.3-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:45006bcd9e8718248a23ab81448a5beb46a72a9dd508e3212d6f3b8c63aeb88a", size = 23214854, upload-time = "2026-04-01T21:46:59.491Z" }, - { url = "https://files.pythonhosted.org/packages/aa/18/8669840657fea9fd668739dec89643afe1061c023c1488228b02f79a2399/uv-0.11.3-py3-none-manylinux_2_31_riscv64.musllinux_1_1_riscv64.whl", hash = "sha256:089b9d338a64463956b6fee456f03f73c9a916479bdb29009600781dc1e1d2a7", size = 23914434, upload-time = "2026-04-01T21:47:29.164Z" }, - { url = "https://files.pythonhosted.org/packages/08/0d/c59f24b3a1ae5f377aa6fd9653562a0968ea6be946fe35761871a0072919/uv-0.11.3-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:3ff461335888336467402cc5cb792c911df95dd0b52e369182cfa4c902bb21f4", size = 23971481, upload-time = "2026-04-01T21:47:48.551Z" }, - { url = "https://files.pythonhosted.org/packages/66/7d/f83ed79921310ef216ed6d73fcd3822dff4b66749054fb97e09b7bd5901e/uv-0.11.3-py3-none-musllinux_1_1_i686.whl", hash = "sha256:a62e29277efd39c35caf4a0fe739c4ebeb14d4ce4f02271f3f74271d608061ff", size = 23784797, upload-time = "2026-04-01T21:47:40.588Z" }, - { url = "https://files.pythonhosted.org/packages/35/19/3ff3539c44ca7dc2aa87b021d4a153ba6a72866daa19bf91c289e4318f95/uv-0.11.3-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:ebccdcdebd2b288925f0f7c18c39705dc783175952eacaf94912b01d3b381b86", size = 24794606, upload-time = "2026-04-01T21:47:36.814Z" }, - { url = "https://files.pythonhosted.org/packages/79/e5/e676454bb7cc5dcf5c4637ed3ef0ff97309d84a149b832a4dea53f04c0ab/uv-0.11.3-py3-none-win32.whl", hash = "sha256:794aae3bab141eafbe37c51dc5dd0139658a755a6fa9cc74d2dbd7c71dcc4826", size = 22573432, upload-time = "2026-04-01T21:47:15.143Z" }, - { url = "https://files.pythonhosted.org/packages/ff/a0/95d22d524bd3b4708043d65035f02fc9656e5fb6e0aaef73510313b1641b/uv-0.11.3-py3-none-win_amd64.whl", hash = "sha256:68fda574f2e5e7536a2b747dcea88329a71aad7222317e8f4717d0af8f99fbd4", size = 24969508, upload-time = "2026-04-01T21:47:19.515Z" }, - { url = "https://files.pythonhosted.org/packages/f8/6d/3f0b90a06e8c4594e11f813651756d6896de6dd4461f554fd7e4984a1c4f/uv-0.11.3-py3-none-win_arm64.whl", hash = "sha256:92ffc4d521ab2c4738ef05d8ef26f2750e26d31f3ad5611cdfefc52445be9ace", size = 23488911, upload-time = "2026-04-01T21:47:52.427Z" }, +version = "0.11.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dd/f3/8aceeab67ea69805293ab290e7ca8cc1b61a064d28b8a35c76d8eba063dd/uv-0.11.6.tar.gz", hash = "sha256:e3b21b7e80024c95ff339fcd147ac6fc3dd98d3613c9d45d3a1f4fd1057f127b", size = 4073298, upload-time = "2026-04-09T12:09:01.738Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/fe/4b61a3d5ad9d02e8a4405026ccd43593d7044598e0fa47d892d4dafe44c9/uv-0.11.6-py3-none-linux_armv6l.whl", hash = "sha256:ada04dcf89ddea5b69d27ac9cdc5ef575a82f90a209a1392e930de504b2321d6", size = 23780079, upload-time = "2026-04-09T12:08:56.609Z" }, + { url = "https://files.pythonhosted.org/packages/52/db/d27519a9e1a5ffee9d71af1a811ad0e19ce7ab9ae815453bef39dd479389/uv-0.11.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5be013888420f96879c6e0d3081e7bcf51b539b034a01777041934457dfbedf3", size = 23214721, upload-time = "2026-04-09T12:09:32.228Z" }, + { url = "https://files.pythonhosted.org/packages/a6/8f/4399fa8b882bd7e0efffc829f73ab24d117d490a93e6bc7104a50282b854/uv-0.11.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:ffa5dc1cbb52bdce3b8447e83d1601a57ad4da6b523d77d4b47366db8b1ceb18", size = 21750109, upload-time = "2026-04-09T12:09:24.357Z" }, + { url = "https://files.pythonhosted.org/packages/32/07/5a12944c31c3dda253632da7a363edddb869ed47839d4d92a2dc5f546c93/uv-0.11.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:bfb107b4dade1d2c9e572992b06992d51dd5f2136eb8ceee9e62dd124289e825", size = 23551146, upload-time = "2026-04-09T12:09:10.439Z" }, + { url = "https://files.pythonhosted.org/packages/79/5b/2ec8b0af80acd1016ed596baf205ddc77b19ece288473b01926c4a9cf6db/uv-0.11.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:9e2fe7ce12161d8016b7deb1eaad7905a76ff7afec13383333ca75e0c4b5425d", size = 23331192, upload-time = "2026-04-09T12:09:34.792Z" }, + { url = "https://files.pythonhosted.org/packages/62/7d/eea35935f2112b21c296a3e42645f3e4b1aa8bcd34dcf13345fbd55134b7/uv-0.11.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7ed9c6f70c25e8dfeedddf4eddaf14d353f5e6b0eb43da9a14d3a1033d51d915", size = 23337686, upload-time = "2026-04-09T12:09:18.522Z" }, + { url = "https://files.pythonhosted.org/packages/21/47/2584f5ab618f6ebe9bdefb2f765f2ca8540e9d739667606a916b35449eec/uv-0.11.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d68a013e609cebf82077cbeeb0809ed5e205257814273bfd31e02fc0353bbfc2", size = 25008139, upload-time = "2026-04-09T12:09:03.983Z" }, + { url = "https://files.pythonhosted.org/packages/95/81/497ae5c1d36355b56b97dc59f550c7e89d0291c163a3f203c6f341dff195/uv-0.11.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93f736dddca03dae732c6fdea177328d3bc4bf137c75248f3d433c57416a4311", size = 25712458, upload-time = "2026-04-09T12:09:07.598Z" }, + { url = "https://files.pythonhosted.org/packages/3c/1c/74083238e4fab2672b63575b9008f1ea418b02a714bcfcf017f4f6a309b6/uv-0.11.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e96a66abe53fced0e3389008b8d2eff8278cfa8bb545d75631ae8ceb9c929aba", size = 24915507, upload-time = "2026-04-09T12:08:50.892Z" }, + { url = "https://files.pythonhosted.org/packages/5a/ee/e14fe10ba455a823ed18233f12de6699a601890905420b5c504abf115116/uv-0.11.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b096311b2743b228df911a19532b3f18fa420bf9530547aecd6a8e04bbfaccd", size = 24971011, upload-time = "2026-04-09T12:08:54.016Z" }, + { url = "https://files.pythonhosted.org/packages/3c/a1/7b9c83eaadf98e343317ff6384a7227a4855afd02cdaf9696bcc71ee6155/uv-0.11.6-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:904d537b4a6e798015b4a64ff5622023bd4601b43b6cd1e5f423d63471f5e948", size = 23640234, upload-time = "2026-04-09T12:09:15.735Z" }, + { url = "https://files.pythonhosted.org/packages/d6/51/75ccdd23e76ff1703b70eb82881cd5b4d2a954c9679f8ef7e0136ef2cfab/uv-0.11.6-py3-none-manylinux_2_31_riscv64.musllinux_1_1_riscv64.whl", hash = "sha256:4ed8150c26b5e319381d75ae2ce6aba1e9c65888f4850f4e3b3fa839953c90a5", size = 24452664, upload-time = "2026-04-09T12:09:26.875Z" }, + { url = "https://files.pythonhosted.org/packages/4d/86/ace80fe47d8d48b5e3b5aee0b6eb1a49deaacc2313782870250b3faa36f5/uv-0.11.6-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:1c9218c8d4ac35ca6e617fb0951cc0ab2d907c91a6aea2617de0a5494cf162c0", size = 24494599, upload-time = "2026-04-09T12:09:37.368Z" }, + { url = "https://files.pythonhosted.org/packages/05/2d/4b642669b56648194f026de79bc992cbfc3ac2318b0a8d435f3c284934e8/uv-0.11.6-py3-none-musllinux_1_1_i686.whl", hash = "sha256:9e211c83cc890c569b86a4183fcf5f8b6f0c7adc33a839b699a98d30f1310d3a", size = 24159150, upload-time = "2026-04-09T12:09:13.17Z" }, + { url = "https://files.pythonhosted.org/packages/ae/24/7eecd76fe983a74fed1fc700a14882e70c4e857f1d562a9f2303d4286c12/uv-0.11.6-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:d2a1d2089afdf117ad19a4c1dd36b8189c00ae1ad4135d3bfbfced82342595cf", size = 25164324, upload-time = "2026-04-09T12:08:59.56Z" }, + { url = "https://files.pythonhosted.org/packages/27/e0/bbd4ba7c2e5067bbba617d87d306ec146889edaeeaa2081d3e122178ca08/uv-0.11.6-py3-none-win32.whl", hash = "sha256:6e8344f38fa29f85dcfd3e62dc35a700d2448f8e90381077ef393438dcd5012e", size = 22865693, upload-time = "2026-04-09T12:09:21.415Z" }, + { url = "https://files.pythonhosted.org/packages/a5/33/1983ce113c538a856f2d620d16e39691962ecceef091a84086c5785e32e5/uv-0.11.6-py3-none-win_amd64.whl", hash = "sha256:a28bea69c1186303d1200f155c7a28c449f8a4431e458fcf89360cc7ef546e40", size = 25371258, upload-time = "2026-04-09T12:09:40.52Z" }, + { url = "https://files.pythonhosted.org/packages/35/01/be0873f44b9c9bc250fcbf263367fcfc1f59feab996355bcb6b52fff080d/uv-0.11.6-py3-none-win_arm64.whl", hash = "sha256:a78f6d64b9950e24061bc7ec7f15ff8089ad7f5a976e7b65fcadce58fe02f613", size = 23869585, upload-time = "2026-04-09T12:09:29.425Z" }, ] [[package]]