# HG changeset patch # User cmlenz # Date 1123511096 0 # Node ID 430c518ebb145bf9a7a9148a7192d27080d48505 # Parent 77dd69f7c405bb5df63c4a9930ed428226fd920d * More logging in master and slave about the build status. * The model classes do cascading deletion now. diff --git a/bitten/master.py b/bitten/master.py --- a/bitten/master.py +++ b/bitten/master.py @@ -123,11 +123,6 @@ build.status = Build.PENDING build.update(db=db) for build in Build.select(self.env, status=Build.PENDING, db=db): - for step in BuildStep.select(self.env, build=build.id, db=db): - for log in BuildLog.select(self.env, build=build.id, - step=step.name, db=db): - log.delete(db=db) - step.delete(db=db) build.delete(db=db) db.commit() @@ -337,7 +332,8 @@ self.name, build.id, build.config, build.rev) def _build_step_completed(self, db, build, elem): - log.debug('Slave completed step "%s"', elem.attr['id']) + log.debug('Slave completed step "%s" with status %s', elem.attr['id'], + elem.attr['result']) step = BuildStep(self.env, build=build.id, name=elem.attr['id'], description=elem.attr.get('description')) step.started = int(_parse_iso_datetime(elem.attr['time'])) @@ -365,8 +361,9 @@ store.store_report(build, step, report) def _build_completed(self, db, build, elem): - log.info('Slave %s completed build %d ("%s" as of [%s])', self.name, - build.id, build.config, build.rev) + 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 elem.attr['result'] == 'failure': build.status = Build.FAILURE diff --git a/bitten/model.py b/bitten/model.py --- a/bitten/model.py +++ b/bitten/model.py @@ -307,8 +307,13 @@ assert self.status == self.PENDING, 'Only pending builds can be deleted' + for step in BuildStep.select(self.env, build=self.id): + step.delete(db=db) + cursor = db.cursor() + cursor.execute("DELETE FROM bitten_slave WHERE build=%s", (self.id,)) cursor.execute("DELETE FROM bitten_build WHERE id=%s", (self.id,)) + if handle_ta: db.commit() @@ -455,6 +460,9 @@ else: handle_ta = False + for log in BuildLog.select(self.env, build=self.build, step=self.name): + log.delete(db=db) + cursor = db.cursor() cursor.execute("DELETE FROM bitten_step WHERE build=%s AND name=%s", (self.build, self.name)) @@ -558,9 +566,9 @@ handle_ta = False cursor = db.cursor() - cursor.execute("DELETE FROM bitten_log WHERE id=%s", (self.id,)) cursor.execute("DELETE FROM bitten_log_message WHERE log=%s", (self.id,)) + cursor.execute("DELETE FROM bitten_log WHERE id=%s", (self.id,)) if handle_ta: db.commit() diff --git a/bitten/slave.py b/bitten/slave.py --- a/bitten/slave.py +++ b/bitten/slave.py @@ -156,8 +156,10 @@ for type, function, output in step.execute(recipe.ctxt): xmlio.SubElement(xml, type, type=function)[output] xml.attr['duration'] = (datetime.utcnow() - started).seconds + log.info('Build step %s completed successfully', step.id) self.channel.send_ans(msgno, beep.Payload(xml)) except (BuildError, InvalidRecipeError), e: + log.warning('Build step %s failed: %s', step.id, e) duration = datetime.utcnow() - started failed = True xml = xmlio.Element('step', id=step.id, result='failure', @@ -166,7 +168,10 @@ duration=duration.seconds)[e] self.channel.send_ans(msgno, beep.Payload(xml)) - log.info('Build completed') + if failed: + log.warning('Build failed') + else: + log.info('Build completed successfully') xml = xmlio.Element('completed', time=datetime.utcnow().isoformat(), result=['success', 'failure'][failed]) self.channel.send_ans(msgno, beep.Payload(xml)) diff --git a/bitten/store.py b/bitten/store.py --- a/bitten/store.py +++ b/bitten/store.py @@ -27,7 +27,7 @@ log = logging.getLogger('bitten.store') -class IReportStore(Interface): +class IReportStoreBackend(Interface): def store_report(build, step, xml): """Store the given report.""" @@ -38,22 +38,25 @@ class ReportStore(Component): - backends = ExtensionPoint(IReportStore) + backends = ExtensionPoint(IReportStoreBackend) - def _get_backend(self): - configured = self.config.get('bitten', 'report_store', 'BDBXMLStore') + def store_report(self, build, step, xml): + assert xml.name == 'report' and 'type' in xml.attr + backend = self._get_configured_backend() + log.debug('Storing report of type "%s" in %s', xml.attr['type'], + backend.__class__.__name__) + backend.store_report(build, step, xml) + + def retrieve_reports(self, build, step, type=None): + backend = self._get_configured_backend() + return backend.retrieve_reports(build, step, type) + + def _get_configured_backend(self): + configured = self.config.get('bitten', 'report_store', 'BDBXMLBackend') for backend in self.backends: if backend.__class__.__name__ == configured: return backend - raise TracError, 'No report store backend available' - backend = property(fget=lambda self: self._get_backend()) - - def store_report(self, build, step, xml): - assert xml.name == 'report' and 'type' in xml.attr - self.backend.store_report(build, step, xml) - - def retrieve_reports(self, build, step, type=None): - return self.backend.retrieve_reports(build, step, type) + raise TracError, 'Report store backend not available' try: @@ -62,8 +65,8 @@ dbxml = None -class BDBXMLStore(Component): - implements(IReportStore) +class BDBXMLBackend(Component): + implements(IReportStoreBackend) indexes = [ ('build', 'node-metadata-equality-decimal'), @@ -127,7 +130,7 @@ query += "]" results = mgr.query(query, ctxt) for value in results: - yield BDBXMLStore.XmlValueWrapper(value) + yield BDBXMLBackend.XmlValueWrapper(value) def _open_container(self, mgr, create=False): if create and not os.path.exists(self.path): diff --git a/bitten/tests/store.py b/bitten/tests/store.py --- a/bitten/tests/store.py +++ b/bitten/tests/store.py @@ -24,11 +24,11 @@ import unittest from trac.test import EnvironmentStub, Mock -from bitten.store import BDBXMLStore +from bitten.store import BDBXMLBackend from bitten.util import xmlio -class BDBXMLStoreTestCase(unittest.TestCase): +class BDBXMLBackendTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() @@ -39,7 +39,7 @@ shutil.rmtree(self.env.path) def test_store_report(self): - store = BDBXMLStore(self.env) + store = BDBXMLBackend(self.env) build = Mock(id=42) step = Mock(name='foo') xml = xmlio.Element('report', type='test')[xmlio.Element('dummy')] @@ -63,4 +63,4 @@ def suite(): - return unittest.makeSuite(BDBXMLStoreTestCase, 'test') + return unittest.makeSuite(BDBXMLBackendTestCase, 'test')