format code
[utils.git] / src / budget_sync / main.py
1 from typing import Dict, List
2 from budget_sync.write_budget_csv import write_budget_csv
3 from bugzilla import Bugzilla
4 import logging
5 import argparse
6 from pathlib import Path
7 from budget_sync.money import Money
8 from budget_sync.util import all_bugs
9 from budget_sync.config import Config, ConfigParseError, Milestone
10 from budget_sync.budget_graph import BudgetGraph, BudgetGraphBaseError, PaymentSummary
11 from budget_sync.write_budget_markdown import write_budget_markdown
12
13
14 def main():
15 parser = argparse.ArgumentParser(
16 description="Check for errors in "
17 "Libre-SOC's style of budget tracking in Bugzilla.")
18 parser.add_argument(
19 "-c", "--config", type=argparse.FileType('r'),
20 required=True, help="The path to the configuration TOML file",
21 dest="config", metavar="<path/to/budget-sync-config.toml>")
22 parser.add_argument(
23 "-o", "--output-dir", type=Path, default=None,
24 help="The path to the output directory, will be created if it "
25 "doesn't exist",
26 dest="output_dir", metavar="<path/to/output/dir>")
27 parser.add_argument('--username', help="Log in with this username")
28 parser.add_argument('--password', help="Log in with this password")
29 args = parser.parse_args()
30 try:
31 with args.config as config_file:
32 config = Config.from_file(config_file)
33 except (IOError, ConfigParseError) as e:
34 logging.error("Failed to parse config file: %s", e)
35 return
36 logging.info("Using Bugzilla instance at %s", config.bugzilla_url)
37 bz = Bugzilla(config.bugzilla_url)
38 if args.username:
39 logging.debug("logging in...")
40 bz.interactive_login(args.username, args.password)
41 logging.debug("Connected to Bugzilla")
42 budget_graph = BudgetGraph(all_bugs(bz), config)
43 for error in budget_graph.get_errors():
44 logging.error("%s", error)
45 if args.output_dir is not None:
46 write_budget_markdown(budget_graph, args.output_dir)
47 write_budget_csv(budget_graph, args.output_dir)
48 summarize_milestones(budget_graph)
49
50
51 def print_budget_then_children(indent, nodes, bug_id):
52 """recursive indented printout of budgets
53 """
54
55 bug = nodes[bug_id]
56 print("bug #%5d %s budget %7s excltasks %7s" %
57 (bug.bug.id, ' ' * (indent*4),
58 str(bug.budget_including_subtasks),
59 str(bug.budget_excluding_subtasks)))
60 #print (repr(bug))
61 for child in bug.immediate_children:
62 if (str(child.budget_including_subtasks) == "0" and
63 str(child.budget_excluding_subtasks) == "0"):
64 continue
65 print_budget_then_children(indent+1, nodes, child.bug.id)
66
67
68 def summarize_milestones(budget_graph: BudgetGraph):
69 for milestone, payments in budget_graph.milestone_payments.items():
70 summary = PaymentSummary(payments)
71 print(f"{milestone.identifier}")
72 print(f"\t{summary.total} submitted: "
73 f"{summary.total_submitted} paid: {summary.total_paid}")
74 not_submitted = summary.get_not_submitted()
75 if not_submitted:
76 print("not submitted", not_submitted)
77
78 # and one to display people
79 for person in budget_graph.milestone_people[milestone]:
80 print(f"\t{person.identifier}")
81 print()
82
83 # now do trees
84 for milestone, payments in budget_graph.milestone_payments.items():
85 print("%s %d" % (milestone.identifier, milestone.canonical_bug_id))
86 print_budget_then_children(0, budget_graph.nodes,
87 milestone.canonical_bug_id)
88 print()
89
90
91 if __name__ == "__main__":
92 main()