Skip to content

Commit e1e7164

Browse files
committed
feat(providers): add dart_provider
closes: #1563
1 parent baa31a6 commit e1e7164

File tree

8 files changed

+307
-1
lines changed

8 files changed

+307
-1
lines changed

‎commitizen/commands/init.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ def is_rust_cargo(self) -> bool:
5959
def is_npm_package(self) -> bool:
6060
return os.path.isfile("package.json")
6161

62+
@property
63+
def is_dart_package(self) -> bool:
64+
return os.path.isfile("pubspec.yaml")
65+
6266
@property
6367
def is_php_composer(self) -> bool:
6468
return os.path.isfile("composer.json")
@@ -234,6 +238,7 @@ def _ask_version_provider(self) -> str:
234238
"cargo": "cargo: Get and set version from Cargo.toml:project.version field",
235239
"composer": "composer: Get and set version from composer.json:project.version field",
236240
"npm": "npm: Get and set version from package.json:project.version field",
241+
"dart": "dart: Get and set version from pubspec.yaml:version field",
237242
"pep621": "pep621: Get and set version from pyproject.toml:project.version field",
238243
"poetry": "poetry: Get and set version from pyproject.toml:tool.poetry.version field",
239244
"uv": "uv: Get and Get and set version from pyproject.toml and uv.lock",
@@ -252,6 +257,8 @@ def _ask_version_provider(self) -> str:
252257
default_val = "cargo"
253258
elif self.project_info.is_npm_package:
254259
default_val = "npm"
260+
elif self.project_info.is_dart_package:
261+
default_val = "dart"
255262
elif self.project_info.is_php_composer:
256263
default_val = "composer"
257264

‎commitizen/providers/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from commitizen.providers.cargo_provider import CargoProvider
1515
from commitizen.providers.commitizen_provider import CommitizenProvider
1616
from commitizen.providers.composer_provider import ComposerProvider
17+
from commitizen.providers.dart_provider import DartProvider
1718
from commitizen.providers.npm_provider import NpmProvider
1819
from commitizen.providers.pep621_provider import Pep621Provider
1920
from commitizen.providers.poetry_provider import PoetryProvider
@@ -24,6 +25,7 @@
2425
"CargoProvider",
2526
"CommitizenProvider",
2627
"ComposerProvider",
28+
"DartProvider",
2729
"NpmProvider",
2830
"Pep621Provider",
2931
"PoetryProvider",

‎commitizen/providers/dart_provider.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
from __future__ import annotations
2+
3+
from collections.abc import Mapping
4+
from pathlib import Path
5+
from typing import Any
6+
7+
from ruamel.yaml import YAML
8+
9+
from commitizen.providers.base_provider import VersionProvider
10+
11+
12+
class DartProvider(VersionProvider):
13+
"""
14+
dart pubspec.yaml version management
15+
"""
16+
17+
package_filename = "pubspec.yaml"
18+
19+
def __init__(self, *args, **kwargs) -> None:
20+
super().__init__(*args, **kwargs)
21+
self._yaml = YAML()
22+
self._yaml.preserve_quotes = True
23+
self._yaml.indent(mapping=2, sequence=4, offset=2)
24+
25+
@property
26+
def package_file(self) -> Path:
27+
return Path() / self.package_filename
28+
29+
def get_version(self) -> str:
30+
print(self.package_file.read_text())
31+
document = self._yaml.load(self.package_file.read_text())
32+
return self.get(document)
33+
34+
def set_version(self, version: str) -> None:
35+
document = self._yaml.load(self.package_file.read_text())
36+
self.set(document, version)
37+
self._yaml.dump(document, self.package_file)
38+
39+
def get(self, document: Mapping[str, str]) -> str:
40+
# Extract the version without the build number
41+
version = document["version"]
42+
return version.split("+")[0] if "+" in version else version
43+
44+
def set(self, document: dict[str, Any], version: str) -> None:
45+
# To enforce to save the version in pubspec without quotes
46+
# even if the version could be interpreted as float by yaml
47+
# dump
48+
version_value: Any
49+
try:
50+
version_value = float(version)
51+
except ValueError:
52+
version_value = version
53+
document["version"] = version_value

‎docs/commands/init.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ During the initialization process, you'll be prompted to configure the following
3333
2. **Version Provider**: Choose how to manage versioning in your project. Commitizen supports multiple version management systems:
3434
- `commitizen`: Uses Commitizen's built-in version management system
3535
- `npm`: Manages version in `package.json` for Node.js projects
36+
- `dart`: Manages version in `pubspec.yaml` for Dart projects
3637
- `cargo`: Manages version in `Cargo.toml` for Rust projects
3738
- `composer`: Manages version in `composer.json` for PHP projects
3839
- `pep621`: Uses `pyproject.toml` with PEP 621 standard

‎docs/config.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ Commitizen provides some version providers for some well known formats:
355355
| `uv` | Get and set version from `pyproject.toml` `project.version` field and `uv.lock` `package.version` field whose `package.name` field is the same as `pyproject.toml` `project.name` field |
356356
| `cargo` | Get and set version from `Cargo.toml` `package.version` field and `Cargo.lock` `package.version` field whose `package.name` field is the same as `Cargo.toml` `package.name` field |
357357
| `npm` | Get and set version from `package.json` `version` field, `package-lock.json` `version,packages.''.version` fields if the file exists, and `npm-shrinkwrap.json` `version,packages.''.version` fields if the file exists |
358+
| `dart` | Get and set version from `pubspec.yaml` `version` field |
358359
| `composer` | Get and set version from `composer.json` `project.version` field |
359360

360361
!!! note

‎poetry.lock

Lines changed: 77 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ dependencies = [
2424
"charset-normalizer (>=2.1.0,<4)",
2525
# Use the Python 3.11 and 3.12 compatible API: https://github.com/python/importlib_metadata#compatibility
2626
"importlib-metadata >=8.0.0,<8.7.0 ; python_version < '3.10'",
27+
"ruamel-yaml (>=0.18.14,<0.19.0)",
2728
]
2829
keywords = ["commitizen", "conventional", "commits", "git"]
2930
# See also: https://pypi.org/classifiers/
@@ -71,6 +72,7 @@ cargo = "commitizen.providers:CargoProvider"
7172
commitizen = "commitizen.providers:CommitizenProvider"
7273
composer = "commitizen.providers:ComposerProvider"
7374
npm = "commitizen.providers:NpmProvider"
75+
dart = "commitizen.providers:DartProvider"
7476
pep621 = "commitizen.providers:Pep621Provider"
7577
poetry = "commitizen.providers:PoetryProvider"
7678
scm = "commitizen.providers:ScmProvider"

‎tests/providers/test_dart_provider.py

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
from __future__ import annotations
2+
3+
from pathlib import Path
4+
from textwrap import dedent
5+
6+
import pytest
7+
8+
from commitizen.config.base_config import BaseConfig
9+
from commitizen.providers import get_provider
10+
from commitizen.providers.dart_provider import DartProvider
11+
12+
DART_YAML = """\
13+
name: my_super_package
14+
description: A new Flutter project.
15+
16+
# Bla, bla, bla
17+
publish_to: "none" # Remove this line if you wish to publish to pub.dev
18+
19+
version: 0.1.0+1
20+
21+
environment:
22+
sdk: ^3.7.2
23+
# note that this only enforces that the Flutter version is at least the value specified. It does not
24+
# force it to this specific version
25+
flutter: 3.29.2
26+
27+
# Bla, bla, bla
28+
dependencies:
29+
flutter:
30+
sdk: flutter
31+
32+
# Some package dependencies
33+
# network
34+
dio: ^5.8.0+1
35+
36+
# The following section is specific to Flutter packages.
37+
flutter:
38+
# The following line ensures that the Material Icons font is
39+
# included with your application, so that you can use the icons in
40+
# the material Icons class.
41+
uses-material-design: true
42+
43+
# To add assets to your application, add an assets section, like this:
44+
assets:
45+
- assets/images/
46+
"""
47+
48+
DART_YAML_FLOAT_PARSEABLE_EXPECTED = """\
49+
name: my_super_package
50+
description: A new Flutter project.
51+
52+
# Bla, bla, bla
53+
publish_to: "none" # Remove this line if you wish to publish to pub.dev
54+
55+
version: 42.1
56+
57+
environment:
58+
sdk: ^3.7.2
59+
# note that this only enforces that the Flutter version is at least the value specified. It does not
60+
# force it to this specific version
61+
flutter: 3.29.2
62+
63+
# Bla, bla, bla
64+
dependencies:
65+
flutter:
66+
sdk: flutter
67+
68+
# Some package dependencies
69+
# network
70+
dio: ^5.8.0+1
71+
72+
# The following section is specific to Flutter packages.
73+
flutter:
74+
# The following line ensures that the Material Icons font is
75+
# included with your application, so that you can use the icons in
76+
# the material Icons class.
77+
uses-material-design: true
78+
79+
# To add assets to your application, add an assets section, like this:
80+
assets:
81+
- assets/images/
82+
"""
83+
84+
DART_YAML_SEMVER_EXPECTED = """\
85+
name: my_super_package
86+
description: A new Flutter project.
87+
88+
# Bla, bla, bla
89+
publish_to: "none" # Remove this line if you wish to publish to pub.dev
90+
91+
version: 2.3.4
92+
93+
environment:
94+
sdk: ^3.7.2
95+
# note that this only enforces that the Flutter version is at least the value specified. It does not
96+
# force it to this specific version
97+
flutter: 3.29.2
98+
99+
# Bla, bla, bla
100+
dependencies:
101+
flutter:
102+
sdk: flutter
103+
104+
# Some package dependencies
105+
# network
106+
dio: ^5.8.0+1
107+
108+
# The following section is specific to Flutter packages.
109+
flutter:
110+
# The following line ensures that the Material Icons font is
111+
# included with your application, so that you can use the icons in
112+
# the material Icons class.
113+
uses-material-design: true
114+
115+
# To add assets to your application, add an assets section, like this:
116+
assets:
117+
- assets/images/
118+
"""
119+
120+
121+
@pytest.mark.parametrize(
122+
"content, expected",
123+
((DART_YAML, DART_YAML_FLOAT_PARSEABLE_EXPECTED),),
124+
)
125+
def test_dart_provider_with_float_parseable_new_version(
126+
config: BaseConfig,
127+
chdir: Path,
128+
content: str,
129+
expected: str,
130+
):
131+
filename = DartProvider.package_filename
132+
file = chdir / filename
133+
file.write_text(dedent(content))
134+
config.settings["version_provider"] = "dart"
135+
136+
provider = get_provider(config)
137+
assert isinstance(provider, DartProvider)
138+
assert provider.get_version() == "0.1.0"
139+
140+
provider.set_version("42.1")
141+
assert file.read_text() == dedent(expected)
142+
143+
144+
@pytest.mark.parametrize(
145+
"content, expected",
146+
((DART_YAML, DART_YAML_SEMVER_EXPECTED),),
147+
)
148+
def test_dart_provider_with_semver_new_version(
149+
config: BaseConfig,
150+
chdir: Path,
151+
content: str,
152+
expected: str,
153+
):
154+
filename = DartProvider.package_filename
155+
file = chdir / filename
156+
file.write_text(dedent(content))
157+
config.settings["version_provider"] = "dart"
158+
159+
provider = get_provider(config)
160+
assert isinstance(provider, DartProvider)
161+
assert provider.get_version() == "0.1.0"
162+
163+
provider.set_version("2.3.4")
164+
assert file.read_text() == dedent(expected)

0 commit comments

Comments
 (0)