2
2
"""
3
3
commit_msg_version_bump.py
4
4
5
- A script to bump the version in pyproject.toml based on commit message keywords.
6
- Handles major, minor, and patch releases. Additionally, it adds icons to commit messages
7
- depending on their type and ensures that changes are committed in a single step.
5
+ A script to bump the version in pyproject.toml based on the latest commit message.
6
+ Adds icons to commit messages depending on their type and ensures that changes are committed in a single step.
8
7
9
8
Usage:
10
9
commit_msg_version_bump.py [--log-level {INFO,DEBUG}]
16
15
import subprocess
17
16
import sys
18
17
from logging .handlers import RotatingFileHandler
19
- from typing import List , Optional , Tuple
18
+ from typing import Optional
20
19
21
- import toml
22
20
23
- # Mapping of commit types to changelog sections and icons
21
+ # Mapping of commit types to icons
24
22
TYPE_MAPPING = {
25
- "feat" : { "section" : "### Features" , "icon" : "✨" } ,
26
- "fix" : { "section" : "### Bug Fixes" , "icon" : "🐛" } ,
27
- "docs" : { "section" : "### Documentation" , "icon" : "📝" } ,
28
- "style" : { "section" : "### Styles" , "icon" : "💄" } ,
29
- "refactor" : { "section" : "### Refactors" , "icon" : " ♻️"} ,
30
- "perf" : { "section" : "### Performance Improvements" , "icon" : " ⚡️"} ,
31
- "test" : { "section" : "### Tests" , "icon" : "✅" } ,
32
- "chore" : { "section" : "### Chores" , "icon" : "🔧" } ,
23
+ "feat" : "✨" ,
24
+ "fix" : "🐛" ,
25
+ "docs" : "📝" ,
26
+ "style" : "💄" ,
27
+ "refactor" : " ♻️" ,
28
+ "perf" : " ⚡️" ,
29
+ "test" : "✅" ,
30
+ "chore" : "🔧" ,
33
31
}
34
32
35
33
# Mapping of commit types to version bump parts
@@ -65,7 +63,7 @@ def parse_arguments() -> argparse.Namespace:
65
63
"""
66
64
parser = argparse .ArgumentParser (
67
65
description = (
68
- "Bump the version in pyproject.toml based on commit message keywords . "
66
+ "Bump the version in pyproject.toml based on the latest commit message. "
69
67
"Adds icons to commit messages depending on their type."
70
68
)
71
69
)
@@ -106,109 +104,28 @@ def configure_logger(log_level: str) -> None:
106
104
logger .addHandler (console_handler )
107
105
108
106
109
- def get_pushed_refs () -> List [ Tuple [ str , str ]] :
107
+ def get_latest_commit_message () -> str :
110
108
"""
111
- Retrieves the list of refs being pushed .
109
+ Retrieves the latest commit message .
112
110
113
111
Returns:
114
- List[Tuple[ str, str]]: List of tuples containing local_ref and remote_sha .
112
+ str: The latest commit message .
115
113
"""
116
- refs = []
117
114
try :
118
- # Read from stdin the refs being pushed
119
- for line in sys .stdin :
120
- parts = line .strip ().split ()
121
- if len (parts ) >= 4 :
122
- local_ref , local_sha , remote_ref , remote_sha = parts [:4 ]
123
- refs .append ((local_ref , remote_sha ))
124
- logger .debug (f"Refs being pushed: { refs } " )
125
- return refs
126
- except Exception as e :
127
- logger .error (f"Error reading refs from stdin: { e } " )
128
- sys .exit (1 )
129
-
130
-
131
- def get_upstream_branch () -> Optional [str ]:
132
- """
133
- Retrieves the upstream branch for the current branch.
134
-
135
- Returns:
136
- Optional[str]: The upstream branch name or None if not found.
137
- """
138
- try :
139
- upstream = subprocess .run (
140
- ["git" , "rev-parse" , "--abbrev-ref" , "--symbolic-full-name" , "@{u}" ],
115
+ message = subprocess .run (
116
+ ["git" , "log" , "-1" , "--pretty=%B" ],
141
117
check = True ,
142
118
stdout = subprocess .PIPE ,
143
119
stderr = subprocess .PIPE ,
144
120
text = True ,
145
121
).stdout .strip ()
146
- logger .debug (f"Upstream branch : { upstream } " )
147
- return upstream
122
+ logger .debug (f"Latest commit message : { message } " )
123
+ return message
148
124
except subprocess .CalledProcessError as e :
149
- logger .error (f"Error retrieving upstream branch: { e .stderr } " )
150
- return None
151
-
152
-
153
- def get_commits_being_pushed (remote_sha : str , local_sha : str ) -> List [str ]:
154
- """
155
- Retrieves the list of commit hashes being pushed for a given ref range.
156
-
157
- Args:
158
- remote_sha (str): The remote SHA before the push.
159
- local_sha (str): The local SHA being pushed.
160
-
161
- Returns:
162
- List[str]: List of commit hashes being pushed.
163
- """
164
- try :
165
- commits = (
166
- subprocess .run (
167
- ["git" , "rev-list" , "--no-merges" , f"{ remote_sha } ..{ local_sha } " ],
168
- check = True ,
169
- stdout = subprocess .PIPE ,
170
- stderr = subprocess .PIPE ,
171
- text = True ,
172
- )
173
- .stdout .strip ()
174
- .split ("\n " )
175
- )
176
- commits = [commit for commit in commits if commit ]
177
- logger .debug (f"Commits being pushed for { remote_sha } ..{ local_sha } : { commits } " )
178
- return commits
179
- except subprocess .CalledProcessError as e :
180
- logger .error (f"Error retrieving commits for { remote_sha } ..{ local_sha } : { e .stderr } " )
125
+ logger .error (f"Error retrieving latest commit message: { e .stderr } " )
181
126
sys .exit (1 )
182
127
183
128
184
- def read_commit_messages (commits : List [str ]) -> List [str ]:
185
- """
186
- Reads commit messages for the given list of commits.
187
-
188
- Args:
189
- commits (List[str]): List of commit hashes.
190
-
191
- Returns:
192
- List[str]: List of commit messages.
193
- """
194
- commit_messages = []
195
- for commit in commits :
196
- try :
197
- message = subprocess .run (
198
- ["git" , "log" , "--format=%B" , "-n" , "1" , commit ],
199
- check = True ,
200
- stdout = subprocess .PIPE ,
201
- stderr = subprocess .PIPE ,
202
- text = True ,
203
- ).stdout .strip ()
204
- logger .debug (f"Commit { commit } : { message } " )
205
- commit_messages .append (message )
206
- except subprocess .CalledProcessError as e :
207
- logger .error (f"Error reading commit { commit } : { e .stderr } " )
208
- sys .exit (1 )
209
- return commit_messages
210
-
211
-
212
129
def add_icon_to_commit_message (commit_msg : str ) -> str :
213
130
"""
214
131
Adds an icon to the commit message based on its type.
@@ -222,7 +139,7 @@ def add_icon_to_commit_message(commit_msg: str) -> str:
222
139
match = COMMIT_TYPE_REGEX .match (commit_msg )
223
140
if match :
224
141
commit_type = match .group ("type" ).lower ()
225
- icon = TYPE_MAPPING .get (commit_type , {}). get ( "icon" , "" )
142
+ icon = TYPE_MAPPING .get (commit_type , "" )
226
143
if icon :
227
144
# Avoid adding multiple icons
228
145
if not commit_msg .startswith (icon ):
@@ -279,30 +196,6 @@ def bump_version(part: str) -> None:
279
196
sys .exit (1 )
280
197
281
198
282
- def get_new_version (pyproject_path : str = "pyproject.toml" ) -> str :
283
- """
284
- Retrieves the new version from pyproject.toml.
285
-
286
- Args:
287
- pyproject_path (str): Path to the pyproject.toml file.
288
-
289
- Returns:
290
- str: The new version string.
291
-
292
- Raises:
293
- SystemExit: If the version cannot be retrieved.
294
- """
295
- try :
296
- with open (pyproject_path , "r" , encoding = "utf-8" ) as file :
297
- data = toml .load (file )
298
- version = data ["tool" ]["poetry" ]["version" ]
299
- logger .debug (f"New version retrieved: { version } " )
300
- return version
301
- except (FileNotFoundError , KeyError , ValueError , toml .TomlDecodeError ) as e :
302
- logger .error (f"Error retrieving the version from { pyproject_path } : { e } " )
303
- sys .exit (1 )
304
-
305
-
306
199
def stage_changes (pyproject_path : str = "pyproject.toml" ) -> None :
307
200
"""
308
201
Stages the specified file for commit.
@@ -332,64 +225,43 @@ def amend_commit(new_commit_msg: str) -> None:
332
225
# Amend the commit with the new commit message
333
226
subprocess .run (["git" , "commit" , "--amend" , "-m" , new_commit_msg ], check = True )
334
227
logger .info ("Successfully amended the commit with the new version bump." )
228
+ logger .info (
229
+ "Please perform a force push using 'git push --force' to update the remote repository."
230
+ )
335
231
except subprocess .CalledProcessError as e :
336
232
logger .error (f"Failed to amend the commit: { e } " )
337
233
sys .exit (1 )
338
234
339
235
340
236
def main () -> None :
341
237
"""
342
- Main function to parse commit messages and perform version bumping and commit message enhancement .
238
+ Main function to parse the latest commit message, add an icon, and perform version bumping .
343
239
"""
344
240
args = parse_arguments ()
345
241
configure_logger (args .log_level )
346
242
347
- # Retrieve refs being pushed from stdin
348
- pushed_refs = get_pushed_refs ()
349
- if not pushed_refs :
350
- logger .info ("No refs being pushed." )
351
- return
352
-
353
- for local_ref , remote_sha in pushed_refs :
354
- try :
355
- local_sha = subprocess .run (
356
- ["git" , "rev-parse" , local_ref ],
357
- check = True ,
358
- stdout = subprocess .PIPE ,
359
- stderr = subprocess .PIPE ,
360
- text = True ,
361
- ).stdout .strip ()
362
- logger .debug (f"Local SHA for { local_ref } : { local_sha } " )
363
- except subprocess .CalledProcessError as e :
364
- logger .error (f"Error retrieving local SHA for { local_ref } : { e .stderr } " )
365
- continue
366
-
367
- commits = get_commits_being_pushed (remote_sha , local_sha )
368
- if not commits :
369
- logger .info (f"No new commits to process for { local_ref } ." )
370
- continue
371
-
372
- commit_messages = read_commit_messages (commits )
373
-
374
- for commit_msg in commit_messages :
375
- updated_commit_msg = add_icon_to_commit_message (commit_msg )
376
- version_bump_part = determine_version_bump (commit_msg )
377
-
378
- if version_bump_part :
379
- logger .info (f"Version bump detected: { version_bump_part } " )
380
- bump_version (version_bump_part )
381
- # new_version = get_new_version()
382
-
383
- # Stage the updated pyproject.toml
384
- stage_changes ()
385
-
386
- # Amend the latest commit with the updated commit message
387
- amend_commit (updated_commit_msg )
388
-
389
- # After bumping and amending, stop processing further commits to avoid multiple bumps
390
- break
391
- else :
392
- logger .info ("No version bump detected in commit message." )
243
+ latest_commit_msg = get_latest_commit_message ()
244
+
245
+ updated_commit_msg = add_icon_to_commit_message (latest_commit_msg )
246
+
247
+ version_bump_part = determine_version_bump (latest_commit_msg )
248
+
249
+ if version_bump_part :
250
+ logger .info (f"Version bump detected: { version_bump_part } " )
251
+ bump_version (version_bump_part )
252
+
253
+ # Stage the updated pyproject.toml
254
+ stage_changes ()
255
+
256
+ # Amend the commit with the updated message
257
+ amend_commit (updated_commit_msg )
258
+
259
+ logger .info (
260
+ "Aborting the current push. Please perform a force push using 'git push --force'."
261
+ )
262
+ sys .exit (1 )
263
+ else :
264
+ logger .info ("No version bump detected in commit message." )
393
265
394
266
395
267
if __name__ == "__main__" :
0 commit comments