|
@@ -1,32 +1,95 @@
|
|
-#!/usr/bin/env python3
|
|
|
|
-from pathlib import Path
|
|
|
|
|
|
+import os
|
|
|
|
+import re
|
|
from argparse import ArgumentParser
|
|
from argparse import ArgumentParser
|
|
|
|
+from collections import defaultdict
|
|
|
|
|
|
|
|
+import github
|
|
|
|
|
|
-def parse_latest_changelog(text: str) -> str:
|
|
|
|
- """Read the contents between the first `##` and the second `##`"""
|
|
|
|
- recording = False
|
|
|
|
- contents: list[str] = []
|
|
|
|
- for line in text.splitlines():
|
|
|
|
- if line.strip().startswith("## ") and recording is False:
|
|
|
|
- recording = True
|
|
|
|
- elif line.strip().startswith("## ") and recording is True:
|
|
|
|
- break
|
|
|
|
- if recording:
|
|
|
|
- contents.append(line)
|
|
|
|
|
|
+docmap = {
|
|
|
|
+ "Enhancement": "改进功能",
|
|
|
|
+ "Document": "文档相关",
|
|
|
|
+ "Refactor": "开发重构",
|
|
|
|
+ "Bug": "修复缺陷",
|
|
|
|
+ "Features": "引入特性",
|
|
|
|
+ "Abolishments": "移除功能"
|
|
|
|
+}
|
|
|
|
|
|
- return "\n".join(contents[1:])
|
|
|
|
|
|
|
|
|
|
+def generate_msg_from_repo(repo_name, tag_name):
|
|
|
|
+ """Generate changelog messages from repository and tag name.
|
|
|
|
|
|
-def get_changelog() -> str:
|
|
|
|
- parser = ArgumentParser(description="Get the latest change log from CHANG_LOGS.md")
|
|
|
|
- parser.add_argument("changelog_file", help="The path of CHANGE_LOGS.md")
|
|
|
|
- args = parser.parse_args()
|
|
|
|
- with Path(args.changelog_file).open() as f:
|
|
|
|
- return f.read()
|
|
|
|
|
|
+ Envs:
|
|
|
|
+ GITHUB_HOST: the custom github host.
|
|
|
|
+ GITHUB_TOKEN: the github access token.
|
|
|
|
+
|
|
|
|
+ Args:
|
|
|
|
+ repo_name (str): The repository name
|
|
|
|
+ tag_name (str): the tag name
|
|
|
|
+ """
|
|
|
|
+ hostname = os.getenv("GITHUB_HOST") or "api.github.com"
|
|
|
|
+ token = os.getenv("GITHUB_TOKEN")
|
|
|
|
+ desc_mapping = defaultdict(list)
|
|
|
|
+
|
|
|
|
+ gh = github.Github(token, base_url=f"https://{hostname}")
|
|
|
|
+ repo = gh.get_repo(repo_name)
|
|
|
|
+ milestone = find_milestone(repo, tag_name)
|
|
|
|
+
|
|
|
|
+ for issue in repo.get_issues(state="closed", milestone=milestone):
|
|
|
|
+ desc_mapping[get_issue_first_label(issue)].append(
|
|
|
|
+ {"title": issue.title, "url": issue.url}
|
|
|
|
+ )
|
|
|
|
+ generate_msg(desc_mapping)
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def find_milestone(repo, title):
|
|
|
|
+ """Find the milestone in a repository that is similar to milestone title
|
|
|
|
+
|
|
|
|
+ Args:
|
|
|
|
+ repo (github.repository.Repository): The repository to search
|
|
|
|
+ title (str): the title to match
|
|
|
|
|
|
|
|
+ Returns:
|
|
|
|
+ The milestone which title matches the given argument.
|
|
|
|
+ If no milestone matches, it will return None
|
|
|
|
+ """
|
|
|
|
+ pat = re.search("v([0-9.]+)", title)
|
|
|
|
+ if not pat:
|
|
|
|
+ return None
|
|
|
|
+ version = pat.group(1)
|
|
|
|
+ for milestone in repo.get_milestones():
|
|
|
|
+ if version in milestone.title:
|
|
|
|
+ return milestone
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def get_issue_first_label(issue):
|
|
|
|
+ """Get the first label from issue, if no labels, return empty string."""
|
|
|
|
+ for label in issue.get_labels():
|
|
|
|
+ if label.name in docmap:
|
|
|
|
+ return label.name
|
|
|
|
+ return ""
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def generate_msg(desc_mapping):
|
|
|
|
+ """Print changelogs from direction."""
|
|
|
|
+ print()
|
|
|
|
+ for header in docmap:
|
|
|
|
+ if not desc_mapping[header]:
|
|
|
|
+ continue
|
|
|
|
+ print(f"### {docmap[header]}\n")
|
|
|
|
+ for item in desc_mapping[header]:
|
|
|
|
+ print(f"* [{item['title']}]({item['url']})")
|
|
|
|
+ print()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+if __name__ == "__main__":
|
|
|
|
+ parser = ArgumentParser(
|
|
|
|
+ description="Automaticly generate information from issues by tag."
|
|
|
|
+ )
|
|
|
|
+ parser.add_argument("-t", "--tag", help="the tag to filter issues.")
|
|
|
|
+ parser.add_argument("repo", help="The repository name")
|
|
|
|
+ args = parser.parse_args()
|
|
|
|
|
|
-if __name__ == '__main__':
|
|
|
|
- changelog = get_changelog()
|
|
|
|
- latest_changelog = parse_latest_changelog(changelog)
|
|
|
|
- print(latest_changelog)
|
|
|
|
|
|
+ try:
|
|
|
|
+ generate_msg_from_repo(args.repo, args.tag)
|
|
|
|
+ except AssertionError:
|
|
|
|
+ print(args.tag)
|