diff --git a/tools/gitlog2changelog.py b/tools/gitlog2changelog.py index 63a54433f8..2a4ad5b788 100644 --- a/tools/gitlog2changelog.py +++ b/tools/gitlog2changelog.py @@ -13,75 +13,27 @@ contributors = { "@[Hao Guan]": "@hguandl", } -# 从哪个 tag 开始 -latest = os.popen("git describe --abbrev=0 --tags").read()[:-1] -print("From:", latest, "\n") - -# 输出一张好看的 git log 图到控制台 -git_pretty_command = rf'git log {latest}..HEAD --pretty=format:"%C(yellow)%d%Creset %s %C(bold blue)@%an%Creset (%Cgreen%h%Creset)" --graph' -os.system(git_pretty_command) - -# 获取详细的 git log 信息 -git_command = rf'git log {latest}..HEAD --pretty=raw' -with os.popen(git_command) as fp: bf = fp._stream.buffer.read() -try: gitlogs = bf.decode().strip() -except: gitlogs = bf.decode("gbk").strip() - -current_commit = None -current_commit_status = "" -raw_commits_info = {} - -for line in gitlogs.split("\n"): - line = re.sub(r"^ *", "", line) - if line.startswith("commit "): - current_commit = line[7:] - current_commit_status = "" - raw_commits_info[current_commit] = {} - if current_commit == None: - continue - - if line == "": - continue - elif line.startswith("parent "): - if "parent" not in raw_commits_info[current_commit]: - raw_commits_info[current_commit]["parent"] = [] - raw_commits_info[current_commit]["parent"].append(line[7:]) - elif line.startswith("author "): - raw_commits_info[current_commit].update({ "author": line[7:].split(' <', 1)[0] }) - elif line.startswith("committer "): - raw_commits_info[current_commit].update({ "committer": line[10:].split(' <', 1)[0] }) - elif line.startswith("gpgsig"): - current_commit_status = "gpgsig" - elif line.find("-----END PGP SIGNATURE-----") != -1: - current_commit_status = "" - elif line.startswith("commit "): - pass - elif line.startswith("tree "): - pass - elif current_commit_status == "": - if "message" in raw_commits_info[current_commit] and not raw_commits_info[current_commit]["message"].startswith("Merge"): - continue - raw_commits_info[current_commit]["message"] = line - -commits = {} - -def search_commits(commit_hash: str, to): +# dfs 建树,Merge commit 是非叶子节点 +def build_commits_tree(commit_hash: str): + res = {} if commit_hash not in raw_commits_info: - return + return res raw_commit_info = raw_commits_info[commit_hash] if "visited" in raw_commit_info: - return + return res raw_commit_info.update({"visited": True}) - commit_key = raw_commit_info["message"] + f" @[{raw_commit_info['author']}]" - to[commit_key] = {} - search_commits(raw_commit_info["parent"][0], to) + commit_key = raw_commit_info["message"] + f" ({raw_commit_info['hash']})" + f" @[{raw_commit_info['author']}]" + res[commit_key] = {} + res.update(build_commits_tree(raw_commit_info["parent"][0])) if len(raw_commit_info["parent"]) == 2: - search_commits(raw_commit_info["parent"][1], to[commit_key]) - -search_commits([x for x in raw_commits_info.keys()][0], commits) - -# print(json.dumps(commits, ensure_ascii=False, indent=2)) -# exit(0) + if commit_key.startswith("Release"): + # 避免合并之后只有一个 Release 主 commit + res.update(build_commits_tree(raw_commit_info["parent"][1])) + else: + res[commit_key].update(build_commits_tree(raw_commit_info["parent"][1])) + if commit_key.startswith("Merge branch") and not res[commit_key]: + res.pop(commit_key) + return res def print_commits(commits: dict, indent: str = "", need_sort: bool = True) -> (str, list): if not commits: return ("", []) @@ -98,18 +50,18 @@ def print_commits(commits: dict, indent: str = "", need_sort: bool = True) -> (s for x in commits.keys(): if False: pass + elif x.find("新增") != -1: + sorted_commits["feat"][x] = commits[x] + elif x.find("改进") != -1 or x.find("更新") != -1 or x.find("优化") != -1 or x.find("重构") != -1: + sorted_commits["perf"][x] = commits[x] + elif x.find("修复") != -1: + sorted_commits["fix"][x] = commits[x] elif x.startswith("feat"): sorted_commits["feat"][x] = commits[x] elif x.startswith("perf"): sorted_commits["perf"][x] = commits[x] elif x.startswith("fix"): sorted_commits["fix"][x] = commits[x] - elif x.find("新增") != -1: - sorted_commits["feat"][x] = commits[x] - elif x.find("改进") != -1 or x.find("优化") != -1: - sorted_commits["perf"][x] = commits[x] - elif x.find("修复") != -1: - sorted_commits["fix"][x] = commits[x] else: sorted_commits["other"][x] = commits[x] @@ -173,8 +125,31 @@ def print_commits(commits: dict, indent: str = "", need_sort: bool = True) -> (s return ret_message, ret_contributor -res = print_commits(commits) -nightly = os.popen("git describe --tags").read()[:-1] +if __name__ == "__main__": + # 从哪个 tag 开始 + latest = os.popen("git describe --abbrev=0 --tags").read()[:-1] + latest = "v4.12.0-beta.1" + nightly = os.popen("git describe --tags").read()[:-1] + print("From:", latest, ", To:", nightly, "\n") -with open("../changelog.md", "w", encoding="utf8") as f: - f.write("## " + nightly + "\n" + res[0]) + # 输出一张好看的 git log 图到控制台 + git_pretty_command = rf'git log {latest}..HEAD --pretty=format:"%C(yellow)%d%Creset %s %C(bold blue)@%an%Creset (%Cgreen%h%Creset)" --graph' + os.system(git_pretty_command) + print() + + # 获取详细的 git log 信息 + git_command = rf'git log {latest}..HEAD --pretty=format:"\"%H\":{{\"hash\":\"%h\",\"author\":\"%aN\",\"committer\":\"%cN\",\"message\":\"%s\",\"parent\":\"%P\"}},"' + + with os.popen(git_command) as fp: bf = fp._stream.buffer.read() + try: gitlogs = bf.decode().strip() + except: gitlogs = bf.decode("gbk").strip() + gitlogs = "{" + gitlogs[:-1] + "}" + raw_commits_info = json.loads(gitlogs) + for x, y in raw_commits_info.items(): + y["parent"] = y["parent"].split() + # print(json.dumps(raw_commits_info, ensure_ascii=False, indent=2)) + + res = print_commits(build_commits_tree([x for x in raw_commits_info.keys()][0])) + + with open("../changelog.md", "w", encoding="utf8") as f: + f.write("## " + nightly + "\n" + res[0])