Add WIP support
Change-Id: I3b690c3bffdb1ca534e42cef0c3c7d9b797f7e80
This commit is contained in:
parent
bb9d860dde
commit
94310529ed
|
@ -0,0 +1,31 @@
|
|||
"""fix_server_table
|
||||
|
||||
Revision ID: 02ca927a2b55
|
||||
Revises: 45d33eccc7a7
|
||||
Create Date: 2020-12-18 10:41:24.274607
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '02ca927a2b55'
|
||||
down_revision = '45d33eccc7a7'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# The original had a reference to own_account.key which is invalid and
|
||||
# caused later upgrades to fail. Drop and recreate the table to
|
||||
# correct; Gertty will fill in the data again.
|
||||
|
||||
def upgrade():
|
||||
op.drop_table('server')
|
||||
op.create_table('server',
|
||||
sa.Column('key', sa.Integer(), nullable=False),
|
||||
sa.Column('own_account_key', sa.Integer(), sa.ForeignKey('account.key'), index=True),
|
||||
sa.PrimaryKeyConstraint('key')
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
pass
|
|
@ -0,0 +1,42 @@
|
|||
"""wip
|
||||
|
||||
Revision ID: ad440301e47f
|
||||
Revises: 02ca927a2b55
|
||||
Create Date: 2020-12-18 10:42:07.689266
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'ad440301e47f'
|
||||
down_revision = '02ca927a2b55'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
import warnings
|
||||
|
||||
from gertty.dbsupport import sqlite_alter_columns
|
||||
|
||||
|
||||
def upgrade():
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
op.add_column('change', sa.Column('wip', sa.Boolean()))
|
||||
op.add_column('change', sa.Column('pending_wip', sa.Boolean()))
|
||||
op.add_column('change', sa.Column('pending_wip_message', sa.Text()))
|
||||
|
||||
connection = op.get_bind()
|
||||
change = sa.sql.table('change',
|
||||
sa.sql.column('wip', sa.Boolean()),
|
||||
sa.sql.column('pending_wip', sa.Boolean()))
|
||||
connection.execute(change.update().values({'wip':False,
|
||||
'pending_wip':False}))
|
||||
|
||||
sqlite_alter_columns('change', [
|
||||
sa.Column('wip', sa.Boolean(), index=True, nullable=False),
|
||||
sa.Column('pending_wip', sa.Boolean(), index=True, nullable=False),
|
||||
])
|
||||
|
||||
|
||||
def downgrade():
|
||||
pass
|
20
gertty/db.py
20
gertty/db.py
|
@ -84,6 +84,9 @@ change_table = Table(
|
|||
Column('pending_status_message', Text),
|
||||
Column('last_seen', DateTime, index=True),
|
||||
Column('outdated', Boolean, index=True, nullable=False),
|
||||
Column('wip', Boolean, index=True, nullable=False),
|
||||
Column('pending_wip', Boolean, index=True, nullable=False),
|
||||
Column('pending_wip_message', Text),
|
||||
)
|
||||
change_conflict_table = Table(
|
||||
'change_conflict', metadata,
|
||||
|
@ -316,11 +319,12 @@ class Topic(object):
|
|||
class Change(object):
|
||||
def __init__(self, project, id, owner, number, branch, change_id,
|
||||
subject, created, updated, status, topic=None,
|
||||
hidden=False, reviewed=False, starred=False, held=False,
|
||||
pending_rebase=False, pending_topic=False,
|
||||
pending_starred=False, pending_status=False,
|
||||
pending_status_message=None, pending_hashtags=False,
|
||||
outdated=False):
|
||||
hidden=False, reviewed=False, starred=False,
|
||||
wip=False, held=False, pending_rebase=False,
|
||||
pending_topic=False, pending_starred=False,
|
||||
pending_status=False, pending_status_message=None,
|
||||
pending_hashtags=False, pending_wip=False,
|
||||
pending_wip_message=None, outdated=False):
|
||||
self.project_key = project.key
|
||||
self.account_key = owner.key
|
||||
self.id = id
|
||||
|
@ -334,6 +338,7 @@ class Change(object):
|
|||
self.status = status
|
||||
self.hidden = hidden
|
||||
self.reviewed = reviewed
|
||||
self.wip = wip
|
||||
self.starred = starred
|
||||
self.held = held
|
||||
self.pending_rebase = pending_rebase
|
||||
|
@ -342,6 +347,8 @@ class Change(object):
|
|||
self.pending_starred = pending_starred
|
||||
self.pending_status = pending_status
|
||||
self.pending_status_message = pending_status_message
|
||||
self.pending_wip = pending_wip
|
||||
self.pending_wip_message = pending_wip_message
|
||||
self.outdated = outdated
|
||||
|
||||
def getCategories(self):
|
||||
|
@ -1098,6 +1105,9 @@ class DatabaseSession(object):
|
|||
def getPendingStarred(self):
|
||||
return self.session().query(Change).filter_by(pending_starred=True).all()
|
||||
|
||||
def getPendingWIP(self):
|
||||
return self.session().query(Change).filter_by(pending_wip=True).all()
|
||||
|
||||
def getPendingStatusChanges(self):
|
||||
return self.session().query(Change).filter_by(pending_status=True).all()
|
||||
|
||||
|
|
|
@ -57,6 +57,8 @@ PREV_CHANGE = 'previous change'
|
|||
TOGGLE_HIDDEN_COMMENTS = 'toggle hidden comments'
|
||||
ABANDON_CHANGE = 'abandon change'
|
||||
RESTORE_CHANGE = 'restore change'
|
||||
WIP_CHANGE = 'mark change work in progress'
|
||||
READY_CHANGE = 'mark change ready for review'
|
||||
REBASE_CHANGE = 'rebase change'
|
||||
CHERRY_PICK_CHANGE = 'cherry pick change'
|
||||
REFRESH = 'refresh'
|
||||
|
@ -126,6 +128,8 @@ DEFAULT_KEYMAP = {
|
|||
TOGGLE_HIDDEN_COMMENTS: 't',
|
||||
ABANDON_CHANGE: 'ctrl a',
|
||||
RESTORE_CHANGE: 'ctrl e',
|
||||
WIP_CHANGE: 'ctrl w',
|
||||
READY_CHANGE: 'ctrl y',
|
||||
REBASE_CHANGE: 'ctrl b',
|
||||
CHERRY_PICK_CHANGE: 'ctrl x',
|
||||
REFRESH: 'ctrl r',
|
||||
|
|
|
@ -688,6 +688,10 @@ class SyncChangeTask(Task):
|
|||
change.starred = True
|
||||
else:
|
||||
change.starred = False
|
||||
if remote_change.get('work_in_progress'):
|
||||
change.wip = True
|
||||
else:
|
||||
change.wip = False
|
||||
change.subject = remote_change['subject']
|
||||
change.updated = dateutil.parser.parse(remote_change['updated'])
|
||||
change.topic = remote_change.get('topic')
|
||||
|
@ -1079,6 +1083,8 @@ class UploadReviewsTask(Task):
|
|||
sync.submitTask(ChangeStatusTask(c.key, self.priority))
|
||||
for c in session.getPendingStarred():
|
||||
sync.submitTask(ChangeStarredTask(c.key, self.priority))
|
||||
for c in session.getPendingWIP():
|
||||
sync.submitTask(ChangeWIPTask(c.key, self.priority))
|
||||
for c in session.getPendingCherryPicks():
|
||||
sync.submitTask(SendCherryPickTask(c.key, self.priority))
|
||||
for r in session.getPendingCommitMessages():
|
||||
|
@ -1228,15 +1234,44 @@ class ChangeStatusTask(Task):
|
|||
change.pending_status_message = None
|
||||
# Inside db session for rollback
|
||||
if change.status == 'ABANDONED':
|
||||
sync.post('changes/%s/abandon' % (change.id,),
|
||||
data)
|
||||
sync.post('changes/%s/abandon' % (change.id,), data)
|
||||
elif change.status == 'NEW':
|
||||
sync.post('changes/%s/restore' % (change.id,),
|
||||
data)
|
||||
sync.post('changes/%s/restore' % (change.id,), data)
|
||||
elif change.status == 'SUBMITTED':
|
||||
sync.post('changes/%s/submit' % (change.id,), {})
|
||||
sync.submitTask(SyncChangeTask(change.id, priority=self.priority))
|
||||
|
||||
class ChangeWIPTask(Task):
|
||||
def __init__(self, change_key, priority=NORMAL_PRIORITY):
|
||||
super(ChangeWIPTask, self).__init__(priority)
|
||||
self.change_key = change_key
|
||||
|
||||
def __repr__(self):
|
||||
return '<ChangeWIPTask %s>' % (self.change_key,)
|
||||
|
||||
def __eq__(self, other):
|
||||
if (other.__class__ == self.__class__ and
|
||||
other.change_key == self.change_key):
|
||||
return True
|
||||
return False
|
||||
|
||||
def run(self, sync):
|
||||
app = sync.app
|
||||
with app.db.getSession() as session:
|
||||
change = session.getChange(self.change_key)
|
||||
if change.pending_wip_message:
|
||||
data = dict(message=change.pending_wip_message)
|
||||
else:
|
||||
data = {}
|
||||
change.pending_wip = False
|
||||
change.pending_wip_message = None
|
||||
# Inside db session for rollback
|
||||
if change.wip:
|
||||
sync.post('changes/%s/wip' % (change.id,), data)
|
||||
else:
|
||||
sync.post('changes/%s/ready' % (change.id,), data)
|
||||
sync.submitTask(SyncChangeTask(change.id, priority=self.priority))
|
||||
|
||||
class SendCherryPickTask(Task):
|
||||
def __init__(self, cp_key, priority=NORMAL_PRIORITY):
|
||||
super(SendCherryPickTask, self).__init__(priority)
|
||||
|
|
|
@ -555,6 +555,8 @@ class ChangeView(urwid.WidgetWrap):
|
|||
"Rebase this change (remotely)"),
|
||||
(keymap.RESTORE_CHANGE,
|
||||
"Restore this change"),
|
||||
(keymap.READY_CHANGE,
|
||||
"Mark this change ready for review"),
|
||||
(keymap.REFRESH,
|
||||
"Refresh this change"),
|
||||
(keymap.EDIT_TOPIC,
|
||||
|
@ -565,6 +567,8 @@ class ChangeView(urwid.WidgetWrap):
|
|||
"Submit this change"),
|
||||
(keymap.CHERRY_PICK_CHANGE,
|
||||
"Propose this change to another branch"),
|
||||
(keymap.WIP_CHANGE,
|
||||
"Mark this change work in progress"),
|
||||
]
|
||||
|
||||
def help(self):
|
||||
|
@ -734,7 +738,8 @@ class ChangeView(urwid.WidgetWrap):
|
|||
self.hashtags_label.set_text(('change-data', ' '.join([x.name for x in change.hashtags])))
|
||||
self.created_label.set_text(('change-data', str(self.app.time(change.created))))
|
||||
self.updated_label.set_text(('change-data', str(self.app.time(change.updated))))
|
||||
self.status_label.set_text(('change-data', change.status))
|
||||
stat = change.wip and 'WIP' or change.status
|
||||
self.status_label.set_text(('change-data', stat))
|
||||
self.permalink_url = urlparse.urljoin(self.app.config.url, str(change.number))
|
||||
self.permalink_label.text.set_text(('change-data', self.permalink_url))
|
||||
self.commit_message.set_text(change.revisions[-1].message)
|
||||
|
@ -1043,6 +1048,12 @@ class ChangeView(urwid.WidgetWrap):
|
|||
if keymap.ABANDON_CHANGE in commands:
|
||||
self.abandonChange()
|
||||
return None
|
||||
if keymap.WIP_CHANGE in commands:
|
||||
self.wipChange()
|
||||
return None
|
||||
if keymap.READY_CHANGE in commands:
|
||||
self.readyChange()
|
||||
return None
|
||||
if keymap.EDIT_COMMIT_MESSAGE in commands:
|
||||
self.editCommitMessage()
|
||||
return None
|
||||
|
@ -1112,6 +1123,39 @@ class ChangeView(urwid.WidgetWrap):
|
|||
self.app.backScreen()
|
||||
self.refresh()
|
||||
|
||||
def wipChange(self):
|
||||
dialog = mywid.TextEditDialog(u'Mark Change Work In Progress',
|
||||
u'WIP message:',
|
||||
u'WIP Change',
|
||||
self.pending_status_message)
|
||||
urwid.connect_signal(dialog, 'cancel', self.app.backScreen)
|
||||
urwid.connect_signal(dialog, 'save', lambda button:
|
||||
self.doWip(dialog, True))
|
||||
self.app.popup(dialog)
|
||||
|
||||
def readyChange(self):
|
||||
dialog = mywid.TextEditDialog(u'Mark Change Ready For Review',
|
||||
u'Ready message:',
|
||||
u'Ready Change',
|
||||
self.pending_status_message)
|
||||
urwid.connect_signal(dialog, 'cancel', self.app.backScreen)
|
||||
urwid.connect_signal(dialog, 'save', lambda button:
|
||||
self.doWip(dialog, False))
|
||||
self.app.popup(dialog)
|
||||
|
||||
def doWip(self, dialog, state):
|
||||
change_key = None
|
||||
with self.app.db.getSession() as session:
|
||||
change = session.getChange(self.change_key)
|
||||
change.wip = state
|
||||
change.pending_wip = True
|
||||
change.pending_wip_message = dialog.entry.edit_text
|
||||
change_key = change.key
|
||||
self.app.sync.submitTask(
|
||||
sync.ChangeWIPTask(change_key, sync.HIGH_PRIORITY))
|
||||
self.app.backScreen()
|
||||
self.refresh()
|
||||
|
||||
def editCommitMessage(self):
|
||||
with self.app.db.getSession() as session:
|
||||
change = session.getChange(self.change_key)
|
||||
|
|
Loading…
Reference in New Issue