f"bug #{self.bug_id}: {self.msg}"
+class BudgetGraphUnknownAssignee(BudgetGraphParseError):
+ def __init__(self, bug_id: int, assignee: str):
+ super().__init__(bug_id)
+ self.assignee = assignee
+
+ def __str__(self):
+ return f"Bug #{self.bug_id} is assigned to an unknown person: " \
+ f"{self.assignee!r}"
+
+
class BudgetGraphLoopError(BudgetGraphBaseError):
def __init__(self, bug_ids: List[int]):
self.bug_ids = bug_ids
new_err = BudgetGraphUnknownStatus(self.bug.id, self.bug.status)
raise new_err.with_traceback(sys.exc_info()[2])
+ @cached_property
+ def assignee(self) -> Person:
+ try:
+ return self.graph.config.all_names[self.bug.assigned_to]
+ except KeyError:
+ raise BudgetGraphUnknownAssignee(self.bug.id,
+ self.bug.assigned_to) \
+ .with_traceback(sys.exc_info()[2])
+
@cached_property
def bug_url(self) -> str:
return f"{self.graph.config.bugzilla_url_stripped}/show_bug.cgi?" \
status = repr(self.status)
except BudgetGraphBaseError:
status = f"<unknown status: {self.bug.status!r}>"
+ try:
+ assignee = f"Person<{self.assignee.identifier!r}>"
+ except BudgetGraphBaseError:
+ assignee = f"<unknown assignee: {self.bug.assigned_to!r}>"
immediate_children = []
for i in self.immediate_children:
immediate_children.append(_NodeSimpleReprWrapper(i))
f"milestone={milestone}, "
f"immediate_children={immediate_children!r}, "
f"payments={payments!r}, "
- f"status={status})")
+ f"status={status}, "
+ f"assignee={assignee})")
class BudgetGraphError(BudgetGraphBaseError):
except BudgetGraphBaseError as e:
errors.append(e)
+ try:
+ # check for assignee errors
+ node.assignee
+ except BudgetGraphBaseError as e:
+ errors.append(e)
+
if node.milestone_str != root.milestone_str:
errors.append(BudgetGraphMilestoneMismatch(
node.bug.id, root.bug.id))
cf_nlnet_milestone: Optional[str] = None,
cf_payees_list: str = "",
summary: str = "<default summary>",
- status: Union[str, BugStatus] = BugStatus.CONFIRMED):
+ status: Union[str, BugStatus] = BugStatus.CONFIRMED,
+ assigned_to: str = "user@example.com"):
self.id = bug_id
self.__budget_parent = cf_budget_parent
self.cf_budget = cf_budget
self.cf_payees_list = cf_payees_list
self.summary = summary
self.status = str(status)
+ self.assigned_to = assigned_to
@property
def cf_budget_parent(self) -> int:
f"cf_nlnet_milestone={self.cf_nlnet_milestone!r}, "
f"cf_payees_list={self.cf_payees_list!r}, "
f"summary={self.summary!r}, "
- f"status={status!r})")
+ f"status={status!r}, "
+ f"assigned_to={self.assigned_to!r})")
BudgetGraphNegativePayeeMoney, BudgetGraphPayeesParseError,
BudgetGraphPayeesMoneyMismatch, BudgetGraphUnknownMilestone,
BudgetGraphDuplicatePayeesForTask, BudgetGraphIncorrectRootForMilestone,
- BudgetGraphUnknownStatus)
+ BudgetGraphUnknownStatus, BudgetGraphUnknownAssignee)
from budget_sync.money import Money
from budget_sync.util import BugStatus
from typing import List, Type
"failed to parse status field of bug "
"#123: unknown status: 'fake status'")
+ def test_budget_graph_unknown_assignee(self):
+ self.assertEqual(str(BudgetGraphUnknownAssignee(
+ 123, "unknown@example.com")),
+ "Bug #123 is assigned to an unknown person:"
+ " 'unknown@example.com'")
+
def test_budget_graph_money_mismatch(self):
self.assertEqual(str(
BudgetGraphMoneyMismatchForBudgetExcludingSubtasks(
aliases = ["person1_alias1", "alias1"]
output_markdown_file = "person1.mdwn"
[people."person2"]
+ email = "person2@example.com"
aliases = ["person1_alias2", "alias2", "person 2"]
output_markdown_file = "person2.mdwn"
[people."person3"]
+ email = "user@example.com"
output_markdown_file = "person3.mdwn"
[milestones]
"milestone 1" = { canonical_bug_id = 1 }
"milestone_str='milestone 1', milestone=Milestone(config=..., "
"identifier='milestone 1', canonical_bug_id=1), "
"immediate_children=[#2], payments=[], "
- "status=BugStatus.CONFIRMED), Node(graph=..., id=#2, root=#1, "
+ "status=BugStatus.CONFIRMED, assignee=Person<'person3'>), "
+ "Node(graph=..., id=#2, root=#1, "
"parent=#1, budget_excluding_subtasks=10, "
"budget_including_subtasks=10, "
"fixed_budget_excluding_subtasks=10, "
"milestone_str='milestone 1', milestone=Milestone(config=..., "
"identifier='milestone 1', canonical_bug_id=1), "
"immediate_children=[], payments=[], "
- "status=BugStatus.CONFIRMED)], roots=[#1]}")
- bg = BudgetGraph([MockBug(bug_id=1, status="blah")],
+ "status=BugStatus.CONFIRMED, assignee=Person<'person3'>)], "
+ "roots=[#1]}")
+ bg = BudgetGraph([MockBug(bug_id=1, status="blah",
+ assigned_to="unknown@example.com")],
EXAMPLE_CONFIG)
self.assertEqual(
repr(bg),
"fixed_budget_excluding_subtasks=0, "
"fixed_budget_including_subtasks=0, milestone_str=None, "
"milestone=None, immediate_children=[], payments=[], "
- "status=<unknown status: 'blah'>)], roots=[#1]}")
+ "status=<unknown status: 'blah'>, "
+ "assignee=<unknown assignee: 'unknown@example.com'>)], "
+ "roots=[#1]}")
def test_empty(self):
bg = BudgetGraph([], EXAMPLE_CONFIG)
self.assertErrorTypesMatches(bg.get_errors(), [])
self.assertEqual(bg.nodes[1].status, status)
+ def test_assignee(self):
+ bg = BudgetGraph([MockBug(bug_id=1, assigned_to="blah")],
+ EXAMPLE_CONFIG)
+ errors = bg.get_errors()
+ self.assertErrorTypesMatches(errors,
+ [BudgetGraphUnknownAssignee])
+ self.assertEqual(errors[0].bug_id, 1)
+ self.assertEqual(errors[0].assignee, "blah")
+ bg = BudgetGraph([MockBug(bug_id=1,
+ assigned_to="person2@example.com")],
+ EXAMPLE_CONFIG)
+ self.assertErrorTypesMatches(bg.get_errors(), [])
+ self.assertEqual(bg.nodes[1].assignee,
+ EXAMPLE_CONFIG.people["person2"])
+
if __name__ == "__main__":
unittest.main()
"MockBug(bug_id=12, cf_budget_parent=None, cf_budget='0', "
"cf_total_budget='0', cf_nlnet_milestone='---', "
"cf_payees_list='', summary='<default summary>', "
- "status=BugStatus.CONFIRMED)")
+ "status=BugStatus.CONFIRMED, "
+ "assigned_to='user@example.com')")
bug = MockBug(bug_id=34,
cf_budget_parent=1,
cf_budget="45",
cf_nlnet_milestone="abc",
cf_payees_list="# a",
summary="blah blah",
- status="blah")
+ status="blah",
+ assigned_to="fake-email@example.com")
self.assertEqual(
repr(bug),
"MockBug(bug_id=34, cf_budget_parent=1, cf_budget='45', "
"cf_total_budget='23', cf_nlnet_milestone='abc', "
- "cf_payees_list='# a', summary='blah blah', status='blah')")
+ "cf_payees_list='# a', summary='blah blah', status='blah', "
+ "assigned_to='fake-email@example.com')")
def test_cf_budget_parent(self):
bug = MockBug(bug_id=1, cf_budget_parent=None)