From 839d10829fe6d541653176067262b2c47a634a7f Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 31 Jan 2025 22:39:34 +0800 Subject: [PATCH 1/3] feat(providers): add uv_provider closes: #1349 --- commitizen/providers/uv_provider.py | 41 +++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 commitizen/providers/uv_provider.py diff --git a/commitizen/providers/uv_provider.py b/commitizen/providers/uv_provider.py new file mode 100644 index 000000000..36c8a49ad --- /dev/null +++ b/commitizen/providers/uv_provider.py @@ -0,0 +1,41 @@ +from __future__ import annotations + +from pathlib import Path +from typing import TYPE_CHECKING + +import tomlkit + +from commitizen.providers.base_provider import TomlProvider + +if TYPE_CHECKING: + import tomlkit.items + + +class UvProvider(TomlProvider): + """ + uv.lock and pyproject.tom version management + """ + + filename = "pyproject.toml" + lock_filename = "uv.lock" + + @property + def lock_file(self) -> Path: + return Path() / self.lock_filename + + def set_version(self, version: str) -> None: + super().set_version(version) + self.set_lock_version(version) + + def set_lock_version(self, version: str) -> None: + pyproject_toml_content = tomlkit.parse(self.file.read_text()) + project_name = pyproject_toml_content["project"]["name"] # type: ignore[index] + + document = tomlkit.parse(self.lock_file.read_text()) + + packages: tomlkit.items.AoT = document["package"] # type: ignore[assignment] + for i, package in enumerate(packages): + if package["name"] == project_name: + document["package"][i]["version"] = version # type: ignore[index] + break + self.lock_file.write_text(tomlkit.dumps(document)) From ebff7927f7877d747b67ce7518c549cfabc2be2e Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Tue, 18 Feb 2025 21:29:30 +0800 Subject: [PATCH 2/3] test(providers/uv_provider): add test case test_uv_provider --- commitizen/providers/__init__.py | 2 + pyproject.toml | 21 ++-- tests/providers/test_uv_provider.py | 97 +++++++++++++++++++ .../test_uv_provider/test_uv_provider.lock | 42 ++++++++ .../test_uv_provider/test_uv_provider.toml | 8 ++ 5 files changed, 159 insertions(+), 11 deletions(-) create mode 100644 tests/providers/test_uv_provider.py create mode 100644 tests/providers/test_uv_provider/test_uv_provider.lock create mode 100644 tests/providers/test_uv_provider/test_uv_provider.toml diff --git a/commitizen/providers/__init__.py b/commitizen/providers/__init__.py index 3fd4ab1bf..9cf4ce592 100644 --- a/commitizen/providers/__init__.py +++ b/commitizen/providers/__init__.py @@ -18,6 +18,7 @@ from commitizen.providers.pep621_provider import Pep621Provider from commitizen.providers.poetry_provider import PoetryProvider from commitizen.providers.scm_provider import ScmProvider +from commitizen.providers.uv_provider import UvProvider __all__ = [ "get_provider", @@ -28,6 +29,7 @@ "Pep621Provider", "PoetryProvider", "ScmProvider", + "UvProvider", ] PROVIDER_ENTRYPOINT = "commitizen.provider" diff --git a/pyproject.toml b/pyproject.toml index c63fe4d23..416032db1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,6 +74,7 @@ npm = "commitizen.providers:NpmProvider" pep621 = "commitizen.providers:Pep621Provider" poetry = "commitizen.providers:PoetryProvider" scm = "commitizen.providers:ScmProvider" +uv = "commitizen.providers:UvProvider" [project.entry-points."commitizen.scheme"] pep440 = "commitizen.version_schemes:Pep440" @@ -165,9 +166,7 @@ omit = [ [tool.pytest.ini_options] addopts = "--strict-markers" -testpaths = [ - "tests/", -] +testpaths = ["tests/"] [tool.tox] requires = ["tox>=4.22"] @@ -178,7 +177,7 @@ description = "Run tests suite against Python {base_python}" skip_install = true deps = ["poetry>=2.0"] commands_pre = [["poetry", "install", "--only", "main,test"]] -commands = [["pytest", { replace = "posargs", extend = true}]] +commands = [["pytest", { replace = "posargs", extend = true }]] [tool.ruff] line-length = 88 @@ -227,14 +226,14 @@ poetry_command = "" [tool.poe.tasks] format.help = "Format the code" format.sequence = [ - {cmd = "ruff check --fix commitizen tests"}, - {cmd = "ruff format commitizen tests"}, + { cmd = "ruff check --fix commitizen tests" }, + { cmd = "ruff format commitizen tests" }, ] lint.help = "Lint the code" lint.sequence = [ - {cmd = "ruff check commitizen/ tests/ --fix"}, - {cmd = "mypy commitizen/ tests/"}, + { cmd = "ruff check commitizen/ tests/ --fix" }, + { cmd = "mypy commitizen/ tests/" }, ] check-commit.help = "Check the commit message" @@ -254,7 +253,7 @@ all.sequence = [ "format", "lint", "cover", - "check-commit" + "check-commit", ] "doc:screenshots".help = "Render documentation screeenshots" @@ -268,10 +267,10 @@ doc.cmd = "mkdocs serve" ci.help = "Run all tasks in CI" ci.sequence = [ - {cmd="pre-commit run --all-files"}, + { cmd = "pre-commit run --all-files" }, "cover", ] -ci.env = {SKIP = "no-commit-to-branch"} +ci.env = { SKIP = "no-commit-to-branch" } setup-pre-commit.help = "Install pre-commit hooks" setup-pre-commit.cmd = "pre-commit install" diff --git a/tests/providers/test_uv_provider.py b/tests/providers/test_uv_provider.py new file mode 100644 index 000000000..409370937 --- /dev/null +++ b/tests/providers/test_uv_provider.py @@ -0,0 +1,97 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +from commitizen.config.base_config import BaseConfig +from commitizen.providers import get_provider +from commitizen.providers.uv_provider import UvProvider + +if TYPE_CHECKING: + from pytest_regressions.file_regression import FileRegressionFixture + + +PYPROJECT_TOML = """ +[project] +name = "test-uv" +version = "4.2.1" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.13" +dependencies = ["commitizen==4.2.1"] +""" + +UV_LOCK_SIMPLIFIED = """ +version = 1 +revision = 1 +requires-python = ">=3.13" + +[[package]] +name = "commitizen" +version = "4.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "argcomplete" }, + { name = "charset-normalizer" }, + { name = "colorama" }, + { name = "decli" }, + { name = "jinja2" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "questionary" }, + { name = "termcolor" }, + { name = "tomlkit" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d8/a3/77ffc9aee014cbf46c84c9f156a1ddef2d4c7cfb87d567decf2541464245/commitizen-4.2.1.tar.gz", hash = "sha256:5255416f6d6071068159f0b97605777f3e25d00927ff157b7a8d01efeda7b952", size = 50645 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/57/ce/2f5d8ebe8376991b5f805e9f33d20c7f4c9ca6155bdbda761117dc41dff1/commitizen-4.2.1-py3-none-any.whl", hash = "sha256:a347889e0fe408c3b920a34130d8f35616be3ea8ac6b7b20c5b9aac19762661b", size = 72646 }, +] + +[[package]] +name = "decli" +version = "0.6.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3d/a0/a4658f93ecb589f479037b164dc13c68d108b50bf6594e54c820749f97ac/decli-0.6.2.tar.gz", hash = "sha256:36f71eb55fd0093895efb4f416ec32b7f6e00147dda448e3365cf73ceab42d6f", size = 7424 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/70/3ea48dc9e958d7d66c44c9944809181f1ca79aaef25703c023b5092d34ff/decli-0.6.2-py3-none-any.whl", hash = "sha256:2fc84106ce9a8f523ed501ca543bdb7e416c064917c12a59ebdc7f311a97b7ed", size = 7854 }, +] + +[[package]] +name = "test-uv" +version = "4.2.1" +source = { virtual = "." } +dependencies = [ + { name = "commitizen" }, +] +""" + + +def test_uv_provider( + config: BaseConfig, tmpdir, file_regression: FileRegressionFixture +): + with tmpdir.as_cwd(): + pyproject_toml_file = tmpdir / UvProvider.filename + pyproject_toml_file.write_text(PYPROJECT_TOML, encoding="utf-8") + + uv_lock_file = tmpdir / UvProvider.lock_filename + uv_lock_file.write_text(UV_LOCK_SIMPLIFIED, encoding="utf-8") + + config.settings["version_provider"] = "uv" + + provider = get_provider(config) + assert isinstance(provider, UvProvider) + assert provider.get_version() == "4.2.1" + + provider.set_version("100.100.100") + assert provider.get_version() == "100.100.100" + + updated_pyproject_toml_content = pyproject_toml_file.read_text(encoding="utf-8") + updated_uv_lock_content = uv_lock_file.read_text(encoding="utf-8") + + for content in (updated_pyproject_toml_content, updated_uv_lock_content): + # updated project version + assert "100.100.100" in content + # commitizen version which was the same as project version and should not be affected + assert "4.2.1" in content + + file_regression.check(updated_pyproject_toml_content, extension=".toml") + file_regression.check(updated_uv_lock_content, extension=".lock") diff --git a/tests/providers/test_uv_provider/test_uv_provider.lock b/tests/providers/test_uv_provider/test_uv_provider.lock new file mode 100644 index 000000000..d353763ce --- /dev/null +++ b/tests/providers/test_uv_provider/test_uv_provider.lock @@ -0,0 +1,42 @@ + +version = 1 +revision = 1 +requires-python = ">=3.13" + +[[package]] +name = "commitizen" +version = "4.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "argcomplete" }, + { name = "charset-normalizer" }, + { name = "colorama" }, + { name = "decli" }, + { name = "jinja2" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "questionary" }, + { name = "termcolor" }, + { name = "tomlkit" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d8/a3/77ffc9aee014cbf46c84c9f156a1ddef2d4c7cfb87d567decf2541464245/commitizen-4.2.1.tar.gz", hash = "sha256:5255416f6d6071068159f0b97605777f3e25d00927ff157b7a8d01efeda7b952", size = 50645 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/57/ce/2f5d8ebe8376991b5f805e9f33d20c7f4c9ca6155bdbda761117dc41dff1/commitizen-4.2.1-py3-none-any.whl", hash = "sha256:a347889e0fe408c3b920a34130d8f35616be3ea8ac6b7b20c5b9aac19762661b", size = 72646 }, +] + +[[package]] +name = "decli" +version = "0.6.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3d/a0/a4658f93ecb589f479037b164dc13c68d108b50bf6594e54c820749f97ac/decli-0.6.2.tar.gz", hash = "sha256:36f71eb55fd0093895efb4f416ec32b7f6e00147dda448e3365cf73ceab42d6f", size = 7424 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/70/3ea48dc9e958d7d66c44c9944809181f1ca79aaef25703c023b5092d34ff/decli-0.6.2-py3-none-any.whl", hash = "sha256:2fc84106ce9a8f523ed501ca543bdb7e416c064917c12a59ebdc7f311a97b7ed", size = 7854 }, +] + +[[package]] +name = "test-uv" +version = "100.100.100" +source = { virtual = "." } +dependencies = [ + { name = "commitizen" }, +] diff --git a/tests/providers/test_uv_provider/test_uv_provider.toml b/tests/providers/test_uv_provider/test_uv_provider.toml new file mode 100644 index 000000000..9fdb6eb5a --- /dev/null +++ b/tests/providers/test_uv_provider/test_uv_provider.toml @@ -0,0 +1,8 @@ + +[project] +name = "test-uv" +version = "100.100.100" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.13" +dependencies = ["commitizen==4.2.1"] From 8bddb2d66a601f98d3f375bfe98ee009bac0d2d2 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Tue, 18 Feb 2025 21:44:15 +0800 Subject: [PATCH 3/3] ci(pre-commit): ignore test file eof --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ba6ec51ba..392d1c040 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: hooks: - id: check-vcs-permalinks - id: end-of-file-fixer - exclude: "tests/((commands|data)/|test_).+" + exclude: "tests/((commands|data|providers/test_uv_provider)/|test_).+" - id: trailing-whitespace args: [ --markdown-linebreak-ext=md ] exclude: '\.svg$'