Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 293b265

Browse files
refactor(Init): make project_info a module and remove self.project_info
1 parent 1bb40c7 commit 293b265

File tree

4 files changed

+147
-88
lines changed

4 files changed

+147
-88
lines changed

‎commitizen/commands/init.py‎

Lines changed: 7 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
from __future__ import annotations
22

3-
import os
4-
import shutil
3+
from pathlib import Path
54
from typing import Any, NamedTuple
65

76
import questionary
87
import yaml
98

10-
from commitizen import cmd, factory, out
9+
from commitizen import cmd, factory, out, project_info
1110
from commitizen.__version__ import __version__
1211
from commitizen.config import BaseConfig, JsonConfig, TomlConfig, YAMLConfig
1312
from commitizen.cz import registry
@@ -65,65 +64,13 @@ def title(self) -> str:
6564
)
6665

6766

68-
class ProjectInfo:
69-
"""Discover information about the current folder."""
70-
71-
@property
72-
def has_pyproject(self) -> bool:
73-
return os.path.isfile("pyproject.toml")
74-
75-
@property
76-
def has_uv_lock(self) -> bool:
77-
return os.path.isfile("uv.lock")
78-
79-
@property
80-
def has_setup(self) -> bool:
81-
return os.path.isfile("setup.py")
82-
83-
@property
84-
def has_pre_commit_config(self) -> bool:
85-
return os.path.isfile(".pre-commit-config.yaml")
86-
87-
@property
88-
def is_python_uv(self) -> bool:
89-
return self.has_pyproject and self.has_uv_lock
90-
91-
@property
92-
def is_python_poetry(self) -> bool:
93-
if not self.has_pyproject:
94-
return False
95-
with open("pyproject.toml") as f:
96-
return "[tool.poetry]" in f.read()
97-
98-
@property
99-
def is_python(self) -> bool:
100-
return self.has_pyproject or self.has_setup
101-
102-
@property
103-
def is_rust_cargo(self) -> bool:
104-
return os.path.isfile("Cargo.toml")
105-
106-
@property
107-
def is_npm_package(self) -> bool:
108-
return os.path.isfile("package.json")
109-
110-
@property
111-
def is_php_composer(self) -> bool:
112-
return os.path.isfile("composer.json")
113-
114-
@property
115-
def is_pre_commit_installed(self) -> bool:
116-
return bool(shutil.which("pre-commit"))
117-
118-
11967
class Init:
12068
_PRE_COMMIT_CONFIG_PATH = ".pre-commit-config.yaml"
12169

12270
def __init__(self, config: BaseConfig, *args: object) -> None:
12371
self.config: BaseConfig = config
12472
self.encoding = config.settings["encoding"]
12573
self.cz = factory.committer_factory(self.config)
126-
self.project_info = ProjectInfo()
12774

12875
def __call__(self) -> None:
12976
if self.config.path:
@@ -195,14 +142,10 @@ def __call__(self) -> None:
195142
out.success("Configuration complete 🚀")
196143

197144
def _ask_config_path(self) -> str:
198-
default_path = (
199-
"pyproject.toml" if self.project_info.has_pyproject else ".cz.toml"
200-
)
201-
202145
name: str = questionary.select(
203146
"Please choose a supported config file: ",
204147
choices=CONFIG_FILES,
205-
default=default_path,
148+
default=project_info.get_default_config_filename(),
206149
style=self.cz.style,
207150
).unsafe_ask()
208151
return name
@@ -267,37 +210,17 @@ def _ask_version_provider(self) -> str:
267210
"Choose the source of the version:",
268211
choices=_VERSION_PROVIDER_CHOICES,
269212
style=self.cz.style,
270-
default=self._default_version_provider,
213+
default=project_info.get_default_version_provider(),
271214
).unsafe_ask()
272215
return version_provider
273216

274-
@property
275-
def _default_version_provider(self) -> str:
276-
if self.project_info.is_python:
277-
if self.project_info.is_python_poetry:
278-
return "poetry"
279-
if self.project_info.is_python_uv:
280-
return "uv"
281-
return "pep621"
282-
283-
if self.project_info.is_rust_cargo:
284-
return "cargo"
285-
if self.project_info.is_npm_package:
286-
return "npm"
287-
if self.project_info.is_php_composer:
288-
return "composer"
289-
290-
return "commitizen"
291-
292217
def _ask_version_scheme(self) -> str:
293218
"""Ask for setting: version_scheme"""
294-
default_scheme = "pep440" if self.project_info.is_python else "semver"
295-
296219
scheme: str = questionary.select(
297220
"Choose version scheme: ",
298221
choices=KNOWN_SCHEMES,
299222
style=self.cz.style,
300-
default=default_scheme,
223+
default=project_info.get_default_version_scheme(),
301224
).unsafe_ask()
302225
return scheme
303226

@@ -351,8 +274,7 @@ def _get_config_data(self) -> dict[str, Any]:
351274
],
352275
}
353276

354-
if not self.project_info.has_pre_commit_config:
355-
# .pre-commit-config.yaml does not exist
277+
if not Path(".pre-commit-config.yaml").is_file():
356278
return {"repos": [CZ_HOOK_CONFIG]}
357279

358280
with open(self._PRE_COMMIT_CONFIG_PATH, encoding=self.encoding) as config_file:
@@ -377,7 +299,7 @@ def _install_pre_commit_hook(self, hook_types: list[str] | None = None) -> None:
377299
) as config_file:
378300
yaml.safe_dump(config_data, stream=config_file)
379301

380-
if not self.project_info.is_pre_commit_installed:
302+
if not project_info.is_pre_commit_installed():
381303
raise InitFailedError("pre-commit is not installed in current environment.")
382304
if hook_types is None:
383305
hook_types = ["commit-msg", "pre-push"]

‎commitizen/project_info.py‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""Resolves project information about the current working directory."""
2+
3+
import shutil
4+
from pathlib import Path
5+
from typing import Literal
6+
7+
8+
def is_pre_commit_installed() -> bool:
9+
return bool(shutil.which("pre-commit"))
10+
11+
12+
def get_default_version_provider() -> Literal[
13+
"commitizen", "cargo", "composer", "npm", "pep621", "poetry", "uv"
14+
]:
15+
pyproject_path = Path("pyproject.toml")
16+
if pyproject_path.is_file():
17+
if "[tool.poetry]" in pyproject_path.read_text():
18+
return "poetry"
19+
if Path("uv.lock").is_file():
20+
return "uv"
21+
return "pep621"
22+
23+
if Path("setup.py").is_file():
24+
return "pep621"
25+
26+
if Path("Cargo.toml").is_file():
27+
return "cargo"
28+
29+
if Path("package.json").is_file():
30+
return "npm"
31+
32+
if Path("composer.json").is_file():
33+
return "composer"
34+
35+
return "commitizen"
36+
37+
38+
def get_default_config_filename() -> Literal["pyproject.toml", ".cz.toml"]:
39+
return "pyproject.toml" if Path("pyproject.toml").is_file() else ".cz.toml"
40+
41+
42+
def get_default_version_scheme() -> Literal["pep440", "semver"]:
43+
return (
44+
"pep440"
45+
if Path("pyproject.toml").is_file() or Path("setup.py").is_file()
46+
else "semver"
47+
)

‎tests/commands/test_init_command.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ def test_executed_pre_commit_command(config: BaseConfig):
127127
def pre_commit_installed(mocker: MockFixture):
128128
# Assume the `pre-commit` is installed
129129
mocker.patch(
130-
"commitizen.commands.init.ProjectInfo.is_pre_commit_installed",
130+
"commitizen.project_info.is_pre_commit_installed",
131131
return_value=True,
132132
)
133133
# And installation success (i.e. no exception raised)
@@ -237,7 +237,7 @@ def test_pre_commit_not_installed(
237237
):
238238
# Assume `pre-commit` is not installed
239239
mocker.patch(
240-
"commitizen.commands.init.ProjectInfo.is_pre_commit_installed",
240+
"commitizen.project_info.is_pre_commit_installed",
241241
return_value=False,
242242
)
243243
with tmpdir.as_cwd():
@@ -249,7 +249,7 @@ def test_pre_commit_exec_failed(
249249
):
250250
# Assume `pre-commit` is installed
251251
mocker.patch(
252-
"commitizen.commands.init.ProjectInfo.is_pre_commit_installed",
252+
"commitizen.project_info.is_pre_commit_installed",
253253
return_value=True,
254254
)
255255
# But pre-commit installation will fail

‎tests/test_project_info.py‎

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
"""Tests for project_info module."""
2+
3+
from __future__ import annotations
4+
5+
from pathlib import Path
6+
7+
import pytest
8+
9+
from commitizen import project_info
10+
11+
12+
def _create_project_files(files: dict[str, str | None]) -> None:
13+
for file_path, content in files.items():
14+
path = Path(file_path)
15+
if content is None:
16+
path.touch()
17+
else:
18+
path.write_text(content)
19+
20+
21+
@pytest.mark.parametrize(
22+
"which_return, expected",
23+
[
24+
("/usr/local/bin/pre-commit", True),
25+
(None, False),
26+
("", False),
27+
],
28+
)
29+
def test_is_pre_commit_installed(mocker, which_return, expected):
30+
mocker.patch("shutil.which", return_value=which_return)
31+
assert project_info.is_pre_commit_installed() is expected
32+
33+
34+
@pytest.mark.parametrize(
35+
"files, expected",
36+
[
37+
(
38+
{"pyproject.toml": '[tool.poetry]\nname = "test"\nversion = "0.1.0"'},
39+
"poetry",
40+
),
41+
({"pyproject.toml": "", "uv.lock": ""}, "uv"),
42+
(
43+
{"pyproject.toml": '[tool.commitizen]\nversion = "0.1.0"'},
44+
"pep621",
45+
),
46+
({"setup.py": ""}, "pep621"),
47+
({"Cargo.toml": ""}, "cargo"),
48+
({"package.json": ""}, "npm"),
49+
({"composer.json": ""}, "composer"),
50+
({}, "commitizen"),
51+
(
52+
{
53+
"pyproject.toml": "",
54+
"Cargo.toml": "",
55+
"package.json": "",
56+
"composer.json": "",
57+
},
58+
"pep621",
59+
),
60+
],
61+
)
62+
def test_get_default_version_provider(chdir, files, expected):
63+
_create_project_files(files)
64+
assert project_info.get_default_version_provider() == expected
65+
66+
67+
@pytest.mark.parametrize(
68+
"files, expected",
69+
[
70+
({"pyproject.toml": ""}, "pyproject.toml"),
71+
({}, ".cz.toml"),
72+
],
73+
)
74+
def test_get_default_config_filename(chdir, files, expected):
75+
_create_project_files(files)
76+
assert project_info.get_default_config_filename() == expected
77+
78+
79+
@pytest.mark.parametrize(
80+
"files, expected",
81+
[
82+
({"pyproject.toml": ""}, "pep440"),
83+
({"setup.py": ""}, "pep440"),
84+
({"package.json": ""}, "semver"),
85+
({}, "semver"),
86+
],
87+
)
88+
def test_get_default_version_scheme(chdir, files, expected):
89+
_create_project_files(files)
90+
assert project_info.get_default_version_scheme() == expected

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /