Skip to content

Commit 1cf8134

Browse files
authored
feat(preprod): add base_size_metrics to build details api (EME-568) (#104516)
Adds `base_size_metrics` to build details API
1 parent 25addc1 commit 1cf8134

File tree

4 files changed

+117
-3
lines changed

4 files changed

+117
-3
lines changed

.vscode/settings.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,5 +101,10 @@
101101
"python.analysis.autoImportCompletions": true,
102102
"prettier.configPath": "prettier.config.mjs",
103103
"biome.enabled": false,
104-
"cursorpyright.analysis.autoImportCompletions": true
104+
"cursorpyright.analysis.autoImportCompletions": true,
105+
"mypy-type-checker.path": ["${workspaceFolder}/.venv/bin/mypy"],
106+
"mypy-type-checker.args": [
107+
"--config-file=${workspaceFolder}/pyproject.toml"
108+
],
109+
"mypy-type-checker.cwd": "${workspaceFolder}",
105110
}

src/sentry/preprod/api/models/project_preprod_build_details_models.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ class SizeInfoCompleted(BaseModel):
106106
# Deprecated, use size_metrics instead
107107
download_size_bytes: int
108108
size_metrics: list[SizeInfoSizeMetric]
109+
base_size_metrics: list[SizeInfoSizeMetric]
109110

110111

111112
class SizeInfoFailed(BaseModel):
@@ -129,6 +130,7 @@ class BuildDetailsApiResponse(BaseModel):
129130
vcs_info: BuildDetailsVcsInfo
130131
size_info: SizeInfo | None = None
131132
posted_status_checks: PostedStatusChecks | None = None
133+
base_artifact_id: str | None = None
132134

133135

134136
def platform_from_artifact_type(artifact_type: PreprodArtifact.ArtifactType) -> Platform:
@@ -143,7 +145,10 @@ def platform_from_artifact_type(artifact_type: PreprodArtifact.ArtifactType) ->
143145
raise ValueError(f"Unknown artifact type: {artifact_type}")
144146

145147

146-
def to_size_info(size_metrics: list[PreprodArtifactSizeMetrics]) -> None | SizeInfo:
148+
def to_size_info(
149+
size_metrics: list[PreprodArtifactSizeMetrics],
150+
base_size_metrics: list[PreprodArtifactSizeMetrics] | None = None,
151+
) -> None | SizeInfo:
147152
if len(size_metrics) == 0:
148153
return None
149154

@@ -182,6 +187,15 @@ def to_size_info(size_metrics: list[PreprodArtifactSizeMetrics]) -> None | SizeI
182187
)
183188
for metric in size_metrics
184189
],
190+
base_size_metrics=[
191+
SizeInfoSizeMetric(
192+
metrics_artifact_type=metric.metrics_artifact_type,
193+
install_size_bytes=metric.max_install_size,
194+
download_size_bytes=metric.max_download_size,
195+
)
196+
for metric in (base_size_metrics or [])
197+
if metric.max_install_size is not None and metric.max_download_size is not None
198+
],
185199
)
186200
case PreprodArtifactSizeMetrics.SizeAnalysisState.FAILED:
187201
error_code = main_metric.error_code
@@ -200,8 +214,18 @@ def transform_preprod_artifact_to_build_details(
200214
size_metrics_qs = PreprodArtifactSizeMetrics.objects.filter(
201215
preprod_artifact=artifact,
202216
)
217+
size_metrics_list = list(size_metrics_qs)
218+
219+
base_size_metrics_list: list[PreprodArtifactSizeMetrics] = []
220+
base_artifact = artifact.get_base_artifact_for_commit().first()
221+
if base_artifact:
222+
base_size_metrics_qs = PreprodArtifactSizeMetrics.objects.filter(
223+
preprod_artifact=base_artifact,
224+
state=PreprodArtifactSizeMetrics.SizeAnalysisState.COMPLETED,
225+
)
226+
base_size_metrics_list = list(base_size_metrics_qs)
203227

204-
size_info = to_size_info(list(size_metrics_qs))
228+
size_info = to_size_info(size_metrics_list, base_size_metrics_list)
205229

206230
platform = None
207231
# artifact_type can be null before preprocessing has completed
@@ -274,6 +298,7 @@ def transform_preprod_artifact_to_build_details(
274298
vcs_info=vcs_info,
275299
size_info=size_info,
276300
posted_status_checks=posted_status_checks,
301+
base_artifact_id=base_artifact.id if base_artifact else None,
277302
)
278303

279304

tests/sentry/preprod/api/endpoints/test_project_preprod_build_details.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,59 @@ def test_size_info_completed(self) -> None:
191191
assert resp_data["size_info"]["install_size_bytes"] == 1024000
192192
assert resp_data["size_info"]["download_size_bytes"] == 512000
193193

194+
def test_size_info_completed_includes_base_metrics(self) -> None:
195+
"""Test that completed size analysis includes base_size_metrics when base artifact exists."""
196+
assert self.preprod_artifact.commit_comparison is not None
197+
base_commit_comparison = self.create_commit_comparison(
198+
organization=self.org,
199+
head_sha=self.preprod_artifact.commit_comparison.base_sha,
200+
base_sha="0000000000000000000000000000000000000000",
201+
)
202+
base_file = self.create_file(name="base_artifact.apk", type="application/octet-stream")
203+
base_artifact = self.create_preprod_artifact(
204+
project=self.project,
205+
file_id=base_file.id,
206+
artifact_type=self.preprod_artifact.artifact_type,
207+
app_id=self.preprod_artifact.app_id,
208+
app_name=self.preprod_artifact.app_name,
209+
build_version="0.9.0",
210+
build_number=41,
211+
commit_comparison=base_commit_comparison,
212+
)
213+
214+
self.create_preprod_artifact_size_metrics(
215+
self.preprod_artifact,
216+
metrics_type=PreprodArtifactSizeMetrics.MetricsArtifactType.MAIN_ARTIFACT,
217+
state=PreprodArtifactSizeMetrics.SizeAnalysisState.COMPLETED,
218+
max_install_size=1536000,
219+
max_download_size=768000,
220+
)
221+
self.create_preprod_artifact_size_metrics(
222+
base_artifact,
223+
metrics_type=PreprodArtifactSizeMetrics.MetricsArtifactType.MAIN_ARTIFACT,
224+
state=PreprodArtifactSizeMetrics.SizeAnalysisState.COMPLETED,
225+
max_install_size=1024000,
226+
max_download_size=512000,
227+
)
228+
229+
url = self._get_url()
230+
response = self.client.get(
231+
url, format="json", HTTP_AUTHORIZATION=f"Bearer {self.api_token.token}"
232+
)
233+
234+
assert response.status_code == 200
235+
resp_data = response.json()
236+
assert resp_data["size_info"] is not None
237+
assert resp_data["size_info"]["state"] == 2
238+
assert len(resp_data["size_info"]["base_size_metrics"]) == 1
239+
base_metric = resp_data["size_info"]["base_size_metrics"][0]
240+
assert (
241+
base_metric["metrics_artifact_type"]
242+
== PreprodArtifactSizeMetrics.MetricsArtifactType.MAIN_ARTIFACT
243+
)
244+
assert base_metric["install_size_bytes"] == 1024000
245+
assert base_metric["download_size_bytes"] == 512000
246+
194247
def test_size_info_failed(self) -> None:
195248
"""Test that failed size analysis returns SizeInfoFailed."""
196249
self.create_preprod_artifact_size_metrics(

tests/sentry/preprod/api/models/test_project_preprod_build_details_models.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,37 @@ def test_to_size_info_completed_state_with_multiple_metrics(self):
9595
assert result.size_metrics[1].install_size_bytes == 512000
9696
assert result.size_metrics[1].download_size_bytes == 256000
9797

98+
def test_to_size_info_completed_state_with_base_metrics(self):
99+
"""Test to_size_info includes base size metrics when provided."""
100+
size_metrics = [
101+
PreprodArtifactSizeMetrics(
102+
state=PreprodArtifactSizeMetrics.SizeAnalysisState.COMPLETED,
103+
metrics_artifact_type=PreprodArtifactSizeMetrics.MetricsArtifactType.MAIN_ARTIFACT,
104+
max_install_size=1024000,
105+
max_download_size=512000,
106+
),
107+
]
108+
base_size_metrics = [
109+
PreprodArtifactSizeMetrics(
110+
state=PreprodArtifactSizeMetrics.SizeAnalysisState.COMPLETED,
111+
metrics_artifact_type=PreprodArtifactSizeMetrics.MetricsArtifactType.MAIN_ARTIFACT,
112+
max_install_size=512000,
113+
max_download_size=256000,
114+
),
115+
]
116+
117+
result = to_size_info(size_metrics, base_size_metrics)
118+
119+
assert isinstance(result, SizeInfoCompleted)
120+
assert len(result.base_size_metrics) == 1
121+
base_metric = result.base_size_metrics[0]
122+
assert (
123+
base_metric.metrics_artifact_type
124+
== PreprodArtifactSizeMetrics.MetricsArtifactType.MAIN_ARTIFACT
125+
)
126+
assert base_metric.install_size_bytes == 512000
127+
assert base_metric.download_size_bytes == 256000
128+
98129
def test_to_size_info_failed_state(self):
99130
"""Test to_size_info returns SizeInfoFailed for FAILED state."""
100131
size_metrics = PreprodArtifactSizeMetrics(

0 commit comments

Comments
 (0)