test_code_owners.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. from datetime import datetime, timezone
  2. from unittest.mock import patch
  3. from sentry.models.commit import Commit
  4. from sentry.models.commitfilechange import CommitFileChange
  5. from sentry.models.integrations.external_actor import ExternalActor
  6. from sentry.models.projectcodeowners import ProjectCodeOwners
  7. from sentry.models.projectownership import ProjectOwnership
  8. from sentry.models.repository import Repository
  9. from sentry.tasks.codeowners import code_owners_auto_sync, update_code_owners_schema
  10. from sentry.testutils.cases import TestCase
  11. LATEST_GITHUB_CODEOWNERS = {
  12. "filepath": "CODEOWNERS",
  13. "html_url": "https://example.com/example/CODEOWNERS",
  14. "raw": "docs/* @NisanthanNanthakumar @getsentry/ecosystem\n* @NisanthanNanthakumar\n",
  15. }
  16. class CodeOwnersTest(TestCase):
  17. def setUp(self):
  18. self.login_as(user=self.user)
  19. self.team = self.create_team(
  20. organization=self.organization, slug="tiger-team", members=[self.user]
  21. )
  22. self.project = self.project = self.create_project(
  23. organization=self.organization, teams=[self.team], slug="bengal"
  24. )
  25. self.repo = Repository.objects.create(
  26. name="example", organization_id=self.organization.id, integration_id=self.integration.id
  27. )
  28. self.code_mapping = self.create_code_mapping(
  29. repo=self.repo,
  30. project=self.project,
  31. )
  32. self.data = {
  33. "raw": "docs/* @NisanthanNanthakumar @getsentry/ecosystem\n",
  34. }
  35. self.ownership = ProjectOwnership.objects.create(
  36. project=self.project, auto_assignment=True, codeowners_auto_sync=True
  37. )
  38. self.code_owners = self.create_codeowners(
  39. self.project, self.code_mapping, raw=self.data["raw"]
  40. )
  41. def test_simple(self):
  42. with self.tasks() and self.feature({"organizations:integrations-codeowners": True}):
  43. # new external team mapping
  44. self.external_team = self.create_external_team(integration=self.integration)
  45. update_code_owners_schema(organization=self.organization, integration=self.integration)
  46. code_owners = ProjectCodeOwners.objects.get(id=self.code_owners.id)
  47. assert code_owners.schema == {
  48. "$version": 1,
  49. "rules": [
  50. {
  51. "matcher": {"type": "codeowners", "pattern": "docs/*"},
  52. "owners": [
  53. {"type": "team", "identifier": "tiger-team"},
  54. ],
  55. }
  56. ],
  57. }
  58. with self.tasks() and self.feature({"organizations:integrations-codeowners": True}):
  59. # delete external team mapping
  60. ExternalActor.objects.get(id=self.external_team.id).delete()
  61. update_code_owners_schema(organization=self.organization, integration=self.integration)
  62. code_owners = ProjectCodeOwners.objects.get(id=self.code_owners.id)
  63. assert code_owners.schema == {"$version": 1, "rules": []}
  64. @patch("django.utils.timezone.now")
  65. @patch(
  66. "sentry.integrations.github.GitHubIntegration.get_codeowner_file",
  67. return_value=LATEST_GITHUB_CODEOWNERS,
  68. )
  69. def test_codeowners_auto_sync_successful(self, mock_get_codeowner_file, mock_timezone_now):
  70. with self.tasks() and self.feature({"organizations:integrations-codeowners": True}):
  71. self.create_external_team()
  72. self.create_external_user(external_name="@NisanthanNanthakumar")
  73. commit = Commit.objects.create(
  74. repository_id=self.repo.id,
  75. organization_id=self.organization.id,
  76. key="1234",
  77. message="Initial commit",
  78. )
  79. CommitFileChange.objects.create(
  80. organization_id=self.organization.id,
  81. commit=commit,
  82. filename=".github/CODEOWNERS",
  83. type="A",
  84. )
  85. mock_now = datetime(2023, 1, 1, 0, 0, tzinfo=timezone.utc)
  86. mock_timezone_now.return_value = mock_now
  87. code_owners_auto_sync(commit.id)
  88. code_owners = ProjectCodeOwners.objects.get(id=self.code_owners.id)
  89. assert code_owners.raw == LATEST_GITHUB_CODEOWNERS["raw"]
  90. assert code_owners.schema == {
  91. "$version": 1,
  92. "rules": [
  93. {
  94. "matcher": {"pattern": "docs/*", "type": "codeowners"},
  95. "owners": [
  96. {"identifier": "admin@localhost", "type": "user"},
  97. {"identifier": "tiger-team", "type": "team"},
  98. ],
  99. },
  100. {
  101. "matcher": {"pattern": "*", "type": "codeowners"},
  102. "owners": [{"identifier": "admin@localhost", "type": "user"}],
  103. },
  104. ],
  105. }
  106. assert code_owners.date_updated == mock_now
  107. @patch(
  108. "sentry.integrations.github.GitHubIntegration.get_codeowner_file",
  109. return_value=None,
  110. )
  111. @patch("sentry.notifications.notifications.codeowners_auto_sync.AutoSyncNotification.send")
  112. def test_codeowners_auto_sync_failed_to_fetch_file(
  113. self,
  114. mock_send_email,
  115. mock_get_codeowner_file,
  116. ):
  117. with self.tasks() and self.feature({"organizations:integrations-codeowners": True}):
  118. commit = Commit.objects.create(
  119. repository_id=self.repo.id,
  120. organization_id=self.organization.id,
  121. key="1234",
  122. message="Initial commit",
  123. )
  124. CommitFileChange.objects.create(
  125. organization_id=self.organization.id,
  126. commit=commit,
  127. filename=".github/CODEOWNERS",
  128. type="A",
  129. )
  130. code_owners_auto_sync(commit.id)
  131. code_owners = ProjectCodeOwners.objects.get(id=self.code_owners.id)
  132. assert code_owners.raw == self.data["raw"]
  133. mock_send_email.assert_called_once_with()