changeset 253:cda723f3ac31

Provide hooks for build notification. Closes #62.
author cmlenz
date Wed, 05 Oct 2005 09:17:47 +0000
parents 36a687797120
children 27ed440902f9
files bitten/master.py bitten/queue.py bitten/trac_ext/api.py bitten/trac_ext/main.py
diffstat 4 files changed, 51 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/bitten/master.py
+++ b/bitten/master.py
@@ -96,7 +96,11 @@
             return
 
         for queue in self.queues:
-            queue.unregister_slave(handler.name)
+            if queue.unregister_slave(handler.name):
+                for build in list(Build.select(queue.env, slave=handler.name,
+                                               status=Build.IN_PROGRESS)):
+                    handler._build_aborted(queue, build)
+
         del self.handlers[handler.name]
 
         log.info('Unregistered slave "%s"', handler.name)
@@ -245,9 +249,12 @@
         if timestamp_delta:
             build.started -= timestamp_delta
         build.status = Build.IN_PROGRESS
+        build.update()
+
         log.info('Slave %s started build %d ("%s" as of [%s])',
                  self.name, build.id, build.config, build.rev)
-        build.update()
+        for listener in BuildSystem(queue.env).listeners:
+            listener.build_started(build)
 
     def _build_step_completed(self, queue, build, elem, timestamp_delta=None):
         log.debug('Slave %s completed step "%s" with status %s', self.name,
@@ -294,10 +301,6 @@
         db.commit()
 
     def _build_completed(self, queue, build, elem, timestamp_delta=None):
-        log.info('Slave %s completed build %d ("%s" as of [%s]) with status %s',
-                 self.name, build.id, build.config, build.rev,
-                 elem.attr['result'])
-
         build.stopped = int(_parse_iso_datetime(elem.attr['time']))
         if timestamp_delta:
             build.stopped -= timestamp_delta
@@ -307,9 +310,17 @@
             build.status = Build.SUCCESS
         build.update()
 
+        log.info('Slave %s completed build %d ("%s" as of [%s]) with status %s',
+                 self.name, build.id, build.config, build.rev,
+                 build.status == Build.FAILURE and 'FAILURE' or 'SUCCESS')
+        for listener in BuildSystem(queue.env).listeners:
+            listener.build_completed(build)
+
     def _build_aborted(self, queue, build):
         log.info('Slave %s aborted build %d ("%s" as of [%s])',
                  self.name, build.id, build.config, build.rev)
+        for listener in BuildSystem(queue.env).listeners:
+            listener.build_aborted(build)
 
         db = queue.env.get_db_cnx()
 
@@ -317,9 +328,9 @@
             step.delete(db=db)
 
         build.slave = None
+        build.slave_info = {}
         build.started = 0
         build.status = Build.PENDING
-        build.slave_info = {}
         build.update(db=db)
 
         db.commit()
--- a/bitten/queue.py
+++ b/bitten/queue.py
@@ -272,6 +272,8 @@
         """Unregister a build slave.
         
         @param name: The name of the slave
+        @return: `True` if the slave was registered for this build queue,
+                 `False` otherwise
 
         This method removes the slave from the registry, and also resets any
         in-progress builds by this slave to `PENDING` state.
@@ -279,20 +281,5 @@
         for slaves in self.slaves.values():
             if name in slaves:
                 slaves.remove(name)
-
-        db = self.env.get_db_cnx()
-        for build in Build.select(self.env, slave=name,
-                                  status=Build.IN_PROGRESS, db=db):
-            log.info('Build %d ("%s" as of [%s]) cancelled by  %s', build.id,
-                     build.rev, build.config, name)
-            for step in list(BuildStep.select(self.env, build=build.id)):
-                step.delete(db=db)
-
-            build.slave = None
-            build.slave_info = {}
-            build.status = Build.PENDING
-            build.started = 0
-            build.update(db=db)
-            break
-
-        db.commit()
+                return True
+        return False
--- a/bitten/trac_ext/api.py
+++ b/bitten/trac_ext/api.py
@@ -10,6 +10,32 @@
 from trac.core import *
 
 
+class IBuildListener(Interface):
+    """Extension point interface for components that need to be notified of
+    build events.
+    
+    Note that these will be notified in the process running the build master."""
+
+    def build_started(build):
+        """Called when a build slave has accepted a build initiation.
+        
+        @param build: The `bitten.model.Build` instance representing the build
+        """
+
+    def build_aborted(config, build):
+        """Called when a build slave cancels a build or disconnects.
+        
+        @param build: The `bitten.model.Build` instance representing the build
+        """
+
+    def build_completed(config, build):
+        """Called when a build slave has completed a build, regardless of the
+        outcome.
+        
+        @param build: The `bitten.model.Build` instance representing the build
+        """
+
+
 class ILogFormatter(Interface):
     """Extension point interface for components that format build log
     messages."""
--- a/bitten/trac_ext/main.py
+++ b/bitten/trac_ext/main.py
@@ -15,6 +15,7 @@
 from trac.env import IEnvironmentSetupParticipant
 from trac.perm import IPermissionRequestor
 from trac.wiki import IWikiSyntaxProvider
+from bitten.trac_ext.api import IBuildListener
 from bitten.model import schema, schema_version, Build, BuildConfig
 
 
@@ -23,6 +24,8 @@
     implements(IEnvironmentSetupParticipant, IPermissionRequestor,
                IWikiSyntaxProvider)
 
+    listeners = ExtensionPoint(IBuildListener)
+
     # IEnvironmentSetupParticipant methods
 
     def environment_created(self):
Copyright (C) 2012-2017 Edgewall Software