Mercurial > bitten > bitten-test
changeset 184:fbf949f4c706
Allow invalidation of builds from the web interface. This results in the build being reset to ''PENDING'' status, and all build logs, slave information and reports deleted. Basically initiates a rebuild for a specific revision and target platform.
author | cmlenz |
---|---|
date | Wed, 31 Aug 2005 16:43:05 +0000 |
parents | fda952491beb |
children | 2c24d9a950ed |
files | bitten/master.py bitten/store.py bitten/trac_ext/charts.py bitten/trac_ext/templates/bitten_build.cs bitten/trac_ext/templates/bitten_config.cs bitten/trac_ext/web_ui.py |
diffstat | 6 files changed, 68 insertions(+), 14 deletions(-) [+] |
line wrap: on
line diff
--- a/bitten/master.py +++ b/bitten/master.py @@ -109,6 +109,7 @@ def _cleanup_orphaned_builds(self): # Reset all in-progress builds db = self.env.get_db_cnx() + store = ReportStore(self.env) for build in Build.select(self.env, status=Build.IN_PROGRESS, db=db): build.status = Build.PENDING build.slave = None @@ -119,6 +120,7 @@ for build_log in BuildLog.select(self.env, build=build.id): build_log.delete(db=db) build.update(db=db) + store.delete_reports(build=build) db.commit() def _cleanup_snapshots(self, when): @@ -188,8 +190,7 @@ build.config, handler.name) for step in BuildStep.select(self.env, build=build.id): step.delete(db=db) - for build_log in BuildLog.select(self.env, build=build.id): - build_log.delete(db=db) + build.slave = None build.slave_info = {} build.status = Build.PENDING @@ -386,12 +387,17 @@ def _build_aborted(self, db, build): log.info('Slave "%s" aborted build %d ("%s" as of [%s])', self.name, build.id, build.config, build.rev) + + for step in BuildStep.select(self.env, build=build.id, db=db): + step.delete(db=db) + + store = ReportStore(self.env) + store.delete_reports(build=build.id) + build.slave = None build.started = 0 build.status = Build.PENDING build.slave_info = {} - for step in BuildStep.select(self.env, build=build.id, db=db): - step.delete(db=db) def _parse_iso_datetime(string):
--- a/bitten/store.py +++ b/bitten/store.py @@ -29,12 +29,9 @@ backends = ExtensionPoint(IReportStoreBackend) - def store_report(self, build, step, xml): - assert xml.name == 'report' and 'type' in xml.attr + def delete_reports(self, config=None, build=None, step=None, type=None): 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) + return backend.delete_reports(config, build, step, type) def query_reports(self, xquery, config=None, build=None, step=None, type=None): @@ -45,6 +42,13 @@ backend = self._get_configured_backend() return backend.retrieve_reports(build, step, type) + 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 _get_configured_backend(self): configured = self.config.get('bitten', 'report_store', 'BDBXMLBackend') for backend in self.backends: @@ -110,6 +114,17 @@ def __init__(self): self.path = os.path.join(self.env.path, 'db', 'bitten.dbxml') + def delete_reports(self, config=None, build=None, step=None, type=None): + if dbxml is None: + log.warning('BDB XML not installed, cannot store report') + return + mgr = dbxml.XmlManager() + container = self._open_container(mgr, create=True) + ctxt = mgr.createUpdateContext() + for elem in self.query_reports('return $reports', config=config, + build=build, step=step, type=type): + container.deleteDocument(elem._value.asDocument(), ctxt) + def store_report(self, build, step, xml): if dbxml is None: log.warning('BDB XML not installed, cannot store report')
--- a/bitten/trac_ext/charts.py +++ b/bitten/trac_ext/charts.py @@ -59,6 +59,8 @@ rev_time = {} rev = {} for build in Build.select(self.env, config=config.name): + if build.status in (Build.PENDING, Build.IN_PROGRESS): + continue rev[str(build.id)] = build.rev rev_time[str(build.id)] = datetime.fromtimestamp(build.rev_time)
--- a/bitten/trac_ext/templates/bitten_build.cs +++ b/bitten/trac_ext/templates/bitten_build.cs @@ -14,6 +14,14 @@ /if ?>)</p> <p class="time">Completed: <?cs var:build.started ?> (<?cs var:build.started_delta ?> ago)<br />Took: <?cs var:build.duration ?></p><?cs + if:build.can_delete ?> + <div class="buttons"> + <form method="post" action=""><div> + <input type="hidden" name="action" value="invalidate" /> + <input type="submit" value="Invalidate build" /> + </div></form> + </div><?cs + /if ?><?cs each:step = build.steps ?> <h2 id="<?cs var:step.name ?>"><?cs var:step.name ?> (<?cs var:step.duration ?>)</h2>
--- a/bitten/trac_ext/templates/bitten_config.cs +++ b/bitten/trac_ext/templates/bitten_config.cs @@ -99,7 +99,6 @@ if:config.description ?><div class="description"><?cs var:config.description ?></div><?cs /if ?> - <div id="charts"><?cs each:chart = config.charts ?> <object type="application/x-shockwave-flash" width="320" height="240" data="<?cs @@ -112,9 +111,8 @@ <param name="wmode" value="transparent" /> </object><br /><?cs /each ?> - </div> - - <?cs + </div><?cs + if:config.can_modify ?> <div class="buttons"> <form method="get" action=""><div>
--- a/bitten/trac_ext/web_ui.py +++ b/bitten/trac_ext/web_ui.py @@ -84,7 +84,7 @@ # IRequestHandler methods def match_request(self, req): - match = re.match(r'/build(?:/([\w.-]+))?$', req.path_info) + match = re.match(r'/build(?:/([\w.-]+))?/?$', req.path_info) if match: if match.group(1): req.args['config'] = match.group(1) @@ -417,6 +417,11 @@ build = Build.fetch(self.env, build_id, db=db) assert build, 'Build %s does not exist' % build_id + if req.method == 'POST': + if req.args.get('action') == 'invalidate': + self._do_invalidate(req, build, db) + req.redirect(self.env.href.build(build.config, build.id)) + add_link(req, 'up', self.env.href.build(build.config), 'Build Configuration') status2title = {Build.SUCCESS: 'Success', Build.FAILURE: 'Failure', @@ -441,6 +446,7 @@ 'reports': self._render_reports(req, build, step) }) req.hdf['build.steps'] = steps + req.hdf['build.can_delete'] = req.perm.has_permission('BUILD_DELETE') add_stylesheet(req, 'bitten/bitten.css') return 'bitten_build.cs', None @@ -477,6 +483,25 @@ # Internal methods + def _do_invalidate(self, req, build, db): + self.log.info('Invalidating build %d', build.id) + + for step in BuildStep.select(self.env, build=build.id, db=db): + step.delete(db=db) + + store = ReportStore(self.env) + store.delete_reports(build=build) + + build.slave = None + build.started = build.stopped = 0 + build.status = Build.PENDING + build.slave_info = {} + build.update() + + db.commit() + + req.redirect(self.env.href.build(build.config)) + def _render_log(self, req, build, step): items = [] for log in BuildLog.select(self.env, build=build.id, step=step.name):