From 0eecd2b508ae99764ee8a22a1ca8ec9a285f5a92 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sun, 17 Sep 2023 09:43:24 +0000 Subject: [PATCH] builds: Add controls to approve builds Signed-off-by: Michael Tremer --- Makefile.am | 1 + src/buildservice/builds.py | 32 +++++++++++++++++++++++++ src/buildservice/distribution.py | 10 ++++++++ src/templates/builds/approve.html | 39 +++++++++++++++++++++++++++++++ src/templates/builds/show.html | 14 +++++++---- src/web/__init__.py | 1 + src/web/builds.py | 30 ++++++++++++++++++++++++ 7 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 src/templates/builds/approve.html diff --git a/Makefile.am b/Makefile.am index eb6f0534..88052273 100644 --- a/Makefile.am +++ b/Makefile.am @@ -182,6 +182,7 @@ dist_templates_builders_modules_DATA = \ templates_builders_modulesdir = $(templates_buildersdir)/modules dist_templates_builds_DATA = \ + src/templates/builds/approve.html \ src/templates/builds/bug.html \ src/templates/builds/bug-created.html \ src/templates/builds/clone.html \ diff --git a/src/buildservice/builds.py b/src/buildservice/builds.py index b20ac9a8..95f0ad09 100644 --- a/src/buildservice/builds.py +++ b/src/buildservice/builds.py @@ -891,6 +891,38 @@ class Build(base.DataObject): for repo in self.repos: await repo.changed() + @property + def next_repo(self): + for repo in self.repos: + return self.distro.get_next_repo(repo) + + def can_be_approved(self, user=None): + if not user or not user.is_admin(): + return False + + if self.owner: + return False + + # This can only be approved if there is another repository + if self.next_repo: + return True + + return False + + async def approve(self, user): + """ + Moves this build to the next stage + """ + # Fetch the next repository + next_repo = self.next_repo + + # Remove the build from all repositories + for repo in self.repos: + await repo.remove_build(build=self, user=user) + + # Add it to the next repository + await next_repo.add_build(build=self, user=user) + ## Bugs @lazy_property diff --git a/src/buildservice/distribution.py b/src/buildservice/distribution.py index 6204fe10..b97dd9c1 100644 --- a/src/buildservice/distribution.py +++ b/src/buildservice/distribution.py @@ -323,6 +323,16 @@ class Distribution(base.DataObject): return repo + def get_next_repo(self, repo): + """ + Returns the next repository if there is one + """ + for r in sorted(self.repos, key=lambda r: r.priority): + if r.priority <= repo.priority: + continue + + return r + # Builds def get_builds_by_name(self, name, limit=None): diff --git a/src/templates/builds/approve.html b/src/templates/builds/approve.html new file mode 100644 index 00000000..6171c66a --- /dev/null +++ b/src/templates/builds/approve.html @@ -0,0 +1,39 @@ +{% extends "../modal.html" %} + +{% block title %}{{ build }} - {{ _("Approve Build") }}{% end block %} + +{% block breadcrumbs %} + +{% end block %} + +{% block modal_title %} +

{{ _("Approve %s") % build }}

+{% end block %} + +{% block modal %} +
+ {% raw xsrf_form_html() %} + + {# Submit! #} +
+ +
+
+{% end block %} diff --git a/src/templates/builds/show.html b/src/templates/builds/show.html index 2739a489..94fc27f4 100644 --- a/src/templates/builds/show.html +++ b/src/templates/builds/show.html @@ -165,8 +165,14 @@ {% module ReposList(build.repos, build=build) %} {% end %} - {% if build.owner and build.has_perm(current_user) %} -
+
+ {% if build.can_be_approved(current_user) %} + + {{ _("Approve") }} + + {% end %} + + {% if build.owner and build.has_perm(current_user) %} {{ _("Add Build To Repository") }} @@ -176,8 +182,8 @@ {{ _("Remove Build From Repository") }} {% end %} -
- {% end %} + {% end %} +
{% end %} diff --git a/src/web/__init__.py b/src/web/__init__.py index c2711df7..7ea0eab5 100644 --- a/src/web/__init__.py +++ b/src/web/__init__.py @@ -157,6 +157,7 @@ class Application(tornado.web.Application): # Builds (r"/builds", builds.IndexHandler), (r"/builds/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})", builds.ShowHandler), + (r"/builds/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/approve", builds.ApproveHandler), (r"/builds/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/bug", builds.BugHandler), (r"/builds/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/clone", builds.CloneHandler), (r"/builds/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/comment", builds.CommentHandler), diff --git a/src/web/builds.py b/src/web/builds.py index 5835d8a8..c613fb5a 100644 --- a/src/web/builds.py +++ b/src/web/builds.py @@ -104,6 +104,36 @@ class ShowHandler(base.BaseHandler): distro=build.distro, bugs=bugs) +class ApproveHandler(base.BaseHandler): + @tornado.web.authenticated + def get(self, uuid): + build = self.backend.builds.get_by_uuid(uuid) + if not build: + raise tornado.web.HTTPError(404, "Could not find build %s" % uuid) + + # Check if this can be approved at all + if not build.can_be_approved(self.current_user): + raise tornado.web.HTTPError(400) + + self.render("builds/approve.html", build=build) + + @tornado.web.authenticated + async def post(self, uuid): + build = self.backend.builds.get_by_uuid(uuid) + if not build: + raise tornado.web.HTTPError(404, "Could not find build %s" % uuid) + + # Check if this can be approved at all + if not build.can_be_approved(self.current_user): + raise tornado.web.HTTPError(400) + + # Approve the build + with self.db.transaction(): + await build.approve(self.current_user) + + self.redirect("/builds/%s" % build.uuid) + + class CloneHandler(base.BaseHandler): @tornado.web.authenticated def get(self, uuid): -- 2.47.2