]> git.ipfire.org Git - pbs.git/commitdiff
builds: Add controls to approve builds
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 17 Sep 2023 09:43:24 +0000 (09:43 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 17 Sep 2023 09:43:24 +0000 (09:43 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
src/buildservice/builds.py
src/buildservice/distribution.py
src/templates/builds/approve.html [new file with mode: 0644]
src/templates/builds/show.html
src/web/__init__.py
src/web/builds.py

index eb6f05342ef269c7c97594a7200953b8fa7ab16a..88052273578b99d69f805d200cddf3aa1a929ac4 100644 (file)
@@ -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 \
index b20ac9a8ba167fcebc6e596f56055bc4fdc09f85..95f0ad097bccc347263549ef747044493eb16af5 100644 (file)
@@ -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
index 6204fe102c4da87c599cd4988adff1eea5c9eb7e..b97dd9c13f17053317d1d69b0cc0f2611f8a30ef 100644 (file)
@@ -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 (file)
index 0000000..6171c66
--- /dev/null
@@ -0,0 +1,39 @@
+{% extends "../modal.html" %}
+
+{% block title %}{{ build }} - {{ _("Approve Build") }}{% end block %}
+
+{% block breadcrumbs %}
+       <nav class="breadcrumb" aria-label="breadcrumbs">
+               <ul>
+                       <li>
+                               <a href="/packages">{{ _("Packages") }}</a>
+                       </li>
+                       <li>
+                               <a href="/packages/{{ build.pkg.name }}">{{ build.pkg.name }}</a>
+                       </li>
+                       <li>
+                               <a href="/builds/{{ build.uuid }}">{{ build.pkg.evr }}</a>
+                       </li>
+                       <li class="is-active">
+                               <a href="#" aria-current="page">{{ _("Approve") }}</a>
+                       </li>
+               </ul>
+       </nav>
+{% end block %}
+
+{% block modal_title %}
+       <h4 class="title is-4">{{ _("Approve %s") % build }}</h4>
+{% end block %}
+
+{% block modal %}
+       <form method="POST" action="">
+               {% raw xsrf_form_html() %}
+
+               {# Submit! #}
+               <div class="field">
+                       <button type="submit" class="button is-primary is-fullwidth">
+                               {{ _("Approve") }}
+                       </button>
+               </div>
+       </form>
+{% end block %}
index 2739a4891398e0c4cb043560c9677ba15ace5e55..94fc27f4bb77d6b01dbf953457ec26a77a619d3b 100644 (file)
                                        {% module ReposList(build.repos, build=build) %}
                                {% end %}
 
-                               {% if build.owner and build.has_perm(current_user) %}
-                                       <div class="buttons">
+                               <div class="buttons">
+                                       {% if build.can_be_approved(current_user) %}
+                                               <a class="button is-success" href="/builds/{{ build.uuid }}/approve">
+                                                       {{ _("Approve") }}
+                                               </a>
+                                       {% end %}
+
+                                       {% if build.owner and build.has_perm(current_user) %}
                                                <a class="button is-success" href="/builds/{{ build.uuid }}/repos/add">
                                                        {{ _("Add Build To Repository") }}
                                                </a>
                                                                {{ _("Remove Build From Repository") }}
                                                        </a>
                                                {% end %}
-                                       </div>
-                               {% end %}
+                                       {% end %}
+                               </div>
                        </div>
                </section>
        {% end %}
index c2711df71faa19ba5a94ec879dc507d5600742f9..7ea0eab58993d3d7152cf7ff17663f8bbfbe32dd 100644 (file)
@@ -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),
index 5835d8a8e48b77bdce5fc96862c2c8c7112477a1..c613fb5aa27624e7dd61abfa14201bf3f27c0cc6 100644 (file)
@@ -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):