diff --git a/gertty/db.py b/gertty/db.py index 23cfccf..3501e0d 100644 --- a/gertty/db.py +++ b/gertty/db.py @@ -629,6 +629,9 @@ class DatabaseSession(object): def getPendingCherryPicks(self): return self.session().query(PendingCherryPick).all() + def getPendingCommitMessages(self): + return self.session().query(Revision).filter_by(pending_message=True).all() + def getAccountByID(self, id, name=None, username=None, email=None): try: account = self.session().query(Account).filter_by(id=id).one() diff --git a/gertty/keymap.py b/gertty/keymap.py index 4904742..d163ee5 100644 --- a/gertty/keymap.py +++ b/gertty/keymap.py @@ -51,6 +51,7 @@ REBASE_CHANGE = 'rebase change' CHERRY_PICK_CHANGE = 'cherry-pick change' REFRESH = 'refresh' EDIT_TOPIC = 'edit topic' +EDIT_COMMIT_MESSAGE = 'edit commit message' # Project list screen: TOGGLE_LIST_REVIEWED = 'toggle list reviewed' TOGGLE_LIST_SUBSCRIBED = 'toggle list subscribed' @@ -93,6 +94,7 @@ DEFAULT_KEYMAP = { CHERRY_PICK_CHANGE: 'ctrl x', REFRESH: 'ctrl r', EDIT_TOPIC: 'ctrl t', + EDIT_COMMIT_MESSAGE: 'ctrl d', TOGGLE_LIST_REVIEWED: 'l', TOGGLE_LIST_SUBSCRIBED: 'L', diff --git a/gertty/mywid.py b/gertty/mywid.py index 42476f9..340bdef 100644 --- a/gertty/mywid.py +++ b/gertty/mywid.py @@ -88,6 +88,28 @@ class ButtonDialog(urwid.WidgetWrap): fill = urwid.Filler(pile, valign='top') super(ButtonDialog, self).__init__(urwid.LineBox(fill, title)) +class TextEditDialog(urwid.WidgetWrap): + signals = ['save', 'cancel'] + def __init__(self, title, prompt, button, text): + save_button = FixedButton(button) + cancel_button = FixedButton('Cancel') + urwid.connect_signal(save_button, 'click', + lambda button:self._emit('save')) + urwid.connect_signal(cancel_button, 'click', + lambda button:self._emit('cancel')) + button_widgets = [('pack', save_button), + ('pack', cancel_button)] + button_columns = urwid.Columns(button_widgets, dividechars=2) + rows = [] + self.entry = urwid.Edit(edit_text=text, multiline=True) + rows.append(urwid.Text(prompt)) + rows.append(self.entry) + rows.append(urwid.Divider()) + rows.append(button_columns) + pile = urwid.Pile(rows) + fill = urwid.Filler(pile, valign='top') + super(TextEditDialog, self).__init__(urwid.LineBox(fill, title)) + class MessageDialog(ButtonDialog): signals = ['close'] def __init__(self, title, message): diff --git a/gertty/sync.py b/gertty/sync.py index 98970ab..9c93aeb 100644 --- a/gertty/sync.py +++ b/gertty/sync.py @@ -341,6 +341,7 @@ class SyncChangeTask(Task): remote_revision['commit']['parents'][0]['commit'], auth, ref) new_revision = True + revision.message = remote_revision['commit']['message'] # TODO: handle multiple parents parent_revision = session.getRevisionByCommit(revision.parent) # TODO: use a singleton list of closed states @@ -584,6 +585,8 @@ class UploadReviewsTask(Task): sync.submitTask(ChangeStatusTask(c.key, self.priority)) for c in session.getPendingCherryPicks(): sync.submitTask(SendCherryPickTask(c.key, self.priority)) + for r in session.getPendingCommitMessages(): + sync.submitTask(ChangeCommitMessageTask(r.key, self.priority)) for m in session.getPendingMessages(): sync.submitTask(UploadReviewTask(m.key, self.priority)) @@ -672,6 +675,27 @@ class SendCherryPickTask(Task): if ret and 'id' in ret: sync.submitTask(SyncChangeTask(ret['id'], priority=self.priority)) +class ChangeCommitMessageTask(Task): + def __init__(self, revision_key, priority=NORMAL_PRIORITY): + super(ChangeCommitMessageTask, self).__init__(priority) + self.revision_key = revision_key + + def __repr__(self): + return '' % (self.revision_key,) + + def run(self, sync): + app = sync.app + with app.db.getSession() as session: + revision = session.getRevision(self.revision_key) + revision.pending_message = False + data = dict(message=revision.message) + # Inside db session for rollback + ret = sync.post('changes/%s/revisions/%s/message' % + (revision.change.id, revision.commit), + data) + change_id = revision.change.id + sync.submitTask(SyncChangeTask(change_id, priority=self.priority)) + class UploadReviewTask(Task): def __init__(self, message_key, priority=NORMAL_PRIORITY): super(UploadReviewTask, self).__init__(priority) diff --git a/gertty/view/change.py b/gertty/view/change.py index 8316817..504666c 100644 --- a/gertty/view/change.py +++ b/gertty/view/change.py @@ -50,29 +50,6 @@ class EditTopicDialog(mywid.ButtonDialog): return None return r -class AbandonRestoreDialog(urwid.WidgetWrap): - signals = ['save', 'cancel'] - def __init__(self, action, text): - self.action = action - save_button = mywid.FixedButton(action) - cancel_button = mywid.FixedButton('Cancel') - urwid.connect_signal(save_button, 'click', - lambda button:self._emit('save')) - urwid.connect_signal(cancel_button, 'click', - lambda button:self._emit('cancel')) - button_widgets = [('pack', save_button), - ('pack', cancel_button)] - button_columns = urwid.Columns(button_widgets, dividechars=2) - rows = [] - self.entry = urwid.Edit(edit_text=text, multiline=True) - rows.append(urwid.Text(u"%s message:" % action)) - rows.append(self.entry) - rows.append(urwid.Divider()) - rows.append(button_columns) - pile = urwid.Pile(rows) - fill = urwid.Filler(pile, valign='top') - super(AbandonRestoreDialog, self).__init__(urwid.LineBox(fill, '%s Change' % (action,))) - class CherryPickDialog(urwid.WidgetWrap): signals = ['save', 'cancel'] def __init__(self, change): @@ -400,6 +377,8 @@ class ChangeView(urwid.WidgetWrap): "Cherry-pick the most recent revision onto the local repo"), (key(keymap.ABANDON_CHANGE), "Abandon this change"), + (key(keymap.EDIT_COMMIT_MESSAGE), + "Edit the commit message of this change"), (key(keymap.REBASE_CHANGE), "Rebase this change (remotely)"), (key(keymap.RESTORE_CHANGE), @@ -778,6 +757,9 @@ class ChangeView(urwid.WidgetWrap): if keymap.ABANDON_CHANGE in commands: self.abandonChange() return None + if keymap.EDIT_COMMIT_MESSAGE in commands: + self.editCommitMessage() + return None if keymap.REBASE_CHANGE in commands: self.rebaseChange() return None @@ -808,14 +790,18 @@ class ChangeView(urwid.WidgetWrap): self.app.changeScreen(screen) def abandonChange(self): - dialog = AbandonRestoreDialog(u'Abandon', self.pending_status_message) + dialog = mywid.TextEditDialog(u'Abandon Change', u'Abandon message:', + u'Abandon Change', + self.pending_status_message) urwid.connect_signal(dialog, 'cancel', self.app.backScreen) urwid.connect_signal(dialog, 'save', lambda button: self.doAbandonRestoreChange(dialog, 'ABANDONED')) self.app.popup(dialog) def restoreChange(self): - dialog = AbandonRestoreDialog(u'Restore', self.pending_status_message) + dialog = mywid.TextEditDialog(u'Restore Change', u'Restore message:', + u'Restore Change', + self.pending_status_message) urwid.connect_signal(dialog, 'cancel', self.app.backScreen) urwid.connect_signal(dialog, 'save', lambda button: self.doAbandonRestoreChange(dialog, 'NEW')) @@ -834,6 +820,31 @@ class ChangeView(urwid.WidgetWrap): self.app.backScreen() self.refresh() + def editCommitMessage(self): + with self.app.db.getSession() as session: + change = session.getChange(self.change_key) + dialog = mywid.TextEditDialog(u'Edit Commit Message', u'Commit message:', + u'Save', change.revisions[-1].message) + urwid.connect_signal(dialog, 'cancel', self.app.backScreen) + urwid.connect_signal(dialog, 'save', lambda button: + self.doEditCommitMessage(dialog)) + self.app.popup(dialog, + relative_width=50, relative_height=75, + min_width=60, min_height=20) + + def doEditCommitMessage(self, dialog): + revision_key = None + with self.app.db.getSession() as session: + change = session.getChange(self.change_key) + revision = change.revisions[-1] + revision.message = dialog.entry.edit_text + revision.pending_message = True + revision_key = revision.key + self.app.sync.submitTask( + sync.ChangeCommitMessageTask(revision_key, sync.HIGH_PRIORITY)) + self.app.backScreen() + self.refresh() + def rebaseChange(self): dialog = mywid.YesNoDialog(u'Rebase Change', u'Perform a remote rebase of this change?')