test_provider.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. from functools import cached_property
  2. from unittest.mock import patch
  3. import orjson
  4. import responses
  5. from sentry.models.integrations.organization_integration import OrganizationIntegration
  6. from sentry.models.repository import Repository
  7. from sentry.silo.base import SiloMode
  8. from sentry.testutils.cases import TestCase
  9. from sentry.testutils.silo import assume_test_silo_mode
  10. from sentry_plugins.github.client import GithubPluginAppsClient, GithubPluginClient
  11. from sentry_plugins.github.plugin import GitHubAppsRepositoryProvider, GitHubRepositoryProvider
  12. from sentry_plugins.github.testutils import (
  13. COMPARE_COMMITS_EXAMPLE,
  14. GET_LAST_COMMITS_EXAMPLE,
  15. INSTALLATION_REPOSITORIES_API_RESPONSE,
  16. LIST_INSTALLATION_API_RESPONSE,
  17. )
  18. class GitHubPluginTest(TestCase):
  19. @cached_property
  20. def provider(self):
  21. return GitHubRepositoryProvider("github")
  22. def test_compare_commits(self):
  23. repo = Repository.objects.create(provider="github", name="example", organization_id=1)
  24. res = self.provider._format_commits(repo, orjson.loads(COMPARE_COMMITS_EXAMPLE)["commits"])
  25. assert res == [
  26. {
  27. "author_email": "support@github.com",
  28. "author_name": "Monalisa Octocat",
  29. "message": "Fix all the bugs",
  30. "id": "6dcb09b5b57875f334f61aebed695e2e4193db5e",
  31. "repository": "example",
  32. }
  33. ]
  34. def test_get_last_commits(self):
  35. repo = Repository.objects.create(provider="github", name="example", organization_id=1)
  36. res = self.provider._format_commits(repo, orjson.loads(GET_LAST_COMMITS_EXAMPLE)[:10])
  37. assert res == [
  38. {
  39. "author_email": "support@github.com",
  40. "author_name": "Monalisa Octocat",
  41. "message": "Fix all the bugs",
  42. "id": "6dcb09b5b57875f334f61aebed695e2e4193db5e",
  43. "repository": "example",
  44. }
  45. ]
  46. @responses.activate
  47. def test_create_repository(self):
  48. responses.add(
  49. responses.POST,
  50. "https://api.github.com/repos/getsentry/example-repo/hooks",
  51. json={"id": "123456", "events": ["push", "pull_request"]},
  52. )
  53. user = self.create_user()
  54. organization = self.create_organization()
  55. self.create_usersocialauth(
  56. user=user, provider="github", extra_data={"access_token": "abcdefg"}
  57. )
  58. data = {"name": "getsentry/example-repo", "external_id": "654321"}
  59. data = self.provider.create_repository(organization, data, user)
  60. assert data == {
  61. "config": {
  62. "name": "getsentry/example-repo",
  63. "webhook_id": "123456",
  64. "webhook_events": ["push", "pull_request"],
  65. },
  66. "external_id": "654321",
  67. "name": "getsentry/example-repo",
  68. "url": "https://github.com/getsentry/example-repo",
  69. }
  70. request = responses.calls[-1].request
  71. req_json = orjson.loads(request.body)
  72. assert req_json == {
  73. "active": True,
  74. "config": {
  75. "url": f"http://testserver/plugins/github/organizations/{organization.id}/webhook/",
  76. "secret": self.provider.get_webhook_secret(organization),
  77. "content_type": "json",
  78. },
  79. "name": "web",
  80. "events": ["push", "pull_request"],
  81. }
  82. @responses.activate
  83. def test_delete_repository(self):
  84. responses.add(
  85. responses.DELETE,
  86. "https://api.github.com/repos/getsentry/example-repo/hooks/123456",
  87. json={},
  88. )
  89. user = self.create_user()
  90. organization = self.create_organization()
  91. self.create_usersocialauth(
  92. user=user, provider="github", extra_data={"access_token": "abcdefg"}
  93. )
  94. repo = Repository.objects.create(
  95. provider="github",
  96. name="example-repo",
  97. organization_id=organization.id,
  98. config={
  99. "name": "getsentry/example-repo",
  100. "external_id": "654321",
  101. "webhook_id": "123456",
  102. },
  103. )
  104. self.provider.delete_repository(repo, user)
  105. @responses.activate
  106. def test_update_repository_without_webhook(self):
  107. responses.add(
  108. responses.POST,
  109. "https://api.github.com/repos/getsentry/example-repo/hooks",
  110. json={"id": "123456", "events": ["push", "pull_request"]},
  111. )
  112. user = self.create_user()
  113. organization = self.create_organization()
  114. self.create_usersocialauth(
  115. user=user, provider="github", extra_data={"access_token": "abcdefg"}
  116. )
  117. repo = Repository.objects.create(
  118. provider="github",
  119. name="example-repo",
  120. organization_id=organization.id,
  121. config={"name": "getsentry/example-repo", "external_id": "654321"},
  122. )
  123. self.provider.update_repository(repo, user)
  124. assert repo.config["webhook_id"] == "123456"
  125. assert repo.config["webhook_events"] == ["push", "pull_request"]
  126. @responses.activate
  127. def test_update_repository_with_webhook(self):
  128. responses.add(
  129. responses.PATCH,
  130. "https://api.github.com/repos/getsentry/example-repo/hooks/123456",
  131. json={"id": "123456", "events": ["push", "pull_request"]},
  132. )
  133. user = self.create_user()
  134. organization = self.create_organization()
  135. self.create_usersocialauth(
  136. user=user, provider="github", extra_data={"access_token": "abcdefg"}
  137. )
  138. repo = Repository.objects.create(
  139. provider="github",
  140. name="example-repo",
  141. organization_id=organization.id,
  142. config={
  143. "name": "getsentry/example-repo",
  144. "external_id": "654321",
  145. "webhook_id": "123456",
  146. },
  147. )
  148. self.provider.update_repository(repo, user)
  149. assert repo.config["webhook_id"] == "123456"
  150. assert repo.config["webhook_events"] == ["push", "pull_request"]
  151. class GitHubAppsProviderTest(TestCase):
  152. @cached_property
  153. def provider(self):
  154. return GitHubAppsRepositoryProvider("github_apps")
  155. @patch.object(
  156. GithubPluginAppsClient,
  157. "get_repositories",
  158. return_value=orjson.loads(INSTALLATION_REPOSITORIES_API_RESPONSE),
  159. )
  160. @patch.object(
  161. GithubPluginClient,
  162. "get_installations",
  163. return_value=orjson.loads(LIST_INSTALLATION_API_RESPONSE),
  164. )
  165. def test_link_auth(self, *args):
  166. user = self.create_user()
  167. organization = self.create_organization()
  168. self.create_usersocialauth(
  169. user=user, provider="github_apps", extra_data={"access_token": "abcdefg"}
  170. )
  171. integration = self.create_integration(
  172. organization=organization, provider="github_apps", external_id="1"
  173. )
  174. self.provider.link_auth(user, organization, {"integration_id": integration.id})
  175. with assume_test_silo_mode(SiloMode.CONTROL):
  176. assert OrganizationIntegration.objects.filter(
  177. organization_id=organization.id, integration=integration
  178. ).exists()
  179. def test_delete_repository(self):
  180. user = self.create_user()
  181. organization = self.create_organization()
  182. integration = self.create_integration(
  183. organization=organization, provider="github_apps", external_id="1"
  184. )
  185. repo = Repository.objects.create(
  186. name="example-repo",
  187. provider="github_apps",
  188. organization_id=organization.id,
  189. integration_id=integration.id,
  190. )
  191. # just check that it doesn't throw / try to delete a webhook
  192. assert self.provider.delete_repository(repo=repo, actor=user) is None
  193. @patch.object(GithubPluginAppsClient, "get_last_commits", return_value=[])
  194. def test_compare_commits_no_start(self, mock_get_last_commits):
  195. organization = self.create_organization()
  196. integration = self.create_integration(
  197. organization=organization, provider="github_apps", external_id="1"
  198. )
  199. repo = Repository.objects.create(
  200. name="example-repo",
  201. provider="github_apps",
  202. organization_id=organization.id,
  203. integration_id=integration.id,
  204. config={"name": "example-repo"},
  205. )
  206. self.provider.compare_commits(repo, None, "a" * 40)
  207. assert mock_get_last_commits.called
  208. @patch.object(GithubPluginAppsClient, "compare_commits", return_value={"commits": []})
  209. def test_compare_commits(self, mock_compare_commits):
  210. organization = self.create_organization()
  211. integration = self.create_integration(
  212. organization=organization, provider="github_apps", external_id="1"
  213. )
  214. repo = Repository.objects.create(
  215. name="example-repo",
  216. provider="github_apps",
  217. organization_id=organization.id,
  218. integration_id=integration.id,
  219. config={"name": "example-repo"},
  220. )
  221. self.provider.compare_commits(repo, "b" * 40, "a" * 40)
  222. assert mock_compare_commits.called