Do not create new deployment if build already exist
This commit is contained in:
parent
c2b2d88f4c
commit
1f137bbdc8
8 changed files with 71 additions and 27 deletions
|
|
@ -3,6 +3,7 @@ disable_existing_loggers: false
|
|||
formatters:
|
||||
rich:
|
||||
datefmt: "[%X]"
|
||||
format: "%(name)25s %(message)s"
|
||||
handlers:
|
||||
console:
|
||||
class: rich.logging.RichHandler
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class Build(BaseModel):
|
|||
repo: str
|
||||
target_branch: str
|
||||
pr: Optional[int]
|
||||
commit: str
|
||||
git_commit: str
|
||||
image: str
|
||||
link: str
|
||||
status: models.BuildStatus
|
||||
|
|
@ -92,11 +92,11 @@ async def trigger_branch(org: str, repo: str, branch: str):
|
|||
"""Trigger build for a branch."""
|
||||
# TODO async github call
|
||||
branch_info = github.get_branch_info(org, repo, branch)
|
||||
await models.Build.deploy(
|
||||
await controller.deploy_or_delay_start(
|
||||
repo=f"{branch_info.org}/{branch_info.repo}",
|
||||
target_branch=branch_info.name,
|
||||
pr=None,
|
||||
commit=branch_info.head_sha,
|
||||
git_commit=branch_info.head_sha,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -109,11 +109,11 @@ async def trigger_pull(org: str, repo: str, pr: int):
|
|||
"""Trigger build for a pull request."""
|
||||
# TODO async github call
|
||||
pull_info = github.get_pull_info(org, repo, pr)
|
||||
await models.Build.deploy(
|
||||
await controller.deploy_or_delay_start(
|
||||
repo=f"{pull_info.org}/{pull_info.repo}",
|
||||
target_branch=pull_info.target_branch,
|
||||
pr=pull_info.number,
|
||||
commit=pull_info.head_sha,
|
||||
git_commit=pull_info.head_sha,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,25 @@ class Controller:
|
|||
def max_deployed(self) -> int:
|
||||
return settings.max_deployed
|
||||
|
||||
async def deploy_or_delay_start(
|
||||
self, repo: str, target_branch: str, pr: int | None, git_commit: str
|
||||
) -> None:
|
||||
build = self.db.get_for_commit(
|
||||
repo=repo,
|
||||
target_branch=target_branch,
|
||||
pr=pr,
|
||||
git_commit=git_commit,
|
||||
)
|
||||
if build is not None:
|
||||
await build.delay_start()
|
||||
return
|
||||
await Build.deploy(
|
||||
repo=repo,
|
||||
target_branch=target_branch,
|
||||
pr=pr,
|
||||
git_commit=git_commit,
|
||||
)
|
||||
|
||||
def _wakeup(self) -> None:
|
||||
self._wakeup_event.set()
|
||||
self._wakeup_event.clear()
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class BuildsDb:
|
|||
" repo TEXT NOT NULL, "
|
||||
" target_branch TEXT NOT NULL, "
|
||||
" pr INTEGER, "
|
||||
" 'commit' TEXT NOT NULL, "
|
||||
" git_commit TEXT NOT NULL, "
|
||||
" image TEXT NOT NULL,"
|
||||
" status TEXT NOT NULL, "
|
||||
" todo TEXT, "
|
||||
|
|
@ -51,6 +51,21 @@ class BuildsDb:
|
|||
return None
|
||||
return self._build_from_row(row)
|
||||
|
||||
def get_for_commit(
|
||||
self, repo: str, target_branch: str, pr: int | None, git_commit: str
|
||||
) -> Build | None:
|
||||
query = "SELECT * FROM builds WHERE repo=? AND target_branch=? AND git_commit=?"
|
||||
params = [repo.lower(), target_branch, git_commit]
|
||||
if pr:
|
||||
query += " AND pr=?"
|
||||
params.append(pr)
|
||||
else:
|
||||
query += " AND pr IS NULL"
|
||||
row = self._con.execute(query, params).fetchone()
|
||||
if not row:
|
||||
return None
|
||||
return self._build_from_row(row)
|
||||
|
||||
def remove(self, name: str) -> None:
|
||||
with self._con:
|
||||
self._con.execute("DELETE FROM builds WHERE name=?", (name,))
|
||||
|
|
@ -65,7 +80,7 @@ class BuildsDb:
|
|||
" repo,"
|
||||
" target_branch,"
|
||||
" pr,"
|
||||
" 'commit',"
|
||||
" git_commit,"
|
||||
" image,"
|
||||
" status,"
|
||||
" todo, "
|
||||
|
|
@ -79,7 +94,7 @@ class BuildsDb:
|
|||
build.repo,
|
||||
build.target_branch,
|
||||
build.pr,
|
||||
build.commit,
|
||||
build.git_commit,
|
||||
build.image,
|
||||
build.status,
|
||||
build.todo,
|
||||
|
|
@ -99,6 +114,7 @@ class BuildsDb:
|
|||
|
||||
def to_start(self, limit: int) -> list[Build]:
|
||||
"""Return the list of builds to start, ordered by todo timestamp."""
|
||||
# TODO ordering is not correct as setting todo does not set last_scaled
|
||||
rows = self._con.execute(
|
||||
"SELECT * FROM builds WHERE todo=? ORDER BY last_scaled LIMIT ?",
|
||||
(BuildTodo.start, limit),
|
||||
|
|
@ -127,7 +143,7 @@ class BuildsDb:
|
|||
for row in self._con.execute(
|
||||
"SELECT * FROM builds WHERE repo=?"
|
||||
"ORDER BY target_branch, pr, created DESC",
|
||||
(repo,),
|
||||
(repo.lower(),),
|
||||
).fetchall():
|
||||
build = self._build_from_row(row)
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ class DeploymentVars(BaseModel):
|
|||
repo: str
|
||||
target_branch: str
|
||||
pr: Optional[int]
|
||||
commit: str
|
||||
git_commit: str
|
||||
image_name: str
|
||||
image_tag: str
|
||||
pghost: str
|
||||
|
|
@ -71,7 +71,7 @@ def make_deployment_vars(
|
|||
repo: str,
|
||||
target_branch: str,
|
||||
pr: int | None,
|
||||
commit: str,
|
||||
git_commit: str,
|
||||
image: str,
|
||||
) -> DeploymentVars:
|
||||
image_name, image_tag = _split_image_name_tag(image)
|
||||
|
|
@ -81,7 +81,7 @@ def make_deployment_vars(
|
|||
repo=repo,
|
||||
target_branch=target_branch,
|
||||
pr=pr,
|
||||
commit=commit,
|
||||
git_commit=git_commit,
|
||||
image_name=image_name,
|
||||
image_tag=image_tag,
|
||||
pghost=settings.build_pghost,
|
||||
|
|
@ -118,6 +118,14 @@ async def _kubectl(args: list[str]) -> None:
|
|||
|
||||
async def deploy(deployment_vars: DeploymentVars) -> None:
|
||||
with _render_kubefiles(deployment_vars) as tmp_path:
|
||||
await _kubectl(
|
||||
[
|
||||
"apply",
|
||||
"--dry-run=server",
|
||||
"-k",
|
||||
str(tmp_path),
|
||||
]
|
||||
)
|
||||
await _kubectl(
|
||||
[
|
||||
"apply",
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ commonAnnotations:
|
|||
runboat/repo: "{{ repo }}"
|
||||
runboat/target-branch: "{{ target_branch }}"
|
||||
runboat/pr: "{{ pr if pr else '' }}"
|
||||
runboat/commit: "{{ commit }}"
|
||||
runboat/git-commit: "{{ git_commit }}"
|
||||
|
||||
images:
|
||||
- name: odoo
|
||||
|
|
@ -37,7 +37,7 @@ configMapGenerator:
|
|||
- PGDATABASE={{ pgdatabase }}
|
||||
- ADDONS_DIR=/build
|
||||
- RUNBOAT_GIT_REPO=https://github.com/{{ repo }}
|
||||
- RUNBOAT_GIT_REF={{ commit }}
|
||||
- RUNBOAT_GIT_REF={{ git_commit }}
|
||||
- name: runboat-scripts
|
||||
files:
|
||||
- runboat-clone-and-install.sh
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class Build(BaseModel):
|
|||
repo: str
|
||||
target_branch: str
|
||||
pr: Optional[int]
|
||||
commit: str
|
||||
git_commit: str
|
||||
image: str
|
||||
status: BuildStatus
|
||||
todo: Optional[BuildTodo]
|
||||
|
|
@ -46,7 +46,7 @@ class Build(BaseModel):
|
|||
repo=deployment.metadata.annotations["runboat/repo"],
|
||||
target_branch=deployment.metadata.annotations["runboat/target-branch"],
|
||||
pr=deployment.metadata.annotations["runboat/pr"] or None,
|
||||
commit=deployment.metadata.annotations["runboat/commit"],
|
||||
git_commit=deployment.metadata.annotations["runboat/git-commit"],
|
||||
image=deployment.spec.template.spec.containers[0].image,
|
||||
status=cls._status_from_deployment(deployment),
|
||||
todo=deployment.metadata.annotations["runboat/todo"] or None,
|
||||
|
|
@ -71,17 +71,17 @@ class Build(BaseModel):
|
|||
|
||||
@classmethod
|
||||
def make_slug(
|
||||
cls, repo: str, target_branch: str, pr: int | None, commit: str
|
||||
cls, repo: str, target_branch: str, pr: int | None, git_commit: str
|
||||
) -> str:
|
||||
slug = f"{slugify(repo)}-{slugify(target_branch)}"
|
||||
if pr:
|
||||
slug = f"{slug}-pr{slugify(pr)}"
|
||||
slug = f"{slug}-{commit[:12]}"
|
||||
slug = f"{slug}-{git_commit[:12]}"
|
||||
return slug
|
||||
|
||||
@property
|
||||
def slug(self) -> str:
|
||||
return self.make_slug(self.repo, self.target_branch, self.pr, self.commit)
|
||||
return self.make_slug(self.repo, self.target_branch, self.pr, self.git_commit)
|
||||
|
||||
@property
|
||||
def link(self) -> str:
|
||||
|
|
@ -147,11 +147,11 @@ class Build(BaseModel):
|
|||
|
||||
@classmethod
|
||||
async def deploy(
|
||||
cls, repo: str, target_branch: str, pr: int | None, commit: str
|
||||
cls, repo: str, target_branch: str, pr: int | None, git_commit: str
|
||||
) -> None:
|
||||
"""Deploy a build, without starting it."""
|
||||
name = str(uuid.uuid4())
|
||||
slug = cls.make_slug(repo, target_branch, pr, commit)
|
||||
slug = cls.make_slug(repo, target_branch, pr, git_commit)
|
||||
_logger.info(f"Deploying {slug} ({name})")
|
||||
image = get_build_image(target_branch)
|
||||
deployment_vars = k8s.make_deployment_vars(
|
||||
|
|
@ -160,7 +160,7 @@ class Build(BaseModel):
|
|||
repo.lower(),
|
||||
target_branch,
|
||||
pr,
|
||||
commit,
|
||||
git_commit,
|
||||
image,
|
||||
)
|
||||
await k8s.deploy(deployment_vars)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import logging
|
|||
|
||||
from fastapi import APIRouter, BackgroundTasks, Header, Request
|
||||
|
||||
from . import models
|
||||
from .controller import controller
|
||||
from .settings import settings
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
|
@ -29,17 +29,17 @@ async def receive_payload(
|
|||
if x_github_event == "pull_request":
|
||||
if action in ("opened", "synchronize"):
|
||||
background_tasks.add_task(
|
||||
models.Build.deploy,
|
||||
controller.deploy_or_delay_start,
|
||||
repo=repo,
|
||||
target_branch=payload["pull_request"]["base"]["ref"],
|
||||
pr=payload["pull_request"]["number"],
|
||||
commit=payload["pull_request"]["head"]["sha"],
|
||||
git_commit=payload["pull_request"]["head"]["sha"],
|
||||
)
|
||||
elif x_github_event == "push":
|
||||
background_tasks.add_task(
|
||||
models.Build.deploy,
|
||||
controller.deploy_or_delay_start,
|
||||
repo=repo,
|
||||
target_branch=payload["ref"].split("/")[-1],
|
||||
pr=None,
|
||||
commit=payload["after"],
|
||||
git_commit=payload["after"],
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue