Coverage for ghtc/cli.py: 0%
66 statements
« prev ^ index » next coverage.py v7.2.7, created at 2024-11-25 11:59 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2024-11-25 11: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
20app = Typer(add_completion=False)
21ALL_TYPES = ", ".join([x.name.lower() for x in ConventionalCommitType])
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))
115def main():
116 app()
119if __name__ == "__main__":
120 main()