Coverage for ghtc/cli.py: 0%

66 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2024-10-08 10:59 +0000

1from typing import Any, Dict, List, Optional 

2from typer import Typer, Argument, Option 

3from git import Repo 

4from ghtc.utils import ( 

5 get_tags, 

6 get_commits_between, 

7 render_template, 

8 get_reverted_commit, 

9) 

10from ghtc.models import ( 

11 ChangelogLine, 

12 ChangelogEntryForATag, 

13 ConventionalCommitMessage, 

14 ConventionalCommitType, 

15 UNRELEASED_TAG_TIMESTAMP, 

16) 

17from ghtc.parser import parse 

18from ghtc.overrides import Overrides 

19 

20app = Typer(add_completion=False) 

21ALL_TYPES = ", ".join([x.name.lower() for x in ConventionalCommitType]) 

22 

23 

24@app.command() 

25def cli( 

26 repo_root: str = Argument(..., help="the fullpath to the git repository"), 

27 tags_regex: str = Option( 

28 "^v[0-9]", help="regex to select tags to show on changelog" 

29 ), 

30 starting_rev: str = Option( 

31 None, 

32 help="starting revision (if not set latest tag starting with " 

33 "ghtc_changelog_start if exists, else first git commit)", 

34 ), 

35 remove_duplicates_entries: bool = Option( 

36 True, help="if True, remove duplicate entries" 

37 ), 

38 unreleased: bool = Option( 

39 True, help="if True, add a section about unreleased changes" 

40 ), 

41 override_file: str = Option( 

42 ".ghtc_overrides.ini", help="the path/name of the 'commit overrides' file" 

43 ), 

44 include_type: List[str] = Option( 

45 [], 

46 help="include (only) given conventional types in changelog (can be used " 

47 "multiple times, all types by default), available types: %s" % ALL_TYPES, 

48 ), 

49 title: str = "CHANGELOG", 

50 unreleased_title: str = "[Unreleased]", 

51 debug: bool = Option(False, help="add debug values for each changelog entry"), 

52): 

53 overrides = Overrides(override_file) 

54 overrides.parse() 

55 repo = Repo(repo_root) 

56 previous_tag = starting_rev 

57 context: Dict[str, Any] = { 

58 "TITLE": title, 

59 "UNRELEASED_TAG_TIMESTAMP": UNRELEASED_TAG_TIMESTAMP, 

60 "TAGS": [], 

61 } 

62 tags = get_tags(repo, tags_regex) 

63 if len(include_type) == 0: 

64 # if include_type is empty, we consider we want all types 

65 included_cats = [x.name.lower() for x in list(ConventionalCommitType)] 

66 else: 

67 included_cats = [x.strip().lower() for x in include_type] 

68 if unreleased: 

69 tags.append(None) 

70 for tag in tags: 

71 if tag is None: 

72 tag_name = unreleased_title 

73 tag_date = UNRELEASED_TAG_TIMESTAMP 

74 rev = "" 

75 else: 

76 tag_name = tag.name 

77 tag_date = tag.object.authored_date 

78 rev = tag_name 

79 reverted_commits = [] 

80 for commit in get_commits_between(repo, previous_tag, rev): 

81 reverted_commit = get_reverted_commit(commit) 

82 if reverted_commit is not None: 

83 reverted_commits.append(reverted_commit) 

84 lines: Dict[ConventionalCommitType, List[ChangelogLine]] = {} 

85 for commit in get_commits_between(repo, previous_tag, rev): 

86 if commit.hexsha in reverted_commits: 

87 continue 

88 msg: Optional[ConventionalCommitMessage] = None 

89 if commit.hexsha in overrides.commits: 

90 msg = overrides.commits[commit.hexsha] 

91 if msg is None: 

92 # ignored message 

93 continue 

94 else: 

95 msg = parse(commit.message) 

96 if msg is None: 

97 continue 

98 cat = msg.type 

99 if cat.name.lower() not in included_cats: 

100 continue 

101 cline = ChangelogLine(msg, commit.hexsha, commit.committed_date) 

102 if cat not in lines: 

103 lines[cat] = [] 

104 if remove_duplicates_entries and cline in lines[cat]: 

105 continue 

106 lines[cat].insert(0, cline) 

107 entry = ChangelogEntryForATag(tag_name, tag_date, lines) 

108 if tag is not None or len(lines) > 0: 

109 context["TAGS"].append(entry) 

110 context["DEBUG"] = debug 

111 previous_tag = tag 

112 print(render_template(context)) 

113 

114 

115def main(): 

116 app() 

117 

118 

119if __name__ == "__main__": 

120 main()