def serialize(data, projects): # Build datastructure of the latest version of each SDK in use for each # project we have events for. latest_sdks = chain.from_iterable( [{ "projectId": project_id, "sdkName": sdk_name, "sdkVersion": max((s["sdk.version"] for s in sdks), key=LooseVersion), } for sdk_name, sdks in groupby(sorted(sdks_used, key=by_sdk_name), key=by_sdk_name)] for project_id, sdks_used in groupby(data, key=by_project_id)) # Determine suggested upgrades for each project index_state = SdkIndexState() return [ dict( **latest, suggestions=list( get_suggested_updates( # TODO: In the future it would be nice to also add # the integrations and modules the SDK is using. # However this isn't currently available in the # discover dataset from snuba. SdkSetupState(latest["sdkName"], latest["sdkVersion"], (), ()), index_state, ignore_patch_version=True, )), ) for latest in latest_sdks ]
from __future__ import absolute_import import pytest from sentry.sdk_updates import SdkSetupState, SdkIndexState, get_suggested_updates PYTHON_INDEX_STATE = SdkIndexState(sdk_versions={"sentry.python": "0.9.0"}) DOTNET_INDEX_STATE = SdkIndexState(sdk_versions={"sentry.dotnet": "1.2.0"}) def test_too_old_django(): setup = SdkSetupState(sdk_name="sentry.python", sdk_version="0.9.0", integrations=[], modules={"django": "1.3"}) assert list(get_suggested_updates(setup, PYTHON_INDEX_STATE)) == [] def test_too_old_sdk(): setup = SdkSetupState(sdk_name="sentry.python", sdk_version="0.1.0", integrations=[], modules={"django": "1.8"}) assert list(get_suggested_updates(setup, PYTHON_INDEX_STATE)) == [{ "enables": [{ "type": "enableIntegration", "enables": [], "integrationName": "django",
class OrganizationSdkUpdates(APITestCase, SnubaTestCase): def setUp(self): super().setUp() self.login_as(user=self.user) self.project2 = self.create_project(organization=self.organization) self.url = reverse( "sentry-api-0-organization-sdk-updates", kwargs={"organization_slug": self.organization.slug}, ) @mock.patch( "sentry.api.endpoints.organization_sdk_updates.SdkIndexState", return_value=SdkIndexState(sdk_versions={"example.sdk": "2.0.0"}), ) def test_simple(self, mock_index_state): min_ago = iso_format(before_now(minutes=1)) self.store_event( data={ "event_id": "a" * 32, "message": "oh no", "timestamp": min_ago, "fingerprint": ["group-1"], "sdk": {"name": "example.sdk", "version": "1.0.0"}, }, project_id=self.project.id, assert_no_errors=False, ) response = self.client.get(self.url) update_suggestions = response.data assert len(update_suggestions) == 1 assert update_suggestions[0]["suggestions"][0] == { "type": "updateSdk", "sdkName": "example.sdk", "newSdkVersion": "2.0.0", "sdkUrl": None, "enables": [], } def test_filtered_project(self): min_ago = iso_format(before_now(minutes=1)) self.store_event( data={ "event_id": "a" * 32, "message": "oh no", "timestamp": min_ago, "fingerprint": ["group-1"], "sdk": {"name": "example.sdk", "version": "1.0.0"}, }, project_id=self.project.id, assert_no_errors=False, ) response = self.client.get(f"{self.url}?project={self.project2.id}") assert len(response.data) == 0 @mock.patch( "sentry.api.endpoints.organization_sdk_updates.SdkIndexState", return_value=SdkIndexState(sdk_versions={"example.sdk": "2.0.0"}), ) def test_multiple_versions_with_latest(self, mock_index_state): min_ago = iso_format(before_now(minutes=1)) self.store_event( data={ "event_id": "a" * 32, "message": "a", "timestamp": min_ago, "fingerprint": ["group-1"], "sdk": {"name": "example.sdk", "version": "1.0.0"}, }, project_id=self.project.id, assert_no_errors=False, ) self.store_event( data={ "event_id": "b" * 32, "message": "b", "timestamp": min_ago, "fingerprint": ["group-2"], "sdk": {"name": "example.sdk", "version": "1.1.0"}, }, project_id=self.project.id, assert_no_errors=False, ) self.store_event( data={ "event_id": "c" * 32, "message": "c", "timestamp": min_ago, "fingerprint": ["group-3"], "sdk": {"name": "example.sdk", "version": "2.0.0"}, }, project_id=self.project.id, assert_no_errors=False, ) response = self.client.get(self.url) update_suggestions = response.data assert len(update_suggestions) == 0