Skip to content

Commit 42301ca

Browse files
Lee-Wwoile
authored andcommitted
feat: new init command
* feat(git): add get_latest_tag, get_all_tags #57 * feat(commands/init): Implment init command set tag and tag_format * feat(commands/init): Implment init command set tag and tag_format * feat(cli): add init command into cli * fix(commands/init): fix logic error #57 * fix(commands/init): fix logic error #57 * test(commands/init): add test case for init command * style(all): black * feat(commands/init): add name into init question * fix(commands/init): fix init command broken due to newly refactored config * style(commands): blackify * feat(config): add init_empty_config_file * fix(commands/init): fix init commands cannot create config file * style(commands/init): blackify * fix(commands/init): fix test_init_when_config_already_exists * fix(commands/init): read version in the format "x.y.z" instead of "vx.y.z" * refactor(commands/init): add default for tag_format * docs(index): add init command
1 parent f4e0658 commit 42301ca

File tree

8 files changed

+161
-3
lines changed

8 files changed

+161
-3
lines changed

commitizen/cli.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@
135135
}
136136
],
137137
},
138+
{
139+
"name": ["init"],
140+
"help": "init commitizen configuration",
141+
"func": commands.Init,
142+
},
138143
],
139144
},
140145
}

commitizen/commands/__init__.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,17 @@
66
from .list_cz import ListCz
77
from .schema import Schema
88
from .version import Version
9+
from .init import Init
910

10-
__all__ = ("Bump", "Check", "Commit", "Example", "Info", "ListCz", "Schema", "Version")
11+
12+
__all__ = (
13+
"Bump",
14+
"Check",
15+
"Commit",
16+
"Example",
17+
"Info",
18+
"ListCz",
19+
"Schema",
20+
"Version",
21+
"Init",
22+
)

commitizen/commands/init.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
from packaging.version import Version
2+
3+
import questionary
4+
5+
from commitizen import factory, out
6+
from commitizen.cz import registry
7+
from commitizen.config import BaseConfig, TomlConfig, IniConfig
8+
from commitizen.git import get_latest_tag, get_all_tags
9+
from commitizen.defaults import config_files
10+
11+
12+
class Init:
13+
def __init__(self, config: BaseConfig, *args):
14+
self.config: BaseConfig = config
15+
self.cz = factory.commiter_factory(self.config)
16+
17+
def __call__(self):
18+
values_to_add = {}
19+
20+
# No config file exist
21+
if not self.config.path:
22+
config_path = self._ask_config_path()
23+
24+
if "toml" in config_path:
25+
self.config = TomlConfig(data="", path=config_path)
26+
else:
27+
self.config = IniConfig(data="", path=config_path)
28+
29+
self.config.init_empty_config_file()
30+
31+
values_to_add["name"] = self._ask_name()
32+
tag = self._ask_tag()
33+
values_to_add["version"] = Version(tag).public
34+
values_to_add["tag_format"] = self._ask_tag_format(tag)
35+
self._update_config_file(values_to_add)
36+
out.write("The configuration are all set.")
37+
else:
38+
# TODO: handle the case that config file exist but no value
39+
out.line(f"Config file {self.config.path} already exists")
40+
41+
def _ask_config_path(self) -> str:
42+
name = questionary.select(
43+
"Please choose a supported config file: (default: pyproject.tml)",
44+
choices=config_files,
45+
default="pyproject.toml",
46+
style=self.cz.style,
47+
).ask()
48+
return name
49+
50+
def _ask_name(self) -> str:
51+
name = questionary.select(
52+
"Please choose a cz: (default: cz_conventional_commits)",
53+
choices=list(registry.keys()),
54+
default="cz_conventional_commits",
55+
style=self.cz.style,
56+
).ask()
57+
return name
58+
59+
def _ask_tag(self) -> str:
60+
latest_tag = get_latest_tag()
61+
if not latest_tag:
62+
out.error("No Existing Tag. Set tag to v0.0.1")
63+
return "0.0.1"
64+
65+
is_correct_tag = questionary.confirm(
66+
f"Is {latest_tag} the latest tag?", style=self.cz.style, default=False
67+
).ask()
68+
if not is_correct_tag:
69+
tags = get_all_tags()
70+
if not tags:
71+
out.error("No Existing Tag. Set tag to v0.0.1")
72+
return "0.0.1"
73+
74+
latest_tag = questionary.select(
75+
"Please choose the latest tag: ",
76+
choices=get_all_tags(),
77+
style=self.cz.style,
78+
).ask()
79+
80+
if not latest_tag:
81+
out.error("Tag is required!")
82+
raise SystemExit()
83+
return latest_tag
84+
85+
def _ask_tag_format(self, latest_tag) -> str:
86+
is_correct_format = False
87+
if latest_tag.startswith("v"):
88+
tag_format = r"v$version"
89+
is_correct_format = questionary.confirm(
90+
f'Is "{tag_format}" the correct tag format?', style=self.cz.style
91+
).ask()
92+
93+
if not is_correct_format:
94+
tag_format = questionary.text(
95+
'Please enter the correct version format: (default: "$version")',
96+
style=self.cz.style,
97+
).ask()
98+
99+
if not tag_format:
100+
tag_format = "$version"
101+
return tag_format
102+
103+
def _update_config_file(self, values):
104+
if not values:
105+
out.write("The configuration were all set. Nothing to add.")
106+
raise SystemExit()
107+
108+
for key, value in values.items():
109+
self.config.set_key(key, value)

commitizen/config/ini_config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ def __init__(self, *, data: str, path: str):
2222
self._parse_setting(data)
2323
self.add_path(path)
2424

25+
def init_empty_config_file(self):
26+
with open(self.path, "w") as toml_file:
27+
toml_file.write("[commitizen]")
28+
2529
def set_key(self, key, value):
2630
"""Set or update a key in the conf.
2731

commitizen/config/toml_config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ def __init__(self, *, data: str, path: str):
1010
self._parse_setting(data)
1111
self.add_path(path)
1212

13+
def init_empty_config_file(self):
14+
with open(self.path, "w") as toml_file:
15+
toml_file.write("[tool.commitizen]")
16+
1317
def set_key(self, key, value):
1418
"""Set or update a key in the conf.
1519

commitizen/git.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
from tempfile import NamedTemporaryFile
3+
from typing import Optional, List
34

45
from commitizen import cmd
56

@@ -40,3 +41,17 @@ def is_staging_clean() -> bool:
4041
c = cmd.run("git diff --no-ext-diff --name-only")
4142
c_cached = cmd.run("git diff --no-ext-diff --cached --name-only")
4243
return not (bool(c.out) or bool(c_cached.out))
44+
45+
46+
def get_latest_tag() -> Optional[str]:
47+
c = cmd.run("git describe --abbrev=0 --tags")
48+
if c.err:
49+
return None
50+
return c.out.strip()
51+
52+
53+
def get_all_tags() -> Optional[List[str]]:
54+
c = cmd.run("git tag --list")
55+
if c.err:
56+
return []
57+
return [tag.strip() for tag in c.out.split("\n") if tag.strip()]

docs/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ commands:
9595
schema show commit schema
9696
bump bump semantic version based on the git log
9797
check validates that a commit message matches the commitizen schema
98+
init init commitizen configuration
9899
```
99100

100101
## Contributing

tests/test_commands.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,14 +166,12 @@ def test_schema(config):
166166

167167
def test_list_cz(config):
168168
with mock.patch("commitizen.out.write") as mocked_write:
169-
170169
commands.ListCz(config)()
171170
mocked_write.assert_called_once()
172171

173172

174173
def test_version(config):
175174
with mock.patch("commitizen.out.write") as mocked_write:
176-
177175
commands.Version(config)()
178176
mocked_write.assert_called_once()
179177

@@ -214,3 +212,13 @@ def test_check_conventional_commit(config, mocker):
214212
def test_check_command_when_commit_file_not_found(config):
215213
with pytest.raises(FileNotFoundError):
216214
commands.Check(config=config, arguments={"commit_msg_file": ""})()
215+
216+
217+
def test_init_when_config_already_exists(config, capsys):
218+
# Set config path
219+
path = "tests/pyproject.toml"
220+
config.add_path(path)
221+
222+
commands.Init(config)()
223+
captured = capsys.readouterr()
224+
assert captured.out == f"Config file {path} already exists\n"

0 commit comments

Comments
 (0)