Display overall duration in buidset page in zuul web
The overall duration is from a user (developer) point of view, how much time it takes from the trigger of the build (e.g. a push, a comment, etc.), till the last build is finished. It takes into account also the time spent in waiting in queue, launching nodes, preparing the nodes, etc. Technically it measures between the event timestamp and the end time of the last build in the build set. This duration reflects the user experience of how much time the user needs to wait. Change-Id: I253d023146c696d0372197e599e0df3c217ef344
This commit is contained in:
committed by
James E. Blair
parent
02efa8fb28
commit
8a01c61991
@@ -73,7 +73,7 @@ class TestSQLConnectionMysql(ZuulTestCase):
|
||||
buildset_table = table_prefix + 'zuul_buildset'
|
||||
build_table = table_prefix + 'zuul_build'
|
||||
|
||||
self.assertEqual(16, len(insp.get_columns(buildset_table)))
|
||||
self.assertEqual(17, len(insp.get_columns(buildset_table)))
|
||||
self.assertEqual(13, len(insp.get_columns(build_table)))
|
||||
|
||||
def test_sql_tables_created(self):
|
||||
@@ -146,6 +146,7 @@ class TestSQLConnectionMysql(ZuulTestCase):
|
||||
'https://review.example.com/%d' % buildset0['change'],
|
||||
buildset0['ref_url'])
|
||||
self.assertNotEqual(None, buildset0['event_id'])
|
||||
self.assertNotEqual(None, buildset0['event_timestamp'])
|
||||
|
||||
buildset0_builds = conn.execute(
|
||||
sa.sql.select([reporter.connection.zuul_build_table]).where(
|
||||
|
||||
@@ -62,6 +62,13 @@ function Buildset({ buildset, timezone, tenant, user }) {
|
||||
(moment.utc(lastEndBuild.end_time).tz(timezone) -
|
||||
moment.utc(firstStartBuild.start_time).tz(timezone)) /
|
||||
1000
|
||||
const overallDuration =
|
||||
(moment.utc(lastEndBuild.end_time).tz(timezone) -
|
||||
moment.utc(
|
||||
buildset.event_timestamp!=null
|
||||
? buildset.event_timestamp : firstStartBuild.start_time
|
||||
).tz(timezone)
|
||||
) / 1000
|
||||
|
||||
const buildLink = (build) => (
|
||||
<Link to={`${tenant.linkPrefix}/build/${build.uuid}`}>
|
||||
@@ -109,7 +116,7 @@ function Buildset({ buildset, timezone, tenant, user }) {
|
||||
icon={<OutlinedClockIcon />}
|
||||
value={
|
||||
<>
|
||||
<strong>Total duration </strong>
|
||||
<strong>Total build duration </strong>
|
||||
{moment
|
||||
.duration(totalDuration, 'seconds')
|
||||
.format('h [hr] m [min] s [sec]')}{' '}
|
||||
@@ -126,6 +133,18 @@ function Buildset({ buildset, timezone, tenant, user }) {
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<IconProperty
|
||||
WrapElement={ListItem}
|
||||
icon={<OutlinedClockIcon />}
|
||||
value={
|
||||
<>
|
||||
<strong>Overall duration </strong>
|
||||
{moment
|
||||
.duration(overallDuration, 'seconds')
|
||||
.format('h [hr] m [min] s [sec]')}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</List>
|
||||
</FlexItem>
|
||||
</Flex>
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""add event timestamp column
|
||||
|
||||
Revision ID: eca077de5e1b
|
||||
Revises: 40c49b6fc2e3
|
||||
Create Date: 2022-01-03 13:52:37.262934
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'eca077de5e1b'
|
||||
down_revision = '40c49b6fc2e3'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade(table_prefix=''):
|
||||
op.add_column(
|
||||
table_prefix + "zuul_buildset",
|
||||
sa.Column("event_timestamp", sa.DateTime, nullable=True)
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
raise Exception("Downgrades not supported")
|
||||
@@ -59,7 +59,7 @@ class DatabaseSession(object):
|
||||
|
||||
def getBuilds(self, tenant=None, project=None, pipeline=None,
|
||||
change=None, branch=None, patchset=None, ref=None,
|
||||
newrev=None, event_id=None, uuid=None,
|
||||
newrev=None, event_id=None, event_timestamp=None, uuid=None,
|
||||
job_name=None, voting=None, nodeset=None,
|
||||
result=None, provides=None, final=None, held=None,
|
||||
complete=None, sort_by_buildset=False, limit=50,
|
||||
@@ -100,6 +100,8 @@ class DatabaseSession(object):
|
||||
q = self.listFilter(q, buildset_table.c.ref, ref)
|
||||
q = self.listFilter(q, buildset_table.c.newrev, newrev)
|
||||
q = self.listFilter(q, buildset_table.c.event_id, event_id)
|
||||
q = self.listFilter(
|
||||
q, buildset_table.c.event_timestamp, event_timestamp)
|
||||
q = self.listFilter(q, build_table.c.uuid, uuid)
|
||||
q = self.listFilter(q, build_table.c.job_name, job_name)
|
||||
q = self.listFilter(q, build_table.c.voting, voting)
|
||||
@@ -331,6 +333,7 @@ class SQLConnection(BaseConnection):
|
||||
branch = sa.Column(sa.String(255))
|
||||
uuid = sa.Column(sa.String(36))
|
||||
event_id = sa.Column(sa.String(255), nullable=True)
|
||||
event_timestamp = sa.Column(sa.DateTime, nullable=True)
|
||||
|
||||
sa.Index(self.table_prefix + 'project_pipeline_idx',
|
||||
project, pipeline)
|
||||
|
||||
@@ -46,9 +46,12 @@ class SQLReporter(BaseReporter):
|
||||
if not buildset.uuid:
|
||||
return
|
||||
event_id = None
|
||||
event_timestamp = None
|
||||
item = buildset.item
|
||||
if item.event is not None:
|
||||
event_id = getattr(item.event, "zuul_event_id", None)
|
||||
event_timestamp = datetime.datetime.fromtimestamp(
|
||||
item.event.timestamp, tz=datetime.timezone.utc)
|
||||
|
||||
with self.connection.getSession() as db:
|
||||
db_buildset = db.createBuildSet(
|
||||
@@ -65,6 +68,7 @@ class SQLReporter(BaseReporter):
|
||||
zuul_ref=buildset.ref,
|
||||
ref_url=item.change.url,
|
||||
event_id=event_id,
|
||||
event_timestamp=event_timestamp,
|
||||
)
|
||||
return db_buildset
|
||||
|
||||
|
||||
@@ -1222,15 +1222,16 @@ class ZuulWebAPI(object):
|
||||
resp.headers['Content-Type'] = 'text/plain'
|
||||
return key
|
||||
|
||||
def _datetimeToString(self, my_datetime):
|
||||
return my_datetime.strftime('%Y-%m-%dT%H:%M:%S')
|
||||
|
||||
def buildToDict(self, build, buildset=None):
|
||||
start_time = build.start_time
|
||||
if build.start_time:
|
||||
start_time = start_time.strftime(
|
||||
'%Y-%m-%dT%H:%M:%S')
|
||||
start_time = self._datetimeToString(start_time)
|
||||
end_time = build.end_time
|
||||
if build.end_time:
|
||||
end_time = end_time.strftime(
|
||||
'%Y-%m-%dT%H:%M:%S')
|
||||
end_time = self._datetimeToString(end_time)
|
||||
if build.start_time and build.end_time:
|
||||
duration = (build.end_time -
|
||||
build.start_time).total_seconds()
|
||||
@@ -1256,6 +1257,9 @@ class ZuulWebAPI(object):
|
||||
}
|
||||
|
||||
if buildset:
|
||||
event_timestamp = buildset.event_timestamp
|
||||
if event_timestamp:
|
||||
event_timestamp = self._datetimeToString(event_timestamp)
|
||||
ret.update({
|
||||
'project': buildset.project,
|
||||
'branch': buildset.branch,
|
||||
@@ -1266,6 +1270,7 @@ class ZuulWebAPI(object):
|
||||
'newrev': buildset.newrev,
|
||||
'ref_url': buildset.ref_url,
|
||||
'event_id': buildset.event_id,
|
||||
'event_timestamp': event_timestamp,
|
||||
'buildset': {
|
||||
'uuid': buildset.uuid,
|
||||
},
|
||||
@@ -1340,6 +1345,9 @@ class ZuulWebAPI(object):
|
||||
return data
|
||||
|
||||
def buildsetToDict(self, buildset, builds=[]):
|
||||
event_timestamp = buildset.event_timestamp
|
||||
if event_timestamp:
|
||||
event_timestamp = self._datetimeToString(event_timestamp)
|
||||
ret = {
|
||||
'_id': buildset.id,
|
||||
'uuid': buildset.uuid,
|
||||
@@ -1354,6 +1362,7 @@ class ZuulWebAPI(object):
|
||||
'newrev': buildset.newrev,
|
||||
'ref_url': buildset.ref_url,
|
||||
'event_id': buildset.event_id,
|
||||
'event_timestamp': event_timestamp,
|
||||
}
|
||||
if builds:
|
||||
ret['builds'] = []
|
||||
|
||||
Reference in New Issue
Block a user