Various api improvements

- tweak function names for better swagger labels
- more build query options
- more build-events query options
- allow undeploying several builds at once
This commit is contained in:
Stéphane Bidoul 2021-11-20 14:22:32 +01:00
parent dc6d75c94a
commit f173688935
No known key found for this signature in database
GPG key ID: BCAB2555446B5B92
4 changed files with 77 additions and 11 deletions

View file

@ -17,3 +17,5 @@ root:
loggers:
kubernetes.client.rest:
level: INFO
sse_starlette.sse:
level: INFO

View file

@ -80,8 +80,33 @@ async def repos() -> list[models.Repo]:
response_model=list[Build],
response_model_exclude_none=True,
)
async def builds(repo: Optional[str] = None) -> list[models.Build]:
return list(controller.db.search(repo))
async def builds(
repo: Optional[str] = None,
target_branch: Optional[str] = None,
branch: Optional[str] = None,
pr: Optional[int] = None,
) -> list[models.Build]:
return list(
controller.db.search(
repo=repo, target_branch=target_branch, branch=branch, pr=pr
)
)
@router.delete(
"/builds",
dependencies=[Depends(authenticated)],
)
async def undeploy_builds(
repo: Optional[str] = None,
target_branch: Optional[str] = None,
branch: Optional[str] = None,
pr: Optional[int] = None,
) -> None:
for build in controller.db.search(
repo=repo, target_branch=target_branch, branch=branch, pr=pr
):
await build.undeploy()
@router.post(
@ -151,21 +176,21 @@ async def log(name: str) -> str:
@router.post("/builds/{name}/start")
async def start(name: str) -> None:
async def start_build(name: str) -> None:
"""Start the deployment."""
build = await _build_by_name(name)
await build.start()
@router.post("/builds/{name}/stop")
async def stop(name: str) -> None:
async def stop_build(name: str) -> None:
"""Stop the deployment."""
build = await _build_by_name(name)
await build.stop()
@router.delete("/builds/{name}", dependencies=[Depends(authenticated)])
async def delete(name: str) -> None:
async def undeploy_build(name: str) -> None:
"""Delete the deployment and drop the database."""
build = await _build_by_name(name)
await build.undeploy()
@ -177,12 +202,16 @@ class BuildEventSource:
request: Request,
repo: str | None = None,
target_branch: str | None = None,
branch: str | None = None,
pr: int | None = None,
build_name: str | None = None,
):
self.queue: asyncio.Queue[str] = asyncio.Queue()
self.request = request
self.repo = repo
self.target_branch = target_branch
self.branch = branch
self.pr = pr
self.build_name = build_name
controller.db.register_listener(self)
@ -195,13 +224,21 @@ class BuildEventSource:
return
if self.target_branch and build.target_branch != self.target_branch:
return
if self.branch and (build.target_branch != self.branch or build.pr):
return
if self.pr and build.pr != self.pr:
return
if self.build_name and build.name != self.build_name:
return
self.queue.put_nowait(self._serialize(event, build))
async def events(self) -> AsyncGenerator[str, None]:
for build in controller.db.search(
self.repo, self.target_branch, self.build_name
repo=self.repo,
target_branch=self.target_branch,
branch=self.branch,
pr=self.pr,
name=self.build_name,
):
yield self._serialize(models.BuildEvent.modified, build)
while True:
@ -217,11 +254,15 @@ class BuildEventSource:
@router.get("/build-events")
async def eventsource_endpoint(
async def build_events(
request: Request,
repo: Optional[str] = None,
target_branch: Optional[str] = None,
branch: Optional[str] = None,
pr: Optional[int] = None,
build_name: Optional[str] = None,
) -> EventSourceResponse:
event_source = BuildEventSource(request, repo, target_branch, build_name)
event_source = BuildEventSource(
request, repo, target_branch, branch, pr, build_name
)
return EventSourceResponse(event_source.events())

View file

@ -13,6 +13,9 @@ class BuildListener(Protocol):
...
NoPr = 0
class BuildsDb:
"""An in-memory database of builds.
@ -192,17 +195,29 @@ class BuildsDb:
self,
repo: str | None = None,
target_branch: str | None = None,
branch: str | None = None,
pr: int | None = None,
name: str | None = None,
) -> Iterator[Build]:
query = "SELECT * FROM builds "
where = []
params = []
params: list[str | int] = []
if repo:
where.append("repo=?")
params.append(repo.lower())
if target_branch:
where.append("target_branch=?")
params.append(target_branch)
if branch:
where.append("target_branch=?")
params.append(branch)
where.append("pr IS NULL")
if pr is not None:
if pr == NoPr:
where.append("pr IS NULL")
else:
where.append("pr=?")
params.append(pr)
if name:
where.append("name=?")
params.append(name)

View file

@ -1,7 +1,7 @@
from typing import Optional
from fastapi import APIRouter, HTTPException, Response, status
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.responses import RedirectResponse
from .controller import controller
from .models import BuildStatus
@ -9,7 +9,15 @@ from .models import BuildStatus
router = APIRouter()
@router.get("/builds/{name}", response_class=HTMLResponse)
@router.get("/builds", response_class=RedirectResponse)
async def builds(repo: str, target_branch: Optional[str] = None) -> Response:
url = f"/webui/builds.html?repo={repo}"
if target_branch:
url += f"&target_branch={target_branch}"
return RedirectResponse(url=url)
@router.get("/builds/{name}", response_class=RedirectResponse)
async def build(name: str, live: Optional[str] = None) -> Response:
build = controller.db.get(name)
if not build: