1+ import contextlib
12import logging
23import re
34import warnings
@@ -231,27 +232,46 @@ def get_hash_link(commit: TGITCommit) -> str:
231232 return out_str
232233
233234
235+ def extract_latest_tag_from_changelog (filepath : str ) -> str | None :
236+ filepath = Path (filepath )
237+ with contextlib .suppress (FileNotFoundError ), filepath .open (encoding = "utf-8" ) as f :
238+ for line in f :
239+ if line .startswith ("## " ):
240+ return line .strip ().removeprefix ("## " ).strip ()
241+ return None
242+
243+
234244def handle_changelog (args : ChangelogArgs ) -> None :
235245 repo = git .Repo (args .path )
236-
237246 from_raw = args .from_raw
238247 to_raw = args .to_raw
239248
240- # 如果未指定 from/to,聚合所有 tag 版本的 changelog(不再包含 HEAD,仅以最后一个 tag 结尾)
249+ # 检查是否需要增量追加
250+ latest_tag_in_file = None
251+ if args .output and Path (args .output ).exists () and from_raw is None and to_raw is None :
252+ latest_tag_in_file = extract_latest_tag_from_changelog (args .output )
253+
254+ # 默认:统计所有 tag 之间的差分(不包含最新 tag 到 HEAD)
241255 if from_raw is None and to_raw is None :
242256 tags = sorted (repo .tags , key = lambda t : t .commit .committed_datetime )
257+ if not tags :
258+ print ("[yellow]No tags found in the repository.[/yellow]" )
259+ return
243260 first_commit = get_first_commit_hash (repo )
244261 points = [first_commit ] + [tag .commit .hexsha for tag in tags ]
245262 point_names = [first_commit ] + [tag .name for tag in tags ]
246263 changelogs = ""
264+ start_idx = 1
265+ if latest_tag_in_file and latest_tag_in_file in point_names :
266+ idx = point_names .index (latest_tag_in_file )
267+ start_idx = idx + 1
247268 with Progress () as progress :
248- task = progress .add_task ("Generating changelog..." , total = len (points ) - 1 )
249- # 反向遍历区间,实现反向输出
250- for i in reversed (range (len (points ) - 1 )):
251- from_hash = points [i ]
252- to_hash = points [i + 1 ]
253- from_name = point_names [i ]
254- to_name = point_names [i + 1 ]
269+ task = progress .add_task ("Generating changelog..." , total = len (points ) - start_idx )
270+ for i in reversed (range (start_idx , len (points ))):
271+ from_hash = points [i - 1 ]
272+ to_hash = points [i ]
273+ from_name = point_names [i - 1 ]
274+ to_name = point_names [i ]
255275 raw_commits = list (repo .iter_commits (f"{ from_hash } ...{ to_hash } " ))
256276 tgit_commits = []
257277 for commit in raw_commits :
@@ -267,8 +287,9 @@ def handle_changelog(args: ChangelogArgs) -> None:
267287 changelog = generate_changelog (commits_by_type , from_name , to_name , remote_uri )
268288 changelogs += changelog
269289 progress .update (task , advance = 1 )
270- if args .output :
271- with Path (args .output ).open ("w" ) as output_file :
290+ if changelogs :
291+ mode = "a" if latest_tag_in_file else "w"
292+ with Path (args .output ).open (mode , encoding = "utf-8" ) as output_file :
272293 output_file .write (changelogs .strip ("\n " ) + "\n " )
273294 print ()
274295 print (changelogs .strip ("\n " ))
@@ -278,7 +299,7 @@ def handle_changelog(args: ChangelogArgs) -> None:
278299 from_ref , to_ref = get_git_commits_range (repo , from_raw , to_raw )
279300 changelog = get_changelog_by_range (repo , from_ref , to_ref )
280301 if args .output :
281- with Path (args .output ).open ("w" ) as output_file :
302+ with Path (args .output ).open ("w" , encoding = "utf-8" ) as output_file :
282303 output_file .write (changelog .strip ("\n " ) + "\n " )
283304 else :
284305 print ()
0 commit comments