6
6
from dataclasses import dataclass
7
7
from pathlib import Path
8
8
from tempfile import NamedTemporaryFile
9
- from typing import TYPE_CHECKING , ClassVar , List , MutableMapping , Optional , Type , Union
9
+ from typing import TYPE_CHECKING , Any , ClassVar , Dict , List , MutableMapping , Optional , Type , Union
10
10
11
11
from bumpversion .ui import get_indented_logger
12
12
from bumpversion .utils import extract_regex_flags , run_command
@@ -51,7 +51,7 @@ def __repr__(self):
51
51
def path_in_repo (self , path : Union [Path , str ]) -> bool :
52
52
"""Return whether a path is inside this repository."""
53
53
if self .repository_root is None :
54
- return False
54
+ return True
55
55
56
56
return Path (path ).is_relative_to (self .repository_root )
57
57
@@ -263,15 +263,36 @@ def latest_tag_info(cls, tag_name: str, parse_pattern: str) -> SCMInfo:
263
263
if not cls .is_usable ():
264
264
return SCMInfo ()
265
265
266
- info = SCMInfo ( tool = cls )
266
+ info : Dict [ str , Any ] = { " tool" : cls }
267
267
268
268
try :
269
269
# git-describe doesn't update the git-index, so we do that
270
270
run_command (["git" , "update-index" , "--refresh" , "-q" ])
271
271
except subprocess .CalledProcessError as e :
272
272
logger .debug ("Error when running git update-index: %s" , e .stderr )
273
273
274
+ commit_info = cls ._commit_info (parse_pattern , tag_name )
275
+ rev_info = cls ._revision_info ()
276
+ info |= commit_info
277
+ info |= rev_info
278
+
279
+ return SCMInfo (** info )
280
+
281
+ @classmethod
282
+ def _commit_info (cls , parse_pattern : str , tag_name : str ) -> dict :
283
+ """
284
+ Get the commit info for the repo.
285
+
286
+ Args:
287
+ parse_pattern: The regular expression pattern used to parse the version from the tag.
288
+ tag_name: The tag name format used to locate the latest tag.
289
+
290
+ Returns:
291
+ A dictionary containing information about the latest commit.
292
+ """
274
293
tag_pattern = tag_name .replace ("{new_version}" , "*" )
294
+ info = dict .fromkeys (["dirty" , "commit_sha" , "distance_to_latest_tag" , "current_version" ])
295
+ info ["distance_to_latest_tag" ] = 0
275
296
try :
276
297
# get info about the latest tag in git
277
298
git_cmd = [
@@ -286,28 +307,45 @@ def latest_tag_info(cls, tag_name: str, parse_pattern: str) -> SCMInfo:
286
307
result = run_command (git_cmd )
287
308
describe_out = result .stdout .strip ().split ("-" )
288
309
if describe_out [- 1 ].strip () == "dirty" :
289
- info . dirty = True
310
+ info [ " dirty" ] = True
290
311
describe_out .pop ()
291
312
else :
292
- info . dirty = False
313
+ info [ " dirty" ] = False
293
314
294
- info . commit_sha = describe_out .pop ().lstrip ("g" )
295
- info . distance_to_latest_tag = int (describe_out .pop ())
315
+ info [ " commit_sha" ] = describe_out .pop ().lstrip ("g" )
316
+ info [ " distance_to_latest_tag" ] = int (describe_out .pop ())
296
317
version = cls .get_version_from_tag ("-" .join (describe_out ), tag_name , parse_pattern )
297
- info . current_version = version or "-" .join (describe_out ).lstrip ("v" )
318
+ info [ " current_version" ] = version or "-" .join (describe_out ).lstrip ("v" )
298
319
except subprocess .CalledProcessError as e :
299
320
logger .debug ("Error when running git describe: %s" , e .stderr )
300
321
322
+ return info
323
+
324
+ @classmethod
325
+ def _revision_info (cls ) -> dict :
326
+ """
327
+ Returns a dictionary containing revision information.
328
+
329
+ If an error occurs while running the git command, the dictionary values will be set to None.
330
+
331
+ Returns:
332
+ A dictionary with the following keys:
333
+ - branch_name: The name of the current branch.
334
+ - short_branch_name: A 20 lowercase characters of the branch name with special characters removed.
335
+ - repository_root: The root directory of the Git repository.
336
+ """
337
+ info = dict .fromkeys (["branch_name" , "short_branch_name" , "repository_root" ])
338
+
301
339
try :
302
340
git_cmd = ["git" , "rev-parse" , "--show-toplevel" , "--abbrev-ref" , "HEAD" ]
303
341
result = run_command (git_cmd )
304
342
lines = [line .strip () for line in result .stdout .split ("\n " )]
305
343
repository_root = Path (lines [0 ])
306
344
branch_name = lines [1 ]
307
345
short_branch_name = re .sub (r"([^a-zA-Z0-9]*)" , "" , branch_name ).lower ()[:20 ]
308
- info . branch_name = branch_name
309
- info . short_branch_name = short_branch_name
310
- info . repository_root = repository_root
346
+ info [ " branch_name" ] = branch_name
347
+ info [ " short_branch_name" ] = short_branch_name
348
+ info [ " repository_root" ] = repository_root
311
349
except subprocess .CalledProcessError as e :
312
350
logger .debug ("Error when running git rev-parse: %s" , e .stderr )
313
351
@@ -316,7 +354,9 @@ def latest_tag_info(cls, tag_name: str, parse_pattern: str) -> SCMInfo:
316
354
@classmethod
317
355
def add_path (cls , path : Union [str , Path ]) -> None :
318
356
"""Add a path to the VCS."""
319
- run_command (["git" , "add" , "--update" , str (path )])
357
+ info = SCMInfo (** cls ._revision_info ())
358
+ if info .path_in_repo (path ):
359
+ run_command (["git" , "add" , "--update" , str (path )])
320
360
321
361
@classmethod
322
362
def tag (cls , name : str , sign : bool = False , message : Optional [str ] = None ) -> None :
0 commit comments