def get_owners(cls, project_id, data): """ For a given project_id, and event data blob. We combine the schemas from IssueOwners and CodeOwners. If Everyone is returned, this means we implicitly are falling through our rules and everyone is responsible. If an empty list is returned, this means there are explicitly no owners. """ from sentry.models import ProjectCodeOwners ownership = cls.get_ownership_cached(project_id) if not ownership: ownership = cls(project_id=project_id) codeowners = ProjectCodeOwners.get_codeowners_cached(project_id) ownership.schema = cls.get_combined_schema(ownership, codeowners) rules = cls._matching_ownership_rules(ownership, project_id, data) if not rules: return cls.Everyone if ownership.fallthrough else [], None owners = {o for rule in rules for o in rule.owners} owners_to_actors = resolve_actors(owners, project_id) ordered_actors = [] for rule in rules: for o in rule.owners: if o in owners and owners_to_actors.get(o) is not None: ordered_actors.append(owners_to_actors[o]) owners.remove(o) return ordered_actors, rules
def get_autoassign_owners(cls, project_id, data, limit=2): """ Get the auto-assign owner for a project if there are any. We combine the schemas from IssueOwners and CodeOwners. Returns a tuple of (auto_assignment_enabled, list_of_owners, assigned_by_codeowners: boolean). """ from sentry.models import ProjectCodeOwners with metrics.timer("projectownership.get_autoassign_owners"): ownership = cls.get_ownership_cached(project_id) codeowners = ProjectCodeOwners.get_codeowners_cached(project_id) assigned_by_codeowners = False if not (ownership or codeowners): return False, [], assigned_by_codeowners if not ownership: ownership = cls(project_id=project_id) ownership_rules = cls._matching_ownership_rules( ownership, project_id, data) codeowners_rules = (cls._matching_ownership_rules( codeowners, project_id, data) if codeowners else []) if not (codeowners_rules or ownership_rules): return ownership.auto_assignment, [], assigned_by_codeowners ownership_actors = cls._find_actors(project_id, ownership_rules, limit) codeowners_actors = cls._find_actors(project_id, codeowners_rules, limit) # Can happen if the ownership rule references a user/team that no longer # is assigned to the project or has been removed from the org. if not (ownership_actors or codeowners_actors): return ownership.auto_assignment, [], assigned_by_codeowners # Ownership rules take precedence over codeowner rules. actors = [*ownership_actors, *codeowners_actors][:limit] # Only the first item in the list is used for assignment, the rest are just used to suggest suspect owners. # So if ownership_actors is empty, it will be assigned by codeowners_actors if len(ownership_actors) == 0: assigned_by_codeowners = True from sentry.models import ActorTuple return ( ownership.auto_assignment, ActorTuple.resolve_many(actors), assigned_by_codeowners, )
def get_autoassign_owners(cls, project_id, data, limit=2): """ Get the auto-assign owner for a project if there are any. We combine the schemas from IssueOwners and CodeOwners. Returns a tuple of (auto_assignment_enabled, list_of_owners). """ from sentry.models import ProjectCodeOwners with metrics.timer("projectownership.get_autoassign_owners"): ownership = cls.get_ownership_cached(project_id) codeowners = ProjectCodeOwners.get_codeowners_cached(project_id) if not (ownership or codeowners): return False, [] if not ownership: ownership = cls(project_id=project_id) ownership.schema = cls.get_combined_schema(ownership, codeowners) rules = cls._matching_ownership_rules(ownership, project_id, data) if not rules: return ownership.auto_assignment, [] # We want the last matching rule to take the most precedence. owners = [owner for rule in rules for owner in rule.owners] owners.reverse() actors = { key: val for key, val in resolve_actors({owner for owner in owners}, project_id).items() if val } actors = [actors[owner] for owner in owners if owner in actors][:limit] # Can happen if the ownership rule references a user/team that no longer # is assigned to the project or has been removed from the org. if not actors: return ownership.auto_assignment, [] from sentry.models import ActorTuple return ownership.auto_assignment, ActorTuple.resolve_many(actors)
def get_owners( cls, project_id: int, data: Mapping[str, Any] ) -> Tuple[Union["Everyone", Sequence["ActorTuple"]], Optional[Sequence[Rule]]]: """ For a given project_id, and event data blob. We combine the schemas from IssueOwners and CodeOwners. If there are no matching rules, check ProjectOwnership.fallthrough: If ProjectOwnership.fallthrough is enabled, return Everyone (all project members) - we implicitly are falling through our rules and everyone is responsible. If ProjectOwnership.fallthrough is disabled, return an empty list - there are explicitly no owners If there are matching rules, return the ordered actors. The order is determined by iterating through rules sequentially, evaluating CODEOWNERS (if present), followed by Ownership Rules """ from sentry.models import ProjectCodeOwners ownership = cls.get_ownership_cached(project_id) if not ownership: ownership = cls(project_id=project_id) codeowners = ProjectCodeOwners.get_codeowners_cached(project_id) ownership.schema = cls.get_combined_schema(ownership, codeowners) rules = cls._matching_ownership_rules(ownership, project_id, data) if not rules: return cls.Everyone if ownership.fallthrough else [], None owners = {o for rule in rules for o in rule.owners} owners_to_actors = resolve_actors(owners, project_id) ordered_actors = [] for rule in rules: for o in rule.owners: if o in owners and owners_to_actors.get(o) is not None: ordered_actors.append(owners_to_actors[o]) owners.remove(o) return ordered_actors, rules