parse-changelog.py 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import os
  2. import re
  3. from argparse import ArgumentParser
  4. from collections import defaultdict
  5. import github
  6. docmap = {
  7. "Feature": "引入特性",
  8. "Enhancement": "改进功能",
  9. "Bug": "修复缺陷",
  10. "Document": "文档相关",
  11. "Refactor": "开发重构",
  12. "Abolishment": "移除功能",
  13. "Development": "开发相关",
  14. }
  15. def generate_msg_from_repo(repo_name, tag_name):
  16. """Generate changelog messages from repository and tag name.
  17. Envs:
  18. GITHUB_HOST: the custom github host.
  19. GITHUB_TOKEN: the github access token.
  20. Args:
  21. repo_name (str): The repository name
  22. tag_name (str): the tag name
  23. """
  24. hostname = os.getenv("GITHUB_HOST") or "api.github.com"
  25. token = os.getenv("GITHUB_TOKEN")
  26. desc_mapping = defaultdict(list)
  27. gh = github.Github(token, base_url=f"https://{hostname}")
  28. repo = gh.get_repo(repo_name)
  29. milestone = find_milestone(repo, tag_name)
  30. for issue in repo.get_issues(state="closed", milestone=milestone):
  31. # REF https://pygithub.readthedocs.io/en/latest/github_objects/Issue.html#github.Issue.Issue
  32. desc_mapping[get_issue_first_label(issue)].append(
  33. {"title": issue.title, "url": issue.html_url}
  34. )
  35. generate_msg(desc_mapping)
  36. def find_milestone(repo, title):
  37. """Find the milestone in a repository that is similar to milestone title
  38. Args:
  39. repo (github.repository.Repository): The repository to search
  40. title (str): the title to match
  41. Returns:
  42. The milestone which title matches the given argument.
  43. If no milestone matches, it will return None
  44. """
  45. pat = re.search("v([0-9.]+)", title)
  46. if not pat:
  47. return None
  48. version = pat.group(1)
  49. for milestone in repo.get_milestones():
  50. if version in milestone.title:
  51. return milestone
  52. def get_issue_first_label(issue):
  53. """Get the first label from issue, if no labels, return empty string."""
  54. for label in issue.get_labels():
  55. if label.name in docmap:
  56. return label.name
  57. return ""
  58. def generate_msg(desc_mapping):
  59. """Print changelogs from direction."""
  60. print()
  61. for header in docmap:
  62. if not desc_mapping[header]:
  63. continue
  64. print(f"### {docmap[header]}\n")
  65. for item in desc_mapping[header]:
  66. print(f"* [{item['title']}]({item['url']})")
  67. print()
  68. if __name__ == "__main__":
  69. parser = ArgumentParser(
  70. description="Automaticly generate information from issues by tag."
  71. )
  72. parser.add_argument("-t", "--tag", help="the tag to filter issues.")
  73. parser.add_argument("repo", help="The repository name")
  74. args = parser.parse_args()
  75. try:
  76. generate_msg_from_repo(args.repo, args.tag)
  77. except AssertionError:
  78. print(args.tag)