mirror of
https://github.com/odoo/runbot.git
synced 2025-03-27 13:25:47 +07:00
[IMP] runbot: add total load time on builds
This commit is contained in:
parent
336e9525d5
commit
60dbbcb72e
@ -12,7 +12,7 @@ import os
|
|||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from babel.dates import format_timedelta
|
from babel.dates import LC_TIME, Locale, TIMEDELTA_UNITS
|
||||||
from markupsafe import Markup
|
from markupsafe import Markup
|
||||||
|
|
||||||
from odoo.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT, html_escape, file_open
|
from odoo.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT, html_escape, file_open
|
||||||
@ -80,11 +80,61 @@ def time_delta(time):
|
|||||||
return time
|
return time
|
||||||
return timedelta(seconds=-time)
|
return timedelta(seconds=-time)
|
||||||
|
|
||||||
|
from babel.dates import format_timedelta as _format_timedelta
|
||||||
|
|
||||||
|
|
||||||
|
def format_timedelta(delta, granularity='second', max_unit=None, threshold=.85,
|
||||||
|
add_direction=False, format='long',
|
||||||
|
locale=LC_TIME):
|
||||||
|
"""
|
||||||
|
Modified version of Dates.format_timedelta
|
||||||
|
"""
|
||||||
|
if format not in ('narrow', 'short', 'long'):
|
||||||
|
raise TypeError('Format must be one of "narrow", "short" or "long"')
|
||||||
|
if isinstance(delta, timedelta):
|
||||||
|
seconds = int((delta.days * 86400) + delta.seconds)
|
||||||
|
else:
|
||||||
|
seconds = delta
|
||||||
|
locale = Locale.parse(locale)
|
||||||
|
|
||||||
|
def _iter_patterns(a_unit):
|
||||||
|
if add_direction:
|
||||||
|
unit_rel_patterns = locale._data['date_fields'][a_unit]
|
||||||
|
if seconds >= 0:
|
||||||
|
yield unit_rel_patterns['future']
|
||||||
|
else:
|
||||||
|
yield unit_rel_patterns['past']
|
||||||
|
a_unit = 'duration-' + a_unit
|
||||||
|
yield locale._data['unit_patterns'].get(a_unit, {}).get(format)
|
||||||
|
|
||||||
|
for unit, secs_per_unit in TIMEDELTA_UNITS:
|
||||||
|
if max_unit and unit != max_unit:
|
||||||
|
continue
|
||||||
|
max_unit = None
|
||||||
|
value = abs(seconds) / secs_per_unit
|
||||||
|
if value >= threshold or unit == granularity:
|
||||||
|
if unit == granularity and value > 0:
|
||||||
|
value = max(1, value)
|
||||||
|
value = int(round(value))
|
||||||
|
plural_form = locale.plural_form(value)
|
||||||
|
pattern = None
|
||||||
|
for patterns in _iter_patterns(unit):
|
||||||
|
if patterns is not None:
|
||||||
|
pattern = patterns[plural_form]
|
||||||
|
break
|
||||||
|
# This really should not happen
|
||||||
|
if pattern is None:
|
||||||
|
return u''
|
||||||
|
return pattern.replace('{0}', str(value))
|
||||||
|
|
||||||
|
return u''
|
||||||
|
|
||||||
|
|
||||||
def s2human(time):
|
def s2human(time):
|
||||||
"""Convert a time in second into an human readable string"""
|
"""Convert a time in second into an human readable string"""
|
||||||
return format_timedelta(
|
return format_timedelta(
|
||||||
time_delta(time),
|
time_delta(time),
|
||||||
|
max_unit='hour',
|
||||||
format="narrow",
|
format="narrow",
|
||||||
threshold=2.1,
|
threshold=2.1,
|
||||||
)
|
)
|
||||||
|
@ -190,6 +190,9 @@ class BuildResult(models.Model):
|
|||||||
docker_start = fields.Datetime('Docker start')
|
docker_start = fields.Datetime('Docker start')
|
||||||
job_time = fields.Integer(compute='_compute_job_time', string='Job time')
|
job_time = fields.Integer(compute='_compute_job_time', string='Job time')
|
||||||
build_time = fields.Integer(compute='_compute_build_time', string='Build time')
|
build_time = fields.Integer(compute='_compute_build_time', string='Build time')
|
||||||
|
wait_time = fields.Integer(compute='_compute_wait_time', string='Wait time')
|
||||||
|
load_time = fields.Integer(compute='_compute_load_time', string='Load time')
|
||||||
|
last_update = fields.Datetime(compute='_compute_last_update', string='Last update')
|
||||||
|
|
||||||
gc_date = fields.Datetime('Local cleanup date', compute='_compute_gc_date')
|
gc_date = fields.Datetime('Local cleanup date', compute='_compute_gc_date')
|
||||||
gc_delay = fields.Integer('Cleanup Delay', help='Used to compute gc_date')
|
gc_delay = fields.Integer('Cleanup Delay', help='Used to compute gc_date')
|
||||||
@ -465,6 +468,24 @@ class BuildResult(models.Model):
|
|||||||
else:
|
else:
|
||||||
build.build_time = 0
|
build.build_time = 0
|
||||||
|
|
||||||
|
#@api.depends('create_date', 'last_update')
|
||||||
|
def _compute_wait_time(self):
|
||||||
|
for build in self:
|
||||||
|
build.wait_time = dt2time(build.last_update) - dt2time(build.create_date)
|
||||||
|
|
||||||
|
#@api.depends('build_end', 'children_ids.last_update')
|
||||||
|
def _compute_last_update(self):
|
||||||
|
for build in self:
|
||||||
|
if not build.build_end:
|
||||||
|
build.last_update = datetime.datetime.now()
|
||||||
|
else:
|
||||||
|
build.last_update = max([child.last_update for child in build.children_ids] + [build.build_end])
|
||||||
|
|
||||||
|
#@api.depends('build_time', 'children_ids.load_time')
|
||||||
|
def _compute_load_time(self):
|
||||||
|
for build in self:
|
||||||
|
build.load_time = sum([build.build_time] + [child.load_time for child in build.children_ids])
|
||||||
|
|
||||||
@api.depends('job_start')
|
@api.depends('job_start')
|
||||||
def _compute_build_age(self):
|
def _compute_build_age(self):
|
||||||
"""Return the time between job start and now"""
|
"""Return the time between job start and now"""
|
||||||
@ -1163,9 +1184,6 @@ class BuildResult(models.Model):
|
|||||||
self._log('write_file', 'exception: %s' % e)
|
self._log('write_file', 'exception: %s' % e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _get_formated_build_time(self):
|
|
||||||
return s2human(self.build_time)
|
|
||||||
|
|
||||||
def _get_color_class(self):
|
def _get_color_class(self):
|
||||||
|
|
||||||
if self.global_result == 'ko':
|
if self.global_result == 'ko':
|
||||||
|
@ -325,7 +325,7 @@ class ConfigStep(models.Model):
|
|||||||
if not self:
|
if not self:
|
||||||
return False
|
return False
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
return self.job_type in ('install_odoo', 'run_odoo', 'restore', 'test_upgrade') or (self.job_type == 'python' and ('docker_params =' in self.python_code or '_run_' in self.python_code))
|
return self.job_type in ('install_odoo', 'run_odoo', 'restore', 'test_upgrade') or (self.job_type == 'python' and ('docker_params =' in self.python_code or '_run_' in self.python_code or 'cmd' in self.python_code))
|
||||||
|
|
||||||
def _run_run_odoo(self, build, force=False):
|
def _run_run_odoo(self, build, force=False):
|
||||||
if not force:
|
if not force:
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<td>
|
<td>
|
||||||
<a t-esc="batch.bundle_id.name" t-attf-href="/runbot/bundle/{{batch.bundle_id.id}}"/>
|
<a t-esc="batch.bundle_id.name" t-attf-href="/runbot/bundle/{{batch.bundle_id.id}}"/>
|
||||||
&emsp;
|
&emsp;
|
||||||
<a groups="runbot.group_runbot_advanced_user" t-attf-href="/web/#id={{batch.id}}&view_type=form&model=runbot.batch&menu_id={{env.ref('runbot.runbot_menu_root').id}}" class="btn btn-default btn-sm" target="new" title="View Batch in Backend">
|
<a groups="runbot.group_runbot_advanced_user" t-attf-href="/web/#id={{batch.id}}&view_type=form&model=runbot.batch&menu_id={{env['ir.model.data']._xmlid_to_res_id('runbot.runbot_menu_root')}}" class="btn btn-default btn-sm" target="new" title="View Batch in Backend">
|
||||||
<i class="fa fa-list"/>
|
<i class="fa fa-list"/>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
@ -156,16 +156,35 @@
|
|||||||
</t>
|
</t>
|
||||||
<b>Host:</b>
|
<b>Host:</b>
|
||||||
<t t-esc="build.host"/>
|
<t t-esc="build.host"/>
|
||||||
<br/>
|
|
||||||
</t>
|
|
||||||
<b>Total time:</b>
|
|
||||||
<t t-esc="build._get_formated_build_time()"/>
|
|
||||||
<br/>
|
|
||||||
<t t-if="build.stat_ids">
|
|
||||||
<b>Stats:</b>
|
|
||||||
<a t-attf-href="/runbot/build/stats/{{build.id}}">Build <t t-esc="build.id"/></a>
|
|
||||||
<br/>
|
|
||||||
</t>
|
</t>
|
||||||
|
<div>
|
||||||
|
<b title="Execution time of this build, without child time">
|
||||||
|
Build time:
|
||||||
|
</b>
|
||||||
|
<t t-att-tile='build.build_time' t-esc="s2human(build.build_time)"/>
|
||||||
|
<i t-if='more'>(<t t-esc="build.build_time"/>s)</i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<b title='Time from creation to finish (queue time + completion time)'>
|
||||||
|
Wait time:
|
||||||
|
</b>
|
||||||
|
<t t-att-tile='build.wait_time' t-esc="s2human(build.wait_time)"/>
|
||||||
|
<i t-if='more'>(<t t-esc="build.wait_time"/>s)</i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<b title='Total time '>
|
||||||
|
Load time:
|
||||||
|
</b>
|
||||||
|
<t t-att-tile='build.load_time' t-esc="s2human(build.load_time)"/>
|
||||||
|
<i t-if='more'>(<t t-esc="build.load_time"/>s)</i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<t t-if="build.stat_ids">
|
||||||
|
<b>Stats:</b>
|
||||||
|
<a t-attf-href="/runbot/build/stats/{{build.id}}">Build <t t-esc="build.id"/></a>
|
||||||
|
<br/>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6" t-if="build.children_ids">
|
<div class="col-md-6" t-if="build.children_ids">
|
||||||
@ -204,7 +223,7 @@
|
|||||||
</t>
|
</t>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span t-attf-class="badge badge-info" t-esc="child._get_formated_build_time()"/>
|
<span t-attf-class="badge badge-info" t-esc="s2human(child.build_time)"/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<t t-call="runbot.build_button">
|
<t t-call="runbot.build_button">
|
||||||
@ -336,7 +355,7 @@
|
|||||||
<td/><td/><td/>
|
<td/><td/><td/>
|
||||||
<td t-attf-class="bg-{{'info' if error.active else 'success'}}-light {{size}}" colspan="2">
|
<td t-attf-class="bg-{{'info' if error.active else 'success'}}-light {{size}}" colspan="2">
|
||||||
This error is already <a href="#" t-attf-title="{{'Was detected by runbot in nightly builds.' if error.active else 'Either the error is not properly fixed or the branch does not contain the fix.'}}"><t t-esc="'known' if error.active else 'fixed'"/></a>.
|
This error is already <a href="#" t-attf-title="{{'Was detected by runbot in nightly builds.' if error.active else 'Either the error is not properly fixed or the branch does not contain the fix.'}}"><t t-esc="'known' if error.active else 'fixed'"/></a>.
|
||||||
<a groups="runbot.group_user" t-attf-href="/web#id={{l.error_id.id}}&view_type=form&model=runbot.build.error&menu_id={{env.ref('runbot.runbot_menu_root').id}}" title="View in Backend" target="new">
|
<a groups="runbot.group_user" t-attf-href="/web#id={{l.error_id.id}}&view_type=form&model=runbot.build.error&menu_id={{env['ir.model.data']._xmlid_to_res_id('runbot.runbot_menu_root')}}" title="View in Backend" target="new">
|
||||||
<i t-attf-class="fa fa-{{icon}}"/>
|
<i t-attf-class="fa fa-{{icon}}"/>
|
||||||
</a>
|
</a>
|
||||||
<span groups="runbot.group_runbot_admin" t-if="error.responsible or error.responsible.id == uid">(<i t-esc="error.responsible.name"/>)</span>
|
<span groups="runbot.group_runbot_admin" t-if="error.responsible or error.responsible.id == uid">(<i t-esc="error.responsible.name"/>)</span>
|
||||||
@ -387,7 +406,7 @@
|
|||||||
<span t-esc="build.params_id.version_id.name"/>
|
<span t-esc="build.params_id.version_id.name"/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span t-esc="build._get_formated_build_time()"/>
|
<span t-esc="s2human(build.build_time)"/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<t t-call="runbot.build_button">
|
<t t-call="runbot.build_button">
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<a t-att-href="build_error.last_seen_build_id.build_url" t-attf-title="View last affected build ({{build_error.last_seen_build_id.id}})"><i class="fa fa-external-link"/></a>
|
<a t-att-href="build_error.last_seen_build_id.build_url" t-attf-title="View last affected build ({{build_error.last_seen_build_id.id}})"><i class="fa fa-external-link"/></a>
|
||||||
<a groups="base.group_user" t-attf-href="/web/#id={{build_error.id}}&view_type=form&model=runbot.build.error&menu_id={{env.ref('runbot.runbot_menu_root').id}}" target="new" title="View in Backend">
|
<a groups="base.group_user" t-attf-href="/web/#id={{build_error.id}}&view_type=form&model=runbot.build.error&menu_id={{env['ir.model.data']._xmlid_to_res_id('runbot.runbot_menu_root')}}" target="new" title="View in Backend">
|
||||||
<span class="badge badge-info" t-esc="build_error.build_count" t-attf-title="This error was seen {{build_error.build_count}} View in backend"/>
|
<span class="badge badge-info" t-esc="build_error.build_count" t-attf-title="This error was seen {{build_error.build_count}} View in backend"/>
|
||||||
</a>
|
</a>
|
||||||
<span groups="!base.group_user" class="badge badge-info" t-esc="build_error.build_count" t-attf-title="This error was seen {{build_error.build_count}}"/>
|
<span groups="!base.group_user" class="badge badge-info" t-esc="build_error.build_count" t-attf-title="This error was seen {{build_error.build_count}}"/>
|
||||||
@ -114,7 +114,7 @@
|
|||||||
<div t-if="team" class='col-md-12'>
|
<div t-if="team" class='col-md-12'>
|
||||||
<div class="col-lg-12 text-center mb16">
|
<div class="col-lg-12 text-center mb16">
|
||||||
<h2>Team <t t-esc="team.name.capitalize()"/>
|
<h2>Team <t t-esc="team.name.capitalize()"/>
|
||||||
<a groups="base.group_user" t-attf-href="/web/#id={{team.id}}&view_type=form&model=runbot.team&menu_id={{env.ref('runbot.runbot_menu_root').id}}" target="new" title="View in Backend">
|
<a groups="base.group_user" t-attf-href="/web/#id={{team.id}}&view_type=form&model=runbot.team&menu_id={{env['ir.model.data']._xmlid_to_res_id('runbot.runbot_menu_root')}}" target="new" title="View in Backend">
|
||||||
<i class="fa fa-list"/>
|
<i class="fa fa-list"/>
|
||||||
</a>
|
</a>
|
||||||
</h2>
|
</h2>
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<t t-esc="bundle.name"/>
|
<t t-esc="bundle.name"/>
|
||||||
<i t-if="bundle.sticky" class="fa fa-star" style="color: #f0ad4e" />
|
<i t-if="bundle.sticky" class="fa fa-star" style="color: #f0ad4e" />
|
||||||
<div class="btn-group" role="group">
|
<div class="btn-group" role="group">
|
||||||
<a groups="runbot.group_runbot_advanced_user" t-attf-href="/web/#id={{bundle.id}}&view_type=form&model=runbot.bundle&menu_id={{env.ref('runbot.runbot_menu_root').id}}" class="btn btn-default btn-sm" target="new" title="View in Backend">
|
<a groups="runbot.group_runbot_advanced_user" t-attf-href="/web/#id={{bundle.id}}&view_type=form&model=runbot.bundle&menu_id={{env['ir.model.data']._xmlid_to_res_id('runbot.runbot_menu_root')}}" class="btn btn-default btn-sm" target="new" title="View in Backend">
|
||||||
<i class="fa fa-list"/>
|
<i class="fa fa-list"/>
|
||||||
</a>
|
</a>
|
||||||
<a groups="runbot.group_runbot_advanced_user" class="btn btn-default" t-attf-href="/runbot/bundle/{{bundle.id}}/force" title="Force A New Batch">
|
<a groups="runbot.group_runbot_advanced_user" class="btn btn-default" t-attf-href="/runbot/bundle/{{bundle.id}}/force" title="Force A New Batch">
|
||||||
|
@ -325,7 +325,7 @@
|
|||||||
<i class="fa fa-search"/>
|
<i class="fa fa-search"/>
|
||||||
Find similar builds
|
Find similar builds
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item" t-attf-href="/web/#id={{bu['id']}}&view_type=form&model=runbot.build&menu_id={{env.ref('runbot.runbot_menu_root').id}}" target="new">
|
<a class="dropdown-item" t-attf-href="/web/#id={{bu['id']}}&view_type=form&model=runbot.build&menu_id={{env['ir.model.data']._xmlid_to_res_id('runbot.runbot_menu_root')}}" target="new">
|
||||||
<i class="fa fa-list"/>
|
<i class="fa fa-list"/>
|
||||||
View in backend
|
View in backend
|
||||||
</a>
|
</a>
|
||||||
|
Loading…
Reference in New Issue
Block a user