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:
parent
dc6d75c94a
commit
f173688935
4 changed files with 77 additions and 11 deletions
|
|
@ -17,3 +17,5 @@ root:
|
||||||
loggers:
|
loggers:
|
||||||
kubernetes.client.rest:
|
kubernetes.client.rest:
|
||||||
level: INFO
|
level: INFO
|
||||||
|
sse_starlette.sse:
|
||||||
|
level: INFO
|
||||||
|
|
|
||||||
|
|
@ -80,8 +80,33 @@ async def repos() -> list[models.Repo]:
|
||||||
response_model=list[Build],
|
response_model=list[Build],
|
||||||
response_model_exclude_none=True,
|
response_model_exclude_none=True,
|
||||||
)
|
)
|
||||||
async def builds(repo: Optional[str] = None) -> list[models.Build]:
|
async def builds(
|
||||||
return list(controller.db.search(repo))
|
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(
|
@router.post(
|
||||||
|
|
@ -151,21 +176,21 @@ async def log(name: str) -> str:
|
||||||
|
|
||||||
|
|
||||||
@router.post("/builds/{name}/start")
|
@router.post("/builds/{name}/start")
|
||||||
async def start(name: str) -> None:
|
async def start_build(name: str) -> None:
|
||||||
"""Start the deployment."""
|
"""Start the deployment."""
|
||||||
build = await _build_by_name(name)
|
build = await _build_by_name(name)
|
||||||
await build.start()
|
await build.start()
|
||||||
|
|
||||||
|
|
||||||
@router.post("/builds/{name}/stop")
|
@router.post("/builds/{name}/stop")
|
||||||
async def stop(name: str) -> None:
|
async def stop_build(name: str) -> None:
|
||||||
"""Stop the deployment."""
|
"""Stop the deployment."""
|
||||||
build = await _build_by_name(name)
|
build = await _build_by_name(name)
|
||||||
await build.stop()
|
await build.stop()
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/builds/{name}", dependencies=[Depends(authenticated)])
|
@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."""
|
"""Delete the deployment and drop the database."""
|
||||||
build = await _build_by_name(name)
|
build = await _build_by_name(name)
|
||||||
await build.undeploy()
|
await build.undeploy()
|
||||||
|
|
@ -177,12 +202,16 @@ class BuildEventSource:
|
||||||
request: Request,
|
request: Request,
|
||||||
repo: str | None = None,
|
repo: str | None = None,
|
||||||
target_branch: str | None = None,
|
target_branch: str | None = None,
|
||||||
|
branch: str | None = None,
|
||||||
|
pr: int | None = None,
|
||||||
build_name: str | None = None,
|
build_name: str | None = None,
|
||||||
):
|
):
|
||||||
self.queue: asyncio.Queue[str] = asyncio.Queue()
|
self.queue: asyncio.Queue[str] = asyncio.Queue()
|
||||||
self.request = request
|
self.request = request
|
||||||
self.repo = repo
|
self.repo = repo
|
||||||
self.target_branch = target_branch
|
self.target_branch = target_branch
|
||||||
|
self.branch = branch
|
||||||
|
self.pr = pr
|
||||||
self.build_name = build_name
|
self.build_name = build_name
|
||||||
controller.db.register_listener(self)
|
controller.db.register_listener(self)
|
||||||
|
|
||||||
|
|
@ -195,13 +224,21 @@ class BuildEventSource:
|
||||||
return
|
return
|
||||||
if self.target_branch and build.target_branch != self.target_branch:
|
if self.target_branch and build.target_branch != self.target_branch:
|
||||||
return
|
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:
|
if self.build_name and build.name != self.build_name:
|
||||||
return
|
return
|
||||||
self.queue.put_nowait(self._serialize(event, build))
|
self.queue.put_nowait(self._serialize(event, build))
|
||||||
|
|
||||||
async def events(self) -> AsyncGenerator[str, None]:
|
async def events(self) -> AsyncGenerator[str, None]:
|
||||||
for build in controller.db.search(
|
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)
|
yield self._serialize(models.BuildEvent.modified, build)
|
||||||
while True:
|
while True:
|
||||||
|
|
@ -217,11 +254,15 @@ class BuildEventSource:
|
||||||
|
|
||||||
|
|
||||||
@router.get("/build-events")
|
@router.get("/build-events")
|
||||||
async def eventsource_endpoint(
|
async def build_events(
|
||||||
request: Request,
|
request: Request,
|
||||||
repo: Optional[str] = None,
|
repo: Optional[str] = None,
|
||||||
target_branch: Optional[str] = None,
|
target_branch: Optional[str] = None,
|
||||||
|
branch: Optional[str] = None,
|
||||||
|
pr: Optional[int] = None,
|
||||||
build_name: Optional[str] = None,
|
build_name: Optional[str] = None,
|
||||||
) -> EventSourceResponse:
|
) -> 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())
|
return EventSourceResponse(event_source.events())
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,9 @@ class BuildListener(Protocol):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
NoPr = 0
|
||||||
|
|
||||||
|
|
||||||
class BuildsDb:
|
class BuildsDb:
|
||||||
"""An in-memory database of builds.
|
"""An in-memory database of builds.
|
||||||
|
|
||||||
|
|
@ -192,17 +195,29 @@ class BuildsDb:
|
||||||
self,
|
self,
|
||||||
repo: str | None = None,
|
repo: str | None = None,
|
||||||
target_branch: str | None = None,
|
target_branch: str | None = None,
|
||||||
|
branch: str | None = None,
|
||||||
|
pr: int | None = None,
|
||||||
name: str | None = None,
|
name: str | None = None,
|
||||||
) -> Iterator[Build]:
|
) -> Iterator[Build]:
|
||||||
query = "SELECT * FROM builds "
|
query = "SELECT * FROM builds "
|
||||||
where = []
|
where = []
|
||||||
params = []
|
params: list[str | int] = []
|
||||||
if repo:
|
if repo:
|
||||||
where.append("repo=?")
|
where.append("repo=?")
|
||||||
params.append(repo.lower())
|
params.append(repo.lower())
|
||||||
if target_branch:
|
if target_branch:
|
||||||
where.append("target_branch=?")
|
where.append("target_branch=?")
|
||||||
params.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:
|
if name:
|
||||||
where.append("name=?")
|
where.append("name=?")
|
||||||
params.append(name)
|
params.append(name)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi import APIRouter, HTTPException, Response, status
|
from fastapi import APIRouter, HTTPException, Response, status
|
||||||
from fastapi.responses import HTMLResponse, RedirectResponse
|
from fastapi.responses import RedirectResponse
|
||||||
|
|
||||||
from .controller import controller
|
from .controller import controller
|
||||||
from .models import BuildStatus
|
from .models import BuildStatus
|
||||||
|
|
@ -9,7 +9,15 @@ from .models import BuildStatus
|
||||||
router = APIRouter()
|
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:
|
async def build(name: str, live: Optional[str] = None) -> Response:
|
||||||
build = controller.db.get(name)
|
build = controller.db.get(name)
|
||||||
if not build:
|
if not build:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue