def validate(self, attrs: Mapping[str, Any]) -> Mapping[str, Any]: # If it already exists, set default attrs with existing values if self.instance: attrs = { "raw": self.instance.raw, "code_mapping_id": self.instance.repository_project_path_config, **attrs, } if not attrs.get("raw", "").strip(): return attrs # Ignore association errors and continue parsing CODEOWNERS for valid lines. # Allow users to incrementally fix association errors; for CODEOWNERS with many external mappings. associations, _ = ProjectCodeOwners.validate_codeowners_associations( attrs, self.context["project"] ) issue_owner_rules = convert_codeowners_syntax( attrs["raw"], associations, attrs["code_mapping_id"] ) # Convert IssueOwner syntax into schema syntax validated_data = ProjectOwnershipSerializer(context=self.context).validate( {"raw": issue_owner_rules} ) return {**validated_data, **attrs}
def validate(self, attrs: Mapping[str, Any]) -> Mapping[str, Any]: # If it already exists, set default attrs with existing values if self.instance: attrs = { "raw": self.instance.raw, "code_mapping_id": self.instance.repository_project_path_config, **attrs, } if not attrs.get("raw", "").strip(): return attrs external_association_err: List[str] = [] # Get list of team/user names from CODEOWNERS file team_names, usernames, emails = parse_code_owners(attrs["raw"]) # Check if there exists Sentry users with the emails listed in CODEOWNERS user_emails = UserEmail.objects.filter( email__in=emails, user__sentry_orgmember_set__organization=self.context["project"]. organization, ) user_emails_diff = validate_association(emails, user_emails, "emails") external_association_err.extend(user_emails_diff) # Check if the usernames have an association external_actors = ExternalActor.objects.filter( external_name__in=usernames + team_names, organization=self.context["project"].organization, ) external_users_diff = validate_association(usernames, external_actors, "usernames") external_association_err.extend(external_users_diff) external_teams_diff = validate_association(team_names, external_actors, "team names") external_association_err.extend(external_teams_diff) if len(external_association_err): raise serializers.ValidationError( {"raw": "\n".join(external_association_err)}) # Convert CODEOWNERS into IssueOwner syntax users_dict = {} teams_dict = {} for external_actor in external_actors: type = actor_type_to_string(external_actor.actor.type) if type == "user": user = external_actor.actor.resolve() users_dict[external_actor.external_name] = user.email elif type == "team": team = external_actor.actor.resolve() teams_dict[external_actor.external_name] = f"#{team.slug}" emails_dict = {email: email for email in emails} associations = {**users_dict, **teams_dict, **emails_dict} issue_owner_rules = convert_codeowners_syntax(attrs["raw"], associations, attrs["code_mapping_id"]) # Convert IssueOwner syntax into schema syntax validated_data = ProjectOwnershipSerializer( context=self.context).validate({"raw": issue_owner_rules}) return {**validated_data, **attrs}
def validate(self, attrs): # If it already exists, set default attrs with existing values if self.instance: attrs = { "raw": self.instance.raw, "code_mapping_id": self.instance.repository_project_path_config, **attrs, } if not attrs.get("raw", "").strip(): return attrs external_association_err = [] # Get list of team/user names from CODEOWNERS file teamnames, usernames, emails = parse_code_owners(attrs["raw"]) # Check if there exists Sentry users with the emails listed in CODEOWNERS user_emails = UserEmail.objects.filter(email__in=emails) user_emails_diff = self._validate_association(emails, user_emails, "emails") external_association_err.extend(user_emails_diff) # Check if the usernames have an association external_users = ExternalUser.objects.filter( external_name__in=usernames, organizationmember__organization=self.context["project"]. organization, ) external_users_diff = self._validate_association( usernames, external_users, "usernames") external_association_err.extend(external_users_diff) # Check if the team names have an association external_teams = ExternalTeam.objects.filter( external_name__in=teamnames, team__organization=self.context["project"].organization, ) external_teams_diff = self._validate_association( teamnames, external_teams, "team names") external_association_err.extend(external_teams_diff) if len(external_association_err): raise serializers.ValidationError( {"raw": "\n".join(external_association_err)}) # Convert CODEOWNERS into IssueOwner syntax users_dict = { user.external_name: user.organizationmember.user.email for user in external_users } teams_dict = { team.external_name: f"#{team.team.slug}" for team in external_teams } emails_dict = {email: email for email in emails} associations = {**users_dict, **teams_dict, **emails_dict} issue_owner_rules = convert_codeowners_syntax(attrs["raw"], associations, attrs["code_mapping_id"]) # Convert IssueOwner syntax into schema syntax validated_data = ProjectOwnershipSerializer( context=self.context).validate({"raw": issue_owner_rules}) return {**validated_data, **attrs}