From 6f50f9425ae33663aa9335c7bdf2e4f111469f0e Mon Sep 17 00:00:00 2001
From: "James E. Blair" <jeblair@hp.com>
Date: Sun, 31 Aug 2014 09:51:01 -0700
Subject: [PATCH] Add database pre-reqs for change actions

Add the fields needed to support topic and commit message editing,
cherry-picking, rebasing, and abandon/restore.

Change-Id: If5103701c008907eade5dee50fc1ed18521188df
---
 .../46b175bfa277_add_pending_actions.py       | 66 +++++++++++++++++++
 gertty/db.py                                  | 57 +++++++++++++++-
 2 files changed, 121 insertions(+), 2 deletions(-)
 create mode 100644 gertty/alembic/versions/46b175bfa277_add_pending_actions.py

diff --git a/gertty/alembic/versions/46b175bfa277_add_pending_actions.py b/gertty/alembic/versions/46b175bfa277_add_pending_actions.py
new file mode 100644
index 0000000..a3e27f8
--- /dev/null
+++ b/gertty/alembic/versions/46b175bfa277_add_pending_actions.py
@@ -0,0 +1,66 @@
+"""add pending actions
+
+Revision ID: 46b175bfa277
+Revises: 3d429503a29a
+Create Date: 2014-08-31 09:20:11.789330
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '46b175bfa277'
+down_revision = '3d429503a29a'
+
+import warnings
+
+from alembic import op
+import sqlalchemy as sa
+
+from gertty.dbsupport import sqlite_alter_columns
+
+
+def upgrade():
+    op.create_table('branch',
+    sa.Column('key', sa.Integer(), nullable=False),
+    sa.Column('project_key', sa.Integer(), sa.ForeignKey('project.key'), index=True, nullable=False),
+    sa.Column('name', sa.String(length=255), nullable=False),
+    sa.PrimaryKeyConstraint('key')
+    )
+    op.create_table('pending_cherry_pick',
+    sa.Column('key', sa.Integer(), nullable=False),
+    sa.Column('revision_key', sa.Integer(), sa.ForeignKey('revision.key'), index=True, nullable=False),
+    sa.Column('branch', sa.String(length=255), nullable=False),
+    sa.Column('message', sa.Text(), nullable=False),
+    sa.PrimaryKeyConstraint('key')
+    )
+
+    with warnings.catch_warnings():
+        warnings.simplefilter("ignore")
+        op.add_column('change', sa.Column('pending_rebase', sa.Boolean()))
+        op.add_column('change', sa.Column('pending_topic', sa.Boolean()))
+        op.add_column('change', sa.Column('pending_status', sa.Boolean()))
+        op.add_column('change', sa.Column('pending_status_message', sa.Text()))
+        op.add_column('revision', sa.Column('pending_message', sa.Boolean()))
+
+    connection = op.get_bind()
+    change = sa.sql.table('change',
+                          sa.sql.column('pending_rebase', sa.Boolean()),
+                          sa.sql.column('pending_topic', sa.Boolean()),
+                          sa.sql.column('pending_status', sa.Boolean()))
+    connection.execute(change.update().values({'pending_rebase':False,
+                                               'pending_topic':False,
+                                               'pending_status':False}))
+    revision = sa.sql.table('revision',
+                            sa.sql.column('pending_message', sa.Boolean()))
+    connection.execute(revision.update().values({'pending_message':False}))
+
+    sqlite_alter_columns('change', [
+        sa.Column('pending_rebase', sa.Boolean(), index=True, nullable=False),
+        sa.Column('pending_topic', sa.Boolean(), index=True, nullable=False),
+        sa.Column('pending_status', sa.Boolean(), index=True, nullable=False),
+        ])
+    sqlite_alter_columns('revision', [
+        sa.Column('pending_message', sa.Boolean(), index=True, nullable=False),
+        ])
+
+def downgrade():
+    pass
diff --git a/gertty/db.py b/gertty/db.py
index e0c97ca..e98ade2 100644
--- a/gertty/db.py
+++ b/gertty/db.py
@@ -36,6 +36,12 @@ project_table = Table(
     Column('description', Text, nullable=False, default=''),
     Column('updated', DateTime, index=True),
     )
+branch_table = Table(
+    'branch', metadata,
+    Column('key', Integer, primary_key=True),
+    Column('project_key', Integer, ForeignKey("project.key"), index=True),
+    Column('name', String(255), index=True, nullable=False),
+    )
 change_table = Table(
     'change', metadata,
     Column('key', Integer, primary_key=True),
@@ -52,6 +58,10 @@ change_table = Table(
     Column('status', String(16), index=True, nullable=False),
     Column('hidden', Boolean, index=True, nullable=False),
     Column('reviewed', Boolean, index=True, nullable=False),
+    Column('pending_rebase', Boolean, index=True, nullable=False),
+    Column('pending_topic', Boolean, index=True, nullable=False),
+    Column('pending_status', Boolean, index=True, nullable=False),
+    Column('pending_status_message', Text),
     )
 revision_table = Table(
     'revision', metadata,
@@ -63,6 +73,7 @@ revision_table = Table(
     Column('parent', String(255), nullable=False),
     Column('fetch_auth', Boolean, nullable=False),
     Column('fetch_ref', String(255), nullable=False),
+    Column('pending_message', Boolean, index=True, nullable=False),
     )
 message_table = Table(
     'message', metadata,
@@ -121,6 +132,15 @@ account_table = Table(
     Column('username', String(255), index=True),
     Column('email', String(255), index=True),
     )
+pending_cherry_pick_table = Table(
+    'pending_cherry_pick', metadata,
+    Column('key', Integer, primary_key=True),
+    Column('revision_key', Integer, ForeignKey("revision.key"), index=True),
+    # Branch is a str here to avoid FK complications if the branch
+    # entry is removed.
+    Column('branch', String(255), nullable=False),
+    Column('message', Text, nullable=False),
+    )
 
 class Account(object):
     def __init__(self, id, name=None, username=None, email=None):
@@ -144,10 +164,26 @@ class Project(object):
         session.flush()
         return c
 
+    def createBranch(self, *args, **kw):
+        session = Session.object_session(self)
+        args = [self] + list(args)
+        b = Branch(*args, **kw)
+        self.branches.append(b)
+        session.add(b)
+        session.flush()
+        return b
+
+class Branch(object):
+    def __init__(self, project, name):
+        self.project_key = project.key
+        self.name = name
+
 class Change(object):
     def __init__(self, project, id, owner, number, branch,
                  change_id, subject, created, updated, status,
-                 topic=False, hidden=False, reviewed=False):
+                 topic=None, hidden=False, reviewed=False,
+                 pending_rebase=False, pending_topic=False,
+                 pending_status=False, pending_status_message=None):
         self.project_key = project.key
         self.account_key = owner.key
         self.id = id
@@ -161,6 +197,10 @@ class Change(object):
         self.status = status
         self.hidden = hidden
         self.reviewed = reviewed
+        self.pending_rebase = pending_rebase
+        self.pending_topic = pending_topic
+        self.pending_status = pending_status
+        self.pending_status_message = pending_status_message
 
     def getCategories(self):
         categories = []
@@ -231,7 +271,8 @@ class Change(object):
         return l
 
 class Revision(object):
-    def __init__(self, change, number, message, commit, parent, fetch_auth, fetch_ref):
+    def __init__(self, change, number, message, commit, parent,
+                 fetch_auth, fetch_ref, pending_message=False):
         self.change_key = change.key
         self.number = number
         self.message = message
@@ -239,6 +280,7 @@ class Revision(object):
         self.parent = parent
         self.fetch_auth = fetch_auth
         self.fetch_ref = fetch_ref
+        self.pending_message = pending_message
 
     def createMessage(self, *args, **kw):
         session = Session.object_session(self)
@@ -315,8 +357,16 @@ class Approval(object):
         self.value = value
         self.draft = draft
 
+class PendingCherryPick(object):
+    def __init__(self, revision, branch, message):
+        self.revision_key = revision.key
+        self.branch = branch
+        self.message = message
+
 mapper(Account, account_table)
 mapper(Project, project_table, properties=dict(
+        branches=relationship(Branch, backref='project',
+                              order_by=branch_table.c.key),
         changes=relationship(Change, backref='project',
                              order_by=change_table.c.number),
         unreviewed_changes=relationship(Change,
@@ -334,6 +384,7 @@ mapper(Project, project_table, properties=dict(
                                   order_by=change_table.c.number,
                                   ),
         ))
+mapper(Branch, branch_table)
 mapper(Change, change_table, properties=dict(
         owner=relationship(Account),
         revisions=relationship(Revision, backref='change',
@@ -373,6 +424,8 @@ mapper(Label, label_table)
 mapper(PermittedLabel, permitted_label_table)
 mapper(Approval, approval_table, properties=dict(
         reviewer=relationship(Account)))
+mapper(PendingCherryPick, pending_cherry_pick_table, properties=dict(
+        revision=relationship(Revision)))
 
 class Database(object):
     def __init__(self, app):