]> git.ipfire.org Git - pbs.git/commitdiff
monitoring: Refactor the whole thing
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 20 May 2023 09:37:15 +0000 (09:37 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 20 May 2023 09:37:15 +0000 (09:37 +0000)
This is now more of an opt-in which will give us more flexibility

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/buildservice/__init__.py
src/buildservice/releasemonitoring.py
src/database.sql
src/scripts/pakfire-build-service
src/web/__init__.py

index 8c7263b5b95853e717e40ac7ff906254541d680b..4ac4770b31f2ab3c256ac2b2c1c1402d2d413116 100644 (file)
@@ -66,24 +66,24 @@ class Backend(object):
                # Initialize the HTTP Client
                self.httpclient = httpclient.HTTPClient(self)
 
-               self.aws               = aws.AWS(self)
-               self.builds            = builds.Builds(self)
-               self.cache             = cache.Cache(self)
-               self.jobs              = jobs.Jobs(self)
-               self.builders          = builders.Builders(self)
-               self.distros           = distribution.Distributions(self)
-               self.events            = events.Events(self)
-               self.keys              = keys.Keys(self)
-               self.logstreams        = logstreams.LogStreams(self)
-               self.messages          = messages.Messages(self)
-               self.mirrors           = mirrors.Mirrors(self)
-               self.packages          = packages.Packages(self)
-               self.releasemonitoring = releasemonitoring.ReleaseMonitoring(self)
-               self.repos             = repository.Repositories(self)
-               self.sessions          = sessions.Sessions(self)
-               self.sources           = sources.Sources(self)
-               self.uploads           = uploads.Uploads(self)
-               self.users             = users.Users(self)
+               self.aws         = aws.AWS(self)
+               self.builds      = builds.Builds(self)
+               self.cache       = cache.Cache(self)
+               self.jobs        = jobs.Jobs(self)
+               self.builders    = builders.Builders(self)
+               self.distros     = distribution.Distributions(self)
+               self.events      = events.Events(self)
+               self.keys        = keys.Keys(self)
+               self.logstreams  = logstreams.LogStreams(self)
+               self.messages    = messages.Messages(self)
+               self.mirrors     = mirrors.Mirrors(self)
+               self.packages    = packages.Packages(self)
+               self.monitorings = releasemonitoring.Monitorings(self)
+               self.repos       = repository.Repositories(self)
+               self.sessions    = sessions.Sessions(self)
+               self.sources     = sources.Sources(self)
+               self.uploads     = uploads.Uploads(self)
+               self.users       = users.Users(self)
 
                # Open a connection to bugzilla.
                self.bugzilla          = bugtracker.Bugzilla(self)
index 1b1e0ba3e0a5d0a7b1f732aa6c996a9c67a00c80..2ae838f2a3053e8a4da46d89ea9fe43303d296ef 100644 (file)
@@ -18,6 +18,7 @@
 #                                                                             #
 ###############################################################################
 
+import asyncio
 import json
 import logging
 import urllib.parse
@@ -29,7 +30,32 @@ from .decorators import *
 # Setup logging
 log = logging.getLogger("pbs.releasemonitoring")
 
-class ReleaseMonitoring(base.Object):
+# Only send up to four simultaneous API requests
+ratelimiter = asyncio.Semaphore(value=4)
+
+BUG_DESCRIPTION = """\
+A new version of %(name)s has been released: %(version)s\
+"""
+
+BUG_DESCRIPTION_WITH_BUILD = BUG_DESCRIPTION + """\n
+XXX PUT STUFF ABOUT THE BUILD HERE
+"""
+
+class ReleaseExistsError(Exception):
+       """
+               Raised if a release already exists
+       """
+       pass
+
+
+class BuildExistsError(Exception):
+       """
+               Raised if the build or a newer one already exists
+       """
+       pass
+
+
+class Monitorings(base.Object):
        baseurl = "https://release-monitoring.org"
 
        @property
@@ -37,6 +63,8 @@ class ReleaseMonitoring(base.Object):
                return self.settings.get("release-monitoring-api-key")
 
        async def _request(self, method, url, data=None):
+               body = {}
+
                # Authenticate to the API
                headers = {
                        "Authorization" : "Token %s" % self.api_key,
@@ -61,36 +89,65 @@ class ReleaseMonitoring(base.Object):
 
                # Decode JSON response
                if res.body:
-                       return json.loads(res.body)
+                       body = json.loads(res.body)
 
-               # Return an empty response
-               return {}
+               # Check if we have received an error
+               error = body.get("error")
 
-       # Packages
+               # Raise the error
+               if error:
+                       raise RuntimeError(error)
 
-       def _get_package(self, query, *args):
+               return body
+
+       def _get_monitoring(self, query, *args):
                res = self.db.get(query, *args)
 
                if res:
-                       return Package(self.backend, id=res.id, data=res)
+                       return Monitoring(self.backend, res.id, res)
+
+       def _get_monitorings(self, query, *args):
+               res = self.db.query(query, *args)
+
+               for row in res:
+                       yield Monitoring(self.backend, row.id, row)
 
-       def get_package(self, distro, name):
-               return self._get_package("""
+       def get_by_id(self, id):
+               return self._get_monitoring("""
                        SELECT
                                *
                        FROM
-                               release_monitoring_packages
+                               release_monitorings
                        WHERE
-                               deleted_at IS NULL
-                       AND
-                               distro = %s
-                       AND
-                               name = %s
-                       """, distro, name,
+                               id = %s
+                       """, id,
                )
 
-       def create_package(self, distro, name):
-               pass
+       async def create(self, distro, name, created_by, project_id,
+                       follow="mainline", create_builds=True):
+               monitoring = self._get_monitoring("""
+                       INSERT INTO
+                               release_monitorings
+                       (
+                               distro_id,
+                               name,
+                               created_by,
+                               project_id,
+                               follow,
+                               create_builds
+                       )
+                       VALUES(
+                               %s, %s, %s, %s, %s, %s
+                       )
+                       RETURNING
+                               *
+                       """, distro, name, created_by, project_id, follow,
+               )
+
+               # Schedule the first check in the background
+               self.backend.run_task(monitoring.check)
+
+               return monitoring
 
        async def search(self, name):
                """
@@ -107,31 +164,116 @@ class ReleaseMonitoring(base.Object):
                # Return all packages
                return [database.Row(item) for item in response.get("items")]
 
+       async def check(self, limit=None):
+               """
+                       Perform checks on monitorings
+               """
+               # Fetch all monitorings that were never checked or checked longer than 24 hours ago
+               monitorings = self._get_monitorings("""
+                       SELECT
+                               *
+                       FROM
+                               release_monitorings
+                       WHERE
+                               deleted_at IS NULL
+                       AND
+                               (
+                                       last_check_at IS NULL
+                               OR
+                                       last_check_at <= CURRENT_TIMESTAMP - INTERVAL '24 hours'
+                               )
+                       ORDER BY
+                               last_check_at ASC NULLS FIRST
+                       LIMIT
+                               %s
+                       """, limit,
+               )
+
+               # Perform all checks concurrently
+               async with asyncio.TaskGroup() as tg:
+                       for monitoring in monitorings:
+                               tg.create_task(monitoring.check())
 
-class Package(base.DataObject):
-       table = "release_monitoring_packages"
+
+class Monitoring(base.DataObject):
+       table = "release_monitorings"
+
+       def __str__(self):
+               return "%s - %s" % (self.distro, self.name)
 
        @property
        def distro(self):
-               return self.data.distro
+               """
+                       The distribution
+               """
+               return self.backend.distros.get_by_id(self.data.distro_id)
 
        @property
        def name(self):
+               """
+                       The package name
+               """
                return self.data.name
 
+       @property
+       def project_id(self):
+               return self.data.project_id
+
+       @property
+       def follow(self):
+               return self.data.follow
+
+       @property
+       def create_builds(self):
+               return self.data.create_builds
+
+       # Check
+
+       async def check(self):
+               # Wait until we are allowed to send an API request
+               async with ratelimiter:
+                       log.info("Checking for new releases for %s" % self)
+
+                       # Fetch the current versions
+                       versions = await self._fetch_versions()
+
+                       with self.db.transaction():
+                               try:
+                                       if self.follow == "mainline":
+                                               await self._follow_mainline(versions)
+                                       else:
+                                               raise ValueError("Cannot handle follow: %s" % self.follow)
+
+                               # If the release exists, do nothing
+                               except ReleaseExistsError as e:
+                                       log.debug("Release %s already exists" % e)
+
+       async def _fetch_versions(self):
+               """
+                       Fetches all versions for this project
+               """
+               response = await self.backend.monitorings._request(
+                       "GET", "/api/v2/versions/", {
+                               "project_id" : self.project_id,
+                       },
+               )
+
+               # Parse the response as JSON and return it
+               return database.Row(response)
+
+       async def _follow_mainline(self, versions):
+               """
+                       This will follow "mainline" i.e. the latest version
+               """
+               return await self.create_release(versions.latest_version)
+
        # Releases
 
        def _get_releases(self, query, *args):
-               res = self.db.query(query, *args)
-
-               for row in res:
-                       yield Release(self.backend, id=row.id, data=row)
+               return self.db.fetch_many(Release, query, *args, monitoring=self)
 
        def _get_release(self, query, *args):
-               res = self.db.get(query, *args)
-
-               if res:
-                       return Release(self.backend, id=res.id, data=res)
+               return self.db.fetch_one(Release, query, *args, monitoring=self)
 
        @property
        def latest_release(self):
@@ -146,14 +288,14 @@ class Package(base.DataObject):
                        WHERE
                                deleted_at IS NULL
                        AND
-                               package_id = %s
+                               monitoring_id = %s
                        ORDER BY
                                created_at DESC
                        LIMIT 1
                        """, self.id,
                )
 
-       @property
+       @lazy_property
        def releases(self):
                releases = self._get_releases("""
                        SELECT
@@ -161,9 +303,7 @@ class Package(base.DataObject):
                        FROM
                                release_monitoring_releases
                        WHERE
-                               deleted_at IS NULL
-                       AND
-                               package_id = %s
+                               monitoring_id = %s
                        ORDER BY
                                created_at DESC
                        """, self.id,
@@ -171,152 +311,170 @@ class Package(base.DataObject):
 
                return list(releases)
 
-       def _create_release(self, version):
+       def _release_exists(self, version):
+               """
+                       Returns True if this version already exists
+               """
+               return version in [release.version for release in self.releases]
+
+       async def create_release(self, version):
                """
                        Creates a new release for this package
                """
                # XXX Do we need to check whether we are going backwards?
 
+               # Raise an error if the release already exists
+               if self._release_exists(version):
+                       raise ReleaseExistsError(version)
+
+               # Raise an error if we already have a newer build
+               elif self._build_exists(version):
+                       raise BuildExistsError(version)
+
+               log.info("%s: Creating new release %s" % (self, version))
+
                release = self._get_release("""
                        INSERT INTO
                                release_monitoring_releases
                        (
-                               package_id,
+                               monitoring_id,
                                version
                        )
                        VALUES
                        (
                                %s, %s
                        )
-                       ON CONFLICT
-                               (package_id, version)
-                       WHERE
-                               deleted_at IS NULL
-                       DO
-                               NOTHING
                        RETURNING
                                *
                        """, self.id, version,
                )
 
+               # Add the release to cache
+               self.releases.append(release)
+
+               # Create a bug report
+               await release._create_bug()
+
+               # Create a build
+               if self.data.create_builds:
+                       await release._create_build()
+
                # Return the release
                return release
 
-       # Update
+       # Builds
 
-       async def _fetch(self):
+       def _build_exists(self, version):
                """
-                       Fetches all sorts of information about a package
+                       Returns True if a build with this version already exists
                """
-               response = await self.backend.releasemonitoring._request(
-                       "GET", "/api/v2/packages/", {
-                               "distribution" : self.distro,
-                               "name"         : self.name,
-                       },
-               )
+               # XXX needs to check if we already have a newer version
 
-               # Fetch all received items
-               items = response.get("items")
+               return version in [build.package.version for build in self.builds]
 
-               # Is the package known?
-               if not items:
-                       # Automatically try to create the package
-                       if await self._auto_create_package():
-                               return await self._fetch()
+       @property
+       def builds(self):
+               return self.distro.get_builds_by_name(self.name)
 
-                       raise PackageNotFoundError(self.name)
+       @lazy_property
+       def latest_build(self):
+               builds = self.distro.get_builds_by_name(self.name, limit=1)
 
-               # Did we receive more than one item?
-               elif len(items) > 1:
-                       raise RuntimeError("More than one item received for %s" % name)
+               for build in builds:
+                       return build
 
-               for item in items:
-                       return database.Row({
-                               "version"        : item.get("version"),
-                               "stable_version" : item.get("stable_version"),
-                       })
 
-       async def _auto_create_package(self):
-               """
-                       Tries to automatically create a package
-               """
-               packages = await self.backend.releasemonitoring.search(self.name)
+class Release(base.DataObject):
+       table = "release_monitoring_releases"
 
-               # Use the first exact match
-               for package in packages:
-                       if not package.name == self.name:
-                               continue
+       def __str__(self):
+               return "%s %s" % (self.monitoring.name, self.version)
 
-                       print(package)
+       # Monitoring
 
-                       # Automatically create a mapping
-                       await self.update_mapping(
-                               project_name=package.name,
-                               project_ecosystem=package.ecosystem,
-                       )
-
-                       return True
+       @lazy_property
+       def monitoring(self):
+               return self.backend.monitorings.get_by_id(self.data.monitoring_id)
 
-               # We could not create a mapping
-               return False
+       # Version
 
-       async def update_mapping(self, project_name=None, project_ecosystem=None):
-               if project_name is None:
-                       project_name = self.name
+       @property
+       def version(self):
+               return self.data.version
 
-               # Send request
-               await self.backend.releasemonitoring._request("POST", "/api/v2/packages/",
-                       {
-                               "distribution"      : self.distro,
-                               "package_name"      : self.name,
-                               "project_name"      : project_name,
-                               "project_ecosystem" : project_ecosystem,
-                       },
-               )
+       # Bug
 
-       async def update(self):
+       async def _create_bug(self):
                """
-                       Update the information we have about this package
+                       Creates a new bug report about this release
                """
-               # Pull information from the API
-               package = await self._fetch()
+               args = {
+                       # Product, Version & Component
+                       "product"     : self.monitoring.distro.bugzilla_product,
+                       "version"     : self.monitoring.distro.bugzilla_version,
+                       "component"   : self.monitoring.name,
+
+                       # Summary & Description
+                       "summary"     : "%s has been released" % self,
+                       "description" : BUG_DESCRIPTION % \
+                               {
+                                       "name"    : self.monitoring.name,
+                                       "version" : self.version
+                               },
+
+                       # Keywords
+                       "keywords"    : [
+                               # Mark this bug as created automatically
+                               "Monitoring",
+
+                               # Mark this bug as a new release
+                               "NewRelease",
+                       ],
+               }
 
-               # Try to create a new release
-               release = self._create_release(package.stable_version)
+               # If we have a build, include it in the bug description
+               if self.build:
+                       args |= {
+                               "description" : BUG_DESCRIPTION_WITH_BUILD % \
+                                       {
+                                               "name"    : self.monitoring.name,
+                                               "version" : self.version
+                                       },
+                       }
 
-               # Return the new release
-               return release
+               # Create the bug
+               bug = await self.backend.bugzilla.create_bug(**args)
 
+               # Store the bug ID
+               self._set_attribute("bug_id", bug.id)
 
-class Release(base.DataObject):
-       table = "release_monitoring_releases"
+               return bug
 
-       def __str__(self):
-               return self.version
+       # Build
 
-       # Version
+       def get_build(self):
+               if self.data.build_id:
+                       return self.backend.builds.get_by_id(self.data.build_id)
 
-       @property
-       def version(self):
-               return self.data.version
+       def set_build(self, build):
+               if self.build:
+                       raise AttributeError("Cannot reset build")
 
-       # Builds
+               self._set_attribute("build_id", build)
 
-       @lazy_property
-       def builds(self):
-               builds = self.backend.builds._get_builds("""
-                       SELECT
-                               builds.*
-                       FROM
-                               release_monitoring_release_builds
-                       LEFT JOIN
-                               builds ON release_monitoring_release_builds.build_id = builds.id
-                       WHERE
-                               release_monitoring_release_builds.release_id = %s
-                       AND
-                               builds.deleted_at IS NULL
-                       """, self.id,
-               )
+       build = lazy_property(get_build, set_build)
+
+       async def _create_build(self):
+               """
+                       Creates a build
+               """
+               if self.build:
+                       raise RuntimeError("Build already exists")
+
+               # XXX since we cannot yet update any builds, we will simply clone the latest one
+               # to test the tooling
+               #print(self.monitoring.latest_build)
 
-               # Return builds by distribution
-               return { build.distro : build for build in builds }
+               # XXX does this need an owner?
+               #self.build = await self.monitoring.latest_build.create(
+               #       repo=None, package=self.monitoring.latest_build.package)
index 95b52c9468f0da55160ed00d439c840cab7747ae..059421770310524c5dab5ca4e1926bcef6191713 100644 (file)
@@ -751,24 +751,24 @@ CREATE VIEW public.relation_sizes AS
 
 
 --
--- Name: release_monitoring_packages; Type: TABLE; Schema: public; Owner: -
+-- Name: release_monitoring_releases; Type: TABLE; Schema: public; Owner: -
 --
 
-CREATE TABLE public.release_monitoring_packages (
+CREATE TABLE public.release_monitoring_releases (
     id integer NOT NULL,
-    distro text NOT NULL,
-    name text NOT NULL,
+    monitoring_id integer NOT NULL,
+    version text NOT NULL,
     created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
-    deleted_at timestamp without time zone,
-    auto_update boolean DEFAULT true NOT NULL
+    bug_id integer,
+    build_id integer
 );
 
 
 --
--- Name: release_monitoring_packages_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+-- Name: release_monitoring_releases_id_seq; Type: SEQUENCE; Schema: public; Owner: -
 --
 
-CREATE SEQUENCE public.release_monitoring_packages_id_seq
+CREATE SEQUENCE public.release_monitoring_releases_id_seq
     AS integer
     START WITH 1
     INCREMENT BY 1
@@ -778,42 +778,36 @@ CREATE SEQUENCE public.release_monitoring_packages_id_seq
 
 
 --
--- Name: release_monitoring_packages_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+-- Name: release_monitoring_releases_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
 --
 
-ALTER SEQUENCE public.release_monitoring_packages_id_seq OWNED BY public.release_monitoring_packages.id;
+ALTER SEQUENCE public.release_monitoring_releases_id_seq OWNED BY public.release_monitoring_releases.id;
 
 
 --
--- Name: release_monitoring_release_builds; Type: TABLE; Schema: public; Owner: -
+-- Name: release_monitorings; Type: TABLE; Schema: public; Owner: -
 --
 
-CREATE TABLE public.release_monitoring_release_builds (
+CREATE TABLE public.release_monitorings (
     id integer NOT NULL,
-    release_id integer NOT NULL,
     distro_id integer NOT NULL,
-    build_id integer NOT NULL
-);
-
-
---
--- Name: release_monitoring_releases; Type: TABLE; Schema: public; Owner: -
---
-
-CREATE TABLE public.release_monitoring_releases (
-    id integer NOT NULL,
-    package_id integer NOT NULL,
-    version text NOT NULL,
+    name text NOT NULL,
     created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
-    deleted_at timestamp without time zone
+    created_by integer NOT NULL,
+    deleted_at timestamp without time zone,
+    deleted_by integer,
+    project_id integer NOT NULL,
+    follow text NOT NULL,
+    last_check_at timestamp without time zone,
+    create_builds boolean DEFAULT true NOT NULL
 );
 
 
 --
--- Name: release_monitoring_releases_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+-- Name: release_monitorings_id_seq; Type: SEQUENCE; Schema: public; Owner: -
 --
 
-CREATE SEQUENCE public.release_monitoring_releases_id_seq
+CREATE SEQUENCE public.release_monitorings_id_seq
     AS integer
     START WITH 1
     INCREMENT BY 1
@@ -823,10 +817,10 @@ CREATE SEQUENCE public.release_monitoring_releases_id_seq
 
 
 --
--- Name: release_monitoring_releases_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+-- Name: release_monitorings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
 --
 
-ALTER SEQUENCE public.release_monitoring_releases_id_seq OWNED BY public.release_monitoring_releases.id;
+ALTER SEQUENCE public.release_monitorings_id_seq OWNED BY public.release_monitorings.id;
 
 
 --
@@ -1246,17 +1240,17 @@ ALTER TABLE ONLY public.packages ALTER COLUMN id SET DEFAULT nextval('public.pac
 
 
 --
--- Name: release_monitoring_packages id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: release_monitoring_releases id; Type: DEFAULT; Schema: public; Owner: -
 --
 
-ALTER TABLE ONLY public.release_monitoring_packages ALTER COLUMN id SET DEFAULT nextval('public.release_monitoring_packages_id_seq'::regclass);
+ALTER TABLE ONLY public.release_monitoring_releases ALTER COLUMN id SET DEFAULT nextval('public.release_monitoring_releases_id_seq'::regclass);
 
 
 --
--- Name: release_monitoring_releases id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: release_monitorings id; Type: DEFAULT; Schema: public; Owner: -
 --
 
-ALTER TABLE ONLY public.release_monitoring_releases ALTER COLUMN id SET DEFAULT nextval('public.release_monitoring_releases_id_seq'::regclass);
+ALTER TABLE ONLY public.release_monitorings ALTER COLUMN id SET DEFAULT nextval('public.release_monitorings_id_seq'::regclass);
 
 
 --
@@ -1420,27 +1414,19 @@ ALTER TABLE ONLY public.packages
 
 
 --
--- Name: release_monitoring_packages release_monitoring_packages_pkey; Type: CONSTRAINT; Schema: public; Owner: -
---
-
-ALTER TABLE ONLY public.release_monitoring_packages
-    ADD CONSTRAINT release_monitoring_packages_pkey PRIMARY KEY (id);
-
-
---
--- Name: release_monitoring_release_builds release_monitoring_release_builds_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: release_monitoring_releases release_monitoring_releases_pkey; Type: CONSTRAINT; Schema: public; Owner: -
 --
 
-ALTER TABLE ONLY public.release_monitoring_release_builds
-    ADD CONSTRAINT release_monitoring_release_builds_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY public.release_monitoring_releases
+    ADD CONSTRAINT release_monitoring_releases_pkey PRIMARY KEY (id);
 
 
 --
--- Name: release_monitoring_releases release_monitoring_releases_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: release_monitorings release_monitorings_pkey; Type: CONSTRAINT; Schema: public; Owner: -
 --
 
-ALTER TABLE ONLY public.release_monitoring_releases
-    ADD CONSTRAINT release_monitoring_releases_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY public.release_monitorings
+    ADD CONSTRAINT release_monitorings_pkey PRIMARY KEY (id);
 
 
 --
@@ -1739,24 +1725,24 @@ CREATE INDEX packages_name ON public.packages USING btree (name);
 
 
 --
--- Name: release_monitoring_packages_unique; Type: INDEX; Schema: public; Owner: -
+-- Name: release_monitoring_releases_search; Type: INDEX; Schema: public; Owner: -
 --
 
-CREATE UNIQUE INDEX release_monitoring_packages_unique ON public.release_monitoring_packages USING btree (distro, name) WHERE (deleted_at IS NULL);
+CREATE INDEX release_monitoring_releases_search ON public.release_monitoring_releases USING btree (monitoring_id, created_at);
 
 
 --
--- Name: release_monitoring_release_builds_release_id; Type: INDEX; Schema: public; Owner: -
+-- Name: release_monitoring_releases_unique; Type: INDEX; Schema: public; Owner: -
 --
 
-CREATE INDEX release_monitoring_release_builds_release_id ON public.release_monitoring_release_builds USING btree (release_id);
+CREATE UNIQUE INDEX release_monitoring_releases_unique ON public.release_monitoring_releases USING btree (monitoring_id, version);
 
 
 --
--- Name: release_monitoring_releases_unique; Type: INDEX; Schema: public; Owner: -
+-- Name: release_monitorings_unique; Type: INDEX; Schema: public; Owner: -
 --
 
-CREATE UNIQUE INDEX release_monitoring_releases_unique ON public.release_monitoring_releases USING btree (package_id, version) WHERE (deleted_at IS NULL);
+CREATE UNIQUE INDEX release_monitorings_unique ON public.release_monitorings USING btree (distro_id, name) WHERE (deleted_at IS NULL);
 
 
 --
@@ -2139,35 +2125,35 @@ ALTER TABLE ONLY public.packages
 
 
 --
--- Name: release_monitoring_release_builds release_monitoring_release_builds_build_id; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: release_monitoring_releases release_monitoring_releases_monitoring_id; Type: FK CONSTRAINT; Schema: public; Owner: -
 --
 
-ALTER TABLE ONLY public.release_monitoring_release_builds
-    ADD CONSTRAINT release_monitoring_release_builds_build_id FOREIGN KEY (build_id) REFERENCES public.builds(id);
+ALTER TABLE ONLY public.release_monitoring_releases
+    ADD CONSTRAINT release_monitoring_releases_monitoring_id FOREIGN KEY (monitoring_id) REFERENCES public.release_monitorings(id);
 
 
 --
--- Name: release_monitoring_release_builds release_monitoring_release_builds_distro_id; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: release_monitorings release_monitorings_created_by; Type: FK CONSTRAINT; Schema: public; Owner: -
 --
 
-ALTER TABLE ONLY public.release_monitoring_release_builds
-    ADD CONSTRAINT release_monitoring_release_builds_distro_id FOREIGN KEY (distro_id) REFERENCES public.distributions(id);
+ALTER TABLE ONLY public.release_monitorings
+    ADD CONSTRAINT release_monitorings_created_by FOREIGN KEY (created_by) REFERENCES public.users(id);
 
 
 --
--- Name: release_monitoring_release_builds release_monitoring_release_builds_release_id; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: release_monitorings release_monitorings_deleted_by; Type: FK CONSTRAINT; Schema: public; Owner: -
 --
 
-ALTER TABLE ONLY public.release_monitoring_release_builds
-    ADD CONSTRAINT release_monitoring_release_builds_release_id FOREIGN KEY (release_id) REFERENCES public.release_monitoring_releases(id);
+ALTER TABLE ONLY public.release_monitorings
+    ADD CONSTRAINT release_monitorings_deleted_by FOREIGN KEY (deleted_by) REFERENCES public.users(id);
 
 
 --
--- Name: release_monitoring_releases release_monitoring_releases_package_id; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: release_monitorings release_monitorings_distro_id; Type: FK CONSTRAINT; Schema: public; Owner: -
 --
 
-ALTER TABLE ONLY public.release_monitoring_releases
-    ADD CONSTRAINT release_monitoring_releases_package_id FOREIGN KEY (package_id) REFERENCES public.release_monitoring_packages(id);
+ALTER TABLE ONLY public.release_monitorings
+    ADD CONSTRAINT release_monitorings_distro_id FOREIGN KEY (distro_id) REFERENCES public.distributions(id);
 
 
 --
index ed30120ed0388b82391a5a2af9a9cec702f3227c..6d5f5fee5667f4bf0ffe3bd82db84150e135b7f1 100644 (file)
@@ -41,7 +41,7 @@ class Cli(object):
                        "mirrors:check"       : self._mirrors_check,
 
                        # Release Monitoring
-                       "releasemonitoring:update"  : self._release_monitoring_update,
+                       "releasemonitoring:check"  : self._release_monitoring_check,
 
                        # Repositories
                        "repos:fetch-sources" : self.backend.repos.fetch_sources,
@@ -174,26 +174,11 @@ class Cli(object):
                for repo in sorted(self.backend.repos):
                        await repo.relaunch_pending_jobs()
 
-       async def _release_monitoring_update(self, *names):
+       async def _release_monitoring_check(self, *names):
                """
-                       Performs an update for the given package
+                       Performs any outstanding checks
                """
-               for name in names:
-                       build = self.backend.builds.get_latest_by_name(name)
-                       if not build:
-                               log.error("Could not find package %s" % name)
-                               continue
-
-                       with self.backend.db.transaction():
-                               # Show what we are working on
-                               print(build.pkg)
-
-                               # Perform the update
-                               release = await build.pkg.release_monitoring.update()
-
-                               # Show any new releases
-                               if release:
-                                       print("  Found new release: %s" % release)
+               await self.backend.monitorings.check()
 
        async def _mirrors_check(self):
                """
index 351ff7b3280778bf56037b4fe949e6e929233ae8..1cf391fbf169002527b3341207c590adb2984e7f 100644 (file)
@@ -225,6 +225,9 @@ class Application(tornado.web.Application):
                # Regularly check the mirrors
                self.backend.run_periodic_task(300, self.backend.mirrors.check)
 
+               # Regularly check for new releases
+               self.backend.run_periodic_task(300, self.backend.monitoring.check)
+
        ## UI methods
 
        def extract_hostname(self, handler, url):