fixed_budget_excluding_subtasks: Money
fixed_budget_including_subtasks: Money
milestone_str: Optional[str]
- is_in_nlnet_mou: bool
def __init__(self, graph: "BudgetGraph", bug: Bug):
self.graph = graph
@cached_property
def is_in_nlnet_mou(self):
- """returns true if this bugreport is a child of the top-level milestone.
- it does *not* return true for the top-level bugreport itself because
- only the immediate child-nodes comprise the MoU.
+ """returns true if this bugreport is an immediate child of a top-level
+ milestone. it does *not* return true for the top-level bug itself
+ because only the immediate children comprise the MoU.
"""
- if self.parent is None:
- return False
- return self.parent == self.root
+ try:
+ if self.parent is not None and self.milestone is not None:
+ return self.parent.bug.id == self.milestone.canonical_bug_id
+ except BudgetGraphBaseError:
+ pass
+ return False
@cached_property
def closest_bug_in_mou(self) -> Optional["Node"]:
f"#{self.milestone_canonical_bug_id}")
-class BudgetGraphRootWithMilestoneNotInMoU(BudgetGraphError):
- def __init__(self, bug_id: int, milestone: str):
- super().__init__(bug_id, bug_id)
- self.milestone = milestone
-
- def __str__(self):
- return (f"Bug #{self.bug_id} has no parent bug set and has an "
- f"assigned milestone {self.milestone!r} but isn't set "
- f"to be part of the signed MoU")
-
-
-class BudgetGraphInMoUButParentNotInMoU(BudgetGraphError):
- def __init__(self, bug_id: int, parent_bug_id: int, root_bug_id: int,
- milestone: str):
- super().__init__(bug_id, root_bug_id)
- self.parent_bug_id = parent_bug_id
- self.milestone = milestone
-
- def __str__(self):
- return (f"Bug #{self.bug_id} is set to be part of the signed MoU for "
- f"milestone {self.milestone!r}, but its parent bug isn't set "
- f"to be part of the signed MoU")
-
-
-class BudgetGraphInMoUWithoutMilestone(BudgetGraphError):
- def __str__(self):
- return (f"Bug #{self.bug_id} is set to be part of a signed MoU but "
- f"has no milestone set")
-
-
class BudgetGraph:
nodes: Dict[int, Node]
node.bug.id, node.milestone.identifier,
node.milestone.canonical_bug_id
))
- # the root level bugs are not themselves "the child MoU list"
- #elif not node.is_in_nlnet_mou:
- # errors.append(BudgetGraphRootWithMilestoneNotInMoU(
- # node.bug.id, node.milestone_str))
except BudgetGraphBaseError as e:
errors.append(e)
errors.append(BudgetGraphMilestoneMismatch(
node.bug.id, root.bug.id))
- if node.is_in_nlnet_mou:
- if node.milestone_str is None:
- errors.append(BudgetGraphInMoUWithoutMilestone(node.bug.id,
- root.bug.id))
- # don't consider the top-level root to be part of the MoU
- #elif node.parent is not None and \
- # not node.parent.is_in_nlnet_mou:
- # errors.append(BudgetGraphInMoUButParentNotInMoU(
- # node.bug.id, node.parent.bug.id, root.bug.id,
- # node.milestone_str))
-
if node.budget_excluding_subtasks < 0 \
or node.budget_including_subtasks < 0:
errors.append(BudgetGraphNegativeMoney(