Mercurial > bitten > bitten-test
changeset 760:306419d32527
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.
author | wbell |
---|---|
date | Sat, 24 Apr 2010 15:03:48 +0000 |
parents | d11ef8024d7c |
children | b2272caf5ac4 |
files | bitten/htdocs/bitten.css bitten/model.py bitten/templates/bitten_config.html bitten/web_ui.py |
diffstat | 4 files changed, 60 insertions(+), 35 deletions(-) [+] |
line wrap: on
line diff
--- 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; }
--- 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)
--- a/bitten/templates/bitten_config.html +++ b/bitten/templates/bitten_config.html @@ -18,6 +18,17 @@ </py:choose> </strong> + <div py:def="build_time(build)" class="system"> + <py:choose> + <span py:when="build.stopped"> + <div>Duration: ${build.duration}</div> + </span> + <span py:otherwise=""> + <div>${build.started} (${build.started_delta} ago)</div> + </span> + </py:choose> + </div> + <div py:def="slave_info(slave)" class="system"> <strong>$slave.name</strong> ($slave.ipnr)<br /> $slave.os_name $slave.os_version @@ -27,12 +38,12 @@ <ul py:def="build_steps(steps)" py:if="steps" class="steps"> <li py:for="step in steps" - class="${step.failed and 'failed' or 'success'}"> + class="${step.cls}"> <span class="duration">$step.duration</span> <a href="$step.href" title="${step.description or None}"> $step.name </a> - <ul py:if="step.failed and step.errors"> + <ul py:if="step.status is 'failed' and step.errors"> <li py:for="error in step.errors">$error</li> </ul> </li> @@ -65,8 +76,7 @@ </py:if></py:for>)</i> </div></py:if><py:if test="config.builds_inprogress"> <div>$config.builds_inprogress in-progress - build<py:if test="config.builds_inprogress > 1">s</py:if> <i>(<py:for each="platform in config.platforms"> - <py:if test="platform.builds_inprogress"> + build<py:if test="config.builds_inprogress > 1">s</py:if> <i>(<py:for each="platform in config.platforms"><py:if test="platform.builds_inprogress"> $platform.name: $platform.builds_inprogress </py:if></py:for>)</i> </div></py:if> @@ -137,9 +147,8 @@ $platform.name: $platform.builds_pending </py:if></py:for>)</i> </div></py:if><py:if test="config.builds_inprogress"> - <div>$config.builds_inprogress in-progress build<py:if test="config.builds_inprogress > 1">s</py:if> <i>(<py:for each="platform in config.platforms"> - <py:if test="platform.builds_inprogress"> - $platform.name: $platform.builds_inprogress + <div>$config.builds_inprogress in-progress build<py:if test="config.builds_inprogress > 1">s</py:if> <i>(<py:for each="platform in config.platforms"><py:if test="platform.builds_inprogress"> + $platform.name: $platform.builds_inprogress </py:if></py:for>)</i> </div></py:if> <div id="charts"><py:for each="chart in config.charts"> @@ -173,6 +182,7 @@ ${build_status(build.status)} </a> ${slave_info(build.slave)} + ${build_time(build)} </div> ${build_steps(build.steps)} </td> @@ -201,6 +211,7 @@ $build.id: <strong class="status">$build.platform</strong> </a> ${slave_info(build.slave)} + ${build_time(build)} </div> ${build_steps(build.steps)} </td>
--- 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,