123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- from __future__ import annotations
- from datetime import timedelta
- from typing import Any
- from unittest.mock import Mock, patch
- import pytest
- from django.utils import timezone
- from sentry.exceptions import HookValidationError
- from sentry.models import (
- Commit,
- Deploy,
- Environment,
- ProjectOption,
- Release,
- ReleaseCommit,
- ReleaseHeadCommit,
- Repository,
- User,
- )
- from sentry.testutils.cases import TestCase
- from sentry.utils import json
- from sentry_plugins.heroku.plugin import HerokuReleaseHook
- class SetRefsTest(TestCase):
- """
- tests that when finish_release is called on a release hook,
- we try to get the previous commits based on the version ref
- and that we create `ReleaseHeadCommit`s for the version
- """
- @patch("sentry.tasks.commits.fetch_commits")
- def test_minimal(self, mock_fetch_commits):
- project = self.create_project()
- version = "bbee5b51f84611e4b14834363b8514c2"
- data_list = [
- {
- "id": "c7155651831549cf8a5e47889fce17eb",
- "message": "foo",
- "author_email": "jane@example.com",
- },
- {
- "id": "62de626b7c7cfb8e77efb4273b1a3df4123e6216",
- "message": "hello",
- "author_name": "Jess",
- },
- {
- "id": "58de626b7c7cfb8e77efb4273b1a3df4123e6345",
- "message": "bar",
- "author_name": "Joe^^",
- },
- {
- "id": "bbee5b51f84611e4b14834363b8514c2",
- "message": "blah",
- "author_email": "katie@example.com",
- },
- ]
- user = User.objects.create(email="stebe@sentry.io")
- repo = Repository.objects.create(
- organization_id=project.organization_id, name=project.name, provider="dummy"
- )
- ProjectOption.objects.set_value(key="heroku:repository", project=project, value=repo.name)
- for data in data_list:
- Commit.objects.create(
- key=data["id"], organization_id=self.project.organization_id, repository_id=repo.id
- )
- old_release = Release.objects.create(
- version="a" * 40,
- organization_id=project.organization_id,
- date_added=timezone.now() - timedelta(minutes=30),
- )
- old_release.add_project(project)
- ReleaseCommit.objects.create(
- organization_id=project.organization_id,
- project_id=project.id,
- release=old_release,
- commit=Commit.objects.get(key="c7155651831549cf8a5e47889fce17eb"),
- order=0,
- )
- ReleaseHeadCommit.objects.create(
- organization_id=project.organization_id,
- repository_id=repo.id,
- release=old_release,
- commit=Commit.objects.get(key="c7155651831549cf8a5e47889fce17eb"),
- )
- release_heads = ReleaseHeadCommit.objects.filter(
- organization_id=project.organization_id,
- repository_id=repo.id,
- commit=Commit.objects.get(key="bbee5b51f84611e4b14834363b8514c2"),
- )
- assert len(release_heads) == 0
- hook = HerokuReleaseHook(project)
- hook.finish_release(version=version, owner_id=user.id)
- release = Release.objects.get(projects=project, version=version)
- new_release_heads = ReleaseHeadCommit.objects.filter(
- organization_id=project.organization_id,
- repository_id=repo.id,
- release=release,
- commit=Commit.objects.get(key="bbee5b51f84611e4b14834363b8514c2"),
- )
- assert len(new_release_heads) == 1
- assert release.version == "bbee5b51f84611e4b14834363b8514c2"
- deploy = Deploy.objects.filter(
- organization_id=project.organization_id,
- release=release,
- environment_id=Environment.objects.get(
- organization_id=project.organization_id, name="production"
- ).id,
- )
- assert len(deploy) == 1
- mock_fetch_commits.apply_async.assert_called_with(
- kwargs={
- "release_id": release.id,
- "user_id": user.id,
- "refs": [{"commit": "bbee5b51f84611e4b14834363b8514c2", "repository": repo.name}],
- "prev_release_id": old_release.id,
- }
- )
- class HookHandleTest(TestCase):
- @pytest.fixture(autouse=True)
- def patch_is_valid_signature(self):
- with patch.object(HerokuReleaseHook, "is_valid_signature"):
- yield
- @patch.object(HerokuReleaseHook, "set_refs")
- def test_user_success(self, set_refs_mock):
- user = self.create_user()
- organization = self.create_organization(owner=user)
- project = self.create_project(organization=organization)
- hook = HerokuReleaseHook(project)
- req = Mock()
- body: dict[str, Any] = {
- "data": {
- "user": {"email": user.email},
- "slug": {"commit": "abcd123"},
- "app": {"name": "example"},
- },
- "action": "update",
- }
- req.body = bytes(json.dumps(body), "utf-8")
- hook.handle(req)
- assert Release.objects.filter(version=body["data"]["slug"]["commit"]).exists()
- assert set_refs_mock.call_count == 1
- @patch.object(HerokuReleaseHook, "set_refs")
- def test_only_run_on_update(self, set_refs_mock):
- user = self.create_user()
- organization = self.create_organization(owner=user)
- project = self.create_project(organization=organization)
- hook = HerokuReleaseHook(project)
- req = Mock()
- body: dict[str, Any] = {
- "data": {
- "user": {"email": user.email},
- "slug": {"commit": "abcd123"},
- "app": {"name": "example"},
- },
- "action": "create",
- }
- req.body = bytes(json.dumps(body), "utf-8")
- hook.handle(req)
- assert not Release.objects.filter(version=body["data"]["slug"]["commit"]).exists()
- assert set_refs_mock.call_count == 0
- @patch.object(HerokuReleaseHook, "set_refs")
- def test_actor_email_success(self, set_refs_mock):
- user = self.create_user()
- organization = self.create_organization(owner=user)
- project = self.create_project(organization=organization)
- hook = HerokuReleaseHook(project)
- req = Mock()
- body: dict[str, Any] = {
- "data": {
- "actor": {"email": user.email},
- "slug": {"commit": "abcd123"},
- "app": {"name": "example"},
- },
- "action": "update",
- }
- req.body = bytes(json.dumps(body), "utf-8")
- hook.handle(req)
- assert Release.objects.filter(version=body["data"]["slug"]["commit"]).exists()
- assert set_refs_mock.call_count == 1
- def test_email_mismatch(self):
- user = self.create_user()
- organization = self.create_organization(owner=user)
- project = self.create_project(organization=organization)
- hook = HerokuReleaseHook(project)
- req = Mock()
- body: dict[str, Any] = {
- "data": {
- "user": {"email": "wrong@example.com"},
- "slug": {"commit": "v999"},
- "app": {"name": "example"},
- },
- "action": "update",
- }
- req.body = bytes(json.dumps(body), "utf-8")
- hook.handle(req)
- assert Release.objects.filter(version=body["data"]["slug"]["commit"]).exists()
- def test_bad_version(self):
- project = self.create_project()
- user = self.create_user()
- hook = HerokuReleaseHook(project)
- req = Mock()
- body = {
- "data": {
- "actor": {"email": user.email},
- "slug": {"commit": ""},
- "app": {"name": "example"},
- },
- "action": "update",
- }
- req.body = bytes(json.dumps(body), "utf-8")
- with pytest.raises(HookValidationError):
- hook.handle(req)
|