diff --git a/alws/crud/build.py b/alws/crud/build.py index eea70886..548127c7 100644 --- a/alws/crud/build.py +++ b/alws/crud/build.py @@ -239,6 +239,39 @@ async def generate_query(count=False): return query.scalars().all() +async def get_build_releases( + db: AsyncSession, + build_id: int, +) -> typing.List[build_schema.BuildRelease]: + """ + Every release the build has ever been put into, newest first. + + models.Build.release_id only keeps the release the build got into last, + so the full history has to be looked up from the releases side. Columns + are selected explicitly to keep the huge release plan out of the query. + """ + result = await db.execute( + select( + models.Release.id, + models.Release.status, + models.Release.created_at, + models.Platform.name.label("platform_name"), + models.Product.name.label("product_name"), + ) + .join( + models.Platform, + models.Release.platform_id == models.Platform.id, + ) + .join( + models.Product, + models.Release.product_id == models.Product.id, + ) + .where(models.Release.build_ids.any(build_id)) + .order_by(models.Release.id.desc()) + ) + return [build_schema.BuildRelease(**row._asdict()) for row in result.all()] + + async def get_module_preview( redis: aioredis.client.Redis, platform: models.Platform, diff --git a/alws/routers/builds.py b/alws/routers/builds.py index 08fcd860..9da0f2df 100644 --- a/alws/routers/builds.py +++ b/alws/routers/builds.py @@ -117,6 +117,17 @@ async def get_build( return db_build +@public_router.get( + '/{build_id}/releases/', + response_model=typing.List[build_schema.BuildRelease], +) +async def get_build_releases( + build_id: int, + db: AsyncSession = Depends(AsyncSessionDependency(key=get_async_db_key())), +): + return await build_crud.get_build_releases(db, build_id) + + @router.patch('/{build_id}/restart-failed', status_code=status.HTTP_200_OK) async def restart_failed_build_items( build_id: int, diff --git a/alws/schemas/build_schema.py b/alws/schemas/build_schema.py index d4e22b40..9c3118e0 100644 --- a/alws/schemas/build_schema.py +++ b/alws/schemas/build_schema.py @@ -248,6 +248,21 @@ class Config: from_attributes = True +class BuildRelease(BaseModel): + """ + A release the build is a part of, without the heavy release plan. + """ + + id: int + status: int + created_at: typing.Optional[datetime.datetime] = None + platform_name: typing.Optional[str] = None + product_name: typing.Optional[str] = None + + class Config: + from_attributes = True + + class Build(BaseModel): id: int created_at: datetime.datetime diff --git a/tests/test_api/test_releases.py b/tests/test_api/test_releases.py index 185351a0..9db7640b 100644 --- a/tests/test_api/test_releases.py +++ b/tests/test_api/test_releases.py @@ -158,6 +158,28 @@ async def test_get_release( message = f"Cannot retrieve release:\n{response.text}" assert response.status_code == self.status_codes.HTTP_200_OK, message + async def test_get_build_releases( + self, + ): + self.headers = {} + response = await self.make_request( + "get", + "/api/v1/releases/", + ) + release = response.json()[0] + build_id = release["build_ids"][0] + response = await self.make_request( + "get", + f"/api/v1/builds/{build_id}/releases/", + ) + message = f"Cannot retrieve build releases:\n{response.text}" + assert response.status_code == self.status_codes.HTTP_200_OK, message + message = ( + f"Release {release['id']} is missing " + f"among the releases of build {build_id}" + ) + assert release["id"] in [row["id"] for row in response.json()], message + async def test_revert_release( self, async_session: AsyncSession,