diff --git a/storyboard/db/migration/alembic_migrations/versions/001_initial_version.py b/storyboard/db/migration/alembic_migrations/versions/001_initial_version.py index 81992cb8..2a1abb58 100644 --- a/storyboard/db/migration/alembic_migrations/versions/001_initial_version.py +++ b/storyboard/db/migration/alembic_migrations/versions/001_initial_version.py @@ -61,337 +61,345 @@ def _define_enums(): def upgrade(active_plugins=None, options=None): + dialect = op.get_bind().engine.dialect enums = _define_enums() - op.create_table( - 'project_groups', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('created_at', sa.DateTime(), nullable=True), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.Column('name', sa.String(length=50), nullable=True), - sa.Column('title', sa.Unicode(length=255), nullable=True), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('name', name='uniq_group_name'), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table( - 'user_preferences', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('created_at', sa.DateTime(), nullable=True), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.Column('user_id', sa.Integer(), nullable=False), - sa.Column('key', sa.Unicode(100), nullable=False), - sa.Column('type', enums['pref_type'], nullable=False), - sa.Column('value', sa.Unicode(255), nullable=False), - sa.PrimaryKeyConstraint('id') - ) - op.create_table( - 'users', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('created_at', sa.DateTime(), nullable=True), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.Column('full_name', sa.Unicode(255), nullable=True), - sa.Column('email', sa.String(length=255), nullable=True), - sa.Column('openid', sa.String(255)), - sa.Column('is_staff', sa.Boolean(), nullable=True), - sa.Column('is_active', sa.Boolean(), nullable=True), - sa.Column('is_superuser', sa.Boolean(), nullable=True), - sa.Column('last_login', sa.DateTime(), nullable=True), - sa.Column('enable_login', sa.Boolean(), default=True, - server_default="1", nullable=False), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('email', name='uniq_user_email'), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table( - 'teams', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('created_at', sa.DateTime(), nullable=True), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.Column('name', sa.Unicode(length=255), nullable=True), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('name', name='uniq_team_name'), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table( - 'permissions', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('created_at', sa.DateTime(), nullable=True), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.Column('name', sa.Unicode(length=50), nullable=True), - sa.Column('codename', sa.Unicode(length=255), nullable=True), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('name', name='uniq_permission_name'), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table( - 'team_membership', - sa.Column('user_id', sa.Integer(), nullable=True), - sa.Column('team_id', sa.Integer(), nullable=True), - sa.ForeignKeyConstraint(['team_id'], ['teams.id'], ), - sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), - sa.PrimaryKeyConstraint(), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table( - 'user_permissions', - sa.Column('user_id', sa.Integer(), nullable=True), - sa.Column('permission_id', sa.Integer(), nullable=True), - sa.ForeignKeyConstraint(['permission_id'], ['permissions.id'], ), - sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), - sa.PrimaryKeyConstraint(), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table( - 'team_permissions', - sa.Column('permission_id', sa.Integer(), nullable=True), - sa.Column('team_id', sa.Integer(), nullable=True), - sa.ForeignKeyConstraint(['team_id'], ['teams.id'], ), - sa.ForeignKeyConstraint(['permission_id'], ['permissions.id'], ), - sa.PrimaryKeyConstraint(), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table( - 'stories', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('created_at', sa.DateTime(), nullable=True), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.Column('creator_id', sa.Integer(), nullable=True), - sa.Column('title', sa.Unicode(length=255), nullable=True), - sa.Column('description', sa.UnicodeText(), nullable=True), - sa.Column('is_bug', sa.Boolean(), nullable=True), - sa.Column('story_type_id', sa.Integer(), default=1), - sa.ForeignKeyConstraint(['creator_id'], ['users.id'], ), - sa.PrimaryKeyConstraint('id'), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table( - 'projects', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('created_at', sa.DateTime(), nullable=True), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.Column('name', sa.String(length=50), nullable=True), - sa.Column('description', sa.UnicodeText(), nullable=True), - sa.Column('team_id', sa.Integer(), nullable=True), - sa.Column('is_active', sa.Boolean(), default=True, - server_default='1', nullable=False), - sa.Column('repo_url', sa.String(255), default=None, nullable=True), - sa.Column('autocreate_branches', sa.Boolean(), default=False), - sa.ForeignKeyConstraint(['team_id'], ['teams.id'], ), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('name', name='uniq_project_name'), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table( - 'project_group_mapping', - sa.Column('project_id', sa.Integer(), nullable=True), - sa.Column('project_group_id', sa.Integer(), nullable=True), - sa.ForeignKeyConstraint(['project_group_id'], ['project_groups.id'], ), - sa.ForeignKeyConstraint(['project_id'], ['projects.id'], ), - sa.PrimaryKeyConstraint(), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table( - 'tasks', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('created_at', sa.DateTime(), nullable=True), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.Column('title', sa.Unicode(length=255), nullable=True), - sa.Column('status', enums['task_status'], nullable=True), - sa.Column('story_id', sa.Integer(), nullable=True), - sa.Column('project_id', sa.Integer(), nullable=True), - sa.Column('assignee_id', sa.Integer(), nullable=True), - sa.Column('creator_id', sa.Integer(), nullable=True), - sa.Column('priority', enums['task_priority'], nullable=True), - sa.Column('branch_id', sa.Integer(), nullable=True), - sa.Column('milestone_id', sa.Integer(), nullable=True), - sa.ForeignKeyConstraint(['assignee_id'], ['users.id'], - name='tasks_ibfk_1'), - sa.ForeignKeyConstraint(['project_id'], ['projects.id'], - name='tasks_ibfk_3'), - sa.ForeignKeyConstraint(['story_id'], ['stories.id'], - name='tasks_ibfk_4'), - sa.PrimaryKeyConstraint('id'), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table( - 'events', - sa.Column('created_at', sa.DateTime(), nullable=True), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('story_id', sa.Integer(), nullable=True), - sa.Column('comment_id', sa.Integer(), nullable=True), - sa.Column('author_id', sa.Integer(), nullable=True), - sa.Column('event_type', sa.Unicode(length=100), nullable=False), - sa.Column('event_info', sa.UnicodeText(), nullable=True), - sa.PrimaryKeyConstraint('id'), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table( - 'comments', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('created_at', sa.DateTime(), nullable=True), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.Column('content', type_=MYSQL_MEDIUM_TEXT, nullable=True), - sa.Column('is_active', sa.Boolean(), default=True, - server_default='1', nullable=False), - sa.PrimaryKeyConstraint('id'), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table( - 'storytags', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('created_at', sa.DateTime(), nullable=True), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.Column('name', sa.String(length=50), nullable=True), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('name', name='uniq_story_tags_name'), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table('story_storytags', - sa.Column('story_id', sa.Integer(), nullable=True), - sa.Column('storytag_id', sa.Integer(), nullable=True), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table( - 'subscriptions', - sa.Column('created_at', sa.DateTime(), nullable=True), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('user_id', sa.Integer(), nullable=True), - sa.Column('target_type', enums['target_type'], nullable=True), - sa.Column('target_id', sa.Integer(), nullable=True), - sa.PrimaryKeyConstraint('id'), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table( - 'subscription_events', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('created_at', sa.DateTime(), nullable=True), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.Column('subscriber_id', sa.Integer(), nullable=False), - sa.Column('event_type', sa.Unicode(100), nullable=False), - sa.Column('event_info', sa.UnicodeText(), nullable=True), - sa.Column('author_id', sa.Integer()), - sa.PrimaryKeyConstraint('id'), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table( - 'authorizationcodes', - sa.Column('created_at', sa.DateTime(), nullable=True), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('code', sa.Unicode(100), nullable=False), - sa.Column('state', sa.Unicode(100), nullable=False), - sa.Column('user_id', sa.Integer(), nullable=False), - sa.Column('expires_in', sa.Integer(), nullable=False), - sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), - sa.PrimaryKeyConstraint('id'), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table( - 'accesstokens', - sa.Column('created_at', sa.DateTime(), nullable=True), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('user_id', sa.Integer(), nullable=False), - sa.Column('access_token', sa.Unicode(length=100), nullable=False), - sa.Column('expires_in', sa.Integer(), nullable=False), - sa.Column('expires_at', sa.DateTime(), nullable=False), - sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), - sa.PrimaryKeyConstraint('id'), - mysql_default_charset=MYSQL_CHARSET, - mysql_engine=MYSQL_ENGINE - ) - op.create_table( - 'refreshtokens', - sa.Column('created_at', sa.DateTime(), nullable=True), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('user_id', sa.Integer(), nullable=False), - sa.Column('refresh_token', sa.Unicode(length=100), nullable=False), - sa.Column('expires_at', sa.DateTime(), nullable=False), - sa.Column('expires_in', sa.Integer(), nullable=False), - sa.Column('access_token_id', sa.Integer(), nullable=False), - sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), - sa.PrimaryKeyConstraint('id'), - mysql_default_charset=MYSQL_CHARSET, - mysql_engine=MYSQL_ENGINE - ) - op.create_table( - 'branches', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('name', sa.String(100), nullable=True), - sa.Column('project_id', sa.Integer(), nullable=True), - sa.Column('created_at', sa.DateTime(), nullable=True), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.Column('expired', sa.Boolean(), default=False, nullable=True), - sa.Column('expiration_date', sa.DateTime(), default=None, - nullable=True), - sa.Column('autocreated', sa.Boolean(), default=False, nullable=True), - sa.Column('restricted', sa.Boolean(), default=False), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('name', 'project_id', name="branch_un_constr"), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table( - 'milestones', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('name', sa.String(100), nullable=True), - sa.Column('branch_id', sa.Integer(), nullable=True), - sa.Column('created_at', sa.DateTime(), nullable=True), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.Column('expired', sa.Boolean(), default=False, nullable=True), - sa.Column('expiration_date', sa.DateTime(), default=None), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('name', 'branch_id', name="milestone_un_constr"), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table( - 'story_types', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('created_at', sa.DateTime(), nullable=True), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.Column('name', sa.String(50), nullable=True), - sa.Column('icon', sa.String(50), nullable=True), - sa.Column('restricted', sa.Boolean(), default=False), - sa.Column('private', sa.Boolean(), default=False), - sa.Column('visible', sa.Boolean(), default=True), - sa.PrimaryKeyConstraint('id'), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) - op.create_table( - 'may_mutate_to', - sa.Column('story_type_id_from', sa.Integer(), nullable=False), - sa.Column('story_type_id_to', sa.Integer(), nullable=False), - sa.UniqueConstraint('story_type_id_from', - 'story_type_id_to', - name="mutate_un_constr"), - sa.PrimaryKeyConstraint(), - mysql_engine=MYSQL_ENGINE, - mysql_charset=MYSQL_CHARSET - ) + if dialect.supports_alter: + op.create_table( + 'project_groups', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('name', sa.String(length=50), nullable=True), + sa.Column('title', sa.Unicode(length=255), nullable=True), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('name', name='uniq_group_name'), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'user_preferences', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('user_id', sa.Integer(), nullable=False), + sa.Column('key', sa.Unicode(100), nullable=False), + sa.Column('type', enums['pref_type'], nullable=False), + sa.Column('value', sa.Unicode(255), nullable=False), + sa.PrimaryKeyConstraint('id') + ) + op.create_table( + 'users', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('full_name', sa.Unicode(255), nullable=True), + sa.Column('email', sa.String(length=255), nullable=True), + sa.Column('openid', sa.String(255)), + sa.Column('is_staff', sa.Boolean(), nullable=True), + sa.Column('is_active', sa.Boolean(), nullable=True), + sa.Column('is_superuser', sa.Boolean(), nullable=True), + sa.Column('last_login', sa.DateTime(), nullable=True), + sa.Column('enable_login', sa.Boolean(), default=True, + server_default="1", nullable=False), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('email', name='uniq_user_email'), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'teams', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('name', sa.Unicode(length=255), nullable=True), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('name', name='uniq_team_name'), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'permissions', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('name', sa.Unicode(length=50), nullable=True), + sa.Column('codename', sa.Unicode(length=255), nullable=True), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('name', name='uniq_permission_name'), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'team_membership', + sa.Column('user_id', sa.Integer(), nullable=True), + sa.Column('team_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['team_id'], ['teams.id'], ), + sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), + sa.PrimaryKeyConstraint(), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'user_permissions', + sa.Column('user_id', sa.Integer(), nullable=True), + sa.Column('permission_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['permission_id'], ['permissions.id'], ), + sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), + sa.PrimaryKeyConstraint(), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'team_permissions', + sa.Column('permission_id', sa.Integer(), nullable=True), + sa.Column('team_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['team_id'], ['teams.id'], ), + sa.ForeignKeyConstraint(['permission_id'], ['permissions.id'], ), + sa.PrimaryKeyConstraint(), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'stories', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('creator_id', sa.Integer(), nullable=True), + sa.Column('title', sa.Unicode(length=255), nullable=True), + sa.Column('description', sa.UnicodeText(), nullable=True), + sa.Column('is_bug', sa.Boolean(), nullable=True), + sa.Column('story_type_id', sa.Integer(), default=1), + sa.ForeignKeyConstraint(['creator_id'], ['users.id'], ), + sa.PrimaryKeyConstraint('id'), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'projects', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('name', sa.String(length=50), nullable=True), + sa.Column('description', sa.UnicodeText(), nullable=True), + sa.Column('team_id', sa.Integer(), nullable=True), + sa.Column('is_active', sa.Boolean(), default=True, + server_default='1', nullable=False), + sa.Column('repo_url', sa.String(255), default=None, nullable=True), + sa.Column('autocreate_branches', sa.Boolean(), default=False), + sa.ForeignKeyConstraint(['team_id'], ['teams.id'], ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('name', name='uniq_project_name'), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'project_group_mapping', + sa.Column('project_id', sa.Integer(), nullable=True), + sa.Column('project_group_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint( + ['project_group_id'], + ['project_groups.id'], + ), + sa.ForeignKeyConstraint(['project_id'], ['projects.id'], ), + sa.PrimaryKeyConstraint(), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'tasks', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('title', sa.Unicode(length=255), nullable=True), + sa.Column('status', enums['task_status'], nullable=True), + sa.Column('story_id', sa.Integer(), nullable=True), + sa.Column('project_id', sa.Integer(), nullable=True), + sa.Column('assignee_id', sa.Integer(), nullable=True), + sa.Column('creator_id', sa.Integer(), nullable=True), + sa.Column('priority', enums['task_priority'], nullable=True), + sa.Column('branch_id', sa.Integer(), nullable=True), + sa.Column('milestone_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['assignee_id'], ['users.id'], + name='tasks_ibfk_1'), + sa.ForeignKeyConstraint(['project_id'], ['projects.id'], + name='tasks_ibfk_3'), + sa.ForeignKeyConstraint(['story_id'], ['stories.id'], + name='tasks_ibfk_4'), + sa.PrimaryKeyConstraint('id'), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'events', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('story_id', sa.Integer(), nullable=True), + sa.Column('comment_id', sa.Integer(), nullable=True), + sa.Column('author_id', sa.Integer(), nullable=True), + sa.Column('event_type', sa.Unicode(length=100), nullable=False), + sa.Column('event_info', sa.UnicodeText(), nullable=True), + sa.PrimaryKeyConstraint('id'), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'comments', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('content', type_=MYSQL_MEDIUM_TEXT, nullable=True), + sa.Column('is_active', sa.Boolean(), default=True, + server_default='1', nullable=False), + sa.PrimaryKeyConstraint('id'), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'storytags', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('name', sa.String(length=50), nullable=True), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('name', name='uniq_story_tags_name'), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'story_storytags', + sa.Column('story_id', sa.Integer(), nullable=True), + sa.Column('storytag_id', sa.Integer(), nullable=True), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'subscriptions', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('user_id', sa.Integer(), nullable=True), + sa.Column('target_type', enums['target_type'], nullable=True), + sa.Column('target_id', sa.Integer(), nullable=True), + sa.PrimaryKeyConstraint('id'), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'subscription_events', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('subscriber_id', sa.Integer(), nullable=False), + sa.Column('event_type', sa.Unicode(100), nullable=False), + sa.Column('event_info', sa.UnicodeText(), nullable=True), + sa.Column('author_id', sa.Integer()), + sa.PrimaryKeyConstraint('id'), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'authorizationcodes', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('code', sa.Unicode(100), nullable=False), + sa.Column('state', sa.Unicode(100), nullable=False), + sa.Column('user_id', sa.Integer(), nullable=False), + sa.Column('expires_in', sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), + sa.PrimaryKeyConstraint('id'), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'accesstokens', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('user_id', sa.Integer(), nullable=False), + sa.Column('access_token', sa.Unicode(length=100), nullable=False), + sa.Column('expires_in', sa.Integer(), nullable=False), + sa.Column('expires_at', sa.DateTime(), nullable=False), + sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), + sa.PrimaryKeyConstraint('id'), + mysql_default_charset=MYSQL_CHARSET, + mysql_engine=MYSQL_ENGINE + ) + op.create_table( + 'refreshtokens', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('user_id', sa.Integer(), nullable=False), + sa.Column('refresh_token', sa.Unicode(length=100), nullable=False), + sa.Column('expires_at', sa.DateTime(), nullable=False), + sa.Column('expires_in', sa.Integer(), nullable=False), + sa.Column('access_token_id', sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), + sa.PrimaryKeyConstraint('id'), + mysql_default_charset=MYSQL_CHARSET, + mysql_engine=MYSQL_ENGINE + ) + op.create_table( + 'branches', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(100), nullable=True), + sa.Column('project_id', sa.Integer(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('expired', sa.Boolean(), default=False, nullable=True), + sa.Column('expiration_date', sa.DateTime(), default=None, + nullable=True), + sa.Column('autocreated', sa.Boolean(), default=False, + nullable=True), + sa.Column('restricted', sa.Boolean(), default=False), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('name', 'project_id', name="branch_un_constr"), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'milestones', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(100), nullable=True), + sa.Column('branch_id', sa.Integer(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('expired', sa.Boolean(), default=False, nullable=True), + sa.Column('expiration_date', sa.DateTime(), default=None), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('name', 'branch_id', + name="milestone_un_constr"), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'story_types', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('name', sa.String(50), nullable=True), + sa.Column('icon', sa.String(50), nullable=True), + sa.Column('restricted', sa.Boolean(), default=False), + sa.Column('private', sa.Boolean(), default=False), + sa.Column('visible', sa.Boolean(), default=True), + sa.PrimaryKeyConstraint('id'), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) + op.create_table( + 'may_mutate_to', + sa.Column('story_type_id_from', sa.Integer(), nullable=False), + sa.Column('story_type_id_to', sa.Integer(), nullable=False), + sa.UniqueConstraint('story_type_id_from', + 'story_type_id_to', + name="mutate_un_constr"), + sa.PrimaryKeyConstraint(), + mysql_engine=MYSQL_ENGINE, + mysql_charset=MYSQL_CHARSET + ) # Create story types bind = op.get_bind() @@ -454,34 +462,37 @@ def upgrade(active_plugins=None, options=None): story_type_id_to=1 )) - op.create_index('accesstokens_access_token_idx', - 'accesstokens', ['access_token']) + if dialect.supports_alter: + op.create_index('accesstokens_access_token_idx', + 'accesstokens', ['access_token']) - version_info = op.get_bind().engine.dialect.server_version_info - if version_info[-1] == "MariaDB": - # Removes fake mysql prefix - version_info = version_info[-4:] - if version_info[0] < 5 or version_info[0] == 5 and version_info[1] < 6: - LOG.warning( - "MySQL version is lower than 5.6. Skipping full-text indexes") - return + version_info = op.get_bind().engine.dialect.server_version_info + if version_info[-1] == "MariaDB": + # Removes fake mysql prefix + version_info = version_info[-4:] + if version_info[0] < 5 or version_info[0] == 5 and version_info[1] < 6: + LOG.warning( + "MySQL version is lower than 5.6. Skipping full-text indexes") + return - # Index for projects - op.execute("ALTER TABLE projects " - "ADD FULLTEXT projects_fti (name, description)") + # Index for projects + op.execute("ALTER TABLE projects " + "ADD FULLTEXT projects_fti (name, description)") - # Index for stories - op.execute("ALTER TABLE stories " - "ADD FULLTEXT stories_fti (title, description)") + # Index for stories + op.execute("ALTER TABLE stories " + "ADD FULLTEXT stories_fti (title, description)") - # Index for tasks - op.execute("ALTER TABLE tasks ADD FULLTEXT tasks_fti (title)") + # Index for tasks + op.execute("ALTER TABLE tasks ADD FULLTEXT tasks_fti (title)") - # Index for comments - op.execute("ALTER TABLE comments ADD FULLTEXT comments_fti (content)") + # Index for comments + op.execute("ALTER TABLE comments ADD FULLTEXT comments_fti (content)") - # Index for users - op.execute("ALTER TABLE users ADD FULLTEXT users_fti (full_name, email)") + # Index for users + op.execute( + "ALTER TABLE users ADD FULLTEXT users_fti (full_name, email)" + ) def downgrade(active_plugins=None, options=None): diff --git a/storyboard/db/migration/alembic_migrations/versions/049_add_tables_for_worklists_and_boards.py b/storyboard/db/migration/alembic_migrations/versions/049_add_tables_for_worklists_and_boards.py index f297f3ce..9943540b 100644 --- a/storyboard/db/migration/alembic_migrations/versions/049_add_tables_for_worklists_and_boards.py +++ b/storyboard/db/migration/alembic_migrations/versions/049_add_tables_for_worklists_and_boards.py @@ -28,9 +28,12 @@ from alembic import op import sqlalchemy as sa import storyboard +from storyboard.db.migration import utils +@utils.not_sqlite def upgrade(active_plugins=None, options=None): + op.create_table('worklists', sa.Column('id', sa.Integer(), nullable=False), sa.Column('created_at', diff --git a/storyboard/db/migration/alembic_migrations/versions/050_add_detailed_permissions_to_boards_and_.py b/storyboard/db/migration/alembic_migrations/versions/050_add_detailed_permissions_to_boards_and_.py index c653d044..7c874c93 100644 --- a/storyboard/db/migration/alembic_migrations/versions/050_add_detailed_permissions_to_boards_and_.py +++ b/storyboard/db/migration/alembic_migrations/versions/050_add_detailed_permissions_to_boards_and_.py @@ -31,9 +31,11 @@ from sqlalchemy.dialects import mysql from storyboard.db.api import base as api_base from storyboard.db.api import boards from storyboard.db.api import worklists +from storyboard.db.migration import utils from storyboard.db import models +@utils.not_sqlite def upgrade(active_plugins=None, options=None): op.create_table('board_permissions', sa.Column('board_id', sa.Integer(), nullable=True), diff --git a/storyboard/db/migration/alembic_migrations/versions/052_add_column_for_task_links.py b/storyboard/db/migration/alembic_migrations/versions/052_add_column_for_task_links.py index 4f410650..eba69f62 100644 --- a/storyboard/db/migration/alembic_migrations/versions/052_add_column_for_task_links.py +++ b/storyboard/db/migration/alembic_migrations/versions/052_add_column_for_task_links.py @@ -27,7 +27,10 @@ down_revision = '051' from alembic import op import sqlalchemy as sa +from storyboard.db.migration import utils + +@utils.not_sqlite def upgrade(active_plugins=None, options=None): op.add_column('tasks', sa.Column('link', sa.UnicodeText(), nullable=True)) diff --git a/storyboard/db/migration/alembic_migrations/versions/053_add_due_dates_for_tasks_and_stories.py b/storyboard/db/migration/alembic_migrations/versions/053_add_due_dates_for_tasks_and_stories.py index 8ee20dc5..3e8996d4 100644 --- a/storyboard/db/migration/alembic_migrations/versions/053_add_due_dates_for_tasks_and_stories.py +++ b/storyboard/db/migration/alembic_migrations/versions/053_add_due_dates_for_tasks_and_stories.py @@ -28,8 +28,10 @@ from alembic import op import sqlalchemy as sa from storyboard.db.decorators import UTCDateTime +from storyboard.db.migration import utils +@utils.not_sqlite def upgrade(active_plugins=None, options=None): op.create_table( 'due_dates', diff --git a/storyboard/db/migration/alembic_migrations/versions/054_add_archived_field_to_cards.py b/storyboard/db/migration/alembic_migrations/versions/054_add_archived_field_to_cards.py index 5ead6708..eb4af343 100644 --- a/storyboard/db/migration/alembic_migrations/versions/054_add_archived_field_to_cards.py +++ b/storyboard/db/migration/alembic_migrations/versions/054_add_archived_field_to_cards.py @@ -27,7 +27,10 @@ down_revision = '053' from alembic import op import sqlalchemy as sa +from storyboard.db.migration import utils + +@utils.not_sqlite def upgrade(active_plugins=None, options=None): op.add_column( 'worklist_items', sa.Column('archived', sa.Boolean(), nullable=True)) diff --git a/storyboard/db/migration/alembic_migrations/versions/055_allow_comments_to_be_replies_to_other_.py b/storyboard/db/migration/alembic_migrations/versions/055_allow_comments_to_be_replies_to_other_.py index 6898b56c..25451430 100644 --- a/storyboard/db/migration/alembic_migrations/versions/055_allow_comments_to_be_replies_to_other_.py +++ b/storyboard/db/migration/alembic_migrations/versions/055_allow_comments_to_be_replies_to_other_.py @@ -27,7 +27,10 @@ down_revision = '054' from alembic import op import sqlalchemy as sa +from storyboard.db.migration import utils + +@utils.not_sqlite def upgrade(active_plugins=None, options=None): op.add_column( 'comments', sa.Column('in_reply_to', sa.Integer(), nullable=True)) diff --git a/storyboard/db/migration/alembic_migrations/versions/056_use_filters_with_multiple_criteria_for_.py b/storyboard/db/migration/alembic_migrations/versions/056_use_filters_with_multiple_criteria_for_.py index 17b36ab3..eb256cf7 100644 --- a/storyboard/db/migration/alembic_migrations/versions/056_use_filters_with_multiple_criteria_for_.py +++ b/storyboard/db/migration/alembic_migrations/versions/056_use_filters_with_multiple_criteria_for_.py @@ -29,8 +29,10 @@ import sqlalchemy as sa from sqlalchemy.dialects import mysql import storyboard +from storyboard.db.migration import utils +@utils.not_sqlite def upgrade(active_plugins=None, options=None): op.create_table( 'worklist_filters', diff --git a/storyboard/db/migration/alembic_migrations/versions/057_allow_stories_and_tasks_to_be_made_.py b/storyboard/db/migration/alembic_migrations/versions/057_allow_stories_and_tasks_to_be_made_.py index 1e2367c0..66b7e492 100644 --- a/storyboard/db/migration/alembic_migrations/versions/057_allow_stories_and_tasks_to_be_made_.py +++ b/storyboard/db/migration/alembic_migrations/versions/057_allow_stories_and_tasks_to_be_made_.py @@ -37,7 +37,10 @@ from alembic import op import sqlalchemy as sa from sqlalchemy.dialects import mysql +from storyboard.db.migration import utils + +@utils.not_sqlite def upgrade(active_plugins=None, options=None): op.create_table( 'story_permissions', diff --git a/storyboard/db/migration/alembic_migrations/versions/058_allow_subscription_to_worklists.py b/storyboard/db/migration/alembic_migrations/versions/058_allow_subscription_to_worklists.py index 23fd7ede..ee9c9932 100644 --- a/storyboard/db/migration/alembic_migrations/versions/058_allow_subscription_to_worklists.py +++ b/storyboard/db/migration/alembic_migrations/versions/058_allow_subscription_to_worklists.py @@ -27,11 +27,14 @@ down_revision = '057' from alembic import op import sqlalchemy as sa +from storyboard.db.migration import utils + old_type_enum = sa.Enum('task', 'story', 'project', 'project_group') new_type_enum = sa.Enum( 'task', 'story', 'project', 'project_group', 'worklist') +@utils.not_sqlite def upgrade(active_plugins=None, options=None): dialect = op.get_bind().engine.dialect if dialect.supports_alter: diff --git a/storyboard/db/migration/alembic_migrations/versions/059_add_a_table_for_comment_history.py b/storyboard/db/migration/alembic_migrations/versions/059_add_a_table_for_comment_history.py index 388c0393..d5f6268d 100644 --- a/storyboard/db/migration/alembic_migrations/versions/059_add_a_table_for_comment_history.py +++ b/storyboard/db/migration/alembic_migrations/versions/059_add_a_table_for_comment_history.py @@ -28,9 +28,11 @@ from alembic import op import sqlalchemy as sa from storyboard.db.decorators import UTCDateTime +from storyboard.db.migration import utils from storyboard.db.models import MYSQL_MEDIUM_TEXT +@utils.not_sqlite def upgrade(active_plugins=None, options=None): op.create_table( 'comments_history', diff --git a/storyboard/db/migration/alembic_migrations/versions/060_allow_timeline_events_to_be_related_to_.py b/storyboard/db/migration/alembic_migrations/versions/060_allow_timeline_events_to_be_related_to_.py index ad685ad4..55ceea01 100644 --- a/storyboard/db/migration/alembic_migrations/versions/060_allow_timeline_events_to_be_related_to_.py +++ b/storyboard/db/migration/alembic_migrations/versions/060_allow_timeline_events_to_be_related_to_.py @@ -27,7 +27,10 @@ down_revision = '059' from alembic import op import sqlalchemy as sa +from storyboard.db.migration import utils + +@utils.not_sqlite def upgrade(active_plugins=None, options=None): op.add_column( 'events', sa.Column('board_id', sa.Integer(), nullable=True)) diff --git a/storyboard/db/migration/alembic_migrations/versions/061_extends_project_name_and_project_group_.py b/storyboard/db/migration/alembic_migrations/versions/061_extends_project_name_and_project_group_.py index 668bcfa5..5287ba0c 100644 --- a/storyboard/db/migration/alembic_migrations/versions/061_extends_project_name_and_project_group_.py +++ b/storyboard/db/migration/alembic_migrations/versions/061_extends_project_name_and_project_group_.py @@ -27,7 +27,10 @@ down_revision = '060' from alembic import op import sqlalchemy as sa +from storyboard.db.migration import utils + +@utils.not_sqlite def upgrade(active_plugins=None, options=None): dialect = op.get_bind().engine.dialect if dialect.supports_alter: diff --git a/storyboard/db/migration/alembic_migrations/versions/063_index_story_storytags.py b/storyboard/db/migration/alembic_migrations/versions/063_index_story_storytags.py index 08fbfe85..761145ab 100644 --- a/storyboard/db/migration/alembic_migrations/versions/063_index_story_storytags.py +++ b/storyboard/db/migration/alembic_migrations/versions/063_index_story_storytags.py @@ -26,7 +26,10 @@ down_revision = '062' from alembic import op +from storyboard.db.migration import utils + +@utils.not_sqlite def upgrade(active_plugins=None, options=None): op.create_index('story_storytags_idx', 'story_storytags', ['story_id']) diff --git a/storyboard/db/migration/utils.py b/storyboard/db/migration/utils.py new file mode 100644 index 00000000..c40c96c5 --- /dev/null +++ b/storyboard/db/migration/utils.py @@ -0,0 +1,27 @@ +# 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 +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import functools + +from alembic import op + + +def not_sqlite(f): + "Decorator to skip migrations for sqlite databases." + @functools.wraps(f) + def upgrade(active_plugins=None, options=None): + dialect = op.get_bind().engine.dialect + if dialect.name == 'sqlite': + return + return f(active_plugins, options) + return upgrade diff --git a/storyboard/db/models.py b/storyboard/db/models.py index e5d32298..c67fe5f2 100644 --- a/storyboard/db/models.py +++ b/storyboard/db/models.py @@ -63,6 +63,30 @@ def table_args(): MYSQL_MEDIUM_TEXT = UnicodeText().with_variant(MEDIUMTEXT(), 'mysql') +class ManagedFullText(FullText): + + @classmethod + def build_fulltext(cls, table): + """Override FullText to avoid adding DDL instructions. + + This mix-in replaces sqlalchemy_fulltext.FullText and does not + automatically cause the database engine to create the full text + search index columns. We do that using our alembic migration + scripts, instead. + + We need this class to support running the unit tests under sqlite, + which doesn't support the full text indexing features of MySQL, + since sqlalchemy-fulltext-search always runs the DDL, even if the + database dialect is not 'mysql'. + + After the change in + https://github.com/mengzhuo/sqlalchemy-fulltext-search/pull/15 + is approved and released we can remove this class. + + """ + return + + class CommonLength(object): top_large_length = 255 top_middle_length = 100 @@ -137,7 +161,7 @@ team_membership = Table( ) -class User(FullText, ModelBuilder, Base): +class User(ManagedFullText, ModelBuilder, Base): __table_args__ = ( schema.UniqueConstraint('email', name='uniq_user_email'), ) @@ -255,7 +279,7 @@ class Permission(ModelBuilder, Base): # TODO(mordred): Do we really need name and title? -class Project(FullText, ModelBuilder, Base): +class Project(ManagedFullText, ModelBuilder, Base): """Represents a software project.""" __table_args__ = ( @@ -300,7 +324,7 @@ story_storytags = Table( ) -class Story(FullText, ModelBuilder, Base): +class Story(ManagedFullText, ModelBuilder, Base): __tablename__ = 'stories' __fulltext_columns__ = ['title', 'description'] @@ -324,7 +348,7 @@ class Story(FullText, ModelBuilder, Base): "tasks", "events", "tags"] -class Task(FullText, ModelBuilder, Base): +class Task(ManagedFullText, ModelBuilder, Base): __fulltext_columns__ = ['title'] TASK_STATUSES = {'todo': 'Todo', @@ -504,7 +528,7 @@ class TimeLineEvent(ModelBuilder, Base): event_info = Column(UnicodeText(), nullable=True) -class Comment(FullText, ModelBuilder, Base): +class Comment(ManagedFullText, ModelBuilder, Base): __fulltext_columns__ = ['content'] id = Column(Integer, primary_key=True) @@ -514,7 +538,7 @@ class Comment(FullText, ModelBuilder, Base): parent = relationship('Comment', remote_side=[id], backref='children') -class HistoricalComment(FullText, ModelBuilder, Base): +class HistoricalComment(ManagedFullText, ModelBuilder, Base): __tablename__ = 'comments_history' __fulltext_columns__ = ['content'] @@ -569,7 +593,7 @@ class WorklistItem(ModelBuilder, Base): "item_id"] -class FilterCriterion(FullText, ModelBuilder, Base): +class FilterCriterion(ManagedFullText, ModelBuilder, Base): __tablename__ = "filter_criteria" __fulltext_columns__ = ['title'] @@ -594,7 +618,7 @@ class WorklistFilter(ModelBuilder, Base): _public_fields = ["id", "list_id", "type"] -class Worklist(FullText, ModelBuilder, Base): +class Worklist(ManagedFullText, ModelBuilder, Base): __tablename__ = "worklists" __fulltext_columns__ = ['title'] @@ -622,7 +646,7 @@ class BoardWorklist(ModelBuilder, Base): _public_fields = ["id", "board_id", "list_id", "position"] -class Board(FullText, ModelBuilder, Base): +class Board(ManagedFullText, ModelBuilder, Base): __tablename__ = "boards" __fulltext_columns__ = ['title', 'description'] @@ -651,7 +675,7 @@ worklist_permissions = Table( ) -class DueDate(FullText, ModelBuilder, Base): +class DueDate(ManagedFullText, ModelBuilder, Base): __tablename__ = "due_dates" __fulltext_columns__ = ['name'] diff --git a/storyboard/tests/base.py b/storyboard/tests/base.py index 661ce24c..4b98aab2 100644 --- a/storyboard/tests/base.py +++ b/storyboard/tests/base.py @@ -18,6 +18,7 @@ import os import os.path import shutil +import sqlite3 import stat import uuid @@ -35,6 +36,7 @@ import testtools import storyboard.common.working_dir as working_dir from storyboard.db.api import base as db_api_base from storyboard.db.migration.cli import get_alembic_config +from storyboard.db import models import storyboard.tests.mock_data as mock_data @@ -152,9 +154,19 @@ class DbTestCase(WorkingDirTestCase): CONF.set_override("connection", dburi, group="database") self._full_db_name = self.test_connection + '/' + self.db_name LOG.info('using database %s', CONF.database.connection) + LOG.info('test_connection %r', self.test_connection) if self.test_connection.startswith('sqlite://'): self.using_sqlite = True + filename = self._full_db_name[9:] + if filename[:2] == '//': + filename = filename[1:] + if not os.path.exists(filename): + # NOTE(dhellmann): Connect and disconnect to create + # the empty database file. + sqlite3.connect(filename).close() + engine = sqlalchemy.create_engine(self._full_db_name) + models.Base.metadata.create_all(engine) else: self.using_sqlite = False # The engine w/o db name