Skip to content

ref(releases): Move release serializers into releases module #95932

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
648 changes: 1 addition & 647 deletions src/sentry/api/serializers/models/release.py

Large diffs are not rendered by default.

51 changes: 1 addition & 50 deletions src/sentry/api/serializers/models/release_file.py
Original file line number Diff line number Diff line change
@@ -1,50 +1 @@
from base64 import urlsafe_b64decode, urlsafe_b64encode

from sentry.api.serializers import Serializer, register
from sentry.models.distribution import Distribution
from sentry.models.releasefile import ReleaseFile


def encode_release_file_id(obj):
"""Generate ID for artifacts that only exist in a bundle

This ID is only unique per release.

We use the name of the release file because it is also the key for lookups
in ArtifactIndex. To prevent any urlencode confusion, we base64 encode it.

"""
if obj.id:
return str(obj.id)
if obj.name:
dist_name = ""
if obj.dist_id:
dist_name = Distribution.objects.get(pk=obj.dist_id).name
return urlsafe_b64encode(f"{dist_name}_{obj.name}".encode())


def decode_release_file_id(id: str):
"""May raise ValueError"""
try:
return int(id)
except ValueError:
decoded = urlsafe_b64decode(id).decode()
dist, url = decoded.split("_", 1)
return dist or None, url


@register(ReleaseFile)
class ReleaseFileSerializer(Serializer):
def serialize(self, obj, attrs, user, **kwargs):
dist_name = None
if obj.dist_id:
dist_name = Distribution.objects.get(pk=obj.dist_id).name
return {
"id": encode_release_file_id(obj),
"name": obj.name,
"dist": dist_name,
"headers": obj.file.headers,
"size": obj.file.size,
"sha1": obj.file.checksum,
"dateCreated": obj.file.timestamp,
}
from sentry.releases.serializers.release_file import * # noqa: F401,F403
22 changes: 1 addition & 21 deletions src/sentry/api/serializers/models/release_threshold.py
Original file line number Diff line number Diff line change
@@ -1,21 +1 @@
from sentry.api.serializers import Serializer, register, serialize
from sentry.models.release_threshold.constants import (
THRESHOLD_TYPE_INT_TO_STR,
TRIGGER_TYPE_INT_TO_STR,
)
from sentry.models.release_threshold.release_threshold import ReleaseThreshold


@register(ReleaseThreshold)
class ReleaseThresholdSerializer(Serializer):
def serialize(self, obj, attrs, user, **kwargs):
return {
"id": str(obj.id),
"threshold_type": THRESHOLD_TYPE_INT_TO_STR[obj.threshold_type],
"trigger_type": TRIGGER_TYPE_INT_TO_STR[obj.trigger_type],
"value": obj.value,
"window_in_seconds": obj.window_in_seconds,
"project": serialize(obj.project),
"environment": serialize(obj.environment) if obj.environment else None,
"date_added": obj.date_added,
}
from sentry.releases.serializers.release_threshold import * # noqa: F401,F403
87 changes: 1 addition & 86 deletions src/sentry/api/serializers/release_details_types.py
Original file line number Diff line number Diff line change
@@ -1,86 +1 @@
from datetime import datetime
from typing import Any, TypedDict


class VersionInfoOptional(TypedDict, total=False):
description: str


class VersionInfo(VersionInfoOptional):
package: str | None
version: dict[str, Any]
buildHash: str | None


class LastDeployOptional(TypedDict, total=False):
dateStarted: str | None
url: str | None


class LastDeploy(LastDeployOptional):
id: str
environment: str
dateFinished: str
name: str


class AuthorOptional(TypedDict, total=False):
lastLogin: str
has2fa: bool
lastActive: str
isSuperuser: bool
isStaff: bool
experiments: dict[str, str | int | float | bool | None]
emails: list[dict[str, int | str | bool]]
avatar: dict[str, str | None]


class Author(AuthorOptional):
id: int
name: str
username: str
email: str
avatarUrl: str
isActive: bool
hasPasswordAuth: bool
isManaged: bool
dateJoined: str


class HealthDataOptional(TypedDict, total=False):
durationP50: float | None
durationP90: float | None
crashFreeUsers: float | None
crashFreeSessions: float | None
totalUsers: int | None
totalUsers24h: int | None
totalProjectUsers24h: int | None
totalSessions: int | None
totalSessions24h: int | None
totalProjectSessions24h: int | None
adoption: float | None
sessionsAdoption: float | None


class HealthData(HealthDataOptional):
sessionsCrashed: int
sessionsErrored: int
hasHealthData: bool
stats: dict[str, Any]


class ProjectOptional(TypedDict, total=False):
healthData: HealthData | None
dateReleased: datetime | None
dateCreated: datetime | None
dateStarted: datetime | None


class Project(ProjectOptional):
id: int
slug: str
name: str
newGroups: int
platform: str | None
platforms: list[str] | None
hasHealthData: bool
from sentry.releases.serializers.release_details_types import * # noqa: F401,F403
105 changes: 1 addition & 104 deletions src/sentry/api/serializers/rest_framework/release.py
Original file line number Diff line number Diff line change
@@ -1,104 +1 @@
from rest_framework import serializers

from sentry.api.fields.user import UserField
from sentry.api.serializers.rest_framework import CommitSerializer
from sentry.constants import COMMIT_RANGE_DELIMITER, MAX_COMMIT_LENGTH, MAX_VERSION_LENGTH
from sentry.models.organizationmember import OrganizationMember
from sentry.models.release import Release, ReleaseStatus


class ReleaseHeadCommitSerializerDeprecated(serializers.Serializer):
currentId = serializers.CharField(max_length=MAX_COMMIT_LENGTH)
repository = serializers.CharField(max_length=64)
previousId = serializers.CharField(
max_length=MAX_COMMIT_LENGTH, required=False, allow_null=True
)


class ReleaseHeadCommitSerializer(serializers.Serializer):
commit = serializers.CharField()
repository = serializers.CharField(max_length=200)
previousCommit = serializers.CharField(
max_length=MAX_COMMIT_LENGTH, required=False, allow_null=True, allow_blank=True
)

def validate_commit(self, value):
"""
Value can be either a single commit or a commit range (1a2b3c..6f5e4d)
"""

if COMMIT_RANGE_DELIMITER in value:
startCommit, endCommit = value.split(COMMIT_RANGE_DELIMITER)

if not startCommit or not endCommit:
raise serializers.ValidationError(
"Commit cannot begin or end with %s" % COMMIT_RANGE_DELIMITER
)

if len(startCommit) > MAX_COMMIT_LENGTH or len(endCommit) > MAX_COMMIT_LENGTH:
raise serializers.ValidationError(
"Start or end commit too long - max is %s chars each" % MAX_COMMIT_LENGTH
)

return value

if len(value) > MAX_COMMIT_LENGTH:
raise serializers.ValidationError(
"Commit too long - max is %s chars" % MAX_COMMIT_LENGTH
)

return value


class ReleaseSerializer(serializers.Serializer):
ref = serializers.CharField(
max_length=MAX_VERSION_LENGTH,
required=False,
allow_null=True,
allow_blank=True,
help_text="An optional commit reference. This is useful if a tagged version has been provided.",
)
url = serializers.URLField(
required=False,
allow_null=True,
allow_blank=True,
help_text="A URL that points to the release. For instance, this can be the path to an online interface to the source code, such as a GitHub URL.",
)
dateReleased = serializers.DateTimeField(
required=False,
allow_null=True,
help_text="An optional date that indicates when the release went live. If not provided the current time is used.",
)
commits = serializers.ListField(
child=CommitSerializer(),
required=False,
allow_null=False,
help_text="An optional list of commit data to be associated.",
)

status = serializers.CharField(required=False, allow_null=False)

def validate_status(self, value):
try:
return ReleaseStatus.from_string(value)
except ValueError:
raise serializers.ValidationError("Invalid status %s" % value)


class ReleaseWithVersionSerializer(ReleaseSerializer):
version = serializers.CharField(
max_length=MAX_VERSION_LENGTH, trim_whitespace=False, required=True
)
owner = UserField(required=False)

def validate_version(self, value):
if not Release.is_valid_version(value):
raise serializers.ValidationError("Release with name %s is not allowed" % value)
return value

def validate_owner(self, owner):
if not OrganizationMember.objects.filter(
organization=self.context["organization"], user_id=owner.id
).exists():
raise serializers.ValidationError("User does not have access to this organization")
return owner
from sentry.releases.serializers.release_dupe import * # noqa: F401,F403
Empty file.
Loading
Loading