]> git.ipfire.org Git - pbs.git/commitdiff
builds: Automatically deprecate previous builds
authorMichael Tremer <michael.tremer@ipfire.org>
Tue, 25 Oct 2022 11:40:30 +0000 (11:40 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Tue, 25 Oct 2022 11:40:30 +0000 (11:40 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/buildservice/builds.py
src/database.sql
src/templates/builds/show.html

index dbc94d8c480ce1e9570056bf38b480495b45c8cc..8082f390264f77cfe3d8640bdbd819f89ae36276 100644 (file)
@@ -138,36 +138,6 @@ class Builds(base.Object):
 
                return list(builds)
 
-       def get_obsolete(self, repo=None):
-               """
-                       Get all obsoleted builds.
-
-                       If repo is True: which are in any repository.
-                       If repo is some Repository object: which are in this repository.
-               """
-               args = []
-
-               if repo is None:
-                       query = "SELECT id FROM builds WHERE state = 'obsolete'"
-
-               else:
-                       query = "SELECT build_id AS id FROM repositories_builds \
-                               JOIN builds ON builds.id = repositories_builds.build_id \
-                               WHERE builds.state = 'obsolete'"
-
-                       if repo and not repo is True:
-                               query += " AND repositories_builds.repo_id = %s"
-                               args.append(repo.id)
-
-               res = self.db.query(query, *args)
-
-               builds = []
-               for build in res:
-                       build = Build(self.backend, build.id)
-                       builds.append(build)
-
-               return builds
-
        def create(self, repo, package, owner=None, group=None):
                """
                        Creates a new build based on the given distribution and package
@@ -203,7 +173,8 @@ class Builds(base.Object):
                # Create all jobs
                build._create_jobs()
 
-               # XXX obsolete other builds
+               # Deprecate previous builds
+               build._deprecate_others()
 
                # Add watchers
                build._add_watchers()
@@ -339,22 +310,6 @@ class Build(base.DataObject):
        def is_broken(self):
                return self.state == "broken"
 
-       def obsolete_others(self):
-               if not self.type == "release":
-                       return
-
-               for build in self.backend.builds.get_by_name(self.pkg.name, type="release"):
-                       # Don't modify ourself.
-                       if self.id == build.id:
-                               continue
-
-                       # Don't touch broken builds.
-                       if build.state in ("obsolete", "broken"):
-                               continue
-
-                       # Obsolete the build.
-                       # XXX
-
        def set_severity(self, severity):
                self._set_attribute("severity", severity)
 
@@ -708,6 +663,111 @@ class Build(base.DataObject):
                for bug_id in self.get_bug_ids():
                        self._update_bug(bug_id, status=status, resolution=resolution, comment=comment)
 
+       # Deprecation
+
+       def _deprecate_others(self):
+               """
+                       Called when this build is being created.
+
+                       This method will find similar builds and automatically deprecate them.
+               """
+               builds = self.backend.builds._get_builds("""
+                       SELECT
+                               builds.*
+
+                       -- Walk through all builds
+                       FROM
+                               builds
+
+                       -- Find all packages belonging to the builds
+                       LEFT JOIN
+                               packages ON builds.pkg_id = packages.id
+
+                       -- Find all packages that match the name
+                       LEFT JOIN
+                               packages other_packages ON
+                                       other_packages.name = packages.name
+                               AND
+                                       other_packages.distro_id = packages.distro_id
+
+                       -- Find all other builds (excluding ourselves)
+                       LEFT JOIN
+                               builds other_builds ON
+                                       other_builds.id <> builds.id
+                               AND
+                                       other_builds.pkg_id = other_packages.id
+                               AND
+                                       other_builds.build_repo_id = builds.build_repo_id
+
+                       -- Start with this build
+                       WHERE
+                               other_builds.id = %s
+
+                       -- Exclude any deleted packages
+                       AND
+                               packages.deleted_at IS NULL
+                       AND
+                               other_packages.deleted_at IS NULL
+
+                       -- Exclude any deleted builds
+                       AND
+                               builds.deleted_at IS NULL
+
+                       -- Exclude everything that is already deprecated
+                       AND
+                               builds.deprecated_by IS NULL
+                       """, self.id,
+               )
+
+               # Deprecate all builds
+               for build in builds:
+                       build.deprecate(self)
+
+       def deprecate(self, build):
+               """
+                       Called when a build needs to be deprecated
+               """
+               log.debug("Deprecating %s by %s" % (self, build))
+
+               # Mark as deprecated
+               self.deprecated_by = build
+
+       def is_deprecated(self):
+               if self.data.deprecated_by:
+                       return True
+
+               return False
+
+       def get_deprecated_by(self):
+               if self.data.deprecated_by:
+                       return self.backend.builds.get_by_id(self.data.deprecated_by)
+
+       def set_deprecated_by(self, build):
+               self._set_attribute("deprecated_by", build)
+
+       deprecated_by = lazy_property(get_deprecated_by, set_deprecated_by)
+
+       @lazy_property
+       def deprecated_builds(self):
+               """
+                       Returns a list of builds that were deprecated by this build
+               """
+               builds = self.backend.builds._get_builds("""
+                       SELECT
+                               *
+                       FROM
+                               builds
+                       WHERE
+                               deleted_at IS NULL
+                       AND
+                               deprecated_by = %s
+                       ORDER BY
+                               created_at
+                       """, self.id,
+               )
+
+               return list(builds)
+
 
 class Groups(base.Object):
        """
index 848a4a67f538b4c69d567c4d45c5aeea7801df33..5fc5172acb23871fc1238957453d8f3ed9233a8f 100644 (file)
@@ -205,7 +205,8 @@ CREATE TABLE public.builds (
     failed boolean DEFAULT false NOT NULL,
     deleted_at timestamp without time zone,
     deleted_by integer,
-    build_group_id integer
+    build_group_id integer,
+    deprecated_by integer
 );
 
 
@@ -1505,6 +1506,13 @@ CREATE INDEX builds_created_at ON public.builds USING btree (created_at DESC) WH
 CREATE INDEX builds_deleted ON public.builds USING btree (deleted_at) WHERE (deleted_at IS NOT NULL);
 
 
+--
+-- Name: builds_deprecated_by; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX builds_deprecated_by ON public.builds USING btree (deprecated_by) WHERE (deleted_at IS NULL);
+
+
 --
 -- Name: builds_pkg_id; Type: INDEX; Schema: public; Owner: -
 --
@@ -1814,6 +1822,14 @@ ALTER TABLE ONLY public.builds
     ADD CONSTRAINT builds_deleted_by FOREIGN KEY (deleted_by) REFERENCES public.users(id);
 
 
+--
+-- Name: builds builds_deprecated_by; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.builds
+    ADD CONSTRAINT builds_deprecated_by FOREIGN KEY (deprecated_by) REFERENCES public.builds(id);
+
+
 --
 -- Name: builds builds_owner_id; Type: FK CONSTRAINT; Schema: public; Owner: -
 --
index 82003892400e7dc4248114b54496d739fb70903f..042596c95d628fcfed0ac94afc1806252c902f8c 100644 (file)
                                                </span>
                                        </div>
 
-                                       <div class="level-item">
-                                               X
-                                       </div>
+                                       {# Deprecation #}
+                                       {% if build.is_deprecated() %}
+                                               <div class="level-item">
+                                                       <a href="/builds/{{ build.deprecated_by.uuid }}">
+                                                               <span class="icon">
+                                                                       <i class="fa-solid fa-arrow-right" title="{{ _("Deprecated") }}"></i>
+                                                               </span>
+                                                       </a>
+                                               </div>
+                                       {% end %}
 
                                        <div class="level-item">
                                                X