|
@@ -1,10 +1,12 @@
|
|
|
from django.db.models import Q
|
|
|
+from drf_spectacular.utils import extend_schema, extend_schema_serializer
|
|
|
from rest_framework.exceptions import ParseError
|
|
|
from rest_framework.request import Request
|
|
|
from rest_framework.response import Response
|
|
|
from rest_framework.serializers import ListField
|
|
|
|
|
|
from sentry import release_health
|
|
|
+from sentry.api.api_owners import ApiOwner
|
|
|
from sentry.api.api_publish_status import ApiPublishStatus
|
|
|
from sentry.api.base import ReleaseAnalyticsMixin, region_silo_endpoint
|
|
|
from sentry.api.bases.organization import OrganizationReleasesBaseEndpoint
|
|
@@ -20,6 +22,16 @@ from sentry.api.serializers.rest_framework import (
|
|
|
ReleaseHeadCommitSerializerDeprecated,
|
|
|
ReleaseSerializer,
|
|
|
)
|
|
|
+from sentry.api.serializers.types import ReleaseSerializerResponse
|
|
|
+from sentry.apidocs.constants import (
|
|
|
+ RESPONSE_FORBIDDEN,
|
|
|
+ RESPONSE_NO_CONTENT,
|
|
|
+ RESPONSE_NOT_FOUND,
|
|
|
+ RESPONSE_UNAUTHORIZED,
|
|
|
+)
|
|
|
+from sentry.apidocs.examples.organization_examples import OrganizationExamples
|
|
|
+from sentry.apidocs.parameters import GlobalParams, ReleaseParams, VisibilityParams
|
|
|
+from sentry.apidocs.utils import inline_sentry_response_serializer
|
|
|
from sentry.models.activity import Activity
|
|
|
from sentry.models.project import Project
|
|
|
from sentry.models.release import Release, ReleaseStatus
|
|
@@ -33,11 +45,19 @@ class InvalidSortException(Exception):
|
|
|
pass
|
|
|
|
|
|
|
|
|
+@extend_schema_serializer(exclude_fields=["headCommits", "status"])
|
|
|
class OrganizationReleaseSerializer(ReleaseSerializer):
|
|
|
headCommits = ListField(
|
|
|
- child=ReleaseHeadCommitSerializerDeprecated(), required=False, allow_null=False
|
|
|
+ child=ReleaseHeadCommitSerializerDeprecated(),
|
|
|
+ required=False,
|
|
|
+ allow_null=False,
|
|
|
+ )
|
|
|
+ refs = ListField(
|
|
|
+ child=ReleaseHeadCommitSerializer(),
|
|
|
+ required=False,
|
|
|
+ allow_null=False,
|
|
|
+ help_text="""An optional way to indicate the start and end commits for each repository included in a release. Head commits must include parameters ``repository`` and ``commit`` (the HEAD SHA). They can optionally include ``previousCommit`` (the SHA of the HEAD of the previous release), which should be specified if this is the first time you've sent commit data.""",
|
|
|
)
|
|
|
- refs = ListField(child=ReleaseHeadCommitSerializer(), required=False, allow_null=False)
|
|
|
|
|
|
|
|
|
def add_status_filter_to_queryset(queryset, status_filter):
|
|
@@ -269,29 +289,46 @@ class OrganizationReleaseDetailsPaginationMixin:
|
|
|
}
|
|
|
|
|
|
|
|
|
+@extend_schema(tags=["Releases"])
|
|
|
@region_silo_endpoint
|
|
|
class OrganizationReleaseDetailsEndpoint(
|
|
|
OrganizationReleasesBaseEndpoint,
|
|
|
ReleaseAnalyticsMixin,
|
|
|
OrganizationReleaseDetailsPaginationMixin,
|
|
|
):
|
|
|
+ owner = ApiOwner.UNOWNED
|
|
|
publish_status = {
|
|
|
- "DELETE": ApiPublishStatus.UNKNOWN,
|
|
|
- "GET": ApiPublishStatus.UNKNOWN,
|
|
|
- "PUT": ApiPublishStatus.UNKNOWN,
|
|
|
+ "DELETE": ApiPublishStatus.PUBLIC,
|
|
|
+ "GET": ApiPublishStatus.PUBLIC,
|
|
|
+ "PUT": ApiPublishStatus.PUBLIC,
|
|
|
}
|
|
|
|
|
|
+ @extend_schema(
|
|
|
+ operation_id="Retrieve an Organization's Release",
|
|
|
+ parameters=[
|
|
|
+ GlobalParams.ORG_ID_OR_SLUG,
|
|
|
+ ReleaseParams.VERSION,
|
|
|
+ ReleaseParams.PROJECT_ID,
|
|
|
+ ReleaseParams.HEALTH,
|
|
|
+ ReleaseParams.ADOPTION_STAGES,
|
|
|
+ ReleaseParams.SUMMARY_STATS_PERIOD,
|
|
|
+ ReleaseParams.HEALTH_STATS_PERIOD,
|
|
|
+ ReleaseParams.SORT,
|
|
|
+ ReleaseParams.STATUS_FILTER,
|
|
|
+ VisibilityParams.QUERY,
|
|
|
+ ],
|
|
|
+ responses={
|
|
|
+ 200: inline_sentry_response_serializer("OrgReleaseResponse", ReleaseSerializerResponse),
|
|
|
+ 401: RESPONSE_UNAUTHORIZED,
|
|
|
+ 403: RESPONSE_FORBIDDEN,
|
|
|
+ 404: RESPONSE_NOT_FOUND,
|
|
|
+ },
|
|
|
+ examples=OrganizationExamples.RELEASE_DETAILS,
|
|
|
+ )
|
|
|
def get(self, request: Request, organization, version) -> Response:
|
|
|
"""
|
|
|
- Retrieve an Organization's Release
|
|
|
- ``````````````````````````````````
|
|
|
|
|
|
Return details on an individual release.
|
|
|
-
|
|
|
- :pparam string organization_id_or_slug: the id or slug of the organization the
|
|
|
- release belongs to.
|
|
|
- :pparam string version: the version identifier of the release.
|
|
|
- :auth: required
|
|
|
"""
|
|
|
# Dictionary responsible for storing selected project meta data
|
|
|
current_project_meta = {}
|
|
@@ -375,38 +412,26 @@ class OrganizationReleaseDetailsEndpoint(
|
|
|
)
|
|
|
)
|
|
|
|
|
|
+ @extend_schema(
|
|
|
+ operation_id="Update an Organization's Release",
|
|
|
+ parameters=[
|
|
|
+ GlobalParams.ORG_ID_OR_SLUG,
|
|
|
+ ReleaseParams.VERSION,
|
|
|
+ ],
|
|
|
+ request=OrganizationReleaseSerializer,
|
|
|
+ responses={
|
|
|
+ 200: inline_sentry_response_serializer("OrgReleaseResponse", ReleaseSerializerResponse),
|
|
|
+ 401: RESPONSE_UNAUTHORIZED,
|
|
|
+ 403: RESPONSE_FORBIDDEN,
|
|
|
+ 404: RESPONSE_NOT_FOUND,
|
|
|
+ },
|
|
|
+ examples=OrganizationExamples.RELEASE_DETAILS,
|
|
|
+ )
|
|
|
def put(self, request: Request, organization, version) -> Response:
|
|
|
"""
|
|
|
- Update an Organization's Release
|
|
|
- ````````````````````````````````
|
|
|
|
|
|
Update a release. This can change some metadata associated with
|
|
|
the release (the ref, url, and dates).
|
|
|
-
|
|
|
- :pparam string organization_id_or_slug: the id or slug of the organization the
|
|
|
- release belongs to.
|
|
|
- :pparam string version: the version identifier of the release.
|
|
|
- :param string ref: an optional commit reference. This is useful if
|
|
|
- a tagged version has been provided.
|
|
|
- :param url url: a URL that points to the release. This can be the
|
|
|
- path to an online interface to the sourcecode
|
|
|
- for instance.
|
|
|
- :param datetime dateReleased: an optional date that indicates when
|
|
|
- the release went live. If not provided
|
|
|
- the current time is assumed.
|
|
|
- :param array commits: an optional list of commit data to be associated
|
|
|
-
|
|
|
- with the release. Commits must include parameters
|
|
|
- ``id`` (the sha of the commit), and can optionally
|
|
|
- include ``repository``, ``message``, ``author_name``,
|
|
|
- ``author_email``, and ``timestamp``.
|
|
|
- :param array refs: an optional way to indicate the start and end commits
|
|
|
- for each repository included in a release. Head commits
|
|
|
- must include parameters ``repository`` and ``commit``
|
|
|
- (the HEAD sha). They can optionally include ``previousCommit``
|
|
|
- (the sha of the HEAD of the previous release), which should
|
|
|
- be specified if this is the first time you've sent commit data.
|
|
|
- :auth: required
|
|
|
"""
|
|
|
bind_organization_context(organization)
|
|
|
|
|
@@ -503,17 +528,23 @@ class OrganizationReleaseDetailsEndpoint(
|
|
|
|
|
|
return Response(serialize(release, request.user))
|
|
|
|
|
|
+ @extend_schema(
|
|
|
+ operation_id="Delete an Organization's Release",
|
|
|
+ parameters=[
|
|
|
+ GlobalParams.ORG_ID_OR_SLUG,
|
|
|
+ ReleaseParams.VERSION,
|
|
|
+ ],
|
|
|
+ responses={
|
|
|
+ 204: RESPONSE_NO_CONTENT,
|
|
|
+ 401: RESPONSE_UNAUTHORIZED,
|
|
|
+ 403: RESPONSE_FORBIDDEN,
|
|
|
+ 404: RESPONSE_NOT_FOUND,
|
|
|
+ },
|
|
|
+ )
|
|
|
def delete(self, request: Request, organization, version) -> Response:
|
|
|
"""
|
|
|
- Delete an Organization's Release
|
|
|
- ````````````````````````````````
|
|
|
|
|
|
Permanently remove a release and all of its files.
|
|
|
-
|
|
|
- :pparam string organization_id_or_slug: the id or slug of the organization the
|
|
|
- release belongs to.
|
|
|
- :pparam string version: the version identifier of the release.
|
|
|
- :auth: required
|
|
|
"""
|
|
|
try:
|
|
|
release = Release.objects.get(organization_id=organization.id, version=version)
|