Skip to content

Commit 7c5215f

Browse files
authored
quality(apidocs): document org repo commits with drf-spectacular (#94984)
part of https://github.com/getsentry/sentry/pull/new/jferg/doc-commits-api
1 parent 42403aa commit 7c5215f

File tree

6 files changed

+137
-93
lines changed

6 files changed

+137
-93
lines changed

api-docs/openapi.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,6 @@
9797
"/api/0/organizations/{organization_id_or_slug}/repos/": {
9898
"$ref": "paths/organizations/repos.json"
9999
},
100-
"/api/0/organizations/{organization_id_or_slug}/repos/{repo_id}/commits/": {
101-
"$ref": "paths/organizations/repo-commits.json"
102-
},
103100
"/api/0/projects/": {
104101
"$ref": "paths/projects/index.json"
105102
},

api-docs/paths/organizations/repo-commits.json

Lines changed: 0 additions & 63 deletions
This file was deleted.

src/sentry/api/serializers/models/commit.py

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,42 @@
11
from collections import defaultdict
22
from collections.abc import Mapping
3+
from datetime import datetime
4+
from typing import NotRequired, TypedDict
35

46
from sentry.api.serializers import Serializer, register, serialize
7+
from sentry.api.serializers.models.pullrequest import PullRequestSerializerResponse
58
from sentry.api.serializers.models.release import Author, get_users_for_authors
9+
from sentry.api.serializers.models.repository import RepositorySerializerResponse
610
from sentry.models.commit import Commit
711
from sentry.models.commitauthor import CommitAuthor
812
from sentry.models.pullrequest import PullRequest
913
from sentry.models.repository import Repository
1014

1115

16+
class CommitSerializerResponse(TypedDict):
17+
id: str
18+
message: str | None
19+
dateCreated: datetime
20+
pullRequest: PullRequestSerializerResponse | None
21+
suspectCommitType: str
22+
23+
repository: NotRequired[RepositorySerializerResponse]
24+
author: NotRequired[Author]
25+
26+
27+
class CommitReleaseSerializerResponse(TypedDict):
28+
version: str
29+
shortVersion: str
30+
ref: str
31+
url: str
32+
dateReleased: datetime
33+
dateCreated: datetime
34+
35+
36+
class CommitSerializerResponseWithReleases(CommitSerializerResponse):
37+
releases: list[CommitReleaseSerializerResponse]
38+
39+
1240
def get_users_for_commits(item_list, user=None) -> Mapping[str, Author]:
1341
authors = list(
1442
CommitAuthor.objects.get_many_from_cache([i.author_id for i in item_list if i.author_id])
@@ -66,8 +94,8 @@ def get_attrs(self, item_list, user, **kwargs):
6694

6795
return result
6896

69-
def serialize(self, obj, attrs, user, **kwargs):
70-
d = {
97+
def serialize(self, obj: Commit, attrs, user, **kwargs) -> CommitSerializerResponse:
98+
d: CommitSerializerResponse = {
7199
"id": obj.key,
72100
"message": obj.message,
73101
"dateCreated": obj.date_added,
@@ -102,17 +130,29 @@ def get_attrs(self, item_list, user, **kwargs):
102130
attrs[item]["releases"] = releases_by_commit[item.id]
103131
return attrs
104132

105-
def serialize(self, obj, attrs, user, **kwargs):
133+
def serialize(self, obj, attrs, user, **kwargs) -> CommitSerializerResponseWithReleases:
106134
data = super().serialize(obj, attrs, user)
107-
data["releases"] = [
108-
{
109-
"version": r.version,
110-
"shortVersion": r.version,
111-
"ref": r.ref,
112-
"url": r.url,
113-
"dateReleased": r.date_released,
114-
"dateCreated": r.date_added,
115-
}
116-
for r in attrs["releases"]
117-
]
118-
return data
135+
ret: CommitSerializerResponseWithReleases = {
136+
"id": data["id"],
137+
"message": data["message"],
138+
"dateCreated": data["dateCreated"],
139+
"pullRequest": data["pullRequest"],
140+
"suspectCommitType": data["suspectCommitType"],
141+
"releases": [
142+
{
143+
"version": r.version,
144+
"shortVersion": r.version,
145+
"ref": r.ref,
146+
"url": r.url,
147+
"dateReleased": r.date_released,
148+
"dateCreated": r.date_added,
149+
}
150+
for r in attrs["releases"]
151+
],
152+
}
153+
if "repository" in data:
154+
ret["repository"] = attrs["repository"]
155+
if "author" in data:
156+
ret["author"] = attrs["user"]
157+
158+
return ret

src/sentry/api/serializers/models/pullrequest.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,24 @@
1+
from datetime import datetime
2+
from typing import TypedDict
3+
14
from sentry.api.serializers import Serializer, register, serialize
2-
from sentry.api.serializers.models.release import get_users_for_authors
5+
from sentry.api.serializers.models.release import Author, get_users_for_authors
6+
from sentry.api.serializers.models.repository import RepositorySerializerResponse
37
from sentry.models.commitauthor import CommitAuthor
48
from sentry.models.pullrequest import PullRequest
59
from sentry.models.repository import Repository
610

711

12+
class PullRequestSerializerResponse(TypedDict):
13+
id: str
14+
title: str | None
15+
message: str | None
16+
dateCreated: datetime
17+
repository: RepositorySerializerResponse
18+
author: Author
19+
externalUrl: str
20+
21+
822
def get_users_for_pull_requests(item_list, user=None):
923
authors = list(
1024
CommitAuthor.objects.filter(id__in=[i.author_id for i in item_list if i.author_id])
@@ -39,7 +53,7 @@ def get_attrs(self, item_list, user, **kwargs):
3953

4054
return result
4155

42-
def serialize(self, obj, attrs, user, **kwargs):
56+
def serialize(self, obj: PullRequest, attrs, user, **kwargs) -> PullRequestSerializerResponse:
4357
return {
4458
"id": obj.key,
4559
"title": obj.title,

src/sentry/api/serializers/models/repository.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,25 @@
1+
from datetime import datetime
2+
from typing import TypedDict
3+
14
from sentry.api.serializers import Serializer, register
25
from sentry.models.repository import Repository
36

47

8+
class RepositorySerializerResponse(TypedDict):
9+
id: str
10+
name: str
11+
url: str | None
12+
provider: dict[str, str]
13+
status: str
14+
dateCreated: datetime
15+
integrationId: str | None
16+
externalSlug: str | None
17+
externalId: str | None
18+
19+
520
@register(Repository)
621
class RepositorySerializer(Serializer):
7-
def serialize(self, obj, attrs, user, **kwargs):
22+
def serialize(self, obj: Repository, attrs, user, **kwargs) -> RepositorySerializerResponse:
823
external_slug = None
924
integration_id = None
1025
if obj.integration_id:

src/sentry/integrations/api/endpoints/organization_repository_commits.py

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from drf_spectacular.utils import OpenApiExample, OpenApiParameter, extend_schema
12
from rest_framework.request import Request
23
from rest_framework.response import Response
34

@@ -7,28 +8,68 @@
78
from sentry.api.bases.organization import OrganizationEndpoint
89
from sentry.api.exceptions import ResourceDoesNotExist
910
from sentry.api.paginator import DateTimePaginator
10-
from sentry.api.serializers import serialize
11+
from sentry.api.serializers.base import serialize
12+
from sentry.api.serializers.models.commit import CommitSerializerResponse
13+
from sentry.apidocs.constants import (
14+
RESPONSE_BAD_REQUEST,
15+
RESPONSE_FORBIDDEN,
16+
RESPONSE_NOT_FOUND,
17+
RESPONSE_UNAUTHORIZED,
18+
)
19+
from sentry.apidocs.parameters import GlobalParams
20+
from sentry.apidocs.utils import inline_sentry_response_serializer
1121
from sentry.models.commit import Commit
1222
from sentry.models.repository import Repository
1323

1424

1525
@region_silo_endpoint
26+
@extend_schema(tags=["Organizations"])
1627
class OrganizationRepositoryCommitsEndpoint(OrganizationEndpoint):
1728
owner = ApiOwner.INTEGRATIONS
1829
publish_status = {
19-
"GET": ApiPublishStatus.UNKNOWN,
30+
"GET": ApiPublishStatus.PUBLIC,
2031
}
2132

33+
@extend_schema(
34+
operation_id="List a Repository's Commits",
35+
parameters=[
36+
GlobalParams.ORG_ID_OR_SLUG,
37+
OpenApiParameter(
38+
name="repo_id",
39+
description="The repository ID.",
40+
required=True,
41+
type=str,
42+
location="path",
43+
),
44+
],
45+
responses={
46+
200: inline_sentry_response_serializer(
47+
"CommitSerializerResponse",
48+
list[CommitSerializerResponse],
49+
),
50+
400: RESPONSE_BAD_REQUEST,
51+
401: RESPONSE_UNAUTHORIZED,
52+
403: RESPONSE_FORBIDDEN,
53+
404: RESPONSE_NOT_FOUND,
54+
},
55+
examples=[
56+
OpenApiExample(
57+
name="Repository Commits",
58+
value=[
59+
{
60+
"dateCreated": "2018-11-06T21:19:58.536Z",
61+
"id": "acbafc639127fd89d10f474520104517ff1d709e",
62+
"message": "Initial commit from Create Next App",
63+
"suspectCommitType": "",
64+
"pullRequest": None,
65+
}
66+
],
67+
),
68+
],
69+
)
2270
def get(self, request: Request, organization, repo_id) -> Response:
2371
"""
2472
List a Repository's Commits
25-
```````````````````````````
26-
27-
Return a list of commits for a given repository.
28-
29-
:pparam string organization_id_or_slug: the id or slug of the organization
30-
:pparam string repo_id: the repository ID
31-
:auth: required
3273
"""
3374
try:
3475
repo = Repository.objects.get(id=repo_id, organization_id=organization.id)

0 commit comments

Comments
 (0)