Add reviewkeys

Reviewkeys are a customizable shortcut for leaving predefined
votes on a change.  For example, if you want to leave a +2
review with no comment, you might simply hit the "meta-2"
key.  The following configuration block is recommended for
use with OpenStack's Gerrit:

  reviewkeys:
    - key: 'meta 0'
      approvals: []
    - key: 'meta 1'
      approvals:
        - category: 'Code-Review'
          value: 1
    - key: 'meta 2'
      approvals:
        - category: 'Code-Review'
          value: 2
    - key: 'meta 3'
      approvals:
        - category: 'Code-Review'
          value: 2
        - category: 'Workflow'
          value: 1

Change-Id: I466024d71d5b1d89fcdc32355e2a9fe13abf5c28
This commit is contained in:
James E. Blair 2014-07-12 20:17:17 -07:00
parent 2fcb7bc219
commit 705ca5c766
6 changed files with 107 additions and 43 deletions

View File

@ -192,7 +192,7 @@ class App(object):
text += '<%s>%s %s\n' % (d['key'], space, d['name'])
text += "\nThis Screen\n"
text += "===========\n"
text += self.loop.widget.help
text += self.loop.widget.help()
dialog = mywid.MessageDialog('Help', text)
lines = text.split('\n')
urwid.connect_signal(dialog, 'close',

View File

@ -13,8 +13,13 @@
# License for the specific language governing permissions and limitations
# under the License.
import collections
import getpass
import os
try:
import ordereddict
except:
pass
import yaml
import voluptuous as v
@ -22,6 +27,11 @@ import voluptuous as v
import gertty.commentlink
import gertty.palette
try:
OrderedDict = collections.OrderedDict
except AttributeError:
OrderedDict = ordereddict.OrderedDict
DEFAULT_CONFIG_PATH='~/.gertty.yaml'
class ConfigSchema(object):
@ -65,11 +75,20 @@ class ConfigSchema(object):
dashboards = [dashboard]
reviewkey_approval = {v.Required('category'): str,
v.Required('value'): int}
reviewkey = {v.Required('approvals'): [reviewkey_approval],
v.Required('key'): str}
reviewkeys = [reviewkey]
def getSchema(self, data):
schema = v.Schema({v.Required('servers'): self.servers,
'palettes': self.palettes,
'commentlinks': self.commentlinks,
'dashboards': self.dashboards,
'reviewkeys': self.reviewkeys,
})
return schema
@ -122,10 +141,14 @@ class Config(object):
text="{url}",
url="{url}"))])))
self.dashboards = {}
self.dashboards = OrderedDict()
for d in self.config.get('dashboards', []):
self.dashboards[d['key']] = d
self.reviewkeys = OrderedDict()
for k in self.config.get('reviewkeys', []):
self.reviewkeys[k['key']] = k
def getServer(self, name=None):
for server in self.config['servers']:
if name is None or name == server['name']:

View File

@ -1,4 +1,5 @@
# Copyright 2014 OpenStack Foundation
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# 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
@ -85,34 +86,13 @@ class ReviewDialog(urwid.WidgetWrap):
super(ReviewDialog, self).__init__(urwid.LineBox(fill, 'Review'))
def save(self):
message_key = None
with self.app.db.getSession() as session:
revision = session.getRevision(self.revision_row.revision_key)
change = revision.change
pending_approvals = {}
for approval in change.pending_approvals:
pending_approvals[approval.category] = approval
for category, group in self.button_groups.items():
approval = pending_approvals.get(category)
if not approval:
approval = change.createApproval(u'(draft)', category, 0, pending=True)
pending_approvals[category] = approval
for button in group:
if button.state:
approval.value = int(button.get_label())
message = None
for m in revision.messages:
if m.pending:
message = m
break
if not message:
message = revision.createMessage(None,
datetime.datetime.utcnow(),
u'(draft)', '', pending=True)
message.message = self.message.edit_text.strip()
message_key = message.key
change.reviewed = True
return message_key
approvals = {}
for category, group in self.button_groups.items():
for button in group:
if button.state:
approvals[category] = int(button.get_label())
message = self.message.edit_text.strip()
self.change_view.saveReview(self.revision_row.revision_key, approvals, message)
def keypress(self, size, key):
r = super(ReviewDialog, self).keypress(size, key)
@ -142,9 +122,6 @@ class ReviewButton(mywid.FixedButton):
def closeReview(self, save):
if save:
message_key = self.dialog.save()
self.change_view.app.sync.submitTask(
sync.UploadReviewTask(message_key, sync.HIGH_PRIORITY))
self.change_view.refresh()
self.change_view.app.backScreen()
class RevisionRow(urwid.WidgetWrap):
@ -293,15 +270,23 @@ class ChangeMessageBox(mywid.HyperText):
self.set_text(text+comment_text)
class ChangeView(urwid.WidgetWrap):
help = """
<c> Checkout the most recent revision into the local repo.
<d> Show the diff of the mont recent revision.
<k> Toggle the hidden flag for the current change.
<r> Leave a review for the most recent revision.
<v> Toggle the reviewed flag for the current change.
<x> Cherry-pick the most recent revision onto the local repo.
_help = """
<c> Checkout the most recent revision into the local repo.
<d> Show the diff of the mont recent revision.
<k> Toggle the hidden flag for the current change.
<r> Leave a review for the most recent revision.
<v> Toggle the reviewed flag for the current change.
<x> Cherry-pick the most recent revision onto the local repo.
"""
def help(self):
text = self._help
for k in self.app.config.reviewkeys.values():
space = max(6 - len(k['key']), 0) * ' '
action = ', '.join(['{category}:{value}'.format(**a) for a in k['approvals']])
text += '<%s>%s %s\n' % (k['key'], space, action)
return text
def __init__(self, app, change_key):
super(ChangeView, self).__init__(urwid.Pile([]))
self.app = app
@ -579,7 +564,54 @@ class ChangeView(urwid.WidgetWrap):
row = self.revision_rows[self.last_revision_key]
row.cherryPick(None)
return None
if r in self.app.config.reviewkeys:
self.reviewKey(self.app.config.reviewkeys[r])
return None
return r
def diff(self, revision_key):
self.app.changeScreen(view_diff.DiffView(self.app, revision_key))
def reviewKey(self, reviewkey):
approvals = {}
for a in reviewkey['approvals']:
approvals[a['category']] = a['value']
self.app.log.debug("Reviewkey %s with approvals %s" %
(reviewkey['key'], approvals))
row = self.revision_rows[self.last_revision_key]
self.saveReview(row.revision_key, approvals, '')
def saveReview(self, revision_key, approvals, message):
message_key = None
with self.app.db.getSession() as session:
revision = session.getRevision(revision_key)
change = revision.change
pending_approvals = {}
for approval in change.pending_approvals:
pending_approvals[approval.category] = approval
categories = set()
for label in change.permitted_labels:
categories.add(label.category)
for category in categories:
value = approvals.get(category, 0)
approval = pending_approvals.get(category)
if not approval:
approval = change.createApproval(u'(draft)', category, 0, pending=True)
pending_approvals[category] = approval
approval.value = value
pending_message = None
for m in revision.messages:
if m.pending:
pending_message = m
break
if not pending_message:
pending_message = revision.createMessage(None,
datetime.datetime.utcnow(),
u'(draft)', '', pending=True)
pending_message.message = message
message_key = pending_message.key
change.reviewed = True
self.app.sync.submitTask(
sync.UploadReviewTask(message_key, sync.HIGH_PRIORITY))
self.refresh()

View File

@ -67,12 +67,15 @@ class ChangeListHeader(urwid.WidgetWrap):
self._w.contents.append((urwid.Text(' %s' % category[0]), self._w.options('given', 3)))
class ChangeListView(urwid.WidgetWrap):
help = """
_help = """
<k> Toggle the hidden flag for the currently selected change.
<l> Toggle whether only unreviewed or all changes are displayed.
<v> Toggle the reviewed flag for the currently selected change.
"""
def help(self):
return self._help
def __init__(self, app, query, query_desc=None, unreviewed=False):
super(ChangeListView, self).__init__(urwid.Pile([]))
self.app = app

View File

@ -210,11 +210,14 @@ class DiffContextButton(urwid.WidgetWrap):
self.view.expandChunk(self.diff, self.chunk, from_end=-10)
class DiffView(urwid.WidgetWrap):
help = """
_help = """
<Enter> Add an inline comment
<p> Select old/new patchsets to diff
"""
def help(self):
return self._help
def __init__(self, app, new_revision_key):
super(DiffView, self).__init__(urwid.Pile([]))
self.log = logging.getLogger('gertty.view.diff')

View File

@ -66,11 +66,14 @@ class ProjectListHeader(urwid.WidgetWrap):
super(ProjectListHeader, self).__init__(urwid.Columns(cols))
class ProjectListView(urwid.WidgetWrap):
help = """
_help = """
<l> Toggle whether only subscribed projects or all projects are listed.
<s> Toggle the subscription flag for the currently selected project.
"""
def help(self):
return self._help
def __init__(self, app):
super(ProjectListView, self).__init__(urwid.Pile([]))
self.app = app