Skip to content

Commit ff90571

Browse files
committed
fix(config): include pyproject.toml in multi config file warning
1 parent a010a8d commit ff90571

File tree

2 files changed

+52
-47
lines changed

2 files changed

+52
-47
lines changed

commitizen/config/__init__.py

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from .base_config import BaseConfig
1010

1111

12-
def _resolve_config_paths() -> list[Path]:
12+
def _resolve_config_candidates() -> list[BaseConfig]:
1313
git_project_root = git.find_git_project_root()
1414
cfg_search_paths = [Path(".")]
1515

@@ -18,12 +18,18 @@ def _resolve_config_paths() -> list[Path]:
1818

1919
# The following algorithm is ugly, but we need to ensure that the order of the candidates are preserved before v5.
2020
# Also, the number of possible config files is limited, so the complexity is not a problem.
21-
candidates: list[Path] = []
21+
candidates: list[BaseConfig] = []
2222
for dir in cfg_search_paths:
2323
for filename in defaults.CONFIG_FILES:
2424
out_path = dir / Path(filename)
25-
if out_path.exists() and all(not out_path.samefile(p) for p in candidates):
26-
candidates.append(out_path)
25+
if (
26+
out_path.exists()
27+
and all(
28+
not out_path.samefile(candidate.path) for candidate in candidates
29+
)
30+
and not (conf := _create_config_from_path(out_path)).is_empty_config
31+
):
32+
candidates.append(conf)
2733
return candidates
2834

2935

@@ -44,21 +50,11 @@ def read_cfg(filepath: str | None = None) -> BaseConfig:
4450
raise ConfigFileIsEmpty()
4551
return conf
4652

47-
config_candidate_paths = _resolve_config_paths()
48-
49-
# Check for multiple config files and warn the user
50-
config_candidates_exclude_pyproject = [
51-
path for path in config_candidate_paths if path.name != "pyproject.toml"
52-
]
53-
54-
for config_candidate_path in config_candidate_paths:
55-
conf = _create_config_from_path(config_candidate_path)
56-
if not conf.is_empty_config:
57-
if len(config_candidates_exclude_pyproject) > 1:
58-
out.warn(
59-
f"Multiple config files detected: {', '.join(map(str, config_candidates_exclude_pyproject))}. "
60-
f"Using config file: '{config_candidate_path}'."
61-
)
62-
return conf
53+
config_candidates = _resolve_config_candidates()
54+
if len(config_candidates) > 1:
55+
out.warn(
56+
f"Multiple config files detected: {', '.join(str(conf.path) for conf in config_candidates)}. "
57+
f"Using config file: '{config_candidates[0].path}'."
58+
)
6359

64-
return BaseConfig()
60+
return config_candidates[0] if config_candidates else BaseConfig()

tests/test_conf.py

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from commitizen.config.yaml_config import YAMLConfig
1515
from commitizen.exceptions import ConfigFileIsEmpty, InvalidConfigurationError
1616

17-
PYPROJECT = """
17+
TOML_STR = """
1818
[tool.commitizen]
1919
name = "cz_jira"
2020
version = "1.0.0"
@@ -30,11 +30,17 @@
3030
"scripts/generate_documentation.sh"
3131
]
3232
post_bump_hooks = ["scripts/slack_notification.sh"]
33+
"""
3334

35+
PYPROJECT = (
36+
TOML_STR
37+
+ """
3438
[tool.black]
3539
line-length = 88
3640
target-version = ['py36', 'py37', 'py38']
3741
"""
42+
)
43+
3844

3945
DICT_CONFIG = {
4046
"commitizen": {
@@ -198,7 +204,7 @@ def test_load_empty_pyproject_toml_and_cz_toml_with_config(_, tmpdir):
198204
p = tmpdir.join("pyproject.toml")
199205
p.write("")
200206
p = tmpdir.join(".cz.toml")
201-
p.write(PYPROJECT)
207+
p.write(TOML_STR)
202208

203209
cfg = config.read_cfg()
204210
assert cfg.settings == _settings
@@ -240,27 +246,25 @@ def test_load_empty_pyproject_toml_from_config_argument(_, tmpdir):
240246

241247
class TestWarnMultipleConfigFiles:
242248
@pytest.mark.parametrize(
243-
"files,expected_path,should_warn",
249+
"files,expected_path",
244250
[
245251
# Same directory, different file types
246-
([(".cz.toml", PYPROJECT), (".cz.json", JSON_STR)], ".cz.toml", True),
247-
([(".cz.json", JSON_STR), (".cz.yaml", YAML_STR)], ".cz.json", True),
248-
([(".cz.toml", PYPROJECT), (".cz.yaml", YAML_STR)], ".cz.toml", True),
249-
# With pyproject.toml (excluded from warning)
252+
([(".cz.toml", TOML_STR), (".cz.json", JSON_STR)], ".cz.toml"),
253+
([(".cz.json", JSON_STR), (".cz.yaml", YAML_STR)], ".cz.json"),
254+
([(".cz.toml", TOML_STR), (".cz.yaml", YAML_STR)], ".cz.toml"),
255+
# With pyproject.toml
250256
(
251257
[("pyproject.toml", PYPROJECT), (".cz.json", JSON_STR)],
252258
".cz.json",
253-
False,
254259
),
255260
(
256-
[("pyproject.toml", PYPROJECT), (".cz.toml", PYPROJECT)],
261+
[("pyproject.toml", PYPROJECT), (".cz.toml", TOML_STR)],
257262
".cz.toml",
258-
False,
259263
),
260264
],
261265
)
262266
def test_warn_multiple_config_files_same_dir(
263-
_, tmpdir, capsys, files, expected_path, should_warn
267+
_, tmpdir, capsys, files, expected_path
264268
):
265269
"""Test warning when multiple config files exist in same directory."""
266270
with tmpdir.as_cwd():
@@ -270,27 +274,20 @@ def test_warn_multiple_config_files_same_dir(
270274
cfg = config.read_cfg()
271275
captured = capsys.readouterr()
272276

273-
if should_warn:
274-
assert "Multiple config files detected" in captured.err
275-
assert "Using" in captured.err
276-
for filename, _ in files:
277-
if filename != "pyproject.toml":
278-
assert filename in captured.err
279-
else:
280-
assert "Multiple config files detected" not in captured.err
277+
assert "Multiple config files detected" in captured.err
278+
for filename, _ in files:
279+
assert filename in captured.err
280+
assert f"Using config file: '{expected_path}'" in captured.err
281281

282282
assert cfg.path == Path(expected_path)
283-
# Verify config loaded correctly (name and version match expected)
284-
assert cfg.settings["name"] == "cz_jira"
285-
assert cfg.settings["version"] == "1.0.0"
286283

287284
@pytest.mark.parametrize(
288285
"config_file,content",
289286
[
290287
(".cz.json", JSON_STR),
291-
(".cz.toml", PYPROJECT),
288+
(".cz.toml", TOML_STR),
292289
(".cz.yaml", YAML_STR),
293-
("cz.toml", PYPROJECT),
290+
("cz.toml", TOML_STR),
294291
("cz.json", JSON_STR),
295292
("cz.yaml", YAML_STR),
296293
],
@@ -340,11 +337,11 @@ def test_no_warn_with_explicit_config_path(_, tmpdir, capsys):
340337
[
341338
(file, content, with_git)
342339
for file, content in [
343-
(".cz.toml", PYPROJECT),
340+
(".cz.toml", TOML_STR),
344341
(".cz.json", JSON_STR),
345342
(".cz.yaml", YAML_STR),
346343
("pyproject.toml", PYPROJECT),
347-
("cz.toml", PYPROJECT),
344+
("cz.toml", TOML_STR),
348345
("cz.json", JSON_STR),
349346
("cz.yaml", YAML_STR),
350347
]
@@ -368,6 +365,18 @@ def test_no_warn_with_single_config_file(
368365
assert "Multiple config files detected" not in captured.err
369366
assert cfg.path == Path(config_file)
370367

368+
def test_no_warn_with_no_commitizen_section_in_pyproject_toml_and_cz_toml(
369+
_, tmpdir, capsys
370+
):
371+
with tmpdir.as_cwd():
372+
tmpdir.join("pyproject.toml").write("[tool.foo]\nbar = 'baz'")
373+
tmpdir.join(".cz.toml").write(TOML_STR)
374+
375+
cfg = config.read_cfg()
376+
captured = capsys.readouterr()
377+
assert "Multiple config files detected" not in captured.err
378+
assert cfg.path == Path(".cz.toml")
379+
371380

372381
@pytest.mark.parametrize(
373382
"config_file, exception_string",

0 commit comments

Comments
 (0)