Add test results to top of change view

Add an option to commentlinks to indicate they are test results
and use that to collect results and display them at the top of the
change view.  The value of 'test-results' is used as the job key
when creating the table (so that only the most recent result for
a given job run on the latest patchset is included).  This is
particularly effective along with the hide-comment system to hide
the results from the comment stream.

Change-Id: I54a787914aab18ad2a2a5ca4cc79dd66add2c588
This commit is contained in:
James E. Blair 2014-08-23 10:38:03 -07:00
parent ccc2a3eebf
commit f4118833af
5 changed files with 67 additions and 5 deletions

View File

@ -16,7 +16,8 @@ palettes:
test-FAILURE: ['light red', '', ''] test-FAILURE: ['light red', '', '']
commentlinks: commentlinks:
- match: "^- (?P<job>.*?) (?P<url>.*?) : (?P<result>.*?) (?P<rest>.*)$" - match: "^- (?P<job>.*?) (?P<url>.*?) : (?P<result>[^ ]+) ?(?P<comment>.*)$"
test-result: "{job}"
replacements: replacements:
- link: - link:
text: "{job:<42}" text: "{job:<42}"
@ -24,7 +25,7 @@ commentlinks:
- text: - text:
color: "test-{result}" color: "test-{result}"
text: "{result} " text: "{result} "
- text: "{rest}" - text: "{comment}"
- match: "(?P<id>I[0-9a-fA-F]{40})" - match: "(?P<id>I[0-9a-fA-F]{40})"
replacements: replacements:
- search: - search:

View File

@ -12,12 +12,22 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import collections
try:
import ordereddict
except:
pass
import re import re
import urwid import urwid
import mywid import mywid
try:
OrderedDict = collections.OrderedDict
except AttributeError:
OrderedDict = ordereddict.OrderedDict
class TextReplacement(object): class TextReplacement(object):
def __init__(self, config): def __init__(self, config):
if isinstance(config, basestring): if isinstance(config, basestring):
@ -57,6 +67,7 @@ class SearchReplacement(object):
class CommentLink(object): class CommentLink(object):
def __init__(self, config): def __init__(self, config):
self.match = re.compile(config['match'], re.M) self.match = re.compile(config['match'], re.M)
self.test_result = config.get('test-result', None)
self.replacements = [] self.replacements = []
for r in config['replacements']: for r in config['replacements']:
if 'text' in r: if 'text' in r:
@ -66,6 +77,18 @@ class CommentLink(object):
if 'search' in r: if 'search' in r:
self.replacements.append(SearchReplacement(r['search'])) self.replacements.append(SearchReplacement(r['search']))
def getTestResults(self, app, text):
if self.test_result is None:
return {}
ret = OrderedDict()
for line in text.split('\n'):
m = self.match.search(line)
if m:
repl = [r.replace(app, m.groupdict()) for r in self.replacements]
job = self.test_result.format(**m.groupdict())
ret[job] = repl + ['\n']
return ret
def run(self, app, chunks): def run(self, app, chunks):
ret = [] ret = []
for chunk in chunks: for chunk in chunks:

View File

@ -66,7 +66,8 @@ class ConfigSchema(object):
palettes = [palette] palettes = [palette]
commentlink = {v.Required('match'): str, commentlink = {v.Required('match'): str,
v.Required('replacements'): [replacement]} v.Required('replacements'): [replacement],
'test-result': str}
commentlinks = [commentlink] commentlinks = [commentlink]

View File

@ -276,3 +276,20 @@ class Link(urwid.Widget):
if focus: if focus:
return self.focused_attr return self.focused_attr
return self.attr return self.attr
# A workaround for the issue fixed in
# https://github.com/wardi/urwid/pull/74
# included here until thi fix is released
class MyGridFlow(urwid.GridFlow):
def generate_display_widget(self, size):
p = super(MyGridFlow, self).generate_display_widget(size)
for item in p.contents:
if isinstance(item[0], urwid.Padding):
c = item[0].original_widget
if isinstance(c, urwid.Columns):
if c.focus_position == 0 and not c.contents[0][0].selectable():
for i, w in enumerate(c.contents):
if w[0].selectable():
c.focus_position = i
break
return p

View File

@ -340,8 +340,9 @@ class ChangeView(urwid.WidgetWrap):
self.needed_by = urwid.Pile([]) self.needed_by = urwid.Pile([])
self.needed_by_rows = {} self.needed_by_rows = {}
self.related_changes = urwid.Pile([self.depends_on, self.needed_by]) self.related_changes = urwid.Pile([self.depends_on, self.needed_by])
self.grid = urwid.GridFlow([change_info, self.commit_message, votes], self.results = mywid.HyperText(u'') # because it scrolls better than a table
cell_width=80, h_sep=2, v_sep=1, align='left') self.grid = mywid.MyGridFlow([change_info, self.commit_message, votes, self.results],
cell_width=80, h_sep=2, v_sep=1, align='left')
self.listbox = urwid.ListBox(urwid.SimpleFocusListWalker([])) self.listbox = urwid.ListBox(urwid.SimpleFocusListWalker([]))
self._w.contents.append((self.app.header, ('pack', 1))) self._w.contents.append((self.app.header, ('pack', 1)))
self._w.contents.append((urwid.Divider(), ('pack', 1))) self._w.contents.append((urwid.Divider(), ('pack', 1)))
@ -486,7 +487,15 @@ class ChangeView(urwid.WidgetWrap):
listbox_index += 1 listbox_index += 1
# Get the set of messages that should be displayed # Get the set of messages that should be displayed
display_messages = [] display_messages = []
result_systems = {}
for message in change.messages: for message in change.messages:
if message.revision == change.revisions[-1]:
for commentlink in self.app.config.commentlinks:
results = commentlink.getTestResults(self.app, message.message)
if results:
result_system = result_systems.get(message.author.name, {})
result_systems[message.author.name] = result_system
result_system.update(results)
skip = False skip = False
if self.hide_comments: if self.hide_comments:
for regex in self.app.config.hide_comments: for regex in self.app.config.hide_comments:
@ -514,6 +523,17 @@ class ChangeView(urwid.WidgetWrap):
self.listbox.body.remove(row) self.listbox.body.remove(row)
del self.message_rows[key] del self.message_rows[key]
listbox_index -= 1 listbox_index -= 1
self._updateTestResults(result_systems)
def _updateTestResults(self, result_systems):
text = []
for system, results in result_systems.items():
for job, result in results.items():
text.append(result)
if text:
self.results.set_text(text)
else:
self.results.set_text('')
def _updateDependenciesWidget(self, changes, widget, widget_rows, header): def _updateDependenciesWidget(self, changes, widget, widget_rows, header):
if not changes: if not changes: