1
1
from __future__ import annotations
2
2
3
3
import os
4
- from enum import Enum
5
- from os import linesep
6
4
from pathlib import Path
7
5
from tempfile import NamedTemporaryFile
8
6
9
7
from commitizen import cmd , out
10
8
from commitizen .exceptions import GitCommandError
11
9
12
- UNIX_EOL = "\n "
13
- WINDOWS_EOL = "\r \n "
14
-
15
-
16
- class EOLTypes (Enum ):
17
- """The EOL type from `git config core.eol`."""
18
-
19
- LF = "lf"
20
- CRLF = "crlf"
21
- NATIVE = "native"
22
-
23
- def get_eol_for_open (self ) -> str :
24
- """Get the EOL character for `open()`."""
25
- map = {
26
- EOLTypes .CRLF : WINDOWS_EOL ,
27
- EOLTypes .LF : UNIX_EOL ,
28
- EOLTypes .NATIVE : linesep ,
29
- }
30
-
31
- return map [self ]
10
+ _UNIX_EOL = "\n "
11
+ _WINDOWS_EOL = "\r \n "
32
12
33
13
34
14
class GitObject :
@@ -37,9 +17,7 @@ class GitObject:
37
17
date : str
38
18
39
19
def __eq__ (self , other ) -> bool :
40
- if not hasattr (other , "rev" ):
41
- return False
42
- return self .rev == other .rev # type: ignore
20
+ return hasattr (other , "rev" ) and self .rev == other .rev
43
21
44
22
45
23
class GitCommit (GitObject ):
@@ -63,6 +41,20 @@ def __init__(
63
41
def message (self ):
64
42
return f"{ self .title } \n \n { self .body } " .strip ()
65
43
44
+ @classmethod
45
+ def from_rev_and_commit (cls , rev_and_commit : str ) -> GitCommit :
46
+ rev , parents , title , author , author_email , * body_list = rev_and_commit .split (
47
+ "\n "
48
+ )
49
+ return cls (
50
+ rev = rev .strip (),
51
+ title = title .strip (),
52
+ body = "\n " .join (body_list ).strip (),
53
+ author = author ,
54
+ author_email = author_email ,
55
+ parents = [p for p in parents .strip ().split (" " ) if p ],
56
+ )
57
+
66
58
def __repr__ (self ):
67
59
return f"{ self .title } ({ self .rev } )"
68
60
@@ -101,13 +93,11 @@ def tag(
101
93
# according to https://git-scm.com/book/en/v2/Git-Basics-Tagging,
102
94
# we're not able to create lightweight tag with message.
103
95
# by adding message, we make it a annotated tags
104
- c = cmd .run (f'git tag { _opt } "{ tag if _opt == "" or msg is None else msg } "' )
105
- return c
96
+ return cmd .run (f'git tag { _opt } "{ tag if _opt == "" or msg is None else msg } "' )
106
97
107
98
108
99
def add (* args : str ) -> cmd .Command :
109
- c = cmd .run (f"git add { ' ' .join (args )} " )
110
- return c
100
+ return cmd .run (f"git add { ' ' .join (args )} " )
111
101
112
102
113
103
def commit (
@@ -140,24 +130,10 @@ def get_commits(
140
130
) -> list [GitCommit ]:
141
131
"""Get the commits between start and end."""
142
132
git_log_entries = _get_log_as_str_list (start , end , args )
143
- git_commits = []
144
- for rev_and_commit in git_log_entries :
145
- if not rev_and_commit :
146
- continue
147
- rev , parents , title , author , author_email , * body_list = rev_and_commit .split (
148
- "\n "
149
- )
150
- if rev_and_commit :
151
- git_commit = GitCommit (
152
- rev = rev .strip (),
153
- title = title .strip (),
154
- body = "\n " .join (body_list ).strip (),
155
- author = author ,
156
- author_email = author_email ,
157
- parents = [p for p in parents .strip ().split (" " ) if p ],
158
- )
159
- git_commits .append (git_commit )
160
- return git_commits
133
+ return [
134
+ GitCommit .from_rev_and_commit (rev_and_commit )
135
+ for rev_and_commit in filter (None , git_log_entries )
136
+ ]
161
137
162
138
163
139
def get_filenames_in_commit (git_reference : str = "" ):
@@ -170,8 +146,7 @@ def get_filenames_in_commit(git_reference: str = ""):
170
146
c = cmd .run (f"git show --name-only --pretty=format: { git_reference } " )
171
147
if c .return_code == 0 :
172
148
return c .out .strip ().split ("\n " )
173
- else :
174
- raise GitCommandError (c .err )
149
+ raise GitCommandError (c .err )
175
150
176
151
177
152
def get_tags (
@@ -197,16 +172,11 @@ def get_tags(
197
172
if c .err :
198
173
out .warn (f"Attempting to proceed after: { c .err } " )
199
174
200
- if not c .out :
201
- return []
202
-
203
- git_tags = [
175
+ return [
204
176
GitTag .from_line (line = line , inner_delimiter = inner_delimiter )
205
177
for line in c .out .split ("\n " )[:- 1 ]
206
178
]
207
179
208
- return git_tags
209
-
210
180
211
181
def tag_exist (tag : str ) -> bool :
212
182
c = cmd .run (f"git tag --list { tag } " )
@@ -231,18 +201,18 @@ def get_tag_message(tag: str) -> str | None:
231
201
return c .out .strip ()
232
202
233
203
234
- def get_tag_names () -> list [str | None ]:
204
+ def get_tag_names () -> list [str ]:
235
205
c = cmd .run ("git tag --list" )
236
206
if c .err :
237
207
return []
238
- return [ tag .strip () for tag in c .out .split ("\n " ) if tag . strip ()]
208
+ return list ( filter ( None , ( tag .strip () for tag in c .out .split ("\n " ))))
239
209
240
210
241
211
def find_git_project_root () -> Path | None :
242
212
c = cmd .run ("git rev-parse --show-toplevel" )
243
- if not c .err :
244
- return Path ( c . out . strip ())
245
- return None
213
+ if c .err :
214
+ return None
215
+ return Path ( c . out . strip ())
246
216
247
217
248
218
def is_staging_clean () -> bool :
@@ -253,32 +223,19 @@ def is_staging_clean() -> bool:
253
223
254
224
def is_git_project () -> bool :
255
225
c = cmd .run ("git rev-parse --is-inside-work-tree" )
256
- if c .out .strip () == "true" :
257
- return True
258
- return False
226
+ return c .out .strip () == "true"
259
227
260
228
261
- def get_eol_style () -> EOLTypes :
229
+ def get_eol_for_open () -> str :
230
+ # See: https://git-scm.com/docs/git-config#Documentation/git-config.txt-coreeol
262
231
c = cmd .run ("git config core.eol" )
263
232
eol = c .out .strip ().lower ()
264
233
265
- # We enumerate the EOL types of the response of
266
- # `git config core.eol`, and map it to our enumration EOLTypes.
267
- #
268
- # It is just like the variant of the "match" syntax.
269
- map = {
270
- "lf" : EOLTypes .LF ,
271
- "crlf" : EOLTypes .CRLF ,
272
- "native" : EOLTypes .NATIVE ,
273
- }
274
-
275
- # If the response of `git config core.eol` is in the map:
276
- if eol in map :
277
- return map [eol ]
278
- else :
279
- # The default value is "native".
280
- # https://git-scm.com/docs/git-config#Documentation/git-config.txt-coreeol
281
- return map ["native" ]
234
+ if eol == "lf" :
235
+ return _UNIX_EOL
236
+ if eol == "crlf" :
237
+ return _WINDOWS_EOL
238
+ return os .linesep
282
239
283
240
284
241
def get_core_editor () -> str | None :
@@ -288,22 +245,18 @@ def get_core_editor() -> str | None:
288
245
return None
289
246
290
247
291
- def smart_open (* args , ** kargs ):
248
+ def smart_open (* args , ** kwargs ):
292
249
"""Open a file with the EOL style determined from Git."""
293
- return open (* args , newline = get_eol_style (). get_eol_for_open (), ** kargs )
250
+ return open (* args , newline = get_eol_for_open (), ** kwargs )
294
251
295
252
296
253
def _get_log_as_str_list (start : str | None , end : str , args : str ) -> list [str ]:
297
254
"""Get string representation of each log entry"""
298
255
delimiter = "----------commit-delimiter----------"
299
256
log_format : str = "%H%n%P%n%s%n%an%n%ae%n%b"
300
- git_log_cmd = (
301
- f"git -c log.showSignature=False log --pretty={ log_format } { delimiter } { args } "
302
- )
303
- if start :
304
- command = f"{ git_log_cmd } { start } ..{ end } "
305
- else :
306
- command = f"{ git_log_cmd } { end } "
257
+ command_range = f"{ start } ..{ end } " if start else end
258
+ command = f"git -c log.showSignature=False log --pretty={ log_format } { delimiter } { args } { command_range } "
259
+
307
260
c = cmd .run (command )
308
261
if c .return_code != 0 :
309
262
raise GitCommandError (c .err )
0 commit comments