1
1
import os
2
+ import shutil
3
+ from typing import Any , Dict , List , Optional
2
4
3
5
import questionary
4
6
import yaml
9
11
from commitizen .config import BaseConfig , JsonConfig , TomlConfig , YAMLConfig
10
12
from commitizen .cz import registry
11
13
from commitizen .defaults import config_files
12
- from commitizen .exceptions import NoAnswersError
14
+ from commitizen .exceptions import InitFailedError , NoAnswersError
13
15
from commitizen .git import get_latest_tag_name , get_tag_names , smart_open
14
16
15
17
@@ -19,34 +21,43 @@ def __init__(self, config: BaseConfig, *args):
19
21
self .cz = factory .commiter_factory (self .config )
20
22
21
23
def __call__ (self ):
22
- values_to_add = {}
24
+ if self .config .path :
25
+ out .line (f"Config file { self .config .path } already exists" )
26
+ return
23
27
24
28
# No config for commitizen exist
25
- if not self .config .path :
26
- config_path = self ._ask_config_path ()
27
- if "toml" in config_path :
28
- self .config = TomlConfig (data = "" , path = config_path )
29
- elif "json" in config_path :
30
- self .config = JsonConfig (data = "{}" , path = config_path )
31
- elif "yaml" in config_path :
32
- self .config = YAMLConfig (data = "" , path = config_path )
33
-
34
- self .config .init_empty_config_content ()
35
-
36
- values_to_add ["name" ] = self ._ask_name ()
37
- tag = self ._ask_tag ()
38
- values_to_add ["version" ] = Version (tag ).public
39
- values_to_add ["tag_format" ] = self ._ask_tag_format (tag )
40
- self ._update_config_file (values_to_add )
41
-
42
- if questionary .confirm ("Do you want to install pre-commit hook?" ).ask ():
43
- self ._install_pre_commit_hook ()
44
-
45
- out .write ("You can bump the version and create changelog running:\n " )
46
- out .info ("cz bump --changelog" )
47
- out .success ("The configuration are all set." )
48
- else :
49
- out .line (f"Config file { self .config .path } already exists" )
29
+ config_path = self ._ask_config_path ()
30
+ if "toml" in config_path :
31
+ self .config = TomlConfig (data = "" , path = config_path )
32
+ elif "json" in config_path :
33
+ self .config = JsonConfig (data = "{}" , path = config_path )
34
+ elif "yaml" in config_path :
35
+ self .config = YAMLConfig (data = "" , path = config_path )
36
+ self .config .init_empty_config_content ()
37
+
38
+ values_to_add = {}
39
+ values_to_add ["name" ] = self ._ask_name ()
40
+ tag = self ._ask_tag ()
41
+ values_to_add ["version" ] = Version (tag ).public
42
+ values_to_add ["tag_format" ] = self ._ask_tag_format (tag )
43
+ self ._update_config_file (values_to_add )
44
+
45
+ hook_types = questionary .checkbox (
46
+ "What types of pre-commit hook you want to install? (Leave blank if you don't want to install)" ,
47
+ choices = [
48
+ questionary .Choice ("commit-msg" , checked = True ),
49
+ questionary .Choice ("pre-push" , checked = True ),
50
+ ],
51
+ ).ask ()
52
+ if hook_types :
53
+ try :
54
+ self ._install_pre_commit_hook (hook_types )
55
+ except InitFailedError as e :
56
+ raise InitFailedError (f"Failed to install pre-commit hook.\n { e } " )
57
+
58
+ out .write ("You can bump the version and create changelog running:\n " )
59
+ out .info ("cz bump --changelog" )
60
+ out .success ("The configuration are all set." )
50
61
51
62
def _ask_config_path (self ) -> str :
52
63
name : str = questionary .select (
@@ -109,17 +120,45 @@ def _ask_tag_format(self, latest_tag) -> str:
109
120
tag_format = "$version"
110
121
return tag_format
111
122
112
- def _install_pre_commit_hook (self ):
123
+ def _search_pre_commit (self ) -> bool :
124
+ """Check whether pre-commit is installed"""
125
+ return shutil .which ("pre-commit" ) is not None
126
+
127
+ def _exec_install_pre_commit_hook (self , hook_types : List [str ]):
128
+ cmd_str = self ._gen_pre_commit_cmd (hook_types )
129
+ c = cmd .run (cmd_str )
130
+ if c .return_code != 0 :
131
+ err_msg = (
132
+ f"Error running { cmd_str } ."
133
+ "Outputs are attached below:\n "
134
+ f"stdout: { c .out } \n "
135
+ f"stderr: { c .err } "
136
+ )
137
+ raise InitFailedError (err_msg )
138
+
139
+ def _gen_pre_commit_cmd (self , hook_types : List [str ]) -> str :
140
+ """Generate pre-commit command according to given hook types"""
141
+ if not hook_types :
142
+ raise ValueError ("At least 1 hook type should be provided." )
143
+ cmd_str = "pre-commit install " + " " .join (
144
+ f"--hook-type { ty } " for ty in hook_types
145
+ )
146
+ return cmd_str
147
+
148
+ def _install_pre_commit_hook (self , hook_types : Optional [List [str ]] = None ):
113
149
pre_commit_config_filename = ".pre-commit-config.yaml"
114
150
cz_hook_config = {
115
151
"repo" : "https://github.com/commitizen-tools/commitizen" ,
116
152
"rev" : f"v{ __version__ } " ,
117
- "hooks" : [{"id" : "commitizen" }],
153
+ "hooks" : [
154
+ {"id" : "commitizen" },
155
+ {"id" : "commitizen-branch" , "stages" : ["push" ]},
156
+ ],
118
157
}
119
158
120
159
config_data = {}
121
160
if not os .path .isfile (pre_commit_config_filename ):
122
- # .pre-commit-config does not exist
161
+ # .pre-commit-config.yaml does not exist
123
162
config_data ["repos" ] = [cz_hook_config ]
124
163
else :
125
164
with open (pre_commit_config_filename ) as config_file :
@@ -135,23 +174,21 @@ def _install_pre_commit_hook(self):
135
174
else :
136
175
config_data ["repos" ].append (cz_hook_config )
137
176
else :
138
- # .pre-commit-config exists but there's no "repos" key
177
+ # .pre-commit-config.yaml exists but there's no "repos" key
139
178
config_data ["repos" ] = [cz_hook_config ]
140
179
141
180
with smart_open (pre_commit_config_filename , "w" ) as config_file :
142
181
yaml .safe_dump (config_data , stream = config_file )
143
182
144
- c = cmd .run ("pre-commit install --hook-type commit-msg" )
145
- if c .return_code == 127 :
146
- out .error (
147
- "pre-commit is not installed in current environement.\n "
148
- "Run 'pre-commit install --hook-type commit-msg' again after it's installed"
183
+ if not self ._search_pre_commit ():
184
+ raise InitFailedError (
185
+ "pre-commit is not installed in current environement."
149
186
)
150
- elif c . return_code != 0 :
151
- out . error ( c . err )
152
- else :
153
- out .write ("commitizen pre-commit hook is now installed in your '.git'\n " )
187
+ if hook_types is None :
188
+ hook_types = [ "commit-msg" , "pre-push" ]
189
+ self . _exec_install_pre_commit_hook ( hook_types )
190
+ out .write ("commitizen pre-commit hook is now installed in your '.git'\n " )
154
191
155
- def _update_config_file (self , values ):
192
+ def _update_config_file (self , values : Dict [ str , Any ] ):
156
193
for key , value in values .items ():
157
194
self .config .set_key (key , value )
0 commit comments