# HG changeset patch # User wbell # Date 1272121428 0 # Node ID 306419d32527658819d2d8289d1baeb51b1f3f3f # Parent d11ef8024d7c66728d56d577d36bfc732f9b7e36 Expand steps to allow in-progress steps. Some small additions to the BuildStep model, but most changes are in the ui to not assume steps are in their final state when they're shown. No change to actual processing. Refs #455, #573. diff --git a/bitten/htdocs/bitten.css b/bitten/htdocs/bitten.css --- a/bitten/htdocs/bitten.css +++ b/bitten/htdocs/bitten.css @@ -93,9 +93,13 @@ list-style-type: none; margin: .5em 0 0; padding: 0; } #content.build #builds ul.steps li.success, +#content.build #builds ul.steps li.in-progress, #content.build #builds ul.steps li.failed { border: 1px solid; margin: 1px 0; padding: 0 2px 0 12px; } +#content.build #builds ul.steps li.in-progress { + background: #dd9; border-color: #966; color: #993; +} #content.build #builds ul.steps li.success { background: #9d9; border-color: #696; color: #393; } diff --git a/bitten/model.py b/bitten/model.py --- a/bitten/model.py +++ b/bitten/model.py @@ -587,6 +587,7 @@ # Step status codes SUCCESS = 'S' + IN_PROGRESS = 'I' FAILURE = 'F' def __init__(self, env, build=None, name=None, description=None, @@ -610,7 +611,8 @@ doc='Whether this build step exists in the database') successful = property(fget=lambda self: self.status == BuildStep.SUCCESS, doc='Whether the build step was successful') - + completed = property(fget=lambda self: self.status == BuildStep.SUCCESS or self.status == BuildStep.FAILURE, + doc='Whether this build step has completed processing') def delete(self, db=None): """Remove the build step from the database.""" if not db: @@ -645,7 +647,7 @@ handle_ta = False assert self.build and self.name - assert self.status in (self.SUCCESS, self.FAILURE) + assert self.status in (self.SUCCESS, self.IN_PROGRESS, self.FAILURE) cursor = db.cursor() cursor.execute("INSERT INTO bitten_step (build,name,description,status," @@ -694,7 +696,7 @@ if not db: db = env.get_db_cnx() - assert status in (None, BuildStep.SUCCESS, BuildStep.FAILURE) + assert status in (None, BuildStep.SUCCESS, BuildStep.IN_PROGRESS, BuildStep.FAILURE) where_clauses = [] if build is not None: @@ -709,7 +711,7 @@ where = "" cursor = db.cursor() - cursor.execute("SELECT build,name FROM bitten_step %s ORDER BY stopped" + cursor.execute("SELECT build,name FROM bitten_step %s ORDER BY started" % where, [wc[1] for wc in where_clauses]) for build, name in cursor: yield BuildStep.fetch(env, build, name, db=db) diff --git a/bitten/templates/bitten_config.html b/bitten/templates/bitten_config.html --- a/bitten/templates/bitten_config.html +++ b/bitten/templates/bitten_config.html @@ -18,6 +18,17 @@ +
+ + +
Duration: ${build.duration}
+
+ +
${build.started} (${build.started_delta} ago)
+
+
+
+
$slave.name ($slave.ipnr)
$slave.os_name $slave.os_version @@ -27,12 +38,12 @@
$config.builds_inprogress in-progress - builds ( - + builds ( $platform.name: $platform.builds_inprogress )
@@ -137,9 +147,8 @@ $platform.name: $platform.builds_pending ) -
$config.builds_inprogress in-progress builds ( - - $platform.name: $platform.builds_inprogress +
$config.builds_inprogress in-progress builds ( + $platform.name: $platform.builds_inprogress )
@@ -173,6 +182,7 @@ ${build_status(build.status)} ${slave_info(build.slave)} + ${build_time(build)}
${build_steps(build.steps)} @@ -201,6 +211,7 @@ $build.id: $build.platform ${slave_info(build.slave)} + ${build_time(build)}
${build_steps(build.steps)} diff --git a/bitten/web_ui.py b/bitten/web_ui.py --- a/bitten/web_ui.py +++ b/bitten/web_ui.py @@ -12,6 +12,7 @@ import posixpath import re +import time from StringIO import StringIO from datetime import datetime @@ -45,6 +46,9 @@ Build.IN_PROGRESS: 'In Progress', Build.SUCCESS: 'Success', Build.FAILURE: 'Failure'} +_step_status_label = {BuildStep.SUCCESS: 'success', + BuildStep.FAILURE: 'failed', + BuildStep.IN_PROGRESS: 'in progress'} def _get_build_data(env, req, build): data = {'id': build.id, 'name': build.slave, 'rev': build.rev, @@ -89,7 +93,7 @@ status = '' if BuildMaster(self.env).quick_status: repos = self.env.get_repository(req.authname) - for config in BuildConfig.select(self.env, + for config in BuildConfig.select(self.env, include_inactive=False): prev_rev = None for platform, rev, build in collect_changes(repos, config): @@ -106,11 +110,11 @@ status='bitteninprogress' elif not status: if (build_data['status'] == 'completed'): - status='bittencompleted' + status='bittencompleted' if not status: status='bittenpending' yield ('mainnav', 'build', - tag.a('Build Status', href=req.href.build(), accesskey=5, + tag.a('Build Status', href=req.href.build(), accesskey=5, class_=status)) # ITemplatesProvider methods @@ -164,16 +168,16 @@ return 'bitten_config.html', data, None # IRequestHandler methods - + def pre_process_request(self, req, handler): return handler def post_process_request(self, req, template, data, content_type): if template: add_stylesheet(req, 'bitten/bitten.css') - + return template, data, content_type - + # Internal methods def _render_overview(self, req): @@ -301,9 +305,10 @@ build_data['steps'].append({ 'name': step.name, 'description': step.description, - 'duration': to_datetime(step.stopped, utc) - \ + 'duration': to_datetime(step.stopped or int(time.time()), utc) - \ to_datetime(step.started, utc), - 'failed': not step.successful, + 'status': _step_status_label[step.status], + 'cls': _step_status_label[step.status].replace(' ', '-'), 'errors': step.errors, 'href': build_data['href'] + '#step_' + step.name }) @@ -311,7 +316,7 @@ builds.append(build_data) current_builds += 1 - if current_builds == 0: + if current_builds == 0: continue description = config.description @@ -325,7 +330,7 @@ 'builds': builds }) - data['configs'] = configs + data['configs'] = sorted(configs, key=lambda x:x['label'].lower()) return data def _render_config(self, req, config_name): @@ -372,7 +377,7 @@ db=db)) data['config']['platforms'] = [ { 'name': platform.name, - 'id': platform.id, + 'id': platform.id, 'builds_pending': len(list(Build.select(self.env, config=config.name, status=Build.PENDING, @@ -393,13 +398,13 @@ if has_reports: chart_generators = [] report_categories = list(self._report_categories_for_config(config)) - for generator in ReportChartController(self.env).generators: - for category in generator.get_supported_categories(): + for generator in ReportChartController(self.env).generators: + for category in generator.get_supported_categories(): if category in report_categories: chart_generators.append({ - 'href': req.href.build(config.name, 'chart/' + category) + 'href': req.href.build(config.name, 'chart/' + category) }) - data['config']['charts'] = chart_generators + data['config']['charts'] = chart_generators charts_license = self.config.get('bitten', 'charts_license') if charts_license: data['config']['charts_license'] = charts_license @@ -428,9 +433,11 @@ build_data['steps'].append({ 'name': step.name, 'description': step.description, - 'duration': to_datetime(step.stopped, utc) - \ + 'duration': to_datetime(step.stopped or int(time.time()), utc) - \ to_datetime(step.started, utc), - 'failed': not step.successful, + 'status': _step_status_label[step.status], + 'cls': _step_status_label[step.status].replace(' ', '-'), + 'errors': step.errors, 'href': build_data['href'] + '#step_' + step.name }) @@ -457,16 +464,16 @@ """Yields the categories of reports that exist for active builds of this configuration. """ - + db = self.env.get_db_cnx() repos = self.env.get_repository() cursor = db.cursor() - + cursor.execute("""SELECT DISTINCT report.category as category -FROM bitten_build AS build +FROM bitten_build AS build JOIN bitten_report AS report ON (report.build=build.id) -WHERE build.config=%s AND build.rev_time >= %s AND build.rev_time <= %s""", - (config.name, +WHERE build.config=%s AND build.rev_time >= %s AND build.rev_time <= %s""", + (config.name, config.min_rev_time(self.env), config.max_rev_time(self.env))) @@ -545,8 +552,9 @@ for step in BuildStep.select(self.env, build=build.id, db=db): steps.append({ 'name': step.name, 'description': step.description, - 'duration': pretty_timedelta(step.started, step.stopped), - 'failed': step.status == BuildStep.FAILURE, + 'duration': pretty_timedelta(step.started, step.stopped or int(time.time())), + 'status': _step_status_label[step.status], + 'cls': _step_status_label[step.status].replace(' ', '-'), 'errors': step.errors, 'log': self._render_log(req, build, formatters, step), 'reports': self._render_reports(req, config, build, summarizers,