Add support for checks plugin

Change-Id: Iabaf1c928571ff0191e1201f395050f278f19a75
This commit is contained in:
James E. Blair 2020-02-20 14:57:26 -08:00
parent 5ff7d2061e
commit 055b11624b
5 changed files with 176 additions and 2 deletions

View File

@ -0,0 +1,43 @@
"""add-checks
Revision ID: 45d33eccc7a7
Revises: 6f6183367a8f
Create Date: 2020-02-20 13:16:22.342039
"""
# revision identifiers, used by Alembic.
revision = '45d33eccc7a7'
down_revision = '6f6183367a8f'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.create_table('checker',
sa.Column('key', sa.Integer(), nullable=False),
sa.Column('uuid', sa.String(255), index=True, unique=True, nullable=False),
sa.Column('name', sa.String(255), nullable=False),
sa.Column('status', sa.String(255), nullable=False),
sa.Column('blocking', sa.String(255)),
sa.Column('description', sa.Text()),
sa.PrimaryKeyConstraint('key')
)
op.create_table('check',
sa.Column('key', sa.Integer(), nullable=False),
sa.Column('revision_key', sa.Integer(), index=True),
sa.Column('checker_key', sa.Integer(), index=True),
sa.Column('state', sa.String(255), nullable=False),
sa.Column('url', sa.Text()),
sa.Column('message', sa.Text()),
sa.Column('started', sa.DateTime()),
sa.Column('finished', sa.DateTime()),
sa.Column('created', sa.DateTime(), index=True, nullable=False),
sa.Column('updated', sa.DateTime(), index=True, nullable=False),
sa.PrimaryKeyConstraint('key')
)
def downgrade():
pass

View File

@ -200,6 +200,28 @@ server_table = Table(
Column('key', Integer, primary_key=True),
Column('own_account_key', Integer, ForeignKey("account.key"), index=True),
)
checker_table = Table(
'checker', metadata,
Column('key', Integer, primary_key=True),
Column('uuid', String(255), index=True, unique=True, nullable=False),
Column('name', String(255), nullable=False),
Column('status', String(255), nullable=False),
Column('blocking', String(255)),
Column('description', Text),
)
check_table = Table(
'check', metadata,
Column('key', Integer, primary_key=True),
Column('revision_key', Integer, ForeignKey("revision.key"), index=True),
Column('checker_key', Integer, ForeignKey("checker.key"), index=True),
Column('state', String(255), nullable=False),
Column('url', Text),
Column('message', Text),
Column('started', DateTime),
Column('finished', DateTime),
Column('created', DateTime, index=True, nullable=False),
Column('updated', DateTime, index=True, nullable=False),
)
class Account(object):
@ -503,6 +525,15 @@ class Revision(object):
self._file_cache[f.path] = f
return f
def createCheck(self, *args, **kw):
session = Session.object_session(self)
args = [self] + list(args)
c = Check(*args, **kw)
self.checks.append(c)
session.add(c)
session.flush()
return c
def getFile(self, path):
if not hasattr(self, '_file_cache'):
self._file_cache = {}
@ -660,6 +691,19 @@ class Server(object):
def __init__(self):
pass
class Checker(object):
def __init__(self, uuid, name, status):
self.uuid = uuid
self.name = name
self.status = status
class Check(object):
def __init__(self, revision, checker, state, created, updated):
self.revision_key = revision.key
self.checker_key = checker.key
self.state = state
self.created = created
self.updated = updated
mapper(Account, account_table)
mapper(Project, project_table, properties=dict(
@ -742,6 +786,9 @@ mapper(Revision, revision_table, properties=dict(
cascade='all, delete-orphan'),
pending_cherry_picks=relationship(PendingCherryPick, backref='revision',
cascade='all, delete-orphan'),
checks=relationship(Check, backref='revision',
cascade='all, delete-orphan'),
))
mapper(Message, message_table, properties=dict(
author=relationship(Account)))
@ -769,6 +816,10 @@ mapper(Hashtag, hashtag_table)
mapper(Server, server_table, properties=dict(
own_account=relationship(Account)
))
mapper(Checker, checker_table)
mapper(Check, check_table, properties=dict(
checker=relationship(Checker)))
def match(expr, item):
if item is None:
@ -779,6 +830,7 @@ def match(expr, item):
def add_sqlite_match(dbapi_connection, connection_record):
dbapi_connection.create_function("matches", 2, match)
class Database(object):
def __init__(self, app, dburi, search):
self.log = logging.getLogger('gertty.db')
@ -1122,3 +1174,15 @@ class DatabaseSession(object):
self.session().add(o)
self.session().flush()
return o
def createChecker(self, *args, **kw):
o = Checker(*args, **kw)
self.session().add(o)
self.session().flush()
return o
def getCheckerByUUID(self, uuid):
try:
return self.session().query(Checker).filter_by(uuid=uuid).one()
except sqlalchemy.orm.exc.NoResultFound:
return None

View File

@ -74,6 +74,12 @@ DEFAULT_PALETTE={
'lines-removed': ['light red', ''],
'reviewer-name': ['yellow', ''],
'reviewer-own-name': ['light cyan', ''],
'check-SUCCESSFUL': ['light green', ''],
'check-FAILED': ['light red', ''],
'check-NOT_STARTED': ['dark gray', ''],
'check-SCHEDULED': ['dark magenta', '', ''],
'check-RUNNING': ['dark magenta', ''],
'check-NOT_RELEVANT': ['dark gray', ''],
# project list
'unreviewed-project': ['white', ''],
'subscribed-project': ['default', ''],

View File

@ -567,6 +567,40 @@ class SyncChangeTask(Task):
return True
return False
def _updateChecks(self, session, change, revision, remote_checks_data):
# Called from run inside of db transaction
local_checks = {c.checker.uuid: c for c in revision.checks}
for checks_data in remote_checks_data:
uuid = checks_data['checker_uuid']
name = checks_data['checker_name']
status = checks_data['checker_status']
checker = session.getCheckerByUUID(uuid)
if checker is None:
self.log.info("Creating checker %s", uuid)
checker = session.createChecker(uuid, name, status)
checker.name = name
checker.status = status
checker.blocking = ' '.join(checks_data['blocking'])
check = local_checks.get(uuid)
updated = dateutil.parser.parse(checks_data['updated'])
state = checks_data['state']
if check is None:
created = dateutil.parser.parse(checks_data['created'])
self.log.info("Creating check %s on revision %s", uuid, revision.key)
check = revision.createCheck(checker,
state,
created, updated)
check.updated = updated
check.state = state
check.url = checks_data.get('url')
check.message = checks_data.get('message')
started = checks_data.get('started')
if started:
check.started = dateutil.parser.parse(started)
finished = checks_data.get('finished')
if finished:
check.finished = dateutil.parser.parse(finished)
def run(self, sync):
start_time = time.time()
try:
@ -596,6 +630,13 @@ class SyncChangeTask(Task):
remote_robot_comments_data = sync.get('changes/%s/revisions/%s/robotcomments' % (
self.change_id, remote_commit))
remote_revision['_gertty_remote_robot_comments_data'] = remote_robot_comments_data
if sync.checks_plugin:
remote_checks_data = sync.get('changes/%s/revisions/%s/checks' % (self.change_id, remote_commit))
if remote_checks_data is None:
sync.checks_plugin = False
else:
remote_revision['_gertty_remote_checks_data'] = remote_checks_data
try:
remote_conflicts = sync.query(['q=status:open+is:mergeable+conflicts:%s' %
remote_change['_number']])
@ -775,6 +816,9 @@ class SyncChangeTask(Task):
else:
if comment.author != account:
comment.author = account
if remote_revision.get('_gertty_remote_checks_data'):
self._updateChecks(session, change, revision, remote_revision['_gertty_remote_checks_data'])
# End revisions
new_message = False
for remote_message in remote_change.get('messages', []):
if 'author' in remote_message:
@ -927,6 +971,7 @@ class SyncChangeTask(Task):
remote_hashtags = remote_change.get('hashtags', [])
change.setHashtags(remote_hashtags)
change.outdated = False
for url, refs in fetches.items():
self.log.debug("Fetching from %s with refs %s", url, refs)
@ -1423,6 +1468,7 @@ class Sync(object):
self.version = (0, 0, 0)
self.offline = False
self.account_id = None
self.checks_plugin = True
self.app = app
self.log = logging.getLogger('gertty.sync')
self.queue = MultiQueue([HIGH_PRIORITY, NORMAL_PRIORITY, LOW_PRIORITY])

View File

@ -854,13 +854,28 @@ class ChangeView(urwid.WidgetWrap):
self.listbox.body.remove(row)
del self.message_rows[key]
listbox_index -= 1
self._updateTestResults(result_systems)
self._updateTestResults(change, result_systems)
def _updateTestResults(self, result_systems):
def _updateTestResults(self, change, result_systems):
text = []
for system, results in result_systems.items():
for job, result in results.items():
text.append(result)
# Add check results
revision = change.revisions[-1]
for check in revision.checks:
# link checker name/url, color result, in time
link = mywid.Link('{:<42}'.format(check.checker.name), 'link', 'focused-link')
urwid.connect_signal(link, 'selected', lambda link:self.app.openURL(check.url))
color = 'check-%s' % check.state
result = (color, check.state)
line = [link, result]
if check.finished and check.started:
line.append(' in %s' % (check.finished-check.started))
line.append('\n')
text.append(line)
if text:
self.results.set_text(text)
else: