Commit 3b95696a authored by Andreas Brandl's avatar Andreas Brandl

Merge branch 'ab/cleanup-migrations' into 'master'

Cleanup migrations introduced before 2019

See merge request gitlab-org/gitlab!31936
parents a38eb0c4 f38880d2
......@@ -192,7 +192,7 @@ db:migrate-from-v12.10.0:
db:rollback:
extends: .db-job-base
script:
- bundle exec rake db:migrate VERSION=20180101160629
- bundle exec rake db:migrate VERSION=20181228175414
- bundle exec rake db:migrate SKIP_SCHEMA_VERSION_CHECK=true
gitlab:setup:
......
---
title: Squash database migrations prior to 2019 into one
merge_request: 31936
author:
type: other
# frozen_string_literal: true
class CreatePrometheusMetrics < ActiveRecord::Migration[4.2]
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def change
create_table :prometheus_metrics do |t|
t.references :project, index: true, foreign_key: { on_delete: :cascade }, null: false
t.string :title, null: false
t.string :query, null: false
t.string :y_label
t.string :unit
t.string :legend
t.integer :group, null: false, index: true
t.timestamps_with_timezone null: false
end
end
# rubocop:enable Migration/PreventStrings
end
# frozen_string_literal: true
class ChangeProjectIdForPrometheusMetrics < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
change_column_null :prometheus_metrics, :project_id, true
end
end
class AddPagesHttpsOnlyToProjects < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :projects, :pages_https_only, :boolean # rubocop:disable Migration/AddColumnsToWideTables
end
end
class AddConfidentialNoteEventsToServices < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column :services, :confidential_note_events, :boolean
change_column_default :services, :confidential_note_events, true
end
def down
remove_column :services, :confidential_note_events
end
end
class AddCommitsCountToMergeRequestDiff < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
MIGRATION = 'AddMergeRequestDiffCommitsCount'.freeze
BATCH_SIZE = 5000
DELAY_INTERVAL = 5.minutes.to_i
class MergeRequestDiff < ActiveRecord::Base
self.table_name = 'merge_request_diffs'
include ::EachBatch
end
disable_ddl_transaction!
def up
add_column :merge_request_diffs, :commits_count, :integer
say 'Populating the MergeRequestDiff `commits_count`'
queue_background_migration_jobs_by_range_at_intervals(MergeRequestDiff, MIGRATION, DELAY_INTERVAL, batch_size: BATCH_SIZE)
end
def down
remove_column :merge_request_diffs, :commits_count
end
end
class ChangeDefaultValueForPagesHttpsOnly < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
change_column_default :projects, :pages_https_only, true
end
def down
change_column_default :projects, :pages_https_only, nil
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class ReworkRedirectRoutesIndexes < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
disable_ddl_transaction!
INDEX_NAME_UNIQUE = "index_redirect_routes_on_path_unique_text_pattern_ops"
INDEX_NAME_PERM = "index_redirect_routes_on_path_text_pattern_ops_where_permanent"
INDEX_NAME_TEMP = "index_redirect_routes_on_path_text_pattern_ops_where_temporary"
OLD_INDEX_NAME_PATH_TPOPS = "index_redirect_routes_on_path_text_pattern_ops"
OLD_INDEX_NAME_PATH_LOWER = "index_on_redirect_routes_lower_path"
def up
disable_statement_timeout do
# this is a plain btree on a single boolean column. It'll never be
# selective enough to be valuable.
if index_exists?(:redirect_routes, :permanent)
remove_concurrent_index(:redirect_routes, :permanent)
end
if_not_exists = Gitlab::Database.version.to_f >= 9.5 ? "IF NOT EXISTS" : ""
# Unique index on lower(path) across both types of redirect_routes:
execute("CREATE UNIQUE INDEX CONCURRENTLY #{if_not_exists} #{INDEX_NAME_UNIQUE} ON redirect_routes (lower(path) varchar_pattern_ops);")
# Make two indexes on path -- one for permanent and one for temporary routes:
execute("CREATE INDEX CONCURRENTLY #{if_not_exists} #{INDEX_NAME_PERM} ON redirect_routes (lower(path) varchar_pattern_ops) where (permanent);")
execute("CREATE INDEX CONCURRENTLY #{if_not_exists} #{INDEX_NAME_TEMP} ON redirect_routes (lower(path) varchar_pattern_ops) where (not permanent or permanent is null) ;")
# Remove the old indexes:
# This one needed to be on lower(path) but wasn't so it's replaced with the two above
execute "DROP INDEX CONCURRENTLY IF EXISTS #{OLD_INDEX_NAME_PATH_TPOPS};"
# This one isn't needed because we only ever do = and LIKE on this
# column so the varchar_pattern_ops index is sufficient
execute "DROP INDEX CONCURRENTLY IF EXISTS #{OLD_INDEX_NAME_PATH_LOWER};"
end
end
def down
disable_statement_timeout do
add_concurrent_index(:redirect_routes, :permanent)
execute("CREATE INDEX CONCURRENTLY #{OLD_INDEX_NAME_PATH_TPOPS} ON redirect_routes (path varchar_pattern_ops);")
execute("CREATE INDEX CONCURRENTLY #{OLD_INDEX_NAME_PATH_LOWER} ON redirect_routes (LOWER(path));")
execute("DROP INDEX CONCURRENTLY IF EXISTS #{INDEX_NAME_UNIQUE};")
execute("DROP INDEX CONCURRENTLY IF EXISTS #{INDEX_NAME_PERM};")
execute("DROP INDEX CONCURRENTLY IF EXISTS #{INDEX_NAME_TEMP};")
end
end
end
class AddDefaultProjectCreationSetting < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
unless column_exists?(:application_settings, :default_project_creation)
add_column_with_default(:application_settings, :default_project_creation, :integer, default: 2) # rubocop:disable Migration/AddColumnWithDefault
end
end
def down
if column_exists?(:application_settings, :default_project_creation)
remove_column(:application_settings, :default_project_creation)
end
end
end
class AddProjectCreationLevelToGroups < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
unless column_exists?(:namespaces, :project_creation_level)
add_column(:namespaces, :project_creation_level, :integer)
end
end
def down
if column_exists?(:namespaces, :project_creation_level)
remove_column(:namespaces, :project_creation_level, :integer)
end
end
end
class AddIndexUpdatedAtToIssues < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :issues, :updated_at
end
def down
remove_concurrent_index :issues, :updated_at
end
end
class CreateLfsFileLocks < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
create_table :lfs_file_locks do |t|
t.references :project, null: false, foreign_key: { on_delete: :cascade }
t.references :user, null: false, index: true, foreign_key: { on_delete: :cascade }
t.datetime :created_at, null: false # rubocop:disable Migration/Datetime
t.string :path, limit: 511 # rubocop:disable Migration/PreventStrings
end
add_index :lfs_file_locks, [:project_id, :path], unique: true
end
def down
if foreign_keys_for(:lfs_file_locks, :project_id).any?
remove_foreign_key :lfs_file_locks, column: :project_id
end
if index_exists?(:lfs_file_locks, [:project_id, :path])
remove_concurrent_index :lfs_file_locks, [:project_id, :path]
end
drop_table :lfs_file_locks
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddUploaderIndexToUploads < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
remove_concurrent_index :uploads, :path
add_concurrent_index :uploads, [:uploader, :path], using: :btree
end
def down
remove_concurrent_index :uploads, [:uploader, :path]
add_concurrent_index :uploads, :path, using: :btree
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class OptimizeCiJobArtifacts < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
disable_ddl_transaction!
def up
# job_id is just here to be a covering index for index only scans
# since we'll almost always be joining against ci_builds on job_id
add_concurrent_index(:ci_job_artifacts, [:expire_at, :job_id])
add_concurrent_index(:ci_builds, [:artifacts_expire_at], where: "artifacts_file <> ''")
end
def down
remove_concurrent_index(:ci_job_artifacts, [:expire_at, :job_id])
remove_concurrent_index(:ci_builds, [:artifacts_expire_at], where: "artifacts_file <> ''")
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddAutoDevopsDomainToApplicationSettings < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def change
add_column :application_settings, :auto_devops_domain, :string
end
# rubocop:enable Migration/PreventStrings
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class CreateUserCallouts < ActiveRecord::Migration[4.2]
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
def change
create_table :user_callouts do |t|
t.integer :feature_name, null: false
t.references :user, index: true, foreign_key: { on_delete: :cascade }, null: false
end
add_index :user_callouts, [:user_id, :feature_name], unique: true
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddUploadsBuilderContext < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def change
add_column :uploads, :mount_point, :string
add_column :uploads, :secret, :string
end
# rubocop:enable Migration/PreventStrings
end
class AddUniqueConstraintToTrendingProjectsProjectId < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :trending_projects, :project_id, unique: true, name: 'index_trending_projects_on_project_id_unique'
remove_concurrent_index_by_name :trending_projects, 'index_trending_projects_on_project_id'
rename_index :trending_projects, 'index_trending_projects_on_project_id_unique', 'index_trending_projects_on_project_id'
end
def down
rename_index :trending_projects, 'index_trending_projects_on_project_id', 'index_trending_projects_on_project_id_old'
add_concurrent_index :trending_projects, :project_id
remove_concurrent_index_by_name :trending_projects, 'index_trending_projects_on_project_id_old'
end
end
class AddForeignKeysToTodos < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
class Todo < ActiveRecord::Base
self.table_name = 'todos'
include EachBatch
end
BATCH_SIZE = 1000
DOWNTIME = false
disable_ddl_transaction!
def up
Todo.where('NOT EXISTS ( SELECT true FROM users WHERE id=todos.user_id )').each_batch(of: BATCH_SIZE) do |batch|
batch.delete_all
end
Todo.where('NOT EXISTS ( SELECT true FROM users WHERE id=todos.author_id )').each_batch(of: BATCH_SIZE) do |batch|
batch.delete_all
end
Todo.where('note_id IS NOT NULL AND NOT EXISTS ( SELECT true FROM notes WHERE id=todos.note_id )').each_batch(of: BATCH_SIZE) do |batch|
batch.delete_all
end
add_concurrent_foreign_key :todos, :users, column: :user_id, on_delete: :cascade
add_concurrent_foreign_key :todos, :users, column: :author_id, on_delete: :cascade
add_concurrent_foreign_key :todos, :notes, column: :note_id, on_delete: :cascade
end
def down
remove_foreign_key :todos, column: :user_id
remove_foreign_key :todos, column: :author_id
remove_foreign_key :todos, :notes
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class MigrateRemainingIssuesClosedAt < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
disable_ddl_transaction!
class Issue < ActiveRecord::Base
self.table_name = 'issues'
include EachBatch
end
def up
Gitlab::BackgroundMigration.steal('CopyColumn')
Gitlab::BackgroundMigration.steal('CleanupConcurrentTypeChange')
if migrate_column_type?
if closed_at_for_type_change_exists?
migrate_remaining_rows
else
# Due to some EE merge problems some environments may not have the
# "closed_at_for_type_change" column. If this is the case we have no
# other option than to migrate the data _right now_.
# rubocop:disable Migration/UpdateLargeTable
change_column_type_concurrently(:issues, :closed_at, :datetime_with_timezone)
cleanup_concurrent_column_type_change(:issues, :closed_at)
end
end
end
def down
# Previous migrations already revert the changes made here.
end
def migrate_remaining_rows
Issue.where('closed_at_for_type_change IS NULL AND closed_at IS NOT NULL').each_batch do |batch|
batch.update_all('closed_at_for_type_change = closed_at')
end
cleanup_concurrent_column_type_change(:issues, :closed_at)
end
def migrate_column_type?
# Some environments may have already executed the previous version of this
# migration, thus we don't need to migrate those environments again.
column_for('issues', 'closed_at').type == :datetime # rubocop:disable Migration/Datetime
end
def closed_at_for_type_change_exists?
columns('issues').any? { |col| col.name == 'closed_at_for_type_change' }
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class ResetEventsPrimaryKeySequence < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
class Event < ActiveRecord::Base
self.table_name = 'events'
end
def up
reset_pk_sequence!(Event.table_name)
end
def down
# No-op
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class SchedulePopulateUntrackedUploadsIfNeeded < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
FOLLOW_UP_MIGRATION = 'PopulateUntrackedUploads'.freeze
class UntrackedFile < ActiveRecord::Base
include EachBatch
self.table_name = 'untracked_files_for_uploads'
end
def up
if table_exists?(:untracked_files_for_uploads)
process_or_remove_table
end
end
def down
# nothing
end
private
def process_or_remove_table
if UntrackedFile.all.empty?
drop_temp_table
else
schedule_populate_untracked_uploads_jobs
end
end
def drop_temp_table
drop_table(:untracked_files_for_uploads, if_exists: true)
end
def schedule_populate_untracked_uploads_jobs
say "Scheduling #{FOLLOW_UP_MIGRATION} background migration jobs since there are rows in untracked_files_for_uploads."
bulk_queue_background_migration_jobs_by_range(
UntrackedFile, FOLLOW_UP_MIGRATION)
end
end
# frozen_string_literal: true
class CreateChatopsTables < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
create_table :ci_pipeline_chat_data, id: :bigserial do |t|
t.integer :pipeline_id, null: false
t.references :chat_name, foreign_key: { on_delete: :cascade }, null: false
t.text :response_url, null: false # rubocop:disable Migration/AddLimitToTextColumns
# A pipeline can only contain one row in this table, hence this index is
# unique.
t.index :pipeline_id, unique: true
t.index :chat_name_id
end
# rubocop:disable Migration/AddConcurrentForeignKey
add_foreign_key :ci_pipeline_chat_data, :ci_pipelines,
column: :pipeline_id,
on_delete: :cascade
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddClosedByToIssues < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
def up
add_column :issues, :closed_by_id, :integer
add_concurrent_foreign_key :issues, :users, column: :closed_by_id, on_delete: :nullify
end
def down
remove_foreign_key :issues, column: :closed_by_id
remove_column :issues, :closed_by_id
end
end
class AddExternalIpToClustersApplicationsIngress < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def change
add_column :clusters_applications_ingress, :external_ip, :string
end
# rubocop:enable Migration/PreventStrings
end
class AddPartialIndexToProjectsForIndexOnlyScans < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
INDEX_NAME = 'index_projects_on_id_partial_for_visibility'
disable_ddl_transaction!
# Adds a partial index to leverage index-only scans when looking up project ids
def up
unless index_exists?(:projects, :id, name: INDEX_NAME)
add_concurrent_index :projects, :id, name: INDEX_NAME, unique: true, where: 'visibility_level IN (10,20)'
end
end
def down
if index_exists?(:projects, :id, name: INDEX_NAME)
remove_concurrent_index_by_name :projects, INDEX_NAME
end
end
end
class CreateBadges < ActiveRecord::Migration[4.2]
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def change
create_table :badges do |t|
t.string :link_url, null: false
t.string :image_url, null: false
t.references :project, index: true, foreign_key: { on_delete: :cascade }, null: true
t.integer :group_id, index: true, null: true
t.string :type, null: false
t.timestamps_with_timezone null: false
end
# rubocop:disable Migration/AddConcurrentForeignKey
add_foreign_key :badges, :namespaces, column: :group_id, on_delete: :cascade
# rubocop:enable Migration/AddConcurrentForeignKey
end
# rubocop:enable Migration/PreventStrings
end
class CreateClustersApplicationsRunners < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
create_table :clusters_applications_runners do |t|
t.references :cluster, null: false, foreign_key: { on_delete: :cascade }
t.references :runner, references: :ci_runners
t.index :runner_id
t.index :cluster_id, unique: true
t.integer :status, null: false
t.timestamps_with_timezone null: false
t.string :version, null: false # rubocop:disable Migration/PreventStrings
t.text :status_reason # rubocop:disable Migration/AddLimitToTextColumns
end
add_concurrent_foreign_key :clusters_applications_runners, :ci_runners,
column: :runner_id,
on_delete: :nullify
end
def down
if foreign_keys_for(:clusters_applications_runners, :runner_id).any?
remove_foreign_key :clusters_applications_runners, column: :runner_id
end
drop_table :clusters_applications_runners
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class UsersNameLowerIndex < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
INDEX_NAME = 'index_on_users_name_lower'
disable_ddl_transaction!
def up
# On GitLab.com this produces an index with a size of roughly 60 MB.
execute "CREATE INDEX CONCURRENTLY #{INDEX_NAME} ON users (LOWER(name))"
end
def down
execute "DROP INDEX CONCURRENTLY IF EXISTS #{INDEX_NAME}"
end
end
class AddPagesDomainVerification < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
add_column :pages_domains, :verified_at, :datetime_with_timezone
add_column :pages_domains, :verification_code, :string # rubocop:disable Migration/PreventStrings
end
end
class AddPagesDomainVerifiedAtIndex < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :pages_domains, :verified_at
end
def down
remove_concurrent_index :pages_domains, :verified_at
end
end
class AllowDomainVerificationToBeDisabled < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
add_column :application_settings, :pages_domain_verification_enabled, :boolean, default: true, null: false
end
end
class AddPagesDomainEnabledUntil < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
add_column :pages_domains, :enabled_until, :datetime_with_timezone
end
end
class AddPagesDomainEnabledUntilIndex < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :pages_domains, [:project_id, :enabled_until]
add_concurrent_index :pages_domains, [:verified_at, :enabled_until]
end
def down
remove_concurrent_index :pages_domains, [:verified_at, :enabled_until]
remove_concurrent_index :pages_domains, [:project_id, :enabled_until]
end
end
class PagesDomainsVerificationGracePeriod < ActiveRecord::Migration[4.2]
DOWNTIME = false
class PagesDomain < ActiveRecord::Base
include EachBatch
end
# Allow this migration to resume if it fails partway through
disable_ddl_transaction!
def up
now = Time.now
grace = now + 30.days
PagesDomain.each_batch do |relation|
relation.update_all(verified_at: now, enabled_until: grace)
# Sleep 2 minutes between batches to not overload the DB with dead tuples
sleep(2.minutes) unless relation.reorder(:id).last == PagesDomain.reorder(:id).last
end
end
def down
# no-op
end
end
class AddMaximumTimeoutToCiRunners < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :ci_runners, :maximum_timeout, :integer
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddAllowMaintainerToPushToMergeRequests < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column :merge_requests, :allow_maintainer_to_push, :boolean
end
def down
remove_column :merge_requests, :allow_maintainer_to_push
end
end
class AddIpAddressToRunner < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :ci_runners, :ip_address, :string # rubocop:disable Migration/PreventStrings
end
end
class CreateUserInteractedProjectsTable < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
INDEX_NAME = 'user_interacted_projects_non_unique_index'
def up
create_table :user_interacted_projects, id: false do |t|
t.references :user, null: false
t.references :project, null: false
end
add_index :user_interacted_projects, [:project_id, :user_id], name: INDEX_NAME
end
def down
drop_table :user_interacted_projects
end
end
class AddAllowLocalRequestsFromHooksAndServicesToApplicationSettings < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :allow_local_requests_from_hooks_and_services, # rubocop:disable Migration/AddColumnWithDefault
:boolean,
default: false,
allow_null: false)
end
def down
remove_column(:application_settings, :allow_local_requests_from_hooks_and_services)
end
end
class AddChecksumToCiJobArtifacts < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
add_column :ci_job_artifacts, :file_sha256, :binary
end
end
class AddGroupIdToBoardsCe < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
DOWNTIME = false
def up
return if group_id_exists?
# rubocop:disable Migration/AddConcurrentForeignKey
add_column :boards, :group_id, :integer
add_foreign_key :boards, :namespaces, column: :group_id, on_delete: :cascade
add_concurrent_index :boards, :group_id
change_column_null :boards, :project_id, true
end
def down
return unless group_id_exists?
# rubocop:disable Migration/RemoveIndex
remove_foreign_key :boards, column: :group_id
remove_index :boards, :group_id if index_exists? :boards, :group_id
remove_column :boards, :group_id
execute "DELETE from boards WHERE project_id IS NULL"
change_column_null :boards, :project_id, false
end
private
def group_id_exists?
column_exists?(:boards, :group_id)
end
end
class AddIncludePrivateContributionsToUsers < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
add_column :users, :include_private_contributions, :boolean # rubocop:disable Migration/AddColumnsToWideTables
end
end
class CreateCiBuildsMetadataTable < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
create_table :ci_builds_metadata do |t|
t.integer :build_id, null: false
t.integer :project_id, null: false
t.integer :timeout
t.integer :timeout_source, null: false, default: 1
t.foreign_key :ci_builds, column: :build_id, on_delete: :cascade
t.foreign_key :projects, column: :project_id, on_delete: :cascade
t.index :build_id, unique: true
t.index :project_id
end
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class EnsureForeignKeysOnClustersApplications < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
# rubocop:disable Cop/InBatches
def up
existing = Clusters::Cluster
.joins(:application_ingress)
.where('clusters.id = clusters_applications_ingress.cluster_id')
Clusters::Applications::Ingress.where('NOT EXISTS (?)', existing).in_batches do |batch|
batch.delete_all
end
unless foreign_keys_for(:clusters_applications_ingress, :cluster_id).any?
add_concurrent_foreign_key :clusters_applications_ingress, :clusters,
column: :cluster_id,
on_delete: :cascade
end
existing = Clusters::Cluster
.joins(:application_prometheus)
.where('clusters.id = clusters_applications_prometheus.cluster_id')
Clusters::Applications::Ingress.where('NOT EXISTS (?)', existing).in_batches do |batch|
batch.delete_all
end
unless foreign_keys_for(:clusters_applications_prometheus, :cluster_id).any?
add_concurrent_foreign_key :clusters_applications_prometheus, :clusters,
column: :cluster_id,
on_delete: :cascade
end
end
def down
if foreign_keys_for(:clusters_applications_ingress, :cluster_id).any?
remove_foreign_key :clusters_applications_ingress, column: :cluster_id
end
if foreign_keys_for(:clusters_applications_prometheus, :cluster_id).any?
remove_foreign_key :clusters_applications_prometheus, column: :cluster_id
end
end
end
class CreateInternalIdsTable < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
create_table :internal_ids, id: :bigserial do |t|
t.references :project, null: false, foreign_key: { on_delete: :cascade }
t.integer :usage, null: false
t.integer :last_value, null: false
t.index [:usage, :project_id], unique: true
end
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddPrivilegedToRunner < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column_with_default :clusters_applications_runners, :privileged, :boolean, default: true, allow_null: false # rubocop:disable Migration/AddColumnWithDefault
end
def down
remove_column :clusters_applications_runners, :privileged
end
end
# This migration comes from acts_as_taggable_on_engine (originally 6)
#
# It has been modified to handle no-downtime GitLab migrations. Several
# indexes have been removed since they are not needed for GitLab.
class AddMissingIndexesActsAsTaggableOnEngine < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :taggings, :tag_id unless index_exists? :taggings, :tag_id
add_concurrent_index :taggings, [:taggable_id, :taggable_type] unless index_exists? :taggings, [:taggable_id, :taggable_type]
end
def down
remove_concurrent_index :taggings, :tag_id
remove_concurrent_index :taggings, [:taggable_id, :taggable_type]
end
end
class AddSectionNameIdIndexOnCiBuildTraceSections < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
INDEX_NAME = 'index_ci_build_trace_sections_on_section_name_id'
disable_ddl_transaction!
def up
add_concurrent_index :ci_build_trace_sections, :section_name_id, name: INDEX_NAME
end
def down
remove_concurrent_index :ci_build_trace_sections, :section_name_id, name: INDEX_NAME
end
end
class AddUserInternalRegexToApplicationSetting < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def up
add_column :application_settings, :user_default_internal_regex, :string, null: true
end
# rubocop:enable Migration/PreventStrings
def down
remove_column :application_settings, :user_default_internal_regex
end
end
class RescheduleCommitsCountForMergeRequestDiff < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
MIGRATION = 'AddMergeRequestDiffCommitsCount'.freeze
BATCH_SIZE = 5000
DELAY_INTERVAL = 5.minutes.to_i
class MergeRequestDiff < ActiveRecord::Base
self.table_name = 'merge_request_diffs'
include ::EachBatch
end
disable_ddl_transaction!
def up
say 'Populating the MergeRequestDiff `commits_count` (reschedule)'
execute("SET statement_timeout TO '60s'")
MergeRequestDiff.where(commits_count: nil).each_batch(of: BATCH_SIZE) do |relation, index|
start_id, end_id = relation.pluck('MIN(id), MAX(id)').first
delay = index * DELAY_INTERVAL
BackgroundMigrationWorker.perform_in(delay, MIGRATION, [start_id, end_id])
end
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddPartialIndexesOnTodos < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
disable_ddl_transaction!
INDEX_NAME_PENDING = "index_todos_on_user_id_and_id_pending"
INDEX_NAME_DONE = "index_todos_on_user_id_and_id_done"
def up
unless index_exists?(:todos, [:user_id, :id], name: INDEX_NAME_PENDING)
add_concurrent_index(:todos, [:user_id, :id], where: "state='pending'", name: INDEX_NAME_PENDING)
end
unless index_exists?(:todos, [:user_id, :id], name: INDEX_NAME_DONE)
add_concurrent_index(:todos, [:user_id, :id], where: "state='done'", name: INDEX_NAME_DONE)
end
end
def down
remove_concurrent_index(:todos, [:user_id, :id], where: "state='pending'", name: INDEX_NAME_PENDING)
remove_concurrent_index(:todos, [:user_id, :id], where: "state='done'", name: INDEX_NAME_DONE)
end
end
class AddExternalAuthorizationServiceTimeoutToApplicationSettings < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
# We can use the regular `add_column` with a default since `application_settings`
# is a small table.
add_column :application_settings,
:external_authorization_service_timeout,
:float,
default: 0.5
end
def down
remove_column :application_settings, :external_authorization_service_timeout
end
end
# frozen_string_literal: true
class AddHeaderAndFooterBannersToAppearancesTable < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
# rubocop:disable Migration/AddLimitToTextColumns
add_column :appearances, :header_message, :text
add_column :appearances, :header_message_html, :text
add_column :appearances, :footer_message, :text
add_column :appearances, :footer_message_html, :text
add_column :appearances, :message_background_color, :text
add_column :appearances, :message_font_color, :text
# rubocop:enable Migration/AddLimitToTextColumns
end
end
class AddExternalAuthMutualTlsFieldsToProjectSettings < ActiveRecord::Migration[4.2]
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
# rubocop:disable Migration/AddLimitToTextColumns
def change
add_column :application_settings,
:external_auth_client_cert, :text
add_column :application_settings,
:encrypted_external_auth_client_key, :text
add_column :application_settings,
:encrypted_external_auth_client_key_iv, :string
add_column :application_settings,
:encrypted_external_auth_client_key_pass, :string
add_column :application_settings,
:encrypted_external_auth_client_key_pass_iv, :string
end
# rubocop:enable Migration/AddLimitToTextColumns
# rubocop:enable Migration/PreventStrings
end
class CreateDeployTokens < ActiveRecord::Migration[4.2]
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def change
create_table :deploy_tokens do |t|
t.boolean :revoked, default: false
t.boolean :read_repository, null: false, default: false
t.boolean :read_registry, null: false, default: false
t.datetime_with_timezone :expires_at, null: false
t.datetime_with_timezone :created_at, null: false
t.string :name, null: false
t.string :token, index: { unique: true }, null: false
t.index [:token, :expires_at, :id], where: "(revoked IS FALSE)"
end
end
# rubocop:enable Migration/PreventStrings
end
class AddIndexesForUserActivityQueries < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :events, [:author_id, :project_id] unless index_exists?(:events, [:author_id, :project_id])
add_concurrent_index :user_interacted_projects, :user_id unless index_exists?(:user_interacted_projects, :user_id)
end
def down
remove_concurrent_index :events, [:author_id, :project_id] if index_exists?(:events, [:author_id, :project_id])
remove_concurrent_index :user_interacted_projects, :user_id if index_exists?(:user_interacted_projects, :user_id)
end
end
class AddPushToMergeRequestToNotificationSettings < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :notification_settings, :push_to_merge_request, :boolean
end
end
class CreateCiBuildTraceChunks < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
create_table :ci_build_trace_chunks, id: :bigserial do |t|
t.integer :build_id, null: false
t.integer :chunk_index, null: false
t.integer :data_store, null: false
t.binary :raw_data
t.foreign_key :ci_builds, column: :build_id, on_delete: :cascade
t.index [:build_id, :chunk_index], unique: true
end
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class RemoveIndexFromEventsTable < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
remove_concurrent_index :events, :author_id
end
def down
add_concurrent_index :events, :author_id
end
end
class AddIssueDueToNotificationSettings < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :notification_settings, :issue_due, :boolean
end
end
class CreateProjectCiCdSettings < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
unless table_exists?(:project_ci_cd_settings)
create_table(:project_ci_cd_settings) do |t|
t.integer(:project_id, null: false)
t.boolean(:group_runners_enabled, default: true, null: false)
end
end
disable_statement_timeout do
# This particular INSERT will take between 10 and 20 seconds.
execute 'INSERT INTO project_ci_cd_settings (project_id) SELECT id FROM projects'
# We add the index and foreign key separately so the above INSERT statement
# takes as little time as possible.
add_concurrent_index(:project_ci_cd_settings, :project_id, unique: true)
add_foreign_key_with_retry
end
end
def down
drop_table :project_ci_cd_settings
end
def add_foreign_key_with_retry
# Between the initial INSERT and the addition of the foreign key some
# projects may have been removed, leaving orphaned rows in our new settings
# table.
loop do
remove_orphaned_settings
begin
add_project_id_foreign_key
break
rescue ActiveRecord::InvalidForeignKey
say 'project_ci_cd_settings contains some orphaned rows, retrying...'
end
end
end
def add_project_id_foreign_key
add_concurrent_foreign_key(:project_ci_cd_settings, :projects, column: :project_id)
end
def remove_orphaned_settings
execute <<~SQL
DELETE FROM project_ci_cd_settings
WHERE NOT EXISTS (
SELECT 1
FROM projects
WHERE projects.id = project_ci_cd_settings.project_id
)
SQL
end
end
class CreateProjectDeployTokens < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
create_table :project_deploy_tokens do |t|
t.integer :project_id, null: false
t.integer :deploy_token_id, null: false
t.datetime_with_timezone :created_at, null: false
t.foreign_key :deploy_tokens, column: :deploy_token_id, on_delete: :cascade
t.foreign_key :projects, column: :project_id, on_delete: :cascade
t.index [:project_id, :deploy_token_id], unique: true
end
end
end
class RenameUsersRssTokenToFeedToken < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
# rubocop:disable Migration/UpdateLargeTable
rename_column_concurrently :users, :rss_token, :feed_token
end
def down
cleanup_concurrent_column_rename :users, :feed_token, :rss_token
end
end
class CreateMissingNamespaceForInternalUsers < ActiveRecord::Migration[4.2]
DOWNTIME = false
def up
connection.exec_query(users_query.to_sql).rows.each do |id, username|
create_namespace(id, username)
# When testing locally I've noticed that these internal users are missing
# the notification email, for more details visit the below link:
# https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/18357#note_68327560
set_notification_email(id)
end
end
def down
# no-op
end
private
def users
@users ||= Arel::Table.new(:users)
end
def namespaces
@namespaces ||= Arel::Table.new(:namespaces)
end
def users_query
condition = users[:ghost].eq(true)
if column_exists?(:users, :support_bot)
condition = condition.or(users[:support_bot].eq(true))
end
users.join(namespaces, Arel::Nodes::OuterJoin)
.on(namespaces[:type].eq(nil).and(namespaces[:owner_id].eq(users[:id])))
.where(namespaces[:owner_id].eq(nil))
.where(condition)
.project(users[:id], users[:username])
end
def create_namespace(user_id, username)
path = Uniquify.new.string(username) do |str|
query = "SELECT id FROM namespaces WHERE parent_id IS NULL AND path='#{str}' LIMIT 1"
connection.exec_query(query).present?
end
insert_query = "INSERT INTO namespaces(owner_id, path, name, created_at, updated_at) VALUES(#{user_id}, '#{path}', '#{path}', NOW(), NOW())"
namespace_id = connection.insert(insert_query)
create_route(namespace_id)
end
def create_route(namespace_id)
return unless namespace_id
row = connection.exec_query("SELECT id, path FROM namespaces WHERE id=#{namespace_id}").first
id, path = row.values_at('id', 'path')
execute("INSERT INTO routes(source_id, source_type, path, name, created_at, updated_at) VALUES(#{id}, 'Namespace', '#{path}', '#{path}', NOW(), NOW())")
end
def set_notification_email(user_id)
execute "UPDATE users SET notification_email = email WHERE notification_email IS NULL AND id = #{user_id}"
end
end
class AddFurtherScopeColumnsToInternalIdTable < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
change_column_null :internal_ids, :project_id, true
add_column :internal_ids, :namespace_id, :integer, null: true
end
def down
change_column_null :internal_ids, :project_id, false
remove_column :internal_ids, :namespace_id
end
end
class AddIndexConstraintsToInternalIdTable < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :internal_ids, [:usage, :namespace_id], unique: true, where: 'namespace_id IS NOT NULL'
replace_index(:internal_ids, [:usage, :project_id], name: 'index_internal_ids_on_usage_and_project_id') do
add_concurrent_index :internal_ids, [:usage, :project_id], unique: true, where: 'project_id IS NOT NULL'
end
add_concurrent_foreign_key :internal_ids, :namespaces, column: :namespace_id, on_delete: :cascade
end
def down
remove_concurrent_index :internal_ids, [:usage, :namespace_id]
replace_index(:internal_ids, [:usage, :project_id], name: 'index_internal_ids_on_usage_and_project_id') do
add_concurrent_index :internal_ids, [:usage, :project_id], unique: true
end
remove_foreign_key :internal_ids, column: :namespace_id
end
private
def replace_index(table, columns, name:)
temporary_name = "#{name}_old"
if index_exists?(table, columns, name: name)
rename_index table, name, temporary_name
end
yield
remove_concurrent_index_by_name table, temporary_name
end
end
class AddTmpStagePriorityIndexToCiBuilds < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index(:ci_builds, [:stage_id, :stage_idx],
where: 'stage_idx IS NOT NULL', name: 'tmp_build_stage_position_index')
end
def down
remove_concurrent_index_by_name(:ci_builds, 'tmp_build_stage_position_index')
end
end
class AddIndexToCiStage < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :ci_stages, :position, :integer
end
end
class AddIndexToCiJobArtifactsFileStore < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :ci_job_artifacts, :file_store
end
def down
# rubocop:disable Migration/RemoveIndex
remove_index :ci_job_artifacts, :file_store if index_exists?(:ci_job_artifacts, :file_store)
end
end
class AddPipelineBuildForeignKey < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
execute <<~SQL
DELETE FROM ci_builds WHERE project_id IS NULL OR commit_id IS NULL
SQL
execute <<~SQL
DELETE FROM ci_builds WHERE NOT EXISTS
(SELECT true FROM ci_pipelines WHERE ci_pipelines.id = ci_builds.commit_id)
AND stage_id IS NULL
SQL
add_concurrent_foreign_key(:ci_builds, :ci_pipelines, column: :commit_id)
end
def down
return unless foreign_key_exists?(:ci_builds, :ci_pipelines, column: :commit_id)
remove_foreign_key(:ci_builds, column: :commit_id)
end
end
class CleanupBuildStageMigration < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
TMP_INDEX = 'tmp_id_stage_partial_null_index'.freeze
disable_ddl_transaction!
class Build < ActiveRecord::Base
include EachBatch
self.table_name = 'ci_builds'
self.inheritance_column = :_type_disabled
end
def up
disable_statement_timeout do
##
# We steal from the background migrations queue to catch up with the
# scheduled migrations set.
#
Gitlab::BackgroundMigration.steal('MigrateBuildStage')
##
# We add temporary index, to make iteration over batches more performant.
# Conditional here is to avoid the need of doing that in a separate
# migration file to make this operation idempotent.
#
unless index_exists_by_name?(:ci_builds, TMP_INDEX)
add_concurrent_index(:ci_builds, :id, where: 'stage_id IS NULL', name: TMP_INDEX)
end
##
# We check if there are remaining rows that should be migrated (for example
# if Sidekiq / Redis fails / is restarted, what could result in not all
# background migrations being executed correctly.
#
# We migrate remaining rows synchronously in a blocking way, to make sure
# that when this migration is done we are confident that all rows are
# already migrated.
#
Build.where('stage_id IS NULL').each_batch(of: 50) do |batch|
range = batch.pluck('MIN(id)', 'MAX(id)').first
Gitlab::BackgroundMigration::MigrateBuildStage.new.perform(*range)
end
##
# We remove temporary index, because it is not required during standard
# operations and runtime.
#
remove_concurrent_index_by_name(:ci_builds, TMP_INDEX)
end
end
def down
if index_exists_by_name?(:ci_builds, TMP_INDEX)
disable_statement_timeout do
remove_concurrent_index_by_name(:ci_builds, TMP_INDEX)
end
end
end
end
class AddPagesAccessLevelToProjectFeature < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
DOWNTIME = false
# rubocop: disable Migration/UpdateLargeTable
# rubocop: disable Migration/AddColumnWithDefault
def up
add_column_with_default(:project_features, :pages_access_level, :integer, default: ProjectFeature::PUBLIC, allow_null: false)
change_column_default(:project_features, :pages_access_level, ProjectFeature::ENABLED)
end
# rubocop: enable Migration/UpdateLargeTable
# rubocop: enable Migration/AddColumnWithDefault
def down
remove_column :project_features, :pages_access_level
end
end
class AddEnforceTermsToApplicationSettings < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
# rubocop:disable Migration/SaferBooleanColumn
add_column :application_settings, :enforce_terms, :boolean, default: false
end
end
class CreateApplicationSettingTerms < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/AddLimitToTextColumns
def change
create_table :application_setting_terms do |t|
t.integer :cached_markdown_version
t.text :terms, null: false
t.text :terms_html
end
end
# rubocop:enable Migration/AddLimitToTextColumns
end
class AddPipelineIidToCiPipelines < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
add_column :ci_pipelines, :iid, :integer
end
def down
remove_column :ci_pipelines, :iid, :integer
end
end
class CreateTermAgreements < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
create_table :term_agreements do |t|
t.references :term, index: true, null: false
t.foreign_key :application_setting_terms, column: :term_id
t.references :user, index: true, null: false, foreign_key: { on_delete: :cascade }
t.boolean :accepted, default: false, null: false
t.timestamps_with_timezone null: false
end
add_index :term_agreements, [:user_id, :term_id],
unique: true,
name: 'term_agreements_unique_index'
end
def down
# rubocop:disable Migration/RemoveIndex
remove_index :term_agreements, name: 'term_agreements_unique_index'
drop_table :term_agreements
end
end
class AssureCommitsCountForMergeRequestDiff < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
class MergeRequestDiff < ActiveRecord::Base
self.table_name = 'merge_request_diffs'
include ::EachBatch
end
def up
Gitlab::BackgroundMigration.steal('AddMergeRequestDiffCommitsCount')
MergeRequestDiff.where(commits_count: nil).each_batch(of: 50) do |batch|
range = batch.pluck('MIN(id)', 'MAX(id)').first
Gitlab::BackgroundMigration::AddMergeRequestDiffCommitsCount.new.perform(*range)
end
end
def down
# noop
end
end
class AddIndexConstraintsToPipelineIid < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :ci_pipelines, [:project_id, :iid], unique: true, where: 'iid IS NOT NULL'
end
def down
remove_concurrent_index :ci_pipelines, [:project_id, :iid]
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddAcceptedTermToUsers < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
change_table :users do |t|
t.references :accepted_term,
null: true
end
add_concurrent_foreign_key :users, :application_setting_terms, column: :accepted_term_id
end
def down
remove_foreign_key :users, column: :accepted_term_id
remove_column :users, :accepted_term_id
end
end
class AddRunnerTypeToCiRunners < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :ci_runners, :runner_type, :smallint
end
end
class CreateProjectMirrorData < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
# rubocop:disable Migration/AddLimitToTextColumns
def up
if table_exists?(:project_mirror_data)
add_column :project_mirror_data, :status, :string unless column_exists?(:project_mirror_data, :status)
add_column :project_mirror_data, :jid, :string unless column_exists?(:project_mirror_data, :jid)
add_column :project_mirror_data, :last_error, :text unless column_exists?(:project_mirror_data, :last_error)
else
create_table :project_mirror_data do |t|
t.references :project, index: true, foreign_key: { on_delete: :cascade }
t.string :status
t.string :jid
t.text :last_error
end
end
end
# rubocop:enable Migration/AddLimitToTextColumns
# rubocop:enable Migration/PreventStrings
def down
remove_column :project_mirror_data, :status
remove_column :project_mirror_data, :jid
remove_column :project_mirror_data, :last_error
# ee/db/migrate/20170509153720_create_project_mirror_data_ee.rb will remove the table.
end
end
class CreateRemoteMirrors < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
# rubocop:disable Migration/PreventStrings
def up
return if table_exists?(:remote_mirrors)
create_table :remote_mirrors do |t|
t.references :project, index: true, foreign_key: { on_delete: :cascade }
t.string :url
t.boolean :enabled, default: true
t.string :update_status
t.datetime :last_update_at # rubocop:disable Migration/Datetime
t.datetime :last_successful_update_at # rubocop:disable Migration/Datetime
t.datetime :last_update_started_at # rubocop:disable Migration/Datetime
t.string :last_error
t.boolean :only_protected_branches, default: false, null: false
t.string :remote_name
t.text :encrypted_credentials # rubocop:disable Migration/AddLimitToTextColumns
t.string :encrypted_credentials_iv
t.string :encrypted_credentials_salt
# rubocop:disable Migration/Timestamps
t.timestamps null: false
end
end
# rubocop:enable Migration/PreventStrings
def down
# ee/db/migrate/20160321161032_create_remote_mirrors_ee.rb will remove the table
end
end
class AddRemoteMirrorAvailableOverriddenToProjects < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column(:projects, :remote_mirror_available_overridden, :boolean) unless column_exists?(:projects, :remote_mirror_available_overridden) # rubocop:disable Migration/AddColumnsToWideTables
end
def down
# ee/db/migrate/20171017130239_add_remote_mirror_available_overridden_to_projects_ee.rb will remove the column.
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddIndexToNamespacesRunnersToken < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :namespaces, :runners_token, unique: true
end
def down
if index_exists?(:namespaces, :runners_token, unique: true)
# rubocop:disable Migration/RemoveIndex
remove_index :namespaces, :runners_token
end
end
end
class EnsureMissingColumnsToProjectMirrorData < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/AddLimitToTextColumns
# rubocop:disable Migration/PreventStrings
def up
add_column :project_mirror_data, :status, :string unless column_exists?(:project_mirror_data, :status)
add_column :project_mirror_data, :jid, :string unless column_exists?(:project_mirror_data, :jid)
add_column :project_mirror_data, :last_error, :text unless column_exists?(:project_mirror_data, :last_error)
end
# rubocop:enable Migration/PreventStrings
# rubocop:enable Migration/AddLimitToTextColumns
def down
# db/migrate/20180502122856_create_project_mirror_data.rb will remove the table
end
end
class AddIndexesToProjectMirrorData < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :project_mirror_data, :jid
add_concurrent_index :project_mirror_data, :status
end
def down
# rubocop:disable Migration/RemoveIndex
remove_index :project_mirror_data, :jid if index_exists? :project_mirror_data, :jid
remove_index :project_mirror_data, :status if index_exists? :project_mirror_data, :status
end
end
class AddIndexesToRemoteMirror < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :remote_mirrors, :last_successful_update_at unless index_exists?(:remote_mirrors, :last_successful_update_at)
end
def down
# ee/db/migrate/20170208144550_add_index_to_mirrors_last_update_at_fields.rb will remove the index.
# rubocop:disable Migration/RemoveIndex
remove_index :remote_mirrors, :last_successful_update_at if index_exists? :remote_mirrors, :last_successful_update_at
end
end
class AddMirrorAvailableToApplicationSettings < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
# rubocop:disable Migration/AddColumnWithDefault
add_column_with_default(:application_settings, :mirror_available, :boolean, default: true, allow_null: false) unless column_exists?(:application_settings, :mirror_available)
# rubocop:enable Migration/AddColumnWithDefault
end
def down
# ee/db/migrate/20171017125928_add_remote_mirror_available_to_application_settings.rb will remove the column.
end
end
class EnablePrometheusMetricsByDefault < ActiveRecord::Migration[4.2]
DOWNTIME = false
def up
change_column_default :application_settings, :prometheus_metrics_enabled, true
end
def down
change_column_default :application_settings, :prometheus_metrics_enabled, false
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class ProjectNameLowerIndex < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
INDEX_NAME = 'index_projects_on_lower_name'
disable_ddl_transaction!
def up
disable_statement_timeout do
execute "CREATE INDEX CONCURRENTLY #{INDEX_NAME} ON projects (LOWER(name))"
end
end
def down
disable_statement_timeout do
execute "DROP INDEX CONCURRENTLY IF EXISTS #{INDEX_NAME}"
end
end
end
class MakeRemoteMirrorsDisabledByDefault < ActiveRecord::Migration[4.2]
DOWNTIME = false
def up
change_column_default :remote_mirrors, :enabled, false
end
def down
change_column_default :remote_mirrors, :enabled, true
end
end
class AddNotNullConstraintToProjectMirrorDataForeignKey < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
class ProjectImportState < ActiveRecord::Base
include EachBatch
self.table_name = 'project_mirror_data'
end
def up
ProjectImportState.where(project_id: nil).delete_all
change_column_null :project_mirror_data, :project_id, false
end
def down
change_column_null :project_mirror_data, :project_id, true
end
end
class AddUniqueConstraintToProjectMirrorDataProjectIdIndex < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index(:project_mirror_data,
:project_id,
unique: true,
name: 'index_project_mirror_data_on_project_id_unique')
remove_concurrent_index_by_name(:project_mirror_data, 'index_project_mirror_data_on_project_id')
rename_index(:project_mirror_data,
'index_project_mirror_data_on_project_id_unique',
'index_project_mirror_data_on_project_id')
end
def down
rename_index(:project_mirror_data,
'index_project_mirror_data_on_project_id',
'index_project_mirror_data_on_project_id_old')
add_concurrent_index(:project_mirror_data, :project_id)
remove_concurrent_index_by_name(:project_mirror_data,
'index_project_mirror_data_on_project_id_old')
end
end
class SetRunnerTypeNotNull < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
change_column_null(:ci_runners, :runner_type, false)
end
end
class AddIndexOnCiRunnersRunnerType < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :ci_runners, :runner_type
end
def down
# rubocop:disable Migration/RemoveIndex
remove_index :ci_runners, :runner_type
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class CreateClustersApplicationsJupyter < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def change
create_table :clusters_applications_jupyter do |t|
t.references :cluster, null: false, unique: true, foreign_key: { on_delete: :cascade }
t.references :oauth_application, foreign_key: { on_delete: :nullify }
t.integer :status, null: false
t.string :version, null: false
t.string :hostname
t.timestamps_with_timezone null: false
t.text :status_reason # rubocop:disable Migration/AddLimitToTextColumns
end
end
# rubocop:enable Migration/PreventStrings
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddSquashToMergeRequests < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
DOWNTIME = false
def up
unless column_exists?(:merge_requests, :squash)
# rubocop:disable Migration/UpdateLargeTable
add_column_with_default :merge_requests, :squash, :boolean, default: false, allow_null: false # rubocop:disable Migration/AddColumnWithDefault
end
end
def down
remove_column :merge_requests, :squash if column_exists?(:merge_requests, :squash)
end
end
class CreateNotesDiffFiles < ActiveRecord::Migration[4.2]
DOWNTIME = false
disable_ddl_transaction!
# rubocop:disable Migration/AddLimitToTextColumns
# rubocop:disable Migration/PreventStrings
def change
create_table :note_diff_files do |t|
t.references :diff_note, references: :notes, null: false, index: { unique: true }
t.text :diff, null: false
t.boolean :new_file, null: false
t.boolean :renamed_file, null: false
t.boolean :deleted_file, null: false
t.string :a_mode, null: false
t.string :b_mode, null: false
t.text :new_path, null: false
t.text :old_path, null: false
end
# rubocop:disable Migration/AddConcurrentForeignKey
add_foreign_key :note_diff_files, :notes, column: :diff_note_id, on_delete: :cascade
# rubocop:enable Migration/AddConcurrentForeignKey
end
# rubocop:enable Migration/PreventStrings
# rubocop:enable Migration/AddLimitToTextColumns
end
class AddNotNullConstraintsToProjectAuthorizations < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
def up
execute <<~SQL
ALTER TABLE project_authorizations
ALTER COLUMN user_id SET NOT NULL,
ALTER COLUMN project_id SET NOT NULL,
ALTER COLUMN access_level SET NOT NULL
SQL
end
def down
execute <<~SQL
ALTER TABLE project_authorizations
ALTER COLUMN user_id DROP NOT NULL,
ALTER COLUMN project_id DROP NOT NULL,
ALTER COLUMN access_level DROP NOT NULL
SQL
end
end
class RenameMergeRequestsAllowMaintainerToPush < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
# NOOP
end
def down
if column_exists?(:merge_requests, :allow_collaboration)
cleanup_concurrent_column_rename :merge_requests, :allow_collaboration, :allow_maintainer_to_push
end
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class MergeRequestsTargetIdIidStatePartialIndex < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
INDEX_NAME = 'index_merge_requests_on_target_project_id_and_iid_opened'
disable_ddl_transaction!
def up
# On GitLab.com this index will take up roughly 5 MB of space.
add_concurrent_index(
:merge_requests,
[:target_project_id, :iid],
where: "state = 'opened'",
name: INDEX_NAME
)
end
def down
remove_concurrent_index_by_name(:merge_requests, INDEX_NAME)
end
end
class EnsureRemoteMirrorColumns < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
# rubocop:disable Migration/Datetime
# rubocop:disable Migration/PreventStrings
def up
add_column :remote_mirrors, :last_update_started_at, :datetime unless column_exists?(:remote_mirrors, :last_update_started_at)
add_column :remote_mirrors, :remote_name, :string unless column_exists?(:remote_mirrors, :remote_name)
unless column_exists?(:remote_mirrors, :only_protected_branches)
add_column_with_default(:remote_mirrors, # rubocop:disable Migration/AddColumnWithDefault
:only_protected_branches,
:boolean,
default: false,
allow_null: false)
end
end
# rubocop:enable Migration/PreventStrings
# rubocop:enable Migration/Datetime
def down
# db/migrate/20180503131624_create_remote_mirrors.rb will remove the table
end
end
class AddIndexToStagesPosition < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :ci_stages, [:pipeline_id, :position]
end
def down
remove_concurrent_index :ci_stages, [:pipeline_id, :position]
end
end
class AddRepositoryLanguages < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def up
create_table(:programming_languages) do |t|
t.string :name, null: false
t.string :color, null: false
t.datetime_with_timezone :created_at, null: false
end
create_table(:repository_languages, id: false) do |t|
t.references :project, null: false, foreign_key: { on_delete: :cascade }
t.references :programming_language, null: false
t.float :share, null: false
end
add_index :programming_languages, :name, unique: true
add_index :repository_languages, [:project_id, :programming_language_id],
unique: true, name: "index_repository_languages_on_project_and_languages_id"
end
# rubocop:enable Migration/PreventStrings
def down
drop_table :repository_languages
drop_table :programming_languages
end
end
class ChangeDefaultValueForDsaKeyRestriction < ActiveRecord::Migration[4.2]
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
def up
change_column :application_settings, :dsa_key_restriction, :integer, null: false,
default: -1
execute("UPDATE application_settings SET dsa_key_restriction = -1")
end
def down
change_column :application_settings, :dsa_key_restriction, :integer, null: false,
default: 0
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddDeployStrategyToProjectAutoDevops < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
disable_ddl_transaction!
def up
add_column_with_default :project_auto_devops, :deploy_strategy, :integer, default: 0, allow_null: false # rubocop:disable Migration/AddColumnWithDefault
end
def down
remove_column :project_auto_devops, :deploy_strategy
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddPushEventsBranchFilterToWebHooks < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :web_hooks, :push_events_branch_filter, :text # rubocop:disable Migration/AddLimitToTextColumns
end
end
class AddGroupToTodos < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
class Todo < ActiveRecord::Base
self.table_name = 'todos'
include ::EachBatch
end
def up
add_column(:todos, :group_id, :integer) unless group_id_exists?
add_concurrent_foreign_key :todos, :namespaces, column: :group_id, on_delete: :cascade
add_concurrent_index :todos, :group_id
change_column_null :todos, :project_id, true
end
def down
remove_foreign_key_without_error(:todos, column: :group_id)
remove_concurrent_index(:todos, :group_id)
remove_column(:todos, :group_id) if group_id_exists?
Todo.where(project_id: nil).each_batch { |batch| batch.delete_all }
change_column_null :todos, :project_id, false
end
private
def group_id_exists?
column_exists?(:todos, :group_id)
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class RenameMergeRequestsAllowCollaboration < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
disable_ddl_transaction!
def up
if column_exists?(:merge_requests, :allow_collaboration)
# rubocop:disable Migration/UpdateLargeTable
rename_column_concurrently :merge_requests, :allow_collaboration, :allow_maintainer_to_push
end
end
def down
# NOOP
end
end
# frozen_string_literal: true
class AddColumnsForHelmTillerCertificates < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/AddLimitToTextColumns
def change
add_column :clusters_applications_helm, :encrypted_ca_key, :text
add_column :clusters_applications_helm, :encrypted_ca_key_iv, :text
add_column :clusters_applications_helm, :ca_cert, :text
end
# rubocop:enable Migration/AddLimitToTextColumns
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class CreateCiBuildsRunnerSession < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def change
create_table :ci_builds_runner_session, id: :bigserial do |t|
t.integer :build_id, null: false
t.string :url, null: false
t.string :certificate
t.string :authorization
t.foreign_key :ci_builds, column: :build_id, on_delete: :cascade
t.index :build_id, unique: true
end
end
# rubocop:enable Migration/PreventStrings
end
class CreateImportExportUploads < ActiveRecord::Migration[4.2]
DOWNTIME = false
# rubocop:disable Migration/AddLimitToTextColumns
def change
create_table :import_export_uploads do |t|
t.datetime_with_timezone :updated_at, null: false
t.references :project, index: true, foreign_key: { on_delete: :cascade }, unique: true
t.text :import_file
t.text :export_file
end
add_index :import_export_uploads, :updated_at
end
# rubocop:enable Migration/AddLimitToTextColumns
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddIndexOnDeployableForDeployments < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :deployments, [:deployable_type, :deployable_id]
end
def down
remove_concurrent_index :deployments, [:deployable_type, :deployable_id]
end
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AlterWebHookLogsIndexes < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
disable_ddl_transaction!
# "created_at" comes first so the Sidekiq worker pruning old webhook logs can
# use a composite index.
#
# We leave the old standalone index on "web_hook_id" in place so future code
# that doesn't care about "created_at" can still use that index.
COLUMNS_TO_INDEX = %i[created_at web_hook_id]
def up
add_concurrent_index(:web_hook_logs, COLUMNS_TO_INDEX)
end
def down
remove_concurrent_index(:web_hook_logs, COLUMNS_TO_INDEX)
end
end
class CreateSiteStatistics < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
create_table :site_statistics do |t|
t.integer :repositories_count, default: 0, null: false
t.integer :wikis_count, default: 0, null: false
end
execute('INSERT INTO site_statistics (id) VALUES(1)')
end
def down
drop_table :site_statistics
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class RemoveOrphanedRoutes < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
class Route < ActiveRecord::Base
self.table_name = 'routes'
include EachBatch
def self.orphaned_namespace_routes
where(source_type: 'Namespace')
.where('NOT EXISTS ( SELECT 1 FROM namespaces WHERE namespaces.id = routes.source_id )')
end
def self.orphaned_project_routes
where(source_type: 'Project')
.where('NOT EXISTS ( SELECT 1 FROM projects WHERE projects.id = routes.source_id )')
end
end
def up
# Some of these queries can take up to 10 seconds to run on GitLab.com,
# which is pretty close to our 15 second statement timeout. To ensure a
# smooth deployment procedure we disable the statement timeouts for this
# migration, just in case.
disable_statement_timeout do
# On GitLab.com there are around 4000 orphaned project routes, and around
# 150 orphaned namespace routes.
[
Route.orphaned_project_routes,
Route.orphaned_namespace_routes
].each do |relation|
relation.each_batch(of: 1_000) do |batch|
batch.delete_all
end
end
end
end
def down
# There is no way to restore orphaned routes, and this doesn't make any
# sense anyway.
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
# This migration generates missing routes for any projects and namespaces that
# don't already have a route.
#
# On GitLab.com this would insert 611 project routes, and 0 namespace routes.
# The exact number could vary per instance, so we take care of both just in
# case.
class GenerateMissingRoutes < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
class User < ActiveRecord::Base
self.table_name = 'users'
end
class Route < ActiveRecord::Base
self.table_name = 'routes'
end
module Routable
def build_full_path
if parent && path
parent.build_full_path + '/' + path
else
path
end
end
def build_full_name
if parent && name
parent.human_name + ' / ' + name
else
name
end
end
def human_name
build_full_name
end
def attributes_for_insert
time = Time.zone.now
{
# We can't use "self.class.name" here as that would include the
# migration namespace.
source_type: source_type_for_route,
source_id: id,
created_at: time,
updated_at: time,
name: build_full_name,
# The route path might already be taken. Instead of trying to generate a
# new unique name on every conflict, we just append the row ID to the
# route path.
path: "#{build_full_path}-#{id}"
}
end
end
class Project < ActiveRecord::Base
self.table_name = 'projects'
include EachBatch
include GenerateMissingRoutes::Routable
belongs_to :namespace, class_name: 'GenerateMissingRoutes::Namespace'
has_one :route,
as: :source,
inverse_of: :source,
class_name: 'GenerateMissingRoutes::Route'
alias_method :parent, :namespace
alias_attribute :parent_id, :namespace_id
def self.without_routes
where(
'NOT EXISTS (
SELECT 1
FROM routes
WHERE source_type = ?
AND source_id = projects.id
)',
'Project'
)
end
def source_type_for_route
'Project'
end
end
class Namespace < ActiveRecord::Base
self.table_name = 'namespaces'
self.inheritance_column = :_type_disabled
include EachBatch
include GenerateMissingRoutes::Routable
belongs_to :parent, class_name: 'GenerateMissingRoutes::Namespace'
belongs_to :owner, class_name: 'GenerateMissingRoutes::User'
has_one :route,
as: :source,
inverse_of: :source,
class_name: 'GenerateMissingRoutes::Route'
def self.without_routes
where(
'NOT EXISTS (
SELECT 1
FROM routes
WHERE source_type = ?
AND source_id = namespaces.id
)',
'Namespace'
)
end
def source_type_for_route
'Namespace'
end
end
def up
[Namespace, Project].each do |model|
model.without_routes.each_batch(of: 100) do |batch|
rows = batch.map(&:attributes_for_insert)
Gitlab::Database.bulk_insert(:routes, rows)
end
end
end
def down
# Removing routes we previously generated makes no sense.
end
end
class AddHideThirdPartyOffersToApplicationSettings < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :hide_third_party_offers, # rubocop:disable Migration/AddColumnWithDefault
:boolean,
default: false,
allow_null: false)
end
def down
remove_column(:application_settings, :hide_third_party_offers)
end
end
class AddFileFormatToCiJobArtifacts < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
add_column :ci_job_artifacts, :file_format, :integer, limit: 2
end
end
class AddForeignKeyFromNotificationSettingsToUsers < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
class NotificationSetting < ActiveRecord::Base
self.table_name = 'notification_settings'
include EachBatch
end
class User < ActiveRecord::Base
self.table_name = 'users'
end
DOWNTIME = false
disable_ddl_transaction!
def up
NotificationSetting.each_batch(of: 1000) do |batch|
batch.where('NOT EXISTS (?)', User.select(1).where('users.id = notification_settings.user_id'))
.delete_all
end
add_concurrent_foreign_key(:notification_settings, :users, column: :user_id, on_delete: :cascade)
end
def down
remove_foreign_key(:notification_settings, column: :user_id)
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class DropDuplicateProtectedTags < ActiveRecord::Migration[4.2]
DOWNTIME = false
disable_ddl_transaction!
BATCH_SIZE = 1000
class Project < ActiveRecord::Base
self.table_name = 'projects'
include ::EachBatch
end
class ProtectedTag < ActiveRecord::Base
self.table_name = 'protected_tags'
end
def up
Project.each_batch(of: BATCH_SIZE) do |projects|
ids = ProtectedTag
.where(project_id: projects)
.group(:name, :project_id)
.select('max(id)')
tags = ProtectedTag
.where(project_id: projects)
.where.not(id: ids)
tags.delete_all
end
end
def down
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddProtectedTagsIndex < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :protected_tags, [:project_id, :name], unique: true
end
def down
remove_concurrent_index :protected_tags, [:project_id, :name]
end
end
# frozen_string_literal: true
class CreateUserStatuses < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def change
create_table :user_statuses, id: false, primary_key: :user_id do |t|
t.references :user,
foreign_key: { on_delete: :cascade },
null: false,
primary_key: true
t.integer :cached_markdown_version, limit: 4
t.string :emoji, null: false, default: 'speech_balloon'
t.string :message, limit: 100
t.string :message_html
end
end
# rubocop:enable Migration/PreventStrings
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
# frozen_string_literal: true
class RemoveRestrictedTodos < ActiveRecord::Migration[4.2]
DOWNTIME = false
disable_ddl_transaction!
MIGRATION = 'RemoveRestrictedTodos'.freeze
BATCH_SIZE = 1000
DELAY_INTERVAL = 5.minutes.to_i
class Project < ActiveRecord::Base
include EachBatch
self.table_name = 'projects'
end
def up
Project.where('EXISTS (SELECT 1 FROM todos WHERE todos.project_id = projects.id)')
.each_batch(of: BATCH_SIZE) do |batch, index|
range = batch.pluck('MIN(id)', 'MAX(id)').first
BackgroundMigrationWorker.perform_in(index * DELAY_INTERVAL, MIGRATION, range)
end
end
def down
# nothing to do
end
end
# frozen_string_literal: true
class AddInstanceStatisticsVisibilityToApplicationSetting < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :instance_statistics_visibility_private, # rubocop:disable Migration/AddColumnWithDefault
:boolean,
default: false,
allow_null: false)
end
def down
remove_column(:application_settings, :instance_statistics_visibility_private)
end
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddReceiveMaxInputSizeToApplicationSettings < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
add_column :application_settings, :receive_max_input_size, :integer
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddPrivateProfileToUsers < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
add_column :users, :private_profile, :boolean # rubocop:disable Migration/AddColumnsToWideTables
end
end
# frozen_string_literal: true
class AddWebIdeClientSidePreviewEnabledToApplicationSettings < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :web_ide_clientside_preview_enabled, # rubocop:disable Migration/AddColumnWithDefault
:boolean,
default: false,
allow_null: false)
end
def down
remove_column(:application_settings, :web_ide_clientside_preview_enabled)
end
end
# frozen_string_literal: true
class CreateResourceLabelEvents < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
create_table :resource_label_events, id: :bigserial do |t|
t.integer :action, null: false
t.references :issue, null: true, index: true, foreign_key: { on_delete: :cascade }
t.references :merge_request, null: true, index: true, foreign_key: { on_delete: :cascade }
t.references :label, index: true, foreign_key: { on_delete: :nullify }
t.references :user, index: true, foreign_key: { on_delete: :nullify }
t.datetime_with_timezone :created_at, null: false
end
end
end
# frozen_string_literal: true
class RemoveRedundantStatusIndexOnCiBuilds < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
remove_concurrent_index :ci_builds, :status
end
def down
add_concurrent_index :ci_builds, :status
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddUserShowAddSshKeyMessageToApplicationSettings < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
disable_ddl_transaction!
def up
# rubocop:disable Migration/AddColumnWithDefault
add_column_with_default :application_settings, :user_show_add_ssh_key_message, :boolean, default: true, allow_null: false
# rubocop:enable Migration/AddColumnWithDefault
end
def down
remove_column :application_settings, :user_show_add_ssh_key_message
end
end
# frozen_string_literal: true
class ChangeDefaultOfAutoDevopsInstanceWide < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
change_column_default :application_settings, :auto_devops_enabled, true
end
def down
change_column_default :application_settings, :auto_devops_enabled, false
end
end
# frozen_string_literal: true
class EnableAutoDevopsInstanceWideForEveryone < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
execute "UPDATE application_settings SET auto_devops_enabled = true"
end
def down
# No way to know here what their previous setting was...
end
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddCommitEmailToUsers < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
# When a migration requires downtime you **must** uncomment the following
# constant and define a short and easy to understand explanation as to why the
# migration requires downtime.
# DOWNTIME_REASON = ''
# When using the methods "add_concurrent_index", "remove_concurrent_index" or
# "add_column_with_default" you must disable the use of transactions
# as these methods can not run in an existing transaction.
# When using "add_concurrent_index" or "remove_concurrent_index" methods make sure
# that either of them is the _only_ method called in the migration,
# any other changes should go in a separate migration.
# This ensures that upon failure _only_ the index creation or removing fails
# and can be retried or reverted easily.
#
# To disable transactions uncomment the following line and remove these
# comments:
# disable_ddl_transaction!
# rubocop:disable Migration/PreventStrings
# rubocop:disable Migration/AddColumnsToWideTables
def change
add_column :users, :commit_email, :string
end
# rubocop:enable Migration/AddColumnsToWideTables
# rubocop:enable Migration/PreventStrings
end
# frozen_string_literal: true
class AddAuthorizationTypeToClusterPlatformsKubernetes < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :cluster_platforms_kubernetes, :authorization_type, :integer, limit: 2
end
end
class AddFileLocationToCiJobArtifacts < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :ci_job_artifacts, :file_location, :integer, limit: 2
end
end
class AddPartialIndexToCiBuildsArtifactsFile < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
INDEX_NAME = 'partial_index_ci_builds_on_id_with_legacy_artifacts'.freeze
disable_ddl_transaction!
def up
add_concurrent_index(:ci_builds, :id, where: "artifacts_file <> ''", name: INDEX_NAME)
end
def down
remove_concurrent_index_by_name(:ci_builds, INDEX_NAME)
end
end
# frozen_string_literal: true
class AddIndexOnListType < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :lists, :list_type
end
def down
remove_concurrent_index :lists, :list_type
end
end
# frozen_string_literal: true
class AddOutboundRequestsWhitelistToApplicationSettings < ActiveRecord::Migration[5.1]
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def change
add_column :application_settings, :outbound_local_requests_whitelist, :string, array: true, limit: 255
end
# rubocop:enable Migration/PreventStrings
end
# frozen_string_literal: true
class AddCommonToPrometheusMetrics < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column_with_default(:prometheus_metrics, :common, :boolean, default: false) # rubocop:disable Migration/AddColumnWithDefault
end
def down
remove_column(:prometheus_metrics, :common)
end
end
# frozen_string_literal: true
class AddIndexOnCommonForPrometheusMetrics < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :prometheus_metrics, :common
end
def down
remove_concurrent_index :prometheus_metrics, :common
end
end
# frozen_string_literal: true
class AddIdentifierToPrometheusMetric < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :prometheus_metrics, :identifier, :string # rubocop:disable Migration/PreventStrings
end
end
# frozen_string_literal: true
class AddIndexForIdentifierToPrometheusMetric < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :prometheus_metrics, :identifier, unique: true
end
def down
remove_concurrent_index :prometheus_metrics, :identifier, unique: true
end
end
# frozen_string_literal: true
class ImportCommonMetrics < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
::Gitlab::DatabaseImporters::CommonMetrics::Importer.new.execute
end
def down
# no-op
end
end
# frozen_string_literal: true
class AddProjectConfigSourceStatusIndexToPipeline < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :ci_pipelines, [:project_id, :status, :config_source]
end
def down
remove_concurrent_index :ci_pipelines, [:project_id, :status, :config_source]
end
end
# frozen_string_literal: true
class AddResourceLabelEventReferenceFields < ActiveRecord::Migration[4.2]
DOWNTIME = false
# rubocop:disable Migration/AddLimitToTextColumns
def change
add_column :resource_label_events, :cached_markdown_version, :integer
add_column :resource_label_events, :reference, :text
add_column :resource_label_events, :reference_html, :text
end
# rubocop:enable Migration/AddLimitToTextColumns
end
# frozen_string_literal: true
class CreateGroupGroupLinks < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
create_table :group_group_links do |t|
t.timestamps_with_timezone null: false
t.references :shared_group, null: false,
index: false,
foreign_key: { on_delete: :cascade,
to_table: :namespaces }
t.references :shared_with_group, null: false,
foreign_key: { on_delete: :cascade,
to_table: :namespaces }
t.date :expires_at
t.index [:shared_group_id, :shared_with_group_id],
{ unique: true,
name: 'index_group_group_links_on_shared_group_and_shared_with_group' }
t.integer :group_access, { limit: 2,
default: 30, # Gitlab::Access::DEVELOPER
null: false }
end
end
def down
drop_table :group_group_links
end
end
# frozen_string_literal: true
class AddUserPingConsentToApplicationSettings < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column :application_settings, :usage_stats_set_by_user_id, :integer
add_concurrent_foreign_key :application_settings, :users, column: :usage_stats_set_by_user_id, on_delete: :nullify
end
def down
remove_foreign_key :application_settings, column: :usage_stats_set_by_user_id
remove_column :application_settings, :usage_stats_set_by_user_id
end
end
# frozen_string_literal: true
class AddLegacyAbacToClusterProvidersGcp < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column_with_default(:cluster_providers_gcp, :legacy_abac, :boolean, default: true) # rubocop:disable Migration/AddColumnWithDefault
end
def down
remove_column(:cluster_providers_gcp, :legacy_abac)
end
end
# frozen_string_literal: true
class AddAttrEncryptedColumnsToWebHook < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def change
add_column :web_hooks, :encrypted_token, :string
add_column :web_hooks, :encrypted_token_iv, :string
add_column :web_hooks, :encrypted_url, :string
add_column :web_hooks, :encrypted_url_iv, :string
end
# rubocop:enable Migration/PreventStrings
end
# frozen_string_literal: true
class AddTokenDigestToPersonalAccessTokens < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
change_column :personal_access_tokens, :token, :string, null: true
add_column :personal_access_tokens, :token_digest, :string # rubocop:disable Migration/PreventStrings
end
def down
remove_column :personal_access_tokens, :token_digest
change_column :personal_access_tokens, :token, :string, null: false
end
end
# frozen_string_literal: true
class AddIndexToTokenDigestOnPersonalAccessTokens < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :personal_access_tokens, :token_digest, unique: true
end
def down
remove_concurrent_index :personal_access_tokens, :token_digest if index_exists?(:personal_access_tokens, :token_digest)
end
end
# frozen_string_literal: true
class AddKnativeApplication < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def change
create_table "clusters_applications_knative" do |t|
t.references :cluster, null: false, unique: true, foreign_key: { on_delete: :cascade }
t.datetime_with_timezone "created_at", null: false
t.datetime_with_timezone "updated_at", null: false
t.integer "status", null: false
t.string "version", null: false
t.string "hostname"
t.text "status_reason" # rubocop:disable Migration/AddLimitToTextColumns
end
end
# rubocop:enable Migration/PreventStrings
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddIndexPipelinesProjectIdSource < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :ci_pipelines, [:project_id, :source]
end
def down
remove_concurrent_index :ci_pipelines, [:project_id, :source]
end
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddDiffMaxPatchBytesToApplicationSettings < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, # rubocop:disable Migration/AddColumnWithDefault
:diff_max_patch_bytes,
:integer,
default: 100.kilobytes,
allow_null: false)
end
def down
remove_column(:application_settings, :diff_max_patch_bytes)
end
end
# frozen_string_literal: true
class AddScheduledAtToCiBuilds < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
add_column :ci_builds, :scheduled_at, :datetime_with_timezone # rubocop:disable Migration/AddColumnsToWideTables
end
end
# frozen_string_literal: true
class AddPartialIndexToScheduledAt < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
INDEX_NAME = 'partial_index_ci_builds_on_scheduled_at_with_scheduled_jobs'.freeze
disable_ddl_transaction!
def up
add_concurrent_index(:ci_builds, :scheduled_at, where: "scheduled_at IS NOT NULL AND type = 'Ci::Build' AND status = 'scheduled'", name: INDEX_NAME)
end
def down
remove_concurrent_index_by_name(:ci_builds, INDEX_NAME)
end
end
# frozen_string_literal: true
class CreateUserPreferences < ActiveRecord::Migration[4.2]
DOWNTIME = false
class UserPreference < ActiveRecord::Base
self.table_name = 'user_preferences'
NOTES_FILTERS = { all_notes: 0, comments: 1 }.freeze
end
def change
create_table :user_preferences do |t|
t.references :user,
null: false,
index: { unique: true },
foreign_key: { on_delete: :cascade }
t.integer :issue_notes_filter,
default: UserPreference::NOTES_FILTERS[:all_notes],
null: false, limit: 2
t.integer :merge_request_notes_filter,
default: UserPreference::NOTES_FILTERS[:all_notes],
null: false,
limit: 2
t.timestamps_with_timezone null: false
end
end
end
# frozen_string_literal: true
class AddIndexToProjectDeployTokensDeployTokenId < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :project_deploy_tokens, :deploy_token_id
end
def down
remove_concurrent_index(:project_deploy_tokens, :deploy_token_id)
end
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
# rescheduling of the revised RemoveRestrictedTodos background migration
class RemoveRestrictedTodosWithCte < ActiveRecord::Migration[4.2]
DOWNTIME = false
disable_ddl_transaction!
MIGRATION = 'RemoveRestrictedTodos'.freeze
BATCH_SIZE = 1000
DELAY_INTERVAL = 5.minutes.to_i
class Project < ActiveRecord::Base
include EachBatch
self.table_name = 'projects'
end
def up
Project.where('EXISTS (SELECT 1 FROM todos WHERE todos.project_id = projects.id)')
.each_batch(of: BATCH_SIZE) do |batch, index|
range = batch.pluck('MIN(id)', 'MAX(id)').first
BackgroundMigrationWorker.perform_in(index * DELAY_INTERVAL, MIGRATION, range)
end
end
def down
# nothing to do
end
end
# frozen_string_literal: true
class AddIndexToLfsObjectsFileStore < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :lfs_objects, :file_store
end
def down
remove_concurrent_index :lfs_objects, :file_store
end
end
# frozen_string_literal: true
class AddIndexToUploadsStore < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :uploads, :store
end
def down
remove_concurrent_index :uploads, :store
end
end
class ImportCommonMetricsNginxVts < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
::Gitlab::DatabaseImporters::CommonMetrics::Importer.new.execute
end
def down
# no-op
end
end
# frozen_string_literal: true
class CreateClustersKubernetesNamespaces < ActiveRecord::Migration[4.2]
DOWNTIME = false
INDEX_NAME = 'kubernetes_namespaces_cluster_and_namespace'
# rubocop:disable Migration/PreventStrings
def change
create_table :clusters_kubernetes_namespaces, id: :bigserial do |t|
t.references :cluster, null: false, index: true, foreign_key: { on_delete: :cascade }
t.references :project, index: true, foreign_key: { on_delete: :nullify }
t.references :cluster_project, index: true, foreign_key: { on_delete: :nullify }
t.timestamps_with_timezone null: false
t.string :encrypted_service_account_token_iv
t.string :namespace, null: false
t.string :service_account_name
t.text :encrypted_service_account_token # rubocop:disable Migration/AddLimitToTextColumns
t.index [:cluster_id, :namespace], name: INDEX_NAME, unique: true
end
end
# rubocop:enable Migration/PreventStrings
end
# frozen_string_literal: true
class CreateBoardProjectRecentVisits < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
create_table :board_project_recent_visits, id: :bigserial do |t|
t.timestamps_with_timezone null: false
t.references :user, index: true, foreign_key: { on_delete: :cascade }
t.references :project, index: true, foreign_key: { on_delete: :cascade }
t.references :board, index: true, foreign_key: { on_delete: :cascade }
end
add_index :board_project_recent_visits, [:user_id, :project_id, :board_id], unique: true, name: 'index_board_project_recent_visits_on_user_project_and_board'
end
end
# frozen_string_literal: true
class CreateClusterGroups < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
create_table :cluster_groups do |t|
t.references :cluster, null: false, foreign_key: { on_delete: :cascade }
t.references :group, null: false, index: true
t.index [:cluster_id, :group_id], unique: true
t.foreign_key :namespaces, column: :group_id, on_delete: :cascade
end
end
end
# frozen_string_literal: true
class AddFinishedAtToDeployments < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
add_column :deployments, :finished_at, :datetime_with_timezone
end
def down
remove_column :deployments, :finished_at, :datetime_with_timezone
end
end
# frozen_string_literal: true
class AddStatusToDeployments < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DEPLOYMENT_STATUS_SUCCESS = 2 # Equivalent to Deployment.state_machine.states['success'].value
DOWNTIME = false
disable_ddl_transaction!
##
# NOTE:
# Ideally, `status` column should not have default value because it should be leveraged by state machine (i.e. application level).
# However, we have to use the default value for avoiding `NOT NULL` violation during the transition period.
# The default value should be removed in the future release.
# rubocop:disable Migration/AddColumnWithDefault
# rubocop:disable Migration/UpdateLargeTable
def up
add_column_with_default(:deployments,
:status,
:integer,
limit: 2,
default: DEPLOYMENT_STATUS_SUCCESS,
allow_null: false)
end
# rubocop:enable Migration/AddColumnWithDefault
# rubocop:enable Migration/UpdateLargeTable
def down
remove_column(:deployments, :status)
end
end
# frozen_string_literal: true
class CreateBoardGroupRecentVisits < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
create_table :board_group_recent_visits, id: :bigserial do |t|
t.timestamps_with_timezone null: false
t.references :user, index: true, foreign_key: { on_delete: :cascade }
t.references :board, index: true, foreign_key: { on_delete: :cascade }
t.references :group, references: :namespace, column: :group_id, index: true
t.foreign_key :namespaces, column: :group_id, on_delete: :cascade
end
add_index :board_group_recent_visits, [:user_id, :group_id, :board_id], unique: true, name: 'index_board_group_recent_visits_on_user_group_and_board'
end
end
# frozen_string_literal: true
class AddClusterTypeToClusters < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
PROJECT_CLUSTER_TYPE = 3
disable_ddl_transaction!
def up
add_column_with_default(:clusters, :cluster_type, :smallint, default: PROJECT_CLUSTER_TYPE) # rubocop:disable Migration/AddColumnWithDefault
end
def down
remove_column(:clusters, :cluster_type)
end
end
# frozen_string_literal: true
class AddShardsTable < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
create_table :shards do |t|
t.string :name, null: false, index: { unique: true } # rubocop:disable Migration/PreventStrings
end
end
end
# frozen_string_literal: true
class AddRepositoriesTable < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
create_table :repositories, id: :bigserial do |t|
t.references :shard, null: false, index: true, foreign_key: { on_delete: :restrict }
t.string :disk_path, null: false, index: { unique: true } # rubocop:disable Migration/PreventStrings
end
add_column :projects, :pool_repository_id, :bigint # rubocop:disable Migration/AddColumnsToWideTables
add_index :projects, :pool_repository_id, where: 'pool_repository_id IS NOT NULL'
end
end
# frozen_string_literal: true
class AddProjectsPoolRepositoryIdForeignKey < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_foreign_key(
:projects,
:repositories,
column: :pool_repository_id,
on_delete: :nullify
)
end
def down
remove_foreign_key(:projects, column: :pool_repository_id)
end
end
# frozen_string_literal: true
class AddIndexOnStatusToDeployments < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :deployments, [:project_id, :status]
add_concurrent_index :deployments, [:environment_id, :status]
end
def down
remove_concurrent_index :deployments, [:project_id, :status]
remove_concurrent_index :deployments, [:environment_id, :status]
end
end
# frozen_string_literal: true
class AddArchiveBuildsDurationToApplicationSettings < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column(:application_settings, :archive_builds_in_seconds, :integer, allow_null: true)
end
end
# frozen_string_literal: true
class AddPartialIndexForLegacySuccessfulDeployments < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
INDEX_NAME = 'partial_index_deployments_for_legacy_successful_deployments'.freeze
disable_ddl_transaction!
def up
add_concurrent_index(:deployments, :id, where: "finished_at IS NULL AND status = 2", name: INDEX_NAME)
end
def down
remove_concurrent_index_by_name(:deployments, INDEX_NAME)
end
end
# frozen_string_literal: true
class AddPrivateCommitEmailHostnameToApplicationSettings < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def change
add_column(:application_settings, :commit_email_hostname, :string, null: true)
end
# rubocop:enable Migration/PreventStrings
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class MigrateSnippetsAccessLevelDefaultValue < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
ENABLED = 20
disable_ddl_transaction!
class ProjectFeature < ActiveRecord::Base
include EachBatch
self.table_name = 'project_features'
end
def up
change_column_default :project_features, :snippets_access_level, ENABLED
# On GitLab.com this will update about 28 000 rows. Since our updates are
# very small and this column is not indexed, these updates should be very
# lightweight.
ProjectFeature.where(snippets_access_level: nil).each_batch do |batch|
batch.update_all(snippets_access_level: ENABLED)
end
# We do not need to perform this in a post-deployment migration as the
# ProjectFeature model already enforces a default value for all new rows.
change_column_null :project_features, :snippets_access_level, false
end
def down
change_column_null :project_features, :snippets_access_level, true
change_column_default :project_features, :snippets_access_level, nil
# We can't migrate from 20 -> NULL, as some projects may have explicitly set
# the access level to 20.
end
end
# frozen_string_literal: true
class AddFirstDayOfWeekToUserPreferences < ActiveRecord::Migration[5.0]
DOWNTIME = false
def change
add_column :user_preferences, :first_day_of_week, :integer
end
end
# frozen_string_literal: true
class AddFirstDayOfWeekToApplicationSettings < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
DOWNTIME = false
def up
add_column_with_default(:application_settings, :first_day_of_week, :integer, default: 0) # rubocop:disable Migration/AddColumnWithDefault
end
def down
remove_column(:application_settings, :first_day_of_week)
end
end
# frozen_string_literal: true
class AddMissingIndexesForForeignKeys < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index(:application_settings, :usage_stats_set_by_user_id)
add_concurrent_index(:ci_pipeline_schedules, :owner_id)
add_concurrent_index(:ci_trigger_requests, :trigger_id)
add_concurrent_index(:ci_triggers, :owner_id)
add_concurrent_index(:clusters_applications_helm, :cluster_id, unique: true)
add_concurrent_index(:clusters_applications_ingress, :cluster_id, unique: true)
add_concurrent_index(:clusters_applications_jupyter, :cluster_id, unique: true)
add_concurrent_index(:clusters_applications_jupyter, :oauth_application_id)
add_concurrent_index(:clusters_applications_knative, :cluster_id, unique: true)
add_concurrent_index(:clusters_applications_prometheus, :cluster_id, unique: true)
add_concurrent_index(:fork_network_members, :forked_from_project_id)
add_concurrent_index(:internal_ids, :namespace_id)
add_concurrent_index(:internal_ids, :project_id)
add_concurrent_index(:issues, :closed_by_id)
add_concurrent_index(:label_priorities, :label_id)
add_concurrent_index(:merge_request_metrics, :merged_by_id)
add_concurrent_index(:merge_request_metrics, :latest_closed_by_id)
add_concurrent_index(:oauth_openid_requests, :access_grant_id)
add_concurrent_index(:project_deploy_tokens, :deploy_token_id)
add_concurrent_index(:protected_tag_create_access_levels, :group_id)
add_concurrent_index(:subscriptions, :project_id)
add_concurrent_index(:user_statuses, :user_id)
add_concurrent_index(:users, :accepted_term_id)
end
def down
remove_concurrent_index(:application_settings, :usage_stats_set_by_user_id)
remove_concurrent_index(:ci_pipeline_schedules, :owner_id)
remove_concurrent_index(:ci_trigger_requests, :trigger_id)
remove_concurrent_index(:ci_triggers, :owner_id)
remove_concurrent_index(:clusters_applications_helm, :cluster_id, unique: true)
remove_concurrent_index(:clusters_applications_ingress, :cluster_id, unique: true)
remove_concurrent_index(:clusters_applications_jupyter, :cluster_id, unique: true)
remove_concurrent_index(:clusters_applications_jupyter, :oauth_application_id)
remove_concurrent_index(:clusters_applications_knative, :cluster_id, unique: true)
remove_concurrent_index(:clusters_applications_prometheus, :cluster_id, unique: true)
remove_concurrent_index(:fork_network_members, :forked_from_project_id)
remove_concurrent_index(:internal_ids, :namespace_id)
remove_concurrent_index(:internal_ids, :project_id)
remove_concurrent_index(:issues, :closed_by_id)
remove_concurrent_index(:label_priorities, :label_id)
remove_concurrent_index(:merge_request_metrics, :merged_by_id)
remove_concurrent_index(:merge_request_metrics, :latest_closed_by_id)
remove_concurrent_index(:oauth_openid_requests, :access_grant_id)
remove_concurrent_index(:project_deploy_tokens, :deploy_token_id)
remove_concurrent_index(:protected_tag_create_access_levels, :group_id)
remove_concurrent_index(:subscriptions, :project_id)
remove_concurrent_index(:user_statuses, :user_id)
remove_concurrent_index(:users, :accepted_term_id)
end
end
# frozen_string_literal: true
class AddProtectedCiVariablesToApplicationSettings < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :protected_ci_variables, :boolean, default: false, allow_null: false) # rubocop:disable Migration/AddColumnWithDefault
end
def down
remove_column(:application_settings, :protected_ci_variables)
end
end
# frozen_string_literal: true
class DropFkGcpClustersTable < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
remove_foreign_key_if_exists :gcp_clusters, column: :project_id
remove_foreign_key_if_exists :gcp_clusters, column: :user_id
remove_foreign_key_if_exists :gcp_clusters, column: :service_id
end
def down
add_foreign_key_if_not_exists :gcp_clusters, :projects, column: :project_id, on_delete: :cascade
add_foreign_key_if_not_exists :gcp_clusters, :users, column: :user_id, on_delete: :nullify
add_foreign_key_if_not_exists :gcp_clusters, :services, column: :service_id, on_delete: :nullify
end
private
def add_foreign_key_if_not_exists(source, target, column:, on_delete:)
return unless table_exists?(source)
return if foreign_key_exists?(source, target, column: column)
add_concurrent_foreign_key(source, target, column: column, on_delete: on_delete)
end
def remove_foreign_key_if_exists(table, column:)
return unless table_exists?(table)
return unless foreign_key_exists?(table, column: column)
remove_foreign_key(table, column: column)
end
end
# frozen_string_literal: true
class DropGcpClustersTable < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
drop_table :gcp_clusters
end
def down
create_table :gcp_clusters do |t|
# Order columns by best align scheme
t.references :project, null: false, index: { unique: true }, foreign_key: { on_delete: :cascade }
t.references :user, foreign_key: { on_delete: :nullify }
t.references :service, foreign_key: { on_delete: :nullify }
t.integer :status
t.integer :gcp_cluster_size, null: false
# Timestamps
t.datetime_with_timezone :created_at, null: false
t.datetime_with_timezone :updated_at, null: false
# Enable/disable
t.boolean :enabled, default: true
# General
t.text :status_reason
# k8s integration specific
t.string :project_namespace
# Cluster details
t.string :endpoint
t.text :ca_cert
t.text :encrypted_kubernetes_token
t.string :encrypted_kubernetes_token_iv
t.string :username
t.text :encrypted_password
t.string :encrypted_password_iv
# GKE
t.string :gcp_project_id, null: false
t.string :gcp_cluster_zone, null: false
t.string :gcp_cluster_name, null: false
t.string :gcp_machine_type
t.string :gcp_operation_id
t.text :encrypted_gcp_token
t.string :encrypted_gcp_token_iv
end
end
end
# frozen_string_literal: true
class AddIndexForStuckMrQuery < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :merge_requests, [:id, :merge_jid], where: "merge_jid IS NOT NULL and state = 'locked'"
end
def down
remove_concurrent_index :merge_requests, [:id, :merge_jid], where: "merge_jid IS NOT NULL and state = 'locked'"
end
end
# frozen_string_literal: true
class CreateClustersApplicationsCertManager < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def change
create_table :clusters_applications_cert_managers do |t|
t.references :cluster, null: false, index: false, foreign_key: { on_delete: :cascade }
t.integer :status, null: false
t.string :version, null: false
t.string :email, null: false
t.timestamps_with_timezone null: false
t.text :status_reason # rubocop:disable Migration/AddLimitToTextColumns
t.index :cluster_id, unique: true
end
end
# rubocop:enable Migration/PreventStrings
end
# frozen_string_literal: true
class AddIndexToDeployments < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :deployments, [:project_id, :status, :created_at]
end
def down
remove_concurrent_index :deployments, [:project_id, :status, :created_at]
end
end
# frozen_string_literal: true
class CleanupEnvironmentsExternalUrl < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
update_column_in_batches(:environments, :external_url, nil) do |table, query|
query.where(table[:external_url].matches('javascript://%'))
end
end
def down
end
end
# frozen_string_literal: true
class DropDefaultValueOnStatusDeployments < ActiveRecord::Migration[4.2]
DOWNTIME = false
DEPLOYMENT_STATUS_SUCCESS = 2 # Equivalent to Deployment.state_machine.states['success'].value
def up
change_column_default :deployments, :status, nil
end
def down
change_column_default :deployments, :status, DEPLOYMENT_STATUS_SUCCESS
end
end
# frozen_string_literal: true
class AddEncryptedRunnersTokenToSettings < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def change
add_column :application_settings, :runners_registration_token_encrypted, :string
end
# rubocop:enable Migration/PreventStrings
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class KnativeExternalIp < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def change
add_column :clusters_applications_knative, :external_ip, :string
end
# rubocop:enable Migration/PreventStrings
end
# frozen_string_literal: true
class AddEncryptedRunnersTokenToNamespaces < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def change
add_column :namespaces, :runners_token_encrypted, :string
end
# rubocop:enable Migration/PreventStrings
end
# frozen_string_literal: true
class AddEncryptedRunnersTokenToProjects < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/AddColumnsToWideTables
# rubocop:disable Migration/PreventStrings
def change
add_column :projects, :runners_token_encrypted, :string
end
# rubocop:enable Migration/PreventStrings
# rubocop:enable Migration/AddColumnsToWideTables
end
# frozen_string_literal: true
class AddMergeRequestIdToCiPipelines < ActiveRecord::Migration[4.2]
DOWNTIME = false
def up
add_column :ci_pipelines, :merge_request_id, :integer
end
def down
remove_column :ci_pipelines, :merge_request_id, :integer
end
end
# frozen_string_literal: true
class AddIndexesToCiBuildsAndPipelines < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
indexes.each do |index|
add_concurrent_index(*index)
end
end
def down
indexes.each do |index|
remove_concurrent_index(*index)
end
end
private
def indexes
[
[
:ci_pipelines,
[:project_id, :ref, :id],
{
order: { id: :desc },
name: 'index_ci_pipelines_on_project_idandrefandiddesc'
}
],
[
:ci_builds,
[:commit_id, :artifacts_expire_at, :id],
{
where: "type::text = 'Ci::Build'::text AND (retried = false OR retried IS NULL) AND (name::text = ANY (ARRAY['sast'::character varying, 'dependency_scanning'::character varying, 'sast:container'::character varying, 'container_scanning'::character varying, 'dast'::character varying]::text[]))",
name: 'index_ci_builds_on_commit_id_and_artifacts_expireatandidpartial'
}
]
]
end
end
class RenameRepositoriesPoolRepositories < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
# This change doesn't require downtime as the table is not in use, so we're
# free to change an empty table
DOWNTIME = false
def change
rename_table :repositories, :pool_repositories
end
end
# frozen_string_literal: true
class AddForeignKeyToCiPipelinesMergeRequests < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :ci_pipelines, :merge_request_id, where: 'merge_request_id IS NOT NULL'
add_concurrent_foreign_key :ci_pipelines, :merge_requests, column: :merge_request_id, on_delete: :cascade
end
def down
if foreign_key_exists?(:ci_pipelines, :merge_requests, column: :merge_request_id)
remove_foreign_key :ci_pipelines, :merge_requests
end
remove_concurrent_index :ci_pipelines, :merge_request_id, where: 'merge_request_id IS NOT NULL'
end
end
# frozen_string_literal: true
class AddTokenEncryptedToCiRunners < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :ci_runners, :token_encrypted, :string # rubocop:disable Migration/PreventStrings
end
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddCiBuildsPartialIndexOnProjectIdAndStatus < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index(*index_arguments)
end
def down
remove_concurrent_index(*index_arguments)
end
private
def index_arguments
[
:ci_builds,
[:project_id, :status],
{
name: 'index_ci_builds_project_id_and_status_for_live_jobs_partial2',
where: "(((type)::text = 'Ci::Build'::text) AND ((status)::text = ANY (ARRAY[('running'::character varying)::text, ('pending'::character varying)::text, ('created'::character varying)::text])))"
}
]
end
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class RemoveRedundantCiBuildsPartialIndex < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
remove_concurrent_index(*index_arguments)
end
def down
add_concurrent_index(*index_arguments)
end
private
def index_arguments
[
:ci_builds,
[:project_id, :status],
{
name: 'index_ci_builds_project_id_and_status_for_live_jobs_partial',
where: "((status)::text = ANY (ARRAY[('running'::character varying)::text, ('pending'::character varying)::text, ('created'::character varying)::text]))"
}
]
end
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class CreateProjectRepositories < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
create_table :project_repositories, id: :bigserial do |t|
t.references :shard, null: false, index: true, foreign_key: { on_delete: :restrict }
t.string :disk_path, null: false, index: { unique: true } # rubocop:disable Migration/PreventStrings
t.references :project, null: false, index: { unique: true }, foreign_key: { on_delete: :cascade }
end
end
end
# frozen_string_literal: true
class DropNotNullConstraintPoolRepositoryDiskPath < ActiveRecord::Migration[5.0]
DOWNTIME = false
def change
change_column_null :pool_repositories, :disk_path, true
end
end
# frozen_string_literal: true
class CreateSuggestions < ActiveRecord::Migration[5.0]
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
# rubocop:disable Migration/AddLimitToTextColumns
def change
create_table :suggestions, id: :bigserial do |t|
t.references :note, foreign_key: { on_delete: :cascade }, null: false
t.integer :relative_order, null: false, limit: 2
t.boolean :applied, null: false, default: false
t.string :commit_id
t.text :from_content, null: false
t.text :to_content, null: false
t.index [:note_id, :relative_order],
name: 'index_suggestions_on_note_id_and_relative_order',
unique: true
end
end
# rubocop:enable Migration/AddLimitToTextColumns
# rubocop:enable Migration/PreventStrings
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddEventsIndexOnProjectIdAndCreatedAt < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index(*index_arguments)
end
def down
remove_concurrent_index(*index_arguments)
end
private
def index_arguments
[
:events,
[:project_id, :created_at],
{
name: 'index_events_on_project_id_and_created_at'
}
]
end
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class RemoveNotesIndexOnUpdatedAt < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
remove_concurrent_index(*index_arguments)
end
def down
add_concurrent_index(*index_arguments)
end
private
def index_arguments
[
:notes,
[:updated_at],
{
name: 'index_notes_on_updated_at'
}
]
end
end
# frozen_string_literal: true
class AddStateToPoolRepository < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# Given the table is empty, and the non concurrent methods are chosen so
# the transactions don't have to be disabled
# rubocop:disable Migration/AddConcurrentForeignKey
# rubocop:disable Migration/AddIndex
# rubocop:disable Migration/PreventStrings
def change
add_column(:pool_repositories, :state, :string, null: true)
add_column :pool_repositories, :source_project_id, :integer
add_index :pool_repositories, :source_project_id, unique: true
add_foreign_key :pool_repositories, :projects, column: :source_project_id, on_delete: :nullify
end
# rubocop:enable Migration/PreventStrings
# rubocop:enable Migration/AddIndex
# rubocop:enable Migration/AddConcurrentForeignKey
end
# frozen_string_literal: true
class AddTokenEncryptedToCiBuilds < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/AddColumnsToWideTables
# rubocop:disable Migration/PreventStrings
def change
add_column :ci_builds, :token_encrypted, :string
end
# rubocop:enable Migration/PreventStrings
# rubocop:enable Migration/AddColumnsToWideTables
end
# frozen_string_literal: true
class AddIndexToCiBuildsTokenEncrypted < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :ci_builds, :token_encrypted, unique: true, where: 'token_encrypted IS NOT NULL'
end
def down
remove_concurrent_index :ci_builds, :token_encrypted
end
end
# frozen_string_literal: true
class AddProjectBfgObjectMapColumn < ActiveRecord::Migration[5.0]
DOWNTIME = false
# rubocop:disable Migration/AddColumnsToWideTables
# rubocop:disable Migration/PreventStrings
def change
add_column :projects, :bfg_object_map, :string
end
# rubocop:enable Migration/PreventStrings
# rubocop:enable Migration/AddColumnsToWideTables
end
# frozen_string_literal: true
class CreateProjectDailyStatistics < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
create_table :project_daily_statistics, id: :bigserial do |t|
t.integer :project_id, null: false
t.integer :fetch_count, null: false
t.date :date
t.index [:project_id, :date], unique: true, order: { date: :desc }
t.foreign_key :projects, on_delete: :cascade
end
end
end
# frozen_string_literal: true
class AddNameAuthorIdAndShaToReleases < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def change
add_column :releases, :author_id, :integer
add_column :releases, :name, :string
add_column :releases, :sha, :string
end
# rubocop:enable Migration/PreventStrings
end
# frozen_string_literal: true
class AddAuthorIdIndexAndFkToReleases < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :releases, :author_id
add_concurrent_foreign_key :releases, :users, column: :author_id, on_delete: :nullify
end
def down
remove_foreign_key :releases, column: :author_id
remove_concurrent_index :releases, column: :author_id
end
end
# frozen_string_literal: true
class BackfillReleasesNameWithTagName < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
update_column_in_batches(:releases, :name, Release.arel_table[:tag])
end
def down
# no-op
end
end
# frozen_string_literal: true
class CreateErrorTrackingSettings < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def change
create_table :project_error_tracking_settings, id: :int, primary_key: :project_id, default: nil do |t|
t.boolean :enabled, null: false, default: true
t.string :api_url, null: false
t.string :encrypted_token
t.string :encrypted_token_iv
t.foreign_key :projects, column: :project_id, on_delete: :cascade
end
end
# rubocop:enable Migration/PreventStrings
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddOptionsToBuildMetadata < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :ci_builds_metadata, :config_options, :jsonb
add_column :ci_builds_metadata, :config_variables, :jsonb
end
end
# frozen_string_literal: true
class CreateReleasesLinkTable < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
# rubocop:disable Migration/PreventStrings
def change
create_table :release_links, id: :bigserial do |t|
t.references :release, null: false, index: false, foreign_key: { on_delete: :cascade }
t.string :url, null: false
t.string :name, null: false
t.timestamps_with_timezone null: false
t.index [:release_id, :url], unique: true
t.index [:release_id, :name], unique: true
end
end
# rubocop:enable Migration/PreventStrings
end
This source diff could not be displayed because it is too large. You can view the blob instead.
class ScheduleSetConfidentialNoteEventsOnWebhooks < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
BATCH_SIZE = 1_000
INTERVAL = 5.minutes
disable_ddl_transaction!
def up
migration = Gitlab::BackgroundMigration::SetConfidentialNoteEventsOnWebhooks
migration_name = migration.to_s.demodulize
relation = migration::WebHook.hooks_to_update
queue_background_migration_jobs_by_range_at_intervals(relation,
migration_name,
INTERVAL,
batch_size: BATCH_SIZE)
end
def down
end
end
class RemoveRedundantPipelineStages < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up(attempts: 100)
remove_redundant_pipeline_stages!
remove_outdated_index!
add_unique_index!
rescue ActiveRecord::RecordNotUnique
retry if (attempts -= 1) > 0
raise StandardError, <<~EOS
Failed to add an unique index to ci_stages, despite retrying the
migration 100 times.
See https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/16580.
EOS
end
def down
remove_concurrent_index :ci_stages, [:pipeline_id, :name], unique: true
add_concurrent_index :ci_stages, [:pipeline_id, :name]
end
private
def remove_outdated_index!
return unless index_exists?(:ci_stages, [:pipeline_id, :name])
remove_concurrent_index :ci_stages, [:pipeline_id, :name]
end
def add_unique_index!
add_concurrent_index :ci_stages, [:pipeline_id, :name], unique: true
end
def remove_redundant_pipeline_stages!
disable_statement_timeout do
redundant_stages_ids = <<~SQL
SELECT id FROM ci_stages WHERE (pipeline_id, name) IN (
SELECT pipeline_id, name FROM ci_stages
GROUP BY pipeline_id, name HAVING COUNT(*) > 1
)
SQL
execute <<~SQL
UPDATE ci_builds SET stage_id = NULL WHERE stage_id IN (#{redundant_stages_ids})
SQL
execute <<~SQL
DELETE FROM ci_stages WHERE id IN (#{redundant_stages_ids})
SQL
end
end
end
class ScheduleSetConfidentialNoteEventsOnServices < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
BATCH_SIZE = 1_000
INTERVAL = 20.minutes
disable_ddl_transaction!
def up
migration = Gitlab::BackgroundMigration::SetConfidentialNoteEventsOnServices
migration_name = migration.to_s.demodulize
relation = migration::Service.services_to_update
queue_background_migration_jobs_by_range_at_intervals(relation,
migration_name,
INTERVAL,
batch_size: BATCH_SIZE)
end
def down
end
end
class ChangeAuthorIdToNotNullInTodos < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
class Todo < ActiveRecord::Base
self.table_name = 'todos'
include EachBatch
end
BATCH_SIZE = 1000
DOWNTIME = false
disable_ddl_transaction!
def up
Todo.where(author_id: nil).each_batch(of: BATCH_SIZE) do |batch|
batch.delete_all
end
change_column_null :todos, :author_id, false
end
def down
change_column_null :todos, :author_id, true
end
end
class AddTmpPartialNullIndexToBuilds < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
def up
add_concurrent_index(:ci_builds, :id, where: 'stage_id IS NULL',
name: 'tmp_id_partial_null_index')
end
def down
remove_concurrent_index_by_name(:ci_builds, 'tmp_id_partial_null_index')
end
end
class ScheduleBuildStageMigration < ActiveRecord::Migration[4.2]
##
# This migration has been rescheduled to run again, see
# `20180405101928_reschedule_builds_stages_migration.rb`
#
def up
# noop
end
def down
# noop
end
end
class RemoveTmpPartialNullIndexFromBuilds < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
def up
remove_concurrent_index_by_name(:ci_builds, 'tmp_id_partial_null_index')
end
def down
add_concurrent_index(:ci_builds, :id, where: 'stage_id IS NULL',
name: 'tmp_id_partial_null_index')
end
end
class FillPagesDomainVerificationCode < ActiveRecord::Migration[4.2]
DOWNTIME = false
class PagesDomain < ActiveRecord::Base
include EachBatch
end
# Allow this migration to resume if it fails partway through
disable_ddl_transaction!
def up
PagesDomain.where(verification_code: [nil, '']).each_batch do |relation|
connection.execute(set_codes_sql(relation))
# Sleep 2 minutes between batches to not overload the DB with dead tuples
sleep(2.minutes) unless relation.reorder(:id).last == PagesDomain.reorder(:id).last
end
change_column_null(:pages_domains, :verification_code, false)
end
def down
change_column_null(:pages_domains, :verification_code, true)
end
private
def set_codes_sql(relation)
ids = relation.pluck(:id)
whens = ids.map { |id| "WHEN #{id} THEN '#{SecureRandom.hex(16)}'" }
<<~SQL
UPDATE pages_domains
SET verification_code =
CASE id
#{whens.join("\n")}
END
WHERE id IN(#{ids.join(',')})
SQL
end
end
class EnqueueVerifyPagesDomainWorkers < ActiveRecord::Migration[4.2]
class PagesDomain < ActiveRecord::Base
include EachBatch
end
def up
PagesDomain.each_batch do |relation|
ids = relation.pluck(:id).map { |id| [id] }
PagesDomainVerificationWorker.bulk_perform_async(ids)
end
end
def down
# no-op
end
end
class RemoveEmptyExternUidAuth0Identities < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
class Identity < ActiveRecord::Base
self.table_name = 'identities'
include EachBatch
end
def up
broken_auth0_identities.each_batch do |identity|
identity.delete_all
end
end
def broken_auth0_identities
Identity.where(provider: 'auth0', extern_uid: [nil, ''])
end
def down
end
end
require_relative '../migrate/20180223120443_create_user_interacted_projects_table.rb'
# rubocop:disable Migration/AddIndex
# rubocop:disable Migration/AddConcurrentForeignKey
class BuildUserInteractedProjectsTable < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
UNIQUE_INDEX_NAME = 'index_user_interacted_projects_on_project_id_and_user_id'
disable_ddl_transaction!
def up
PostgresStrategy.new.up
if index_exists_by_name?(:user_interacted_projects, CreateUserInteractedProjectsTable::INDEX_NAME)
remove_concurrent_index_by_name :user_interacted_projects, CreateUserInteractedProjectsTable::INDEX_NAME
end
end
def down
execute "TRUNCATE user_interacted_projects"
if foreign_key_exists?(:user_interacted_projects, :users)
remove_foreign_key :user_interacted_projects, :users
end
if foreign_key_exists?(:user_interacted_projects, :projects)
remove_foreign_key :user_interacted_projects, :projects
end
if index_exists_by_name?(:user_interacted_projects, UNIQUE_INDEX_NAME)
remove_concurrent_index_by_name :user_interacted_projects, UNIQUE_INDEX_NAME
end
unless index_exists_by_name?(:user_interacted_projects, CreateUserInteractedProjectsTable::INDEX_NAME)
add_concurrent_index :user_interacted_projects, [:project_id, :user_id], name: CreateUserInteractedProjectsTable::INDEX_NAME
end
end
class PostgresStrategy < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
BATCH_SIZE = 100_000
SLEEP_TIME = 5
def up
with_index(:events, [:author_id, :project_id], name: 'events_user_interactions_temp', where: 'project_id IS NOT NULL') do
insert_missing_records
# Do this once without lock to speed up the second invocation
remove_duplicates
with_table_lock(:user_interacted_projects) do
remove_duplicates
create_unique_index
end
remove_without_project
with_table_lock(:user_interacted_projects, :projects) do
remove_without_project
create_fk :user_interacted_projects, :projects, :project_id
end
remove_without_user
with_table_lock(:user_interacted_projects, :users) do
remove_without_user
create_fk :user_interacted_projects, :users, :user_id
end
end
execute "ANALYZE user_interacted_projects"
end
private
def insert_missing_records
iteration = 0
records = 0
begin
Rails.logger.info "Building user_interacted_projects table, batch ##{iteration}" # rubocop:disable Gitlab/RailsLogger
result = execute <<~SQL
INSERT INTO user_interacted_projects (user_id, project_id)
SELECT e.user_id, e.project_id
FROM (SELECT DISTINCT author_id AS user_id, project_id FROM events WHERE project_id IS NOT NULL) AS e
LEFT JOIN user_interacted_projects ucp USING (user_id, project_id)
WHERE ucp.user_id IS NULL
LIMIT #{BATCH_SIZE}
SQL
iteration += 1
records += result.cmd_tuples
Rails.logger.info "Building user_interacted_projects table, batch ##{iteration} complete, created #{records} overall" # rubocop:disable Gitlab/RailsLogger
Kernel.sleep(SLEEP_TIME) if result.cmd_tuples > 0
end while result.cmd_tuples > 0
end
def remove_duplicates
execute <<~SQL
WITH numbered AS (select ctid, ROW_NUMBER() OVER (PARTITION BY (user_id, project_id)) as row_number, user_id, project_id from user_interacted_projects)
DELETE FROM user_interacted_projects WHERE ctid IN (SELECT ctid FROM numbered WHERE row_number > 1);
SQL
end
def remove_without_project
execute "DELETE FROM user_interacted_projects WHERE NOT EXISTS (SELECT 1 FROM projects WHERE id = user_interacted_projects.project_id)"
end
def remove_without_user
execute "DELETE FROM user_interacted_projects WHERE NOT EXISTS (SELECT 1 FROM users WHERE id = user_interacted_projects.user_id)"
end
def create_fk(table, target, column)
return if foreign_key_exists?(table, target, column: column)
add_foreign_key table, target, column: column, on_delete: :cascade
end
def create_unique_index
return if index_exists_by_name?(:user_interacted_projects, UNIQUE_INDEX_NAME)
add_index :user_interacted_projects, [:project_id, :user_id], unique: true, name: UNIQUE_INDEX_NAME
end
# Protect table against concurrent data changes while still allowing reads
def with_table_lock(*tables)
ActiveRecord::Base.connection.transaction do
execute "LOCK TABLE #{tables.join(", ")} IN SHARE MODE"
yield
end
end
def with_index(*args)
add_concurrent_index(*args) unless index_exists?(*args)
yield
ensure
remove_concurrent_index(*args) if index_exists?(*args)
end
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class ChangeProjectNamespaceIdNotNull < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
class Project < ActiveRecord::Base
self.table_name = 'projects'
include EachBatch
end
BATCH_SIZE = 1000
DOWNTIME = false
disable_ddl_transaction!
def up
Project.where(namespace_id: nil).each_batch(of: BATCH_SIZE) do |batch|
batch.delete_all
end
change_column_null :projects, :namespace_id, false
end
def down
change_column_null :projects, :namespace_id, true
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class RemovePermanentFromRedirectRoutes < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
INDEX_NAME_PERM = "index_redirect_routes_on_path_text_pattern_ops_where_permanent"
INDEX_NAME_TEMP = "index_redirect_routes_on_path_text_pattern_ops_where_temporary"
def up
# These indexes were created on Postgres only in:
# ReworkRedirectRoutesIndexes:
# https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/16211
disable_statement_timeout do
execute "DROP INDEX CONCURRENTLY IF EXISTS #{INDEX_NAME_PERM};"
execute "DROP INDEX CONCURRENTLY IF EXISTS #{INDEX_NAME_TEMP};"
end
remove_column(:redirect_routes, :permanent)
end
def down
add_column(:redirect_routes, :permanent, :boolean)
disable_statement_timeout do
execute("CREATE INDEX CONCURRENTLY #{INDEX_NAME_PERM} ON redirect_routes (lower(path) varchar_pattern_ops) where (permanent);")
execute("CREATE INDEX CONCURRENTLY #{INDEX_NAME_TEMP} ON redirect_routes (lower(path) varchar_pattern_ops) where (not permanent or permanent is null) ;")
end
end
end
class MigrateCreateTraceArtifactSidekiqQueue < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
sidekiq_queue_migrate 'pipeline_default:create_trace_artifact', to: 'pipeline_background:archive_trace'
end
def down
sidekiq_queue_migrate 'pipeline_background:archive_trace', to: 'pipeline_default:create_trace_artifact'
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddPathIndexToRedirectRoutes < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
disable_ddl_transaction!
INDEX_NAME = 'index_redirect_routes_on_path_unique_text_pattern_ops'
# Indexing on LOWER(path) varchar_pattern_ops speeds up the LIKE query in
# RedirectRoute.matching_path_and_descendants
#
# This same index is also added in the `ReworkRedirectRoutesIndexes` so this
# is a no-op in most cases.
def up
disable_statement_timeout do
unless index_exists_by_name?(:redirect_routes, INDEX_NAME)
execute("CREATE UNIQUE INDEX CONCURRENTLY #{INDEX_NAME} ON redirect_routes (lower(path) varchar_pattern_ops);")
end
end
end
def down
# Do nothing in the DOWN. Since the index above is originally created in the
# `ReworkRedirectRoutesIndexes`. This migration wouldn't have actually
# created any new index.
end
end
class MigrateUpdateHeadPipelineForMergeRequestSidekiqQueue < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
sidekiq_queue_migrate 'pipeline_default:update_head_pipeline_for_merge_request',
to: 'pipeline_processing:update_head_pipeline_for_merge_request'
end
def down
sidekiq_queue_migrate 'pipeline_processing:update_head_pipeline_for_merge_request',
to: 'pipeline_default:update_head_pipeline_for_merge_request'
end
end
class RescheduleBuildsStagesMigration < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
##
# Rescheduled `20180212101928_schedule_build_stage_migration.rb`
#
DOWNTIME = false
MIGRATION = 'MigrateBuildStage'.freeze
BATCH_SIZE = 500
disable_ddl_transaction!
class Build < ActiveRecord::Base
include EachBatch
self.table_name = 'ci_builds'
end
def up
disable_statement_timeout do
Build.where('stage_id IS NULL').tap do |relation|
queue_background_migration_jobs_by_range_at_intervals(relation,
MIGRATION,
5.minutes,
batch_size: BATCH_SIZE)
end
end
end
def down
# noop
end
end
class CleanupUsersRssTokenRename < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
def up
cleanup_concurrent_column_rename :users, :rss_token, :feed_token
end
def down
# rubocop:disable Migration/UpdateLargeTable
rename_column_concurrently :users, :feed_token, :rss_token
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class PopulateMissingProjectCiCdSettings < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
# Projects created after the initial migration but before the code started
# using ProjectCiCdSetting won't have a corresponding row in
# project_ci_cd_settings, so let's fix that.
execute <<~SQL
INSERT INTO project_ci_cd_settings (project_id)
SELECT id
FROM projects
WHERE NOT EXISTS (
SELECT 1
FROM project_ci_cd_settings
WHERE project_ci_cd_settings.project_id = projects.id
)
SQL
end
def down
# There's nothing to revert for this migration.
end
end
class ScheduleStagesIndexMigration < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
MIGRATION = 'MigrateStageIndex'.freeze
BATCH_SIZE = 10000
disable_ddl_transaction!
class Stage < ActiveRecord::Base
include EachBatch
self.table_name = 'ci_stages'
end
def up
disable_statement_timeout do
Stage.all.tap do |relation|
queue_background_migration_jobs_by_range_at_intervals(relation,
MIGRATION,
5.minutes,
batch_size: BATCH_SIZE)
end
end
end
def down
# noop
end
end
class FillFileStore < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
class JobArtifact < ActiveRecord::Base
include EachBatch
self.table_name = 'ci_job_artifacts'
BATCH_SIZE = 10_000
def self.params_for_background_migration
yield self.where(file_store: nil), 'FillFileStoreJobArtifact', 5.minutes, BATCH_SIZE
end
end
class LfsObject < ActiveRecord::Base
include EachBatch
self.table_name = 'lfs_objects'
BATCH_SIZE = 10_000
def self.params_for_background_migration
yield self.where(file_store: nil), 'FillFileStoreLfsObject', 5.minutes, BATCH_SIZE
end
end
class Upload < ActiveRecord::Base
include EachBatch
self.table_name = 'uploads'
self.inheritance_column = :_type_disabled # Disable STI
BATCH_SIZE = 10_000
def self.params_for_background_migration
yield self.where(store: nil), 'FillStoreUpload', 5.minutes, BATCH_SIZE
end
end
def up
# NOTE: Schedule background migrations that fill 'NULL' value by '1'(ObjectStorage::Store::LOCAL) on `file_store`, `store` columns
#
# Here are the target columns
# - ci_job_artifacts.file_store
# - lfs_objects.file_store
# - uploads.store
FillFileStore::JobArtifact.params_for_background_migration do |relation, class_name, delay_interval, batch_size|
queue_background_migration_jobs_by_range_at_intervals(relation,
class_name,
delay_interval,
batch_size: batch_size)
end
FillFileStore::LfsObject.params_for_background_migration do |relation, class_name, delay_interval, batch_size|
queue_background_migration_jobs_by_range_at_intervals(relation,
class_name,
delay_interval,
batch_size: batch_size)
end
FillFileStore::Upload.params_for_background_migration do |relation, class_name, delay_interval, batch_size|
queue_background_migration_jobs_by_range_at_intervals(relation,
class_name,
delay_interval,
batch_size: batch_size)
end
end
def down
# noop
end
end
class BackfillRunnerTypeForCiRunnersPostMigrate < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
INSTANCE_RUNNER_TYPE = 1
PROJECT_RUNNER_TYPE = 3
disable_ddl_transaction!
def up
# rubocop:disable Migration/UpdateColumnInBatches
update_column_in_batches(:ci_runners, :runner_type, INSTANCE_RUNNER_TYPE) do |table, query|
query.where(table[:is_shared].eq(true)).where(table[:runner_type].eq(nil))
end
update_column_in_batches(:ci_runners, :runner_type, PROJECT_RUNNER_TYPE) do |table, query|
query.where(table[:is_shared].eq(false)).where(table[:runner_type].eq(nil))
end
end
def down
end
end
class SetMinimalProjectBuildTimeout < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
MINIMUM_TIMEOUT = 600
# Allow this migration to resume if it fails partway through
disable_ddl_transaction!
def up
# rubocop:disable Migration/UpdateLargeTable
# rubocop:disable Migration/UpdateColumnInBatches
update_column_in_batches(:projects, :build_timeout, MINIMUM_TIMEOUT) do |table, query|
query.where(table[:build_timeout].lt(MINIMUM_TIMEOUT))
end
end
def down
# no-op
end
end
class AddUniqueConstraintToProjectFeaturesProjectId < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
class ProjectFeature < ActiveRecord::Base
self.table_name = 'project_features'
include EachBatch
end
def up
remove_duplicates
add_concurrent_index :project_features, :project_id, unique: true, name: 'index_project_features_on_project_id_unique'
remove_concurrent_index_by_name :project_features, 'index_project_features_on_project_id'
rename_index :project_features, 'index_project_features_on_project_id_unique', 'index_project_features_on_project_id'
end
def down
rename_index :project_features, 'index_project_features_on_project_id', 'index_project_features_on_project_id_old'
add_concurrent_index :project_features, :project_id
remove_concurrent_index_by_name :project_features, 'index_project_features_on_project_id_old'
end
private
def remove_duplicates
features = ProjectFeature
.select('MAX(id) AS max, COUNT(id), project_id')
.group(:project_id)
.having('COUNT(id) > 1')
features.each do |feature|
ProjectFeature
.where(project_id: feature['project_id'])
.where('id <> ?', feature['max'])
.each_batch { |batch| batch.delete_all }
end
end
end
class AddNotNullConstraintToProjectFeaturesProjectId < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
class ProjectFeature < ActiveRecord::Base
include EachBatch
self.table_name = 'project_features'
end
def up
ProjectFeature.where(project_id: nil).delete_all
change_column_null :project_features, :project_id, false
end
def down
change_column_null :project_features, :project_id, true
end
end
class RemoveGemnasiumService < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
disable_statement_timeout
execute("DELETE FROM services WHERE type='GemnasiumService';")
end
def down
# noop
end
end
class CleanupMergeRequestsAllowMaintainerToPushRename < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
# NOOP
end
def down
if column_exists?(:merge_requests, :allow_collaboration)
# rubocop:disable Migration/UpdateLargeTable
rename_column_concurrently :merge_requests, :allow_collaboration, :allow_maintainer_to_push
end
end
end
class ScheduleToArchiveLegacyTraces < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
BATCH_SIZE = 5000
BACKGROUND_MIGRATION_CLASS = 'ArchiveLegacyTraces'
disable_ddl_transaction!
class Build < ActiveRecord::Base
include EachBatch
self.table_name = 'ci_builds'
self.inheritance_column = :_type_disabled # Disable STI
scope :type_build, -> { where(type: 'Ci::Build') }
scope :finished, -> { where(status: [:success, :failed, :canceled]) }
scope :without_archived_trace, -> do
where('NOT EXISTS (SELECT 1 FROM ci_job_artifacts WHERE ci_builds.id = ci_job_artifacts.job_id AND ci_job_artifacts.file_type = 3)')
end
end
def up
queue_background_migration_jobs_by_range_at_intervals(
::ScheduleToArchiveLegacyTraces::Build.type_build.finished.without_archived_trace,
BACKGROUND_MIGRATION_CLASS,
5.minutes,
batch_size: BATCH_SIZE)
end
def down
# noop
end
end
class MigrateObjectStorageUploadSidekiqQueue < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
sidekiq_queue_migrate 'object_storage_upload', to: 'object_storage:object_storage_background_move'
end
def down
# do not migrate any jobs back because we would migrate also
# jobs which were not part of the 'object_storage_upload'
end
end
class CleanupStagesPositionMigration < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
TMP_INDEX_NAME = 'tmp_id_stage_position_partial_null_index'.freeze
disable_ddl_transaction!
class Stages < ActiveRecord::Base
include EachBatch
self.table_name = 'ci_stages'
end
def up
disable_statement_timeout do
Gitlab::BackgroundMigration.steal('MigrateStageIndex')
unless index_exists_by_name?(:ci_stages, TMP_INDEX_NAME)
add_concurrent_index(:ci_stages, :id, where: 'position IS NULL', name: TMP_INDEX_NAME)
end
migratable = <<~SQL
position IS NULL AND EXISTS (
SELECT 1 FROM ci_builds WHERE stage_id = ci_stages.id AND stage_idx IS NOT NULL
)
SQL
Stages.where(migratable).each_batch(of: 1000) do |batch|
batch.pluck(:id).each do |stage|
Gitlab::BackgroundMigration::MigrateStageIndex.new.perform(stage, stage)
end
end
remove_concurrent_index_by_name(:ci_stages, TMP_INDEX_NAME)
end
end
def down
if index_exists_by_name?(:ci_stages, TMP_INDEX_NAME)
disable_statement_timeout do
remove_concurrent_index_by_name(:ci_stages, TMP_INDEX_NAME)
end
end
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class CleanupMergeRequestsAllowCollaborationRename < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
if column_exists?(:merge_requests, :allow_collaboration)
cleanup_concurrent_column_rename :merge_requests, :allow_collaboration, :allow_maintainer_to_push
end
end
def down
# NOOP
end
end
class AddPartialIndexToProjectsForLastRepositoryCheckAt < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
disable_ddl_transaction!
INDEX_NAME = "index_projects_on_last_repository_check_at"
def up
add_concurrent_index(:projects, :last_repository_check_at, where: "last_repository_check_at IS NOT NULL", name: INDEX_NAME)
end
def down
remove_concurrent_index(:projects, :last_repository_check_at, where: "last_repository_check_at IS NOT NULL", name: INDEX_NAME)
end
end
class EnqueueFixCrossProjectLabelLinks < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
BATCH_SIZE = 100
MIGRATION = 'FixCrossProjectLabelLinks'
DELAY_INTERVAL = 5.minutes
disable_ddl_transaction!
class Label < ActiveRecord::Base
self.table_name = 'labels'
end
class Namespace < ActiveRecord::Base
self.table_name = 'namespaces'
include ::EachBatch
default_scope { where(type: 'Group', id: Label.where(type: 'GroupLabel').select('distinct group_id')) }
end
def up
queue_background_migration_jobs_by_range_at_intervals(Namespace, MIGRATION, DELAY_INTERVAL, batch_size: BATCH_SIZE)
end
def down
# noop
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class UpdateProjectIndexes < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
NEW_INDEX_NAME = 'idx_project_repository_check_partial'
disable_ddl_transaction!
def up
add_concurrent_index(:projects,
[:repository_storage, :created_at],
name: NEW_INDEX_NAME,
where: 'last_repository_check_at IS NULL'
)
end
def down
remove_concurrent_index_by_name(:projects, NEW_INDEX_NAME)
end
end
class PopulateSiteStatistics < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
transaction do
execute('SET LOCAL statement_timeout TO 0') # see https://gitlab.com/gitlab-org/gitlab-foss/issues/48967
execute("UPDATE site_statistics SET repositories_count = (SELECT COUNT(*) FROM projects)")
end
transaction do
execute('SET LOCAL statement_timeout TO 0') # see https://gitlab.com/gitlab-org/gitlab-foss/issues/48967
execute("UPDATE site_statistics SET wikis_count = (SELECT COUNT(*) FROM project_features WHERE wiki_access_level != 0)")
end
end
def down
# No downside in keeping the counter up-to-date
end
end
# frozen_string_literal: true
class MigrateNullWikiAccessLevels < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
class ProjectFeature < ActiveRecord::Base
include EachBatch
self.table_name = 'project_features'
end
def up
ProjectFeature.where(wiki_access_level: nil).each_batch do |relation|
relation.update_all(wiki_access_level: 20)
end
# We need to re-count wikis as previous attempt was not considering the NULLs.
transaction do
execute('SET LOCAL statement_timeout TO 0') # see https://gitlab.com/gitlab-org/gitlab-foss/issues/48967
execute("UPDATE site_statistics SET wikis_count = (SELECT COUNT(*) FROM project_features WHERE wiki_access_level != 0)")
end
end
def down
# there is no way to rollback this change, there are no downsides in keeping migrated data.
end
end
class MigrateLegacyArtifactsToJobArtifacts < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
MIGRATION = 'MigrateLegacyArtifacts'.freeze
BATCH_SIZE = 100
disable_ddl_transaction!
class Build < ActiveRecord::Base
include EachBatch
self.table_name = 'ci_builds'
self.inheritance_column = :_type_disabled
scope :with_legacy_artifacts, -> { where("artifacts_file <> ''") }
end
def up
MigrateLegacyArtifactsToJobArtifacts::Build
.with_legacy_artifacts.tap do |relation|
queue_background_migration_jobs_by_range_at_intervals(relation,
MIGRATION,
5.minutes,
batch_size: BATCH_SIZE)
end
end
def down
# no-op
end
end
# frozen_string_literal: true
class RenameLoginRootNamespaces < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
include Gitlab::Database::RenameReservedPathsMigration::V1
DOWNTIME = false
disable_ddl_transaction!
# We're taking over the /login namespace as part of a fix for the Jira integration
def up
disable_statement_timeout do
rename_root_paths 'login'
end
end
def down
disable_statement_timeout do
revert_renames
end
end
end
# frozen_string_literal: true
class RecalculateSiteStatistics < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
transaction do
execute('SET LOCAL statement_timeout TO 0') # see https://gitlab.com/gitlab-org/gitlab-foss/issues/48967
execute("UPDATE site_statistics SET repositories_count = (SELECT COUNT(*) FROM projects)")
end
transaction do
execute('SET LOCAL statement_timeout TO 0') # see https://gitlab.com/gitlab-org/gitlab-foss/issues/48967
execute("UPDATE site_statistics SET wikis_count = (SELECT COUNT(*) FROM project_features WHERE wiki_access_level != 0)")
end
end
def down
# No downside in keeping the counter up-to-date
end
end
class ScheduleDigestPersonalAccessTokens < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
BATCH_SIZE = 10_000
MIGRATION = 'DigestColumn'
DELAY_INTERVAL = 5.minutes.to_i
disable_ddl_transaction!
class PersonalAccessToken < ActiveRecord::Base
include EachBatch
self.table_name = 'personal_access_tokens'
end
def up
PersonalAccessToken.where('token is NOT NULL').each_batch(of: BATCH_SIZE) do |batch, index|
range = batch.pluck('MIN(id)', 'MAX(id)').first
BackgroundMigrationWorker.perform_in(index * DELAY_INTERVAL, MIGRATION, ['PersonalAccessToken', :token, :token_digest, *range])
end
end
def down
# raise ActiveRecord::IrreversibleMigration
end
end
# frozen_string_literal: true
class EncryptWebHooksColumns < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
BATCH_SIZE = 10000
RANGE_SIZE = 100
MIGRATION = 'EncryptColumns'
COLUMNS = [:token, :url]
WebHook = ::Gitlab::BackgroundMigration::Models::EncryptColumns::WebHook
disable_ddl_transaction!
def up
WebHook.each_batch(of: BATCH_SIZE) do |relation, index|
delay = index * 2.minutes
relation.each_batch(of: RANGE_SIZE) do |relation|
range = relation.pluck('MIN(id)', 'MAX(id)').first
args = [WebHook, COLUMNS, *range]
BackgroundMigrationWorker.perform_in(delay, MIGRATION, args)
end
end
end
def down
# noop
end
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class RemoveSidekiqThrottlingFromApplicationSettings < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
remove_column :application_settings, :sidekiq_throttling_enabled, :boolean, default: false
remove_column :application_settings, :sidekiq_throttling_queues, :string
remove_column :application_settings, :sidekiq_throttling_factor, :decimal
Rails.cache.delete("ApplicationSetting:#{Gitlab::VERSION}:#{Rails.version}")
end
end
# frozen_string_literal: true
class RemoveWikisCountFromSiteStatistics < ActiveRecord::Migration[4.2]
def change
remove_column :site_statistics, :wikis_count, :integer
end
end
class StealEncryptColumns < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
Gitlab::BackgroundMigration.steal('EncryptColumns')
end
def down
# no-op
end
end
class RemoveWebHooksTokenAndUrl < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
remove_column :web_hooks, :token, :string
remove_column :web_hooks, :url, :string, limit: 2000
end
end
# frozen_string_literal: true
class RemoveCircuitBreaker < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
disable_ddl_transaction!
CIRCUIT_BREAKER_COLUMS_WITH_DEFAULT = {
circuitbreaker_failure_count_threshold: 3,
circuitbreaker_failure_reset_time: 1800,
circuitbreaker_storage_timeout: 15,
circuitbreaker_access_retries: 3,
circuitbreaker_check_interval: 1
}.freeze
def up
CIRCUIT_BREAKER_COLUMS_WITH_DEFAULT.keys.each do |column|
remove_column(:application_settings, column) if column_exists?(:application_settings, column)
end
end
def down
CIRCUIT_BREAKER_COLUMS_WITH_DEFAULT.each do |column, default|
# rubocop:disable Migration/AddColumnWithDefault
add_column_with_default(:application_settings, column, :integer, default: default) unless column_exists?(:application_settings, column)
# rubocop:enable Migration/AddColumnWithDefault
end
end
end
# frozen_string_literal: true
class BackfillStoreProjectFullPathInRepo < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
BATCH_SIZE = 1_000
DELAY_INTERVAL = 5.minutes
UP_MIGRATION = 'BackfillProjectFullpathInRepoConfig::Up'
DOWN_MIGRATION = 'BackfillProjectFullpathInRepoConfig::Down'
disable_ddl_transaction!
class Project < ActiveRecord::Base
self.table_name = 'projects'
include EachBatch
end
def up
queue_background_migration_jobs_by_range_at_intervals(Project, UP_MIGRATION, DELAY_INTERVAL)
end
def down
queue_background_migration_jobs_by_range_at_intervals(Project, DOWN_MIGRATION, DELAY_INTERVAL)
end
end
# frozen_string_literal: true
class RemoveKodingFromApplicationSettings < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
remove_column :application_settings, :koding_enabled
remove_column :application_settings, :koding_url
end
def down
add_column :application_settings, :koding_enabled, :boolean # rubocop:disable Migration/SaferBooleanColumn
add_column :application_settings, :koding_url, :string
end
end
# frozen_string_literal: true
class EnqueuePopulateClusterKubernetesNamespace < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
MIGRATION = 'PopulateClusterKubernetesNamespaceTable'.freeze
disable_ddl_transaction!
def up
BackgroundMigrationWorker.perform_async(MIGRATION)
end
def down
Clusters::KubernetesNamespace.delete_all
end
end
# frozen_string_literal: true
class MigrateForbiddenRedirectUris < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
FORBIDDEN_SCHEMES = %w[data:// vbscript:// javascript://]
NEW_URI = 'http://forbidden-scheme-has-been-overwritten'
disable_ddl_transaction!
def up
update_forbidden_uris(:oauth_applications)
update_forbidden_uris(:oauth_access_grants)
end
def down
# noop
end
private
def update_forbidden_uris(table_name)
update_column_in_batches(table_name, :redirect_uri, NEW_URI) do |table, query|
where_clause = FORBIDDEN_SCHEMES.map do |scheme|
table[:redirect_uri].matches("#{scheme}%")
end.inject(&:or)
query.where(where_clause)
end
end
end
# frozen_string_literal: true
class FillEmptyFinishedAtInDeployments < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
DEPLOYMENT_STATUS_SUCCESS = 2 # Equivalent to Deployment.statuses[:success]
class Deployments < ActiveRecord::Base
self.table_name = 'deployments'
include EachBatch
end
def up
FillEmptyFinishedAtInDeployments::Deployments
.where('finished_at IS NULL')
.where('status = ?', DEPLOYMENT_STATUS_SUCCESS)
.each_batch(of: 10_000) do |relation|
relation.update_all('finished_at=created_at')
end
end
def down
# no-op
end
end
# frozen_string_literal: true
class StealDigestColumn < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
Gitlab::BackgroundMigration.steal('DigestColumn')
end
def down
# raise ActiveRecord::IrreversibleMigration
end
end
# frozen_string_literal: true
class RemoveTokenFromPersonalAccessTokens < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
remove_column :personal_access_tokens, :token, :string
end
end
# frozen_string_literal: true
class StealFillStoreUpload < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
BATCH_SIZE = 10_000
disable_ddl_transaction!
class Upload < ActiveRecord::Base
include EachBatch
self.table_name = 'uploads'
self.inheritance_column = :_type_disabled # Disable STI
end
def up
Gitlab::BackgroundMigration.steal('FillStoreUpload')
Upload.where(store: nil).each_batch(of: BATCH_SIZE) do |batch|
range = batch.pluck('MIN(id)', 'MAX(id)').first
Gitlab::BackgroundMigration::FillStoreUpload.new.perform(*range)
end
end
def down
# noop
end
end
# frozen_string_literal: true
# rescheduling of the revised RemoveRestrictedTodosWithCte background migration
class RemoveRestrictedTodosAgain < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
MIGRATION = 'RemoveRestrictedTodos'.freeze
BATCH_SIZE = 1000
DELAY_INTERVAL = 5.minutes.to_i
class Project < ActiveRecord::Base
include EachBatch
self.table_name = 'projects'
end
def up
Project.where('EXISTS (SELECT 1 FROM todos WHERE todos.project_id = projects.id)')
.each_batch(of: BATCH_SIZE) do |batch, index|
range = batch.pluck('MIN(id)', 'MAX(id)').first
BackgroundMigrationWorker.perform_in(index * DELAY_INTERVAL, MIGRATION, range)
end
end
def down
# nothing to do
end
end
# frozen_string_literal: true
class ScheduleRunnersTokenEncryption < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
BATCH_SIZE = 10000
RANGE_SIZE = 2000
MIGRATION = 'EncryptRunnersTokens'
MODELS = [
::Gitlab::BackgroundMigration::Models::EncryptColumns::Settings,
::Gitlab::BackgroundMigration::Models::EncryptColumns::Namespace,
::Gitlab::BackgroundMigration::Models::EncryptColumns::Project,
::Gitlab::BackgroundMigration::Models::EncryptColumns::Runner
].freeze
disable_ddl_transaction!
def up
MODELS.each do |model|
model.each_batch(of: BATCH_SIZE) do |relation, index|
delay = index * 4.minutes
relation.each_batch(of: RANGE_SIZE) do |relation|
range = relation.pluck('MIN(id)', 'MAX(id)').first
args = [model.name.demodulize.downcase, *range]
BackgroundMigrationWorker.perform_in(delay, MIGRATION, args)
end
end
end
end
def down
# no-op
end
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class DropSiteStatistics < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
drop_table :site_statistics
end
def down
create_table :site_statistics do |t|
t.integer :repositories_count, default: 0, null: false
end
execute('INSERT INTO site_statistics (id) VALUES(1)')
end
end
# frozen_string_literal: true
class BackfillHashedProjectRepositories < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
BATCH_SIZE = 1_000
DELAY_INTERVAL = 5.minutes
MIGRATION = 'BackfillHashedProjectRepositories'
disable_ddl_transaction!
class Project < ActiveRecord::Base
include EachBatch
self.table_name = 'projects'
end
def up
queue_background_migration_jobs_by_range_at_intervals(Project, MIGRATION, DELAY_INTERVAL)
end
def down
# no-op: since there could have been existing rows before the migration do not remove anything
end
end
# frozen_string_literal: true
class UpdateProjectImportVisibilityLevel < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
BATCH_SIZE = 100
PRIVATE = 0
INTERNAL = 10
disable_ddl_transaction!
class Namespace < ActiveRecord::Base
self.table_name = 'namespaces'
end
class Project < ActiveRecord::Base
include EachBatch
belongs_to :namespace
IMPORT_TYPE = 'gitlab_project'
scope :with_group_visibility, ->(visibility) do
joins(:namespace)
.where(namespaces: { type: 'Group', visibility_level: visibility })
.where(import_type: IMPORT_TYPE)
.where('projects.visibility_level > namespaces.visibility_level')
end
self.table_name = 'projects'
end
def up
# Update project's visibility to be the same as the group
# if it is more restrictive than `PUBLIC`.
update_projects_visibility(PRIVATE)
update_projects_visibility(INTERNAL)
end
def down
# no-op: unrecoverable data migration
end
private
def update_projects_visibility(visibility)
say_with_time("Updating project visibility to #{visibility} on #{Project::IMPORT_TYPE} imports.") do
Project.with_group_visibility(visibility).select(:id).each_batch(of: BATCH_SIZE) do |batch, _index|
batch_sql = batch.select(:id).to_sql
say("Updating #{batch.size} items.", true)
execute("UPDATE projects SET visibility_level = '#{visibility}' WHERE id IN (#{batch_sql})")
end
end
end
end
# frozen_string_literal: true
class MigrateClusterConfigureWorkerSidekiqQueue < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
sidekiq_queue_migrate 'gcp_cluster:cluster_platform_configure', to: 'gcp_cluster:cluster_configure'
end
def down
sidekiq_queue_migrate 'gcp_cluster:cluster_configure', to: 'gcp_cluster:cluster_platform_configure'
end
end
......@@ -12792,282 +12792,6 @@ ALTER TABLE ONLY public.u2f_registrations
ADD CONSTRAINT fk_u2f_registrations_user_id FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
COPY "schema_migrations" (version) FROM STDIN;
20171230123729
20180101160629
20180101160630
20180102220145
20180103123548
20180104131052
20180105212544
20180109183319
20180113220114
20180115094742
20180115113902
20180115201419
20180116193854
20180119121225
20180119135717
20180119160751
20180122154930
20180122162010
20180125214301
20180129193323
20180201102129
20180201110056
20180201145907
20180204200836
20180206200543
20180208183958
20180209115333
20180209165249
20180212030105
20180212101828
20180212101928
20180212102028
20180213131630
20180214093516
20180214155405
20180215181245
20180216120000
20180216120010
20180216120020
20180216120030
20180216120040
20180216120050
20180216121020
20180216121030
20180219153455
20180220150310
20180221151752
20180222043024
20180223120443
20180223124427
20180223144945
20180226050030
20180227182112
20180228172924
20180301010859
20180301084653
20180302152117
20180305095250
20180305100050
20180305144721
20180306074045
20180306134842
20180306164012
20180307012445
20180308052825
20180308125206
20180309121820
20180309160427
20180314100728
20180314145917
20180315160435
20180319190020
20180320182229
20180323150945
20180326202229
20180327101207
20180330121048
20180403035759
20180405101928
20180405142733
20180408143354
20180408143355
20180409170809
20180413022611
20180416155103
20180417090132
20180417101040
20180417101940
20180418053107
20180420010016
20180420010616
20180420080616
20180423204600
20180424090541
20180424134533
20180424151928
20180424160449
20180425075446
20180425131009
20180425205249
20180426102016
20180430101916
20180430143705
20180502122856
20180503131624
20180503141722
20180503150427
20180503175053
20180503175054
20180503193542
20180503193953
20180503200320
20180504195842
20180507083701
20180508055821
20180508100222
20180508102840
20180508135515
20180511090724
20180511131058
20180511174224
20180512061621
20180514161336
20180515005612
20180515121227
20180517082340
20180523042841
20180523125103
20180524132016
20180529093006
20180529152628
20180530135500
20180531185349
20180531220618
20180601213245
20180603190921
20180604123514
20180607071808
20180608091413
20180608110058
20180608201435
20180612103626
20180613081317
20180625113853
20180626125654
20180628124813
20180629153018
20180629191052
20180702120647
20180702124358
20180702134423
20180704145007
20180704204006
20180705160945
20180706223200
20180710162338
20180711103851
20180711103922
20180713092803
20180717125853
20180718005113
20180720023512
20180722103201
20180723135214
20180726172057
20180807153545
20180808162000
20180809195358
20180813101999
20180813102000
20180814153625
20180815040323
20180815160409
20180815170510
20180815175440
20180816161409
20180816193530
20180824202952
20180826111825
20180831164905
20180831164907
20180831164908
20180831164909
20180831164910
20180901171833
20180901200537
20180902070406
20180906101639
20180907015926
20180910115836
20180910153412
20180910153413
20180912111628
20180913142237
20180914162043
20180914201132
20180916011959
20180917172041
20180924141949
20180924190739
20180924201039
20180925200829
20180927073410
20181002172433
20181005110927
20181005125926
20181006004100
20181008145341
20181008145359
20181008200441
20181009190428
20181010133639
20181010235606
20181013005024
20181014203236
20181015155839
20181016141739
20181016152238
20181017001059
20181019032400
20181019032408
20181019105553
20181022135539
20181022173835
20181023104858
20181023144439
20181025115728
20181026091631
20181026143227
20181027114222
20181028120717
20181030135124
20181030154446
20181031145139
20181031190558
20181031190559
20181101091005
20181101091124
20181101144347
20181101191341
20181105201455
20181106135939
20181107054254
20181108091549
20181112103239
20181115140140
20181116050532
20181116141415
20181116141504
20181119081539
20181119132520
20181120082911
20181120091639
20181120151656
20181121101842
20181121101843
20181121111200
20181122160027
20181123042307
20181123135036
20181123144235
20181126150622
20181126153547
20181128123704
20181129104854
20181129104944
20181130102132
20181203002526
20181205171941
20181211092510
20181211092514
20181212104941
20181212171634
20181219130552
20181219145520
20181219145521
20181228175414
20190102152410
20190103140724
......
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20180122154930_schedule_set_confidential_note_events_on_services.rb')
describe ScheduleSetConfidentialNoteEventsOnServices do
let(:services_table) { table(:services) }
let(:migration_class) { Gitlab::BackgroundMigration::SetConfidentialNoteEventsOnServices }
let(:migration_name) { migration_class.to_s.demodulize }
let!(:service_1) { services_table.create!(confidential_note_events: nil, note_events: true) }
let!(:service_2) { services_table.create!(confidential_note_events: nil, note_events: true) }
let!(:service_migrated) { services_table.create!(confidential_note_events: true, note_events: true) }
let!(:service_skip) { services_table.create!(confidential_note_events: nil, note_events: false) }
let!(:service_new) { services_table.create!(confidential_note_events: false, note_events: true) }
let!(:service_4) { services_table.create!(confidential_note_events: nil, note_events: true) }
before do
stub_const("#{described_class}::BATCH_SIZE", 1)
end
it 'schedules background migrations at correct time' do
Sidekiq::Testing.fake! do
Timecop.freeze do
migrate!
expect(migration_name).to be_scheduled_delayed_migration(20.minutes, service_1.id, service_1.id)
expect(migration_name).to be_scheduled_delayed_migration(40.minutes, service_2.id, service_2.id)
expect(migration_name).to be_scheduled_delayed_migration(60.minutes, service_4.id, service_4.id)
expect(BackgroundMigrationWorker.jobs.size).to eq 3
end
end
end
it 'correctly processes services', :sidekiq_might_not_need_inline do
perform_enqueued_jobs do
expect(services_table.where(confidential_note_events: nil).count).to eq 4
expect(services_table.where(confidential_note_events: true).count).to eq 1
migrate!
expect(services_table.where(confidential_note_events: nil).count).to eq 1
expect(services_table.where(confidential_note_events: true).count).to eq 4
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20180710162338_add_foreign_key_from_notification_settings_to_users.rb')
describe AddForeignKeyFromNotificationSettingsToUsers do
let(:notification_settings) { table(:notification_settings) }
let(:users) { table(:users) }
let(:projects) { table(:projects) }
before do
users.create!(email: 'email@email.com', name: 'foo', username: 'foo', projects_limit: 0)
projects.create!(name: 'gitlab', path: 'gitlab-org/gitlab-ce', namespace_id: 1)
end
describe 'removal of orphans without user' do
let!(:notification_setting_without_user) { create_notification_settings!(user_id: 123) }
let!(:notification_setting_with_user) { create_notification_settings!(user_id: users.last.id) }
it 'removes orphaned notification_settings without user' do
expect { migrate! }.to change { notification_settings.count }.by(-1)
end
it "doesn't remove notification_settings with valid user" do
expect { migrate! }.not_to change { notification_setting_with_user.reload }
end
end
def create_notification_settings!(**opts)
notification_settings.create!(
source_id: projects.last.id,
source_type: 'Project',
user_id: users.last.id,
**opts)
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20180201110056_add_foreign_keys_to_todos.rb')
describe AddForeignKeysToTodos do
let(:todos) { table(:todos) }
let(:users) { table(:users) }
let(:projects) { table(:projects) }
let(:project) { projects.create!(name: 'gitlab', path: 'gitlab-org/gitlab-ce', namespace_id: 1) }
let(:user) { users.create!(email: 'email@email.com', name: 'foo', username: 'foo', projects_limit: 0) }
context 'add foreign key on user_id' do
let!(:todo_with_user) { create_todo(user_id: user.id) }
let!(:todo_without_user) { create_todo(user_id: 4711) }
it 'removes orphaned todos without corresponding user' do
expect { migrate! }.to change { Todo.count }.from(2).to(1)
end
it 'does not remove entries with valid user_id' do
expect { migrate! }.not_to change { todo_with_user.reload }
end
end
context 'add foreign key on author_id' do
let!(:todo_with_author) { create_todo(author_id: user.id) }
let!(:todo_with_invalid_author) { create_todo(author_id: 4711) }
it 'removes orphaned todos by author_id' do
expect { migrate! }.to change { Todo.count }.from(2).to(1)
end
it 'does not touch author_id for valid entries' do
expect { migrate! }.not_to change { todo_with_author.reload }
end
end
context 'add foreign key on note_id' do
let(:note) { table(:notes).create! }
let!(:todo_with_note) { create_todo(note_id: note.id) }
let!(:todo_with_invalid_note) { create_todo(note_id: 4711) }
let!(:todo_without_note) { create_todo(note_id: nil) }
it 'deletes todo if note_id is set but does not exist in notes table' do
expect { migrate! }.to change { Todo.count }.from(3).to(2)
end
it 'does not touch entry if note_id is nil' do
expect { migrate! }.not_to change { todo_without_note.reload }
end
it 'does not touch note_id for valid entries' do
expect { migrate! }.not_to change { todo_with_note.reload }
end
end
def create_todo(**opts)
todos.create!(
project_id: project.id,
user_id: user.id,
author_id: user.id,
target_type: '',
action: 0,
state: '', **opts
)
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20180508100222_add_not_null_constraint_to_project_mirror_data_foreign_key.rb')
describe AddNotNullConstraintToProjectMirrorDataForeignKey do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:import_state) { table(:project_mirror_data) }
before do
import_state.create!(id: 1, project_id: nil, status: :started)
end
it 'removes every import state without an associated project_id' do
expect do
subject.up
end.to change { import_state.count }.from(1).to(0)
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20180423204600_add_pages_access_level_to_project_feature.rb')
describe AddPagesAccessLevelToProjectFeature do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:features) { table(:project_features) }
let!(:namespace) { namespaces.create(name: 'gitlab', path: 'gitlab') }
let!(:first_project) { projects.create(name: 'gitlab1', path: 'gitlab1', namespace_id: namespace.id) }
let!(:first_project_features) { features.create(project_id: first_project.id) }
let!(:second_project) { projects.create(name: 'gitlab2', path: 'gitlab2', namespace_id: namespace.id) }
let!(:second_project_features) { features.create(project_id: second_project.id) }
it 'correctly migrate pages for old projects to be public' do
migrate!
# For old projects pages should be public
expect(first_project_features.reload.pages_access_level).to eq ProjectFeature::PUBLIC
expect(second_project_features.reload.pages_access_level).to eq ProjectFeature::PUBLIC
end
it 'after migration pages are enabled as default' do
migrate!
# For new project default is enabled
third_project = projects.create(name: 'gitlab3', path: 'gitlab3', namespace_id: namespace.id)
third_project_features = features.create(project_id: third_project.id)
expect(third_project_features.reload.pages_access_level).to eq ProjectFeature::ENABLED
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20180420010016_add_pipeline_build_foreign_key.rb')
describe AddPipelineBuildForeignKey do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:pipelines) { table(:ci_pipelines) }
let(:builds) { table(:ci_builds) }
before do
namespaces.create(id: 10, name: 'gitlab-org', path: 'gitlab-org')
projects.create!(id: 11, namespace_id: 10, name: 'gitlab', path: 'gitlab')
pipelines.create!(id: 12, project_id: 11, ref: 'master', sha: 'adf43c3a')
builds.create!(id: 101, commit_id: 12, project_id: 11)
builds.create!(id: 102, commit_id: 222, project_id: 11)
builds.create!(id: 103, commit_id: 333, project_id: 11)
builds.create!(id: 104, commit_id: 12, project_id: 11)
builds.create!(id: 106, commit_id: nil, project_id: 11)
builds.create!(id: 107, commit_id: 12, project_id: nil)
end
it 'adds foreign key after removing orphans' do
expect(builds.all.count).to eq 6
expect(foreign_key_exists?(:ci_builds, :ci_pipelines, column: :commit_id)).to be_falsey
migrate!
expect(builds.all.pluck(:id)).to eq [101, 104]
expect(foreign_key_exists?(:ci_builds, :ci_pipelines, column: :commit_id)).to be_truthy
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20180511174224_add_unique_constraint_to_project_features_project_id.rb')
describe AddUniqueConstraintToProjectFeaturesProjectId do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:features) { table(:project_features) }
let(:migration) { described_class.new }
describe '#up' do
before do
(1..3).each do |i|
namespaces.create(id: i, name: "ns-test-#{i}", path: "ns-test-i#{i}")
projects.create!(id: i, name: "test-#{i}", path: "test-#{i}", namespace_id: i)
end
features.create!(id: 1, project_id: 1)
features.create!(id: 2, project_id: 1)
features.create!(id: 3, project_id: 2)
features.create!(id: 4, project_id: 2)
features.create!(id: 5, project_id: 2)
features.create!(id: 6, project_id: 3)
end
it 'creates a unique index and removes duplicates' do
expect(migration.index_exists?(:project_features, :project_id, unique: false, name: 'index_project_features_on_project_id')).to be true
expect { migration.up }.to change { features.count }.from(6).to(3)
expect(migration.index_exists?(:project_features, :project_id, unique: true, name: 'index_project_features_on_project_id')).to be true
expect(migration.index_exists?(:project_features, :project_id, name: 'index_project_features_on_project_id_unique')).to be false
project_1_features = features.where(project_id: 1)
expect(project_1_features.count).to eq(1)
expect(project_1_features.first.id).to eq(2)
project_2_features = features.where(project_id: 2)
expect(project_2_features.count).to eq(1)
expect(project_2_features.first.id).to eq(5)
project_3_features = features.where(project_id: 3)
expect(project_3_features.count).to eq(1)
expect(project_3_features.first.id).to eq(6)
end
end
describe '#down' do
it 'restores the original index' do
migration.up
expect(migration.index_exists?(:project_features, :project_id, unique: true, name: 'index_project_features_on_project_id')).to be true
migration.down
expect(migration.index_exists?(:project_features, :project_id, unique: false, name: 'index_project_features_on_project_id')).to be true
expect(migration.index_exists?(:project_features, :project_id, name: 'index_project_features_on_project_id_old')).to be false
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20180425131009_assure_commits_count_for_merge_request_diff.rb')
describe AssureCommitsCountForMergeRequestDiff, :redis do
let(:migration) { spy('migration') }
before do
allow(Gitlab::BackgroundMigration::AddMergeRequestDiffCommitsCount)
.to receive(:new).and_return(migration)
end
context 'when there are still unmigrated commit_counts afterwards' do
let(:namespaces) { table('namespaces') }
let(:projects) { table('projects') }
let(:merge_requests) { table('merge_requests') }
let(:diffs) { table('merge_request_diffs') }
before do
namespace = namespaces.create(name: 'foo', path: 'foo')
project = projects.create!(namespace_id: namespace.id)
merge_request = merge_requests.create!(source_branch: 'x', target_branch: 'y', target_project_id: project.id)
diffs.create!(commits_count: nil, merge_request_id: merge_request.id)
diffs.create!(commits_count: nil, merge_request_id: merge_request.id)
end
it 'migrates commit_counts sequentially in batches' do
migrate!
expect(migration).to have_received(:perform).once
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20181212104941_backfill_releases_name_with_tag_name.rb')
describe BackfillReleasesNameWithTagName do
let(:releases) { table(:releases) }
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:namespace) { namespaces.create(name: 'foo', path: 'foo') }
let(:project) { projects.create!(namespace_id: namespace.id) }
let(:release) { releases.create!(project_id: project.id, tag: 'v1.0.0') }
it 'defaults name to tag value' do
expect(release.tag).to be_present
migrate!
release.reload
expect(release.name).to eq(release.tag)
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20181010133639_backfill_store_project_full_path_in_repo.rb')
describe BackfillStoreProjectFullPathInRepo do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:group) { namespaces.create!(name: 'foo', path: 'foo') }
let(:subgroup) { namespaces.create!(name: 'bar', path: 'bar', parent_id: group.id) }
subject(:migration) { described_class.new }
around do |example|
perform_enqueued_jobs do
example.run
end
end
describe '#up' do
shared_examples_for 'writes the full path to git config' do
it 'writes the git config', :sidekiq_might_not_need_inline do
expect_next_instance_of(Gitlab::GitalyClient::RepositoryService) do |repository_service|
allow(repository_service).to receive(:cleanup)
expect(repository_service).to receive(:set_config).with('gitlab.fullpath' => expected_path)
end
migration.up
end
it 'retries in case of failure', :sidekiq_might_not_need_inline do
repository_service = spy(:repository_service)
allow(Gitlab::GitalyClient::RepositoryService).to receive(:new).and_return(repository_service)
allow(repository_service).to receive(:set_config).and_raise(GRPC::BadStatus, 'Retry me')
expect(repository_service).to receive(:set_config).exactly(3).times
migration.up
end
it 'cleans up repository before writing the config', :sidekiq_might_not_need_inline do
expect_next_instance_of(Gitlab::GitalyClient::RepositoryService) do |repository_service|
expect(repository_service).to receive(:cleanup).ordered
expect(repository_service).to receive(:set_config).ordered
end
migration.up
end
context 'legacy storage' do
it 'finds the repository at the correct location' do
Project.find(project.id).create_repository
expect { migration.up }.not_to raise_error
end
end
context 'hashed storage' do
it 'finds the repository at the correct location' do
project.update_attribute(:storage_version, 1)
Project.find(project.id).create_repository
expect { migration.up }.not_to raise_error
end
end
end
context 'project in group' do
let!(:project) { projects.create!(namespace_id: group.id, name: 'baz', path: 'baz') }
let(:expected_path) { 'foo/baz' }
it_behaves_like 'writes the full path to git config'
end
context 'project in subgroup' do
let!(:project) { projects.create!(namespace_id: subgroup.id, name: 'baz', path: 'baz') }
let(:expected_path) { 'foo/bar/baz' }
it_behaves_like 'writes the full path to git config'
end
end
describe '#down' do
context 'project in group' do
let!(:project) { projects.create!(namespace_id: group.id, name: 'baz', path: 'baz') }
it 'deletes the gitlab full config value', :sidekiq_might_not_need_inline do
expect_any_instance_of(Gitlab::GitalyClient::RepositoryService)
.to receive(:delete_config).with(['gitlab.fullpath'])
migration.down
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20180531220618_change_default_value_for_dsa_key_restriction.rb')
describe ChangeDefaultValueForDsaKeyRestriction do
let(:application_settings) { table(:application_settings) }
before do
application_settings.create!
end
it 'changes the default value for dsa_key_restriction' do
expect(application_settings.first.dsa_key_restriction).to eq(0)
migrate!
application_settings.reset_column_information
new_setting = application_settings.create!
expect(application_settings.count).to eq(2)
expect(new_setting.dsa_key_restriction).to eq(-1)
end
it 'changes the existing setting' do
setting = application_settings.last
expect(setting.dsa_key_restriction).to eq(0)
migrate!
expect(application_settings.count).to eq(1)
expect(setting.reload.dsa_key_restriction).to eq(-1)
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20180420010616_cleanup_build_stage_migration.rb')
describe CleanupBuildStageMigration, :redis do
let(:migration) { spy('migration') }
before do
allow(Gitlab::BackgroundMigration::MigrateBuildStage)
.to receive(:new).and_return(migration)
end
context 'when there are pending background migrations' do
it 'processes pending jobs synchronously' do
Sidekiq::Testing.disable! do
BackgroundMigrationWorker
.perform_in(2.minutes, 'MigrateBuildStage', [1, 1])
BackgroundMigrationWorker
.perform_async('MigrateBuildStage', [1, 1])
migrate!
expect(migration).to have_received(:perform).with(1, 1).twice
end
end
end
context 'when there are no background migrations pending' do
it 'does nothing' do
Sidekiq::Testing.disable! do
migrate!
expect(migration).not_to have_received(:perform)
end
end
end
context 'when there are still unmigrated builds present' do
let(:builds) { table('ci_builds') }
before do
builds.create!(name: 'test:1', ref: 'master')
builds.create!(name: 'test:2', ref: 'master')
end
it 'migrates stages sequentially in batches' do
expect(builds.all).to all(have_attributes(stage_id: nil))
migrate!
expect(migration).to have_received(:perform).once
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20181108091549_cleanup_environments_external_url.rb')
describe CleanupEnvironmentsExternalUrl do
let(:environments) { table(:environments) }
let(:invalid_entries) { environments.where(environments.arel_table[:external_url].matches('javascript://%')) }
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
before do
namespace = namespaces.create(name: 'foo', path: 'foo')
project = projects.create!(namespace_id: namespace.id)
environments.create!(id: 1, project_id: project.id, name: 'poisoned', slug: 'poisoned', external_url: 'javascript://alert("1")')
end
it 'clears every environment with a javascript external_url' do
expect do
subject.up
end.to change { invalid_entries.count }.from(1).to(0)
end
it 'do not removes environments' do
expect do
subject.up
end.not_to change { environments.count }
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20180604123514_cleanup_stages_position_migration.rb')
describe CleanupStagesPositionMigration, :redis do
let(:migration) { spy('migration') }
before do
allow(Gitlab::BackgroundMigration::MigrateStageIndex)
.to receive(:new).and_return(migration)
end
context 'when there are pending background migrations' do
it 'processes pending jobs synchronously' do
Sidekiq::Testing.disable! do
BackgroundMigrationWorker
.perform_in(2.minutes, 'MigrateStageIndex', [1, 1])
BackgroundMigrationWorker
.perform_async('MigrateStageIndex', [1, 1])
migrate!
expect(migration).to have_received(:perform).with(1, 1).twice
end
end
end
context 'when there are no background migrations pending' do
it 'does nothing' do
Sidekiq::Testing.disable! do
migrate!
expect(migration).not_to have_received(:perform)
end
end
end
context 'when there are still unmigrated stages present' do
let(:stages) { table('ci_stages') }
let(:builds) { table('ci_builds') }
let!(:entities) do
%w[build test broken].map do |name|
stages.create(name: name)
end
end
before do
stages.update_all(position: nil)
builds.create(name: 'unit', stage_id: entities.first.id, stage_idx: 1, ref: 'master')
builds.create(name: 'unit', stage_id: entities.second.id, stage_idx: 1, ref: 'master')
end
it 'migrates stages sequentially for every stage' do
expect(stages.all).to all(have_attributes(position: nil))
migrate!
expect(migration).to have_received(:perform)
.with(entities.first.id, entities.first.id)
expect(migration).to have_received(:perform)
.with(entities.second.id, entities.second.id)
expect(migration).not_to have_received(:perform)
.with(entities.third.id, entities.third.id)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20180413022611_create_missing_namespace_for_internal_users.rb')
describe CreateMissingNamespaceForInternalUsers do
let(:users) { table(:users) }
let(:namespaces) { table(:namespaces) }
let(:routes) { table(:routes) }
context "for ghost user" do
let(:internal_user) do
users.create!(email: 'test@example.com', projects_limit: 100, username: 'test', ghost: true)
end
it 'creates the missing namespace' do
expect(namespaces.find_by(owner_id: internal_user.id)).to be_nil
migrate!
namespace = Namespace.find_by(type: nil, owner_id: internal_user.id)
route = namespace.route
expect(namespace.path).to eq(route.path)
expect(namespace.name).to eq(route.name)
end
it 'sets notification email' do
users.update(internal_user.id, notification_email: nil)
expect(users.find(internal_user.id).notification_email).to be_nil
migrate!
user = users.find(internal_user.id)
expect(user.notification_email).to eq(user.email)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20180711103851_drop_duplicate_protected_tags.rb')
describe DropDuplicateProtectedTags do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:protected_tags) { table(:protected_tags) }
before do
stub_const("#{described_class}::BATCH_SIZE", 2)
namespaces.create(id: 1, name: 'gitlab-org', path: 'gitlab-org')
projects.create!(id: 1, namespace_id: 1, name: 'gitlab1', path: 'gitlab1')
projects.create!(id: 2, namespace_id: 1, name: 'gitlab2', path: 'gitlab2')
end
it 'removes duplicated protected tags' do
protected_tags.create!(id: 1, project_id: 1, name: 'foo')
tag2 = protected_tags.create!(id: 2, project_id: 1, name: 'foo1')
protected_tags.create!(id: 3, project_id: 1, name: 'foo')
tag4 = protected_tags.create!(id: 4, project_id: 1, name: 'foo')
tag5 = protected_tags.create!(id: 5, project_id: 2, name: 'foo')
migrate!
expect(protected_tags.all.count).to eq 3
expect(protected_tags.all.pluck(:id)).to contain_exactly(tag2.id, tag4.id, tag5.id)
end
it 'does not remove unique protected tags' do
tag1 = protected_tags.create!(id: 1, project_id: 1, name: 'foo1')
tag2 = protected_tags.create!(id: 2, project_id: 1, name: 'foo2')
tag3 = protected_tags.create!(id: 3, project_id: 1, name: 'foo3')
migrate!
expect(protected_tags.all.count).to eq 3
expect(protected_tags.all.pluck(:id)).to contain_exactly(tag1.id, tag2.id, tag3.id)
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20190711201818_encrypt_deploy_tokens_tokens.rb')
describe EncryptDeployTokensTokens do
let(:migration) { described_class.new }
let(:deployment_tokens) { table(:deploy_tokens) }
let(:plaintext) { "secret-token" }
let(:expires_at) { DateTime.now + 1.year }
let(:ciphertext) { Gitlab::CryptoHelper.aes256_gcm_encrypt(plaintext) }
describe '#up' do
it 'keeps plaintext token the same and populates token_encrypted if not present' do
deploy_token = deployment_tokens.create!(
name: 'test_token',
read_repository: true,
expires_at: expires_at,
username: 'gitlab-token-1',
token: plaintext
)
migration.up
expect(deploy_token.reload.token).to eq(plaintext)
expect(deploy_token.reload.token_encrypted).to eq(ciphertext)
end
end
describe '#down' do
it 'decrypts encrypted token and saves it' do
deploy_token = deployment_tokens.create!(
name: 'test_token',
read_repository: true,
expires_at: expires_at,
username: 'gitlab-token-1',
token_encrypted: ciphertext
)
migration.down
expect(deploy_token.reload.token).to eq(plaintext)
expect(deploy_token.reload.token_encrypted).to eq(ciphertext)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20180216121030_enqueue_verify_pages_domain_workers')
describe EnqueueVerifyPagesDomainWorkers do
around do |example|
Sidekiq::Testing.fake! do
example.run
end
end
let(:domains_table) { table(:pages_domains) }
describe '#up' do
it 'enqueues a verification worker for every domain' do
domains = Array.new(3) do |i|
domains_table.create!(domain: "my#{i}.domain.com", verification_code: "123#{i}")
end
expect { migrate! }.to change(PagesDomainVerificationWorker.jobs, :size).by(3)
enqueued_ids = PagesDomainVerificationWorker.jobs.map { |job| job['args'] }
expected_ids = domains.map { |domain| [domain.id] }
expect(enqueued_ids).to match_array(expected_ids)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20181030135124_fill_empty_finished_at_in_deployments')
describe FillEmptyFinishedAtInDeployments do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:environments) { table(:environments) }
let(:deployments) { table(:deployments) }
context 'when a deployment row does not have a value on finished_at' do
context 'when a deployment succeeded' do
before do
namespaces.create!(id: 123, name: 'gitlab1', path: 'gitlab1')
projects.create!(id: 1, name: 'gitlab1', path: 'gitlab1', namespace_id: 123)
environments.create!(id: 1, name: 'production', slug: 'production', project_id: 1)
deployments.create!(id: 1, iid: 1, project_id: 1, environment_id: 1, ref: 'master', sha: 'xxx', tag: false)
end
it 'correctly replicates finished_at by created_at' do
expect(deployments.last.created_at).not_to be_nil
expect(deployments.last.finished_at).to be_nil
migrate!
expect(deployments.last.created_at).not_to be_nil
expect(deployments.last.finished_at).to eq(deployments.last.created_at)
end
end
context 'when a deployment is running' do
before do
namespaces.create!(id: 123, name: 'gitlab1', path: 'gitlab1')
projects.create!(id: 1, name: 'gitlab1', path: 'gitlab1', namespace_id: 123)
environments.create!(id: 1, name: 'production', slug: 'production', project_id: 1)
deployments.create!(id: 1, iid: 1, project_id: 1, environment_id: 1, ref: 'master', sha: 'xxx', tag: false, status: 1)
end
it 'does not fill finished_at' do
expect(deployments.last.created_at).not_to be_nil
expect(deployments.last.finished_at).to be_nil
migrate!
expect(deployments.last.created_at).not_to be_nil
expect(deployments.last.finished_at).to be_nil
end
end
end
context 'when a deployment row does has a value on finished_at' do
let(:finished_at) { '2018-10-30 11:12:02 UTC' }
before do
namespaces.create!(id: 123, name: 'gitlab1', path: 'gitlab1')
projects.create!(id: 1, name: 'gitlab1', path: 'gitlab1', namespace_id: 123)
environments.create!(id: 1, name: 'production', slug: 'production', project_id: 1)
deployments.create!(id: 1, iid: 1, project_id: 1, environment_id: 1, ref: 'master', sha: 'xxx', tag: false, finished_at: finished_at)
end
it 'does not affect existing value' do
expect(deployments.last.created_at).not_to be_nil
expect(deployments.last.finished_at).not_to be_nil
migrate!
expect(deployments.last.created_at).not_to be_nil
expect(deployments.last.finished_at).to eq(finished_at)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20180424151928_fill_file_store')
describe FillFileStore do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:builds) { table(:ci_builds) }
let(:job_artifacts) { table(:ci_job_artifacts) }
let(:lfs_objects) { table(:lfs_objects) }
let(:uploads) { table(:uploads) }
before do
namespaces.create!(id: 123, name: 'gitlab1', path: 'gitlab1')
projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1', namespace_id: 123)
builds.create!(id: 1)
##
# Create rows that have nullfied `file_store` column
job_artifacts.create!(project_id: 123, job_id: 1, file_type: 1, file_store: nil)
lfs_objects.create!(oid: 123, size: 10, file: 'file_name', file_store: nil)
uploads.create!(size: 10, path: 'path', uploader: 'uploader', mount_point: 'file_name', store: nil)
end
it 'correctly migrates nullified file_store/store column', :sidekiq_might_not_need_inline do
expect(job_artifacts.where(file_store: nil).count).to eq(1)
expect(lfs_objects.where(file_store: nil).count).to eq(1)
expect(uploads.where(store: nil).count).to eq(1)
expect(job_artifacts.where(file_store: 1).count).to eq(0)
expect(lfs_objects.where(file_store: 1).count).to eq(0)
expect(uploads.where(store: 1).count).to eq(0)
migrate!
expect(job_artifacts.where(file_store: nil).count).to eq(0)
expect(lfs_objects.where(file_store: nil).count).to eq(0)
expect(uploads.where(store: nil).count).to eq(0)
expect(job_artifacts.where(file_store: 1).count).to eq(1)
expect(lfs_objects.where(file_store: 1).count).to eq(1)
expect(uploads.where(store: 1).count).to eq(1)
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20180702134423_generate_missing_routes.rb')
describe GenerateMissingRoutes do
describe '#up' do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:routes) { table(:routes) }
it 'creates routes for projects without a route' do
namespace = namespaces.create!(name: 'GitLab', path: 'gitlab', type: 'Group')
routes.create!(
path: 'gitlab',
source_type: 'Namespace',
source_id: namespace.id
)
project = projects.create!(
name: 'GitLab CE',
path: 'gitlab-ce',
namespace_id: namespace.id
)
described_class.new.up
route = routes.find_by(source_type: 'Project')
expect(route.source_id).to eq(project.id)
expect(route.path).to eq("gitlab/gitlab-ce-#{project.id}")
end
it 'creates routes for namespaces without a route' do
namespace = namespaces.create!(name: 'GitLab', path: 'gitlab')
described_class.new.up
route = routes.find_by(source_type: 'Namespace')
expect(route.source_id).to eq(namespace.id)
expect(route.path).to eq("gitlab-#{namespace.id}")
end
it 'does not create routes for namespaces that already have a route' do
namespace = namespaces.create!(name: 'GitLab', path: 'gitlab')
routes.create!(
path: 'gitlab',
source_type: 'Namespace',
source_id: namespace.id
)
described_class.new.up
expect(routes.count).to eq(1)
end
it 'does not create routes for projects that already have a route' do
namespace = namespaces.create!(name: 'GitLab', path: 'gitlab')
routes.create!(
path: 'gitlab',
source_type: 'Namespace',
source_id: namespace.id
)
project = projects.create!(
name: 'GitLab CE',
path: 'gitlab-ce',
namespace_id: namespace.id
)
routes.create!(
path: 'gitlab/gitlab-ce',
source_type: 'Project',
source_id: project.id
)
described_class.new.up
expect(routes.count).to eq(2)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20180831164910_import_common_metrics.rb')
describe ImportCommonMetrics do
describe '#up' do
it "imports all prometheus metrics" do
expect(PrometheusMetric.common).to be_empty
migrate!
expect(PrometheusMetric.common).not_to be_empty
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20181219145520_migrate_cluster_configure_worker_sidekiq_queue.rb')
describe MigrateClusterConfigureWorkerSidekiqQueue, :redis do
include Gitlab::Database::MigrationHelpers
include StubWorker
context 'when there are jobs in the queue' do
it 'correctly migrates queue when migrating up' do
Sidekiq::Testing.disable! do
stub_worker(queue: 'gcp_cluster:cluster_platform_configure').perform_async('Something', [1])
stub_worker(queue: 'gcp_cluster:cluster_configure').perform_async('Something', [1])
described_class.new.up
expect(sidekiq_queue_length('gcp_cluster:cluster_platform_configure')).to eq 0
expect(sidekiq_queue_length('gcp_cluster:cluster_configure')).to eq 2
end
end
it 'does not affect other queues under the same namespace' do
Sidekiq::Testing.disable! do
stub_worker(queue: 'gcp_cluster:cluster_install_app').perform_async('Something', [1])
stub_worker(queue: 'gcp_cluster:cluster_provision').perform_async('Something', [1])
stub_worker(queue: 'gcp_cluster:cluster_wait_for_app_installation').perform_async('Something', [1])
stub_worker(queue: 'gcp_cluster:wait_for_cluster_creation').perform_async('Something', [1])
stub_worker(queue: 'gcp_cluster:cluster_wait_for_ingress_ip_address').perform_async('Something', [1])
stub_worker(queue: 'gcp_cluster:cluster_project_configure').perform_async('Something', [1])
described_class.new.up
expect(sidekiq_queue_length('gcp_cluster:cluster_install_app')).to eq 1
expect(sidekiq_queue_length('gcp_cluster:cluster_provision')).to eq 1
expect(sidekiq_queue_length('gcp_cluster:cluster_wait_for_app_installation')).to eq 1
expect(sidekiq_queue_length('gcp_cluster:wait_for_cluster_creation')).to eq 1
expect(sidekiq_queue_length('gcp_cluster:cluster_wait_for_ingress_ip_address')).to eq 1
expect(sidekiq_queue_length('gcp_cluster:cluster_project_configure')).to eq 1
end
end
it 'correctly migrates queue when migrating down' do
Sidekiq::Testing.disable! do
stub_worker(queue: 'gcp_cluster:cluster_configure').perform_async('Something', [1])
described_class.new.down
expect(sidekiq_queue_length('gcp_cluster:cluster_platform_configure')).to eq 1
expect(sidekiq_queue_length('gcp_cluster:cluster_configure')).to eq 0
end
end
end
context 'when there are no jobs in the queues' do
it 'does not raise error when migrating up' do
expect { described_class.new.up }.not_to raise_error
end
it 'does not raise error when migrating down' do
expect { described_class.new.down }.not_to raise_error
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20180306074045_migrate_create_trace_artifact_sidekiq_queue.rb')
describe MigrateCreateTraceArtifactSidekiqQueue, :redis do
include Gitlab::Database::MigrationHelpers
include StubWorker
context 'when there are jobs in the queues' do
it 'correctly migrates queue when migrating up' do
Sidekiq::Testing.disable! do
stub_worker(queue: 'pipeline_default:create_trace_artifact').perform_async('Something', [1])
stub_worker(queue: 'pipeline_background:archive_trace').perform_async('Something', [1])
described_class.new.up
expect(sidekiq_queue_length('pipeline_default:create_trace_artifact')).to eq 0
expect(sidekiq_queue_length('pipeline_background:archive_trace')).to eq 2
end
end
it 'does not affect other queues under the same namespace' do
Sidekiq::Testing.disable! do
stub_worker(queue: 'pipeline_default:build_coverage').perform_async('Something', [1])
stub_worker(queue: 'pipeline_default:build_trace_sections').perform_async('Something', [1])
stub_worker(queue: 'pipeline_default:pipeline_metrics').perform_async('Something', [1])
stub_worker(queue: 'pipeline_default:pipeline_notification').perform_async('Something', [1])
stub_worker(queue: 'pipeline_default:update_head_pipeline_for_merge_request').perform_async('Something', [1])
described_class.new.up
expect(sidekiq_queue_length('pipeline_default:build_coverage')).to eq 1
expect(sidekiq_queue_length('pipeline_default:build_trace_sections')).to eq 1
expect(sidekiq_queue_length('pipeline_default:pipeline_metrics')).to eq 1
expect(sidekiq_queue_length('pipeline_default:pipeline_notification')).to eq 1
expect(sidekiq_queue_length('pipeline_default:update_head_pipeline_for_merge_request')).to eq 1
end
end
it 'correctly migrates queue when migrating down' do
Sidekiq::Testing.disable! do
stub_worker(queue: 'pipeline_background:archive_trace').perform_async('Something', [1])
described_class.new.down
expect(sidekiq_queue_length('pipeline_default:create_trace_artifact')).to eq 1
expect(sidekiq_queue_length('pipeline_background:archive_trace')).to eq 0
end
end
end
context 'when there are no jobs in the queues' do
it 'does not raise error when migrating up' do
expect { described_class.new.up }.not_to raise_error
end
it 'does not raise error when migrating down' do
expect { described_class.new.down }.not_to raise_error
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20181026091631_migrate_forbidden_redirect_uris.rb')
describe MigrateForbiddenRedirectUris do
let(:oauth_application) { table(:oauth_applications) }
let(:oauth_access_grant) { table(:oauth_access_grants) }
let!(:control_app) { oauth_application.create(random_params) }
let!(:control_access_grant) { oauth_application.create(random_params) }
let!(:forbidden_js_app) { oauth_application.create(random_params.merge(redirect_uri: 'javascript://alert()')) }
let!(:forbidden_vb_app) { oauth_application.create(random_params.merge(redirect_uri: 'VBSCRIPT://alert()')) }
let!(:forbidden_access_grant) { oauth_application.create(random_params.merge(redirect_uri: 'vbscript://alert()')) }
context 'oauth application' do
it 'migrates forbidden javascript URI' do
expect { migrate! }.to change { forbidden_js_app.reload.redirect_uri }.to('http://forbidden-scheme-has-been-overwritten')
end
it 'migrates forbidden VBScript URI' do
expect { migrate! }.to change { forbidden_vb_app.reload.redirect_uri }.to('http://forbidden-scheme-has-been-overwritten')
end
it 'does not migrate a valid URI' do
expect { migrate! }.not_to change { control_app.reload.redirect_uri }
end
end
context 'access grant' do
it 'migrates forbidden VBScript URI' do
expect { migrate! }.to change { forbidden_access_grant.reload.redirect_uri }.to('http://forbidden-scheme-has-been-overwritten')
end
it 'does not migrate a valid URI' do
expect { migrate! }.not_to change { control_access_grant.reload.redirect_uri }
end
end
def random_params
{
name: 'test',
secret: 'test',
uid: Doorkeeper::OAuth::Helpers::UniqueToken.generate,
redirect_uri: 'http://valid.com'
}
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20180816161409_migrate_legacy_artifacts_to_job_artifacts.rb')
describe MigrateLegacyArtifactsToJobArtifacts do
let(:migration_class) { Gitlab::BackgroundMigration::MigrateLegacyArtifacts }
let(:migration_name) { migration_class.to_s.demodulize }
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:pipelines) { table(:ci_pipelines) }
let(:jobs) { table(:ci_builds) }
let(:job_artifacts) { table(:ci_job_artifacts) }
let(:namespace) { namespaces.create!(name: 'gitlab', path: 'gitlab-org') }
let(:project) { projects.create!(name: 'gitlab', path: 'gitlab-ce', namespace_id: namespace.id) }
let(:pipeline) { pipelines.create!(project_id: project.id, ref: 'master', sha: 'adf43c3a') }
let(:archive_file_type) { Gitlab::BackgroundMigration::MigrateLegacyArtifacts::ARCHIVE_FILE_TYPE }
let(:metadata_file_type) { Gitlab::BackgroundMigration::MigrateLegacyArtifacts::METADATA_FILE_TYPE }
let(:local_store) { ::ObjectStorage::Store::LOCAL }
let(:remote_store) { ::ObjectStorage::Store::REMOTE }
let(:legacy_location) { Gitlab::BackgroundMigration::MigrateLegacyArtifacts::LEGACY_PATH_FILE_LOCATION }
context 'when legacy artifacts exist' do
before do
jobs.create!(id: 1, commit_id: pipeline.id, project_id: project.id, status: :success, artifacts_file: 'archive.zip')
jobs.create!(id: 2, commit_id: pipeline.id, project_id: project.id, status: :failed, artifacts_metadata: 'metadata.gz')
jobs.create!(id: 3, commit_id: pipeline.id, project_id: project.id, status: :failed, artifacts_file: 'archive.zip', artifacts_metadata: 'metadata.gz')
jobs.create!(id: 4, commit_id: pipeline.id, project_id: project.id, status: :running)
jobs.create!(id: 5, commit_id: pipeline.id, project_id: project.id, status: :success, artifacts_file: 'archive.zip', artifacts_file_store: remote_store, artifacts_metadata: 'metadata.gz')
jobs.create!(id: 6, commit_id: pipeline.id, project_id: project.id, status: :failed, artifacts_file: 'archive.zip', artifacts_metadata: 'metadata.gz')
end
it 'schedules a background migration' do
Sidekiq::Testing.fake! do
Timecop.freeze do
migrate!
expect(migration_name).to be_scheduled_delayed_migration(5.minutes, 1, 6)
expect(BackgroundMigrationWorker.jobs.size).to eq 1
end
end
end
it 'migrates legacy artifacts to ci_job_artifacts table', :sidekiq_might_not_need_inline do
migrate!
expect(job_artifacts.order(:job_id, :file_type).pluck('project_id, job_id, file_type, file_store, size, expire_at, file, file_sha256, file_location'))
.to eq([[project.id, 1, archive_file_type, local_store, nil, nil, 'archive.zip', nil, legacy_location],
[project.id, 3, archive_file_type, local_store, nil, nil, 'archive.zip', nil, legacy_location],
[project.id, 3, metadata_file_type, local_store, nil, nil, 'metadata.gz', nil, legacy_location],
[project.id, 5, archive_file_type, remote_store, nil, nil, 'archive.zip', nil, legacy_location],
[project.id, 5, metadata_file_type, local_store, nil, nil, 'metadata.gz', nil, legacy_location],
[project.id, 6, archive_file_type, local_store, nil, nil, 'archive.zip', nil, legacy_location],
[project.id, 6, metadata_file_type, local_store, nil, nil, 'metadata.gz', nil, legacy_location]])
end
end
context 'when legacy artifacts do not exist' do
before do
jobs.create!(id: 1, commit_id: pipeline.id, project_id: project.id, status: :success)
jobs.create!(id: 2, commit_id: pipeline.id, project_id: project.id, status: :failed, artifacts_metadata: 'metadata.gz')
end
it 'does not schedule background migrations' do
Sidekiq::Testing.fake! do
Timecop.freeze do
migrate!
expect(BackgroundMigrationWorker.jobs.size).to eq 0
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20180809195358_migrate_null_wiki_access_levels.rb')
describe MigrateNullWikiAccessLevels do
let(:namespaces) { table('namespaces') }
let(:projects) { table(:projects) }
let(:project_features) { table(:project_features) }
let(:migration) { described_class.new }
before do
namespace = namespaces.create(name: 'foo', path: 'foo')
projects.create!(id: 1, name: 'gitlab1', path: 'gitlab1', namespace_id: namespace.id)
projects.create!(id: 2, name: 'gitlab2', path: 'gitlab2', namespace_id: namespace.id)
projects.create!(id: 3, name: 'gitlab3', path: 'gitlab3', namespace_id: namespace.id)
project_features.create!(id: 1, project_id: 1, wiki_access_level: nil)
project_features.create!(id: 2, project_id: 2, wiki_access_level: 10)
project_features.create!(id: 3, project_id: 3, wiki_access_level: 20)
end
describe '#up' do
it 'migrates existing project_features with wiki_access_level NULL to 20' do
expect { migration.up }.to change { project_features.where(wiki_access_level: 20).count }.by(1)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20180603190921_migrate_object_storage_upload_sidekiq_queue.rb')
describe MigrateObjectStorageUploadSidekiqQueue, :redis do
include Gitlab::Database::MigrationHelpers
include StubWorker
context 'when there are jobs in the queue' do
it 'correctly migrates queue when migrating up' do
Sidekiq::Testing.disable! do
stub_worker(queue: 'object_storage_upload').perform_async('Something', [1])
stub_worker(queue: 'object_storage:object_storage_background_move').perform_async('Something', [1])
described_class.new.up
expect(sidekiq_queue_length('object_storage_upload')).to eq 0
expect(sidekiq_queue_length('object_storage:object_storage_background_move')).to eq 2
end
end
end
context 'when there are no jobs in the queues' do
it 'does not raise error when migrating up' do
expect { described_class.new.up }.not_to raise_error
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20180307012445_migrate_update_head_pipeline_for_merge_request_sidekiq_queue.rb')
describe MigrateUpdateHeadPipelineForMergeRequestSidekiqQueue, :redis do
include Gitlab::Database::MigrationHelpers
include StubWorker
context 'when there are jobs in the queues' do
it 'correctly migrates queue when migrating up' do
Sidekiq::Testing.disable! do
stub_worker(queue: 'pipeline_default:update_head_pipeline_for_merge_request').perform_async('Something', [1])
stub_worker(queue: 'pipeline_processing:update_head_pipeline_for_merge_request').perform_async('Something', [1])
described_class.new.up
expect(sidekiq_queue_length('pipeline_default:update_head_pipeline_for_merge_request')).to eq 0
expect(sidekiq_queue_length('pipeline_processing:update_head_pipeline_for_merge_request')).to eq 2
end
end
it 'does not affect other queues under the same namespace' do
Sidekiq::Testing.disable! do
stub_worker(queue: 'pipeline_default:build_coverage').perform_async('Something', [1])
stub_worker(queue: 'pipeline_default:build_trace_sections').perform_async('Something', [1])
stub_worker(queue: 'pipeline_default:pipeline_metrics').perform_async('Something', [1])
stub_worker(queue: 'pipeline_default:pipeline_notification').perform_async('Something', [1])
described_class.new.up
expect(sidekiq_queue_length('pipeline_default:build_coverage')).to eq 1
expect(sidekiq_queue_length('pipeline_default:build_trace_sections')).to eq 1
expect(sidekiq_queue_length('pipeline_default:pipeline_metrics')).to eq 1
expect(sidekiq_queue_length('pipeline_default:pipeline_notification')).to eq 1
end
end
it 'correctly migrates queue when migrating down' do
Sidekiq::Testing.disable! do
stub_worker(queue: 'pipeline_processing:update_head_pipeline_for_merge_request').perform_async('Something', [1])
described_class.new.down
expect(sidekiq_queue_length('pipeline_default:update_head_pipeline_for_merge_request')).to eq 1
expect(sidekiq_queue_length('pipeline_processing:update_head_pipeline_for_merge_request')).to eq 0
end
end
end
context 'when there are no jobs in the queues' do
it 'does not raise error when migrating up' do
expect { described_class.new.up }.not_to raise_error
end
it 'does not raise error when migrating down' do
expect { described_class.new.down }.not_to raise_error
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20180220150310_remove_empty_extern_uid_auth0_identities.rb')
describe RemoveEmptyExternUidAuth0Identities do
let(:identities) { table(:identities) }
before do
identities.create(provider: 'auth0', extern_uid: '')
identities.create(provider: 'auth0', extern_uid: 'valid')
identities.create(provider: 'github', extern_uid: '')
migrate!
end
it 'leaves the correct auth0 identity' do
expect(identities.where(provider: 'auth0').pluck(:extern_uid)).to eq(['valid'])
end
it 'leaves the correct github identity' do
expect(identities.where(provider: 'github').count).to eq(1)
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20180119121225_remove_redundant_pipeline_stages.rb')
describe RemoveRedundantPipelineStages do
let(:projects) { table(:projects) }
let(:pipelines) { table(:ci_pipelines) }
let(:stages) { table(:ci_stages) }
let(:builds) { table(:ci_builds) }
before do
projects.create!(id: 123, name: 'gitlab', path: 'gitlab-ce')
pipelines.create!(id: 234, project_id: 123, ref: 'master', sha: 'adf43c3a')
stages.create!(id: 6, project_id: 123, pipeline_id: 234, name: 'build')
stages.create!(id: 10, project_id: 123, pipeline_id: 234, name: 'build')
stages.create!(id: 21, project_id: 123, pipeline_id: 234, name: 'build')
stages.create!(id: 41, project_id: 123, pipeline_id: 234, name: 'test')
stages.create!(id: 62, project_id: 123, pipeline_id: 234, name: 'test')
stages.create!(id: 102, project_id: 123, pipeline_id: 234, name: 'deploy')
builds.create!(id: 1, commit_id: 234, project_id: 123, stage_id: 10)
builds.create!(id: 2, commit_id: 234, project_id: 123, stage_id: 21)
builds.create!(id: 3, commit_id: 234, project_id: 123, stage_id: 21)
builds.create!(id: 4, commit_id: 234, project_id: 123, stage_id: 41)
builds.create!(id: 5, commit_id: 234, project_id: 123, stage_id: 62)
builds.create!(id: 6, commit_id: 234, project_id: 123, stage_id: 102)
end
it 'removes ambiguous stages and preserves builds' do
expect(stages.all.count).to eq 6
expect(builds.all.count).to eq 6
migrate!
expect(stages.all.count).to eq 1
expect(builds.all.count).to eq 6
expect(builds.all.pluck(:stage_id).compact).to eq [102]
end
it 'retries when incorrectly added index exception is caught' do
allow_any_instance_of(described_class)
.to receive(:remove_redundant_pipeline_stages!)
expect_any_instance_of(described_class)
.to receive(:remove_outdated_index!)
.exactly(100).times.and_call_original
expect { migrate! }
.to raise_error StandardError, /Failed to add an unique index/
end
it 'does not retry when unknown exception is being raised' do
allow(subject).to receive(:remove_outdated_index!)
expect(subject).to receive(:remove_redundant_pipeline_stages!).once
allow(subject).to receive(:add_unique_index!).and_raise(StandardError)
expect { subject.up(attempts: 3) }.to raise_error StandardError
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20180405101928_reschedule_builds_stages_migration')
describe RescheduleBuildsStagesMigration do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:pipelines) { table(:ci_pipelines) }
let(:stages) { table(:ci_stages) }
let(:jobs) { table(:ci_builds) }
before do
stub_const("#{described_class}::BATCH_SIZE", 1)
namespaces.create(id: 12, name: 'gitlab-org', path: 'gitlab-org')
projects.create!(id: 123, namespace_id: 12, name: 'gitlab', path: 'gitlab')
pipelines.create!(id: 1, project_id: 123, ref: 'master', sha: 'adf43c3a')
stages.create!(id: 1, project_id: 123, pipeline_id: 1, name: 'test')
jobs.create!(id: 11, commit_id: 1, project_id: 123, stage_id: nil)
jobs.create!(id: 206, commit_id: 1, project_id: 123, stage_id: nil)
jobs.create!(id: 3413, commit_id: 1, project_id: 123, stage_id: nil)
jobs.create!(id: 4109, commit_id: 1, project_id: 123, stage_id: 1)
end
it 'schedules delayed background migrations in batches in bulk' do
Sidekiq::Testing.fake! do
Timecop.freeze do
migrate!
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(5.minutes, 11, 11)
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(10.minutes, 206, 206)
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(15.minutes, 3413, 3413)
expect(BackgroundMigrationWorker.jobs.size).to eq 3
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20180309121820_reschedule_commits_count_for_merge_request_diff')
describe RescheduleCommitsCountForMergeRequestDiff do
let(:merge_request_diffs) { table(:merge_request_diffs) }
let(:merge_requests) { table(:merge_requests) }
let(:projects) { table(:projects) }
let(:namespaces) { table(:namespaces) }
before do
stub_const("#{described_class.name}::BATCH_SIZE", 1)
namespaces.create!(id: 1, name: 'gitlab', path: 'gitlab')
projects.create!(id: 1, namespace_id: 1)
merge_requests.create!(id: 1, target_project_id: 1, source_project_id: 1, target_branch: 'feature', source_branch: 'master')
merge_request_diffs.create!(id: 1, merge_request_id: 1)
merge_request_diffs.create!(id: 2, merge_request_id: 1)
merge_request_diffs.create!(id: 3, merge_request_id: 1, commits_count: 0)
merge_request_diffs.create!(id: 4, merge_request_id: 1)
end
it 'correctly schedules background migrations' do
Sidekiq::Testing.fake! do
Timecop.freeze do
migrate!
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(5.minutes, 1, 1)
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(10.minutes, 2, 2)
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(15.minutes, 4, 4)
expect(BackgroundMigrationWorker.jobs.size).to eq 3
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20180913142237_schedule_digest_personal_access_tokens.rb')
describe ScheduleDigestPersonalAccessTokens do
let(:personal_access_tokens) { table(:personal_access_tokens) }
let(:users) { table(:users) }
before do
stub_const("#{described_class.name}::BATCH_SIZE", 4)
users.create(id: 1, email: 'user@example.com', projects_limit: 10)
personal_access_tokens.create!(id: 1, user_id: 1, name: 'pat-01', token: 'token-01')
personal_access_tokens.create!(id: 2, user_id: 1, name: 'pat-02', token: 'token-02')
personal_access_tokens.create!(id: 3, user_id: 1, name: 'pat-03', token_digest: 'token_digest')
personal_access_tokens.create!(id: 4, user_id: 1, name: 'pat-04', token: 'token-04')
personal_access_tokens.create!(id: 5, user_id: 1, name: 'pat-05', token: 'token-05')
personal_access_tokens.create!(id: 6, user_id: 1, name: 'pat-06', token: 'token-06')
end
it 'correctly schedules background migrations' do
Sidekiq::Testing.fake! do
migrate!
expect(described_class::MIGRATION).to(
be_scheduled_delayed_migration(
5.minutes, 'PersonalAccessToken', 'token', 'token_digest', 1, 5))
expect(described_class::MIGRATION).to(
be_scheduled_delayed_migration(
10.minutes, 'PersonalAccessToken', 'token', 'token_digest', 6, 6))
expect(BackgroundMigrationWorker.jobs.size).to eq 2
end
end
it 'schedules background migrations', :sidekiq_might_not_need_inline do
perform_enqueued_jobs do
plain_text_token = 'token IS NOT NULL'
expect(personal_access_tokens.where(plain_text_token).count).to eq 5
migrate!
expect(personal_access_tokens.where(plain_text_token).count).to eq 0
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20181121111200_schedule_runners_token_encryption')
describe ScheduleRunnersTokenEncryption do
let(:settings) { table(:application_settings) }
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:runners) { table(:ci_runners) }
before do
stub_const("#{described_class.name}::BATCH_SIZE", 1)
settings.create!(id: 1, runners_registration_token: 'plain-text-token1')
namespaces.create!(id: 11, name: 'gitlab', path: 'gitlab-org', runners_token: 'my-token1')
namespaces.create!(id: 12, name: 'gitlab', path: 'gitlab-org', runners_token: 'my-token2')
projects.create!(id: 111, namespace_id: 11, name: 'gitlab', path: 'gitlab-ce', runners_token: 'my-token1')
projects.create!(id: 114, namespace_id: 11, name: 'gitlab', path: 'gitlab-ce', runners_token: 'my-token2')
runners.create!(id: 201, runner_type: 1, token: 'plain-text-token1')
runners.create!(id: 202, runner_type: 1, token: 'plain-text-token2')
end
it 'schedules runners token encryption migration for multiple resources' do
Sidekiq::Testing.fake! do
Timecop.freeze do
migrate!
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(4.minutes, 'settings', 1, 1)
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(4.minutes, 'namespace', 11, 11)
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(8.minutes, 'namespace', 12, 12)
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(4.minutes, 'project', 111, 111)
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(8.minutes, 'project', 114, 114)
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(4.minutes, 'runner', 201, 201)
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(8.minutes, 'runner', 202, 202)
expect(BackgroundMigrationWorker.jobs.size).to eq 7
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20180104131052_schedule_set_confidential_note_events_on_webhooks.rb')
describe ScheduleSetConfidentialNoteEventsOnWebhooks do
let(:web_hooks_table) { table(:web_hooks) }
let(:migration_class) { Gitlab::BackgroundMigration::SetConfidentialNoteEventsOnWebhooks }
let(:migration_name) { migration_class.to_s.demodulize }
let!(:web_hook_1) { web_hooks_table.create!(confidential_note_events: nil, note_events: true) }
let!(:web_hook_2) { web_hooks_table.create!(confidential_note_events: nil, note_events: true) }
let!(:web_hook_migrated) { web_hooks_table.create!(confidential_note_events: true, note_events: true) }
let!(:web_hook_skip) { web_hooks_table.create!(confidential_note_events: nil, note_events: false) }
let!(:web_hook_new) { web_hooks_table.create!(confidential_note_events: false, note_events: true) }
let!(:web_hook_4) { web_hooks_table.create!(confidential_note_events: nil, note_events: true) }
before do
stub_const("#{described_class}::BATCH_SIZE", 1)
end
it 'schedules background migrations at correct time' do
Sidekiq::Testing.fake! do
Timecop.freeze do
migrate!
expect(migration_name).to be_scheduled_delayed_migration(5.minutes, web_hook_1.id, web_hook_1.id)
expect(migration_name).to be_scheduled_delayed_migration(10.minutes, web_hook_2.id, web_hook_2.id)
expect(migration_name).to be_scheduled_delayed_migration(15.minutes, web_hook_4.id, web_hook_4.id)
expect(BackgroundMigrationWorker.jobs.size).to eq 3
end
end
end
it 'correctly processes web hooks', :sidekiq_might_not_need_inline do
perform_enqueued_jobs do
expect(web_hooks_table.where(confidential_note_events: nil).count).to eq 4
expect(web_hooks_table.where(confidential_note_events: true).count).to eq 1
migrate!
expect(web_hooks_table.where(confidential_note_events: nil).count).to eq 1
expect(web_hooks_table.where(confidential_note_events: true).count).to eq 4
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20180420080616_schedule_stages_index_migration')
describe ScheduleStagesIndexMigration do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:pipelines) { table(:ci_pipelines) }
let(:stages) { table(:ci_stages) }
before do
stub_const("#{described_class}::BATCH_SIZE", 1)
namespaces.create(id: 12, name: 'gitlab-org', path: 'gitlab-org')
projects.create!(id: 123, namespace_id: 12, name: 'gitlab', path: 'gitlab')
pipelines.create!(id: 1, project_id: 123, ref: 'master', sha: 'adf43c3a')
stages.create!(id: 121, project_id: 123, pipeline_id: 1, name: 'build')
stages.create!(id: 122, project_id: 123, pipeline_id: 1, name: 'test')
stages.create!(id: 123, project_id: 123, pipeline_id: 1, name: 'deploy')
end
it 'schedules delayed background migrations in batches' do
Sidekiq::Testing.fake! do
Timecop.freeze do
expect(stages.all).to all(have_attributes(position: be_nil))
migrate!
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(5.minutes, 121, 121)
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(10.minutes, 122, 122)
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(15.minutes, 123, 123)
expect(BackgroundMigrationWorker.jobs.size).to eq 3
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20180529152628_schedule_to_archive_legacy_traces')
describe ScheduleToArchiveLegacyTraces do
include TraceHelpers
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:builds) { table(:ci_builds) }
let(:job_artifacts) { table(:ci_job_artifacts) }
before do
namespaces.create!(id: 123, name: 'gitlab1', path: 'gitlab1')
projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1', namespace_id: 123)
@build_success = builds.create!(id: 1, project_id: 123, status: 'success', type: 'Ci::Build')
@build_failed = builds.create!(id: 2, project_id: 123, status: 'failed', type: 'Ci::Build')
@builds_canceled = builds.create!(id: 3, project_id: 123, status: 'canceled', type: 'Ci::Build')
@build_running = builds.create!(id: 4, project_id: 123, status: 'running', type: 'Ci::Build')
create_legacy_trace(@build_success, 'This job is done')
create_legacy_trace(@build_failed, 'This job is done')
create_legacy_trace(@builds_canceled, 'This job is done')
create_legacy_trace(@build_running, 'This job is not done yet')
end
it 'correctly archive legacy traces', :sidekiq_might_not_need_inline do
expect(job_artifacts.count).to eq(0)
expect(File.exist?(legacy_trace_path(@build_success))).to be_truthy
expect(File.exist?(legacy_trace_path(@build_failed))).to be_truthy
expect(File.exist?(legacy_trace_path(@builds_canceled))).to be_truthy
expect(File.exist?(legacy_trace_path(@build_running))).to be_truthy
migrate!
expect(job_artifacts.count).to eq(3)
expect(File.exist?(legacy_trace_path(@build_success))).to be_falsy
expect(File.exist?(legacy_trace_path(@build_failed))).to be_falsy
expect(File.exist?(legacy_trace_path(@builds_canceled))).to be_falsy
expect(File.exist?(legacy_trace_path(@build_running))).to be_truthy
expect(File.exist?(archived_trace_path(job_artifacts.find_by(job_id: @build_success.id)))).to be_truthy
expect(File.exist?(archived_trace_path(job_artifacts.find_by(job_id: @build_failed.id)))).to be_truthy
expect(File.exist?(archived_trace_path(job_artifacts.find_by(job_id: @builds_canceled.id)))).to be_truthy
expect(job_artifacts.where(job_id: @build_running.id)).not_to be_exist
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20181105201455_steal_fill_store_upload.rb')
describe StealFillStoreUpload do
let(:uploads) { table(:uploads) }
describe '#up' do
it 'steals the FillStoreUpload background migration' do
expect(Gitlab::BackgroundMigration).to receive(:steal).with('FillStoreUpload').and_call_original
migrate!
end
it 'does not run migration if not needed' do
uploads.create(size: 100.kilobytes,
uploader: 'AvatarUploader',
path: 'uploads/-/system/avatar.jpg',
store: 1)
expect_any_instance_of(Gitlab::BackgroundMigration::FillStoreUpload).not_to receive(:perform)
migrate!
end
it 'ensures all rows are migrated' do
uploads.create(size: 100.kilobytes,
uploader: 'AvatarUploader',
path: 'uploads/-/system/avatar.jpg',
store: nil)
expect_any_instance_of(Gitlab::BackgroundMigration::FillStoreUpload).to receive(:perform).and_call_original
expect do
migrate!
end.to change { uploads.where(store: nil).count }.from(1).to(0)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20181219130552_update_project_import_visibility_level.rb')
describe UpdateProjectImportVisibilityLevel do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:project) { projects.find_by_name(name) }
before do
stub_const("#{described_class}::BATCH_SIZE", 1)
end
context 'private visibility level' do
let(:name) { 'private-public' }
it 'updates the project visibility' do
create_namespace(name, Gitlab::VisibilityLevel::PRIVATE)
create_project(name, Gitlab::VisibilityLevel::PUBLIC)
expect { migrate! }.to change { project.reload.visibility_level }.to(Gitlab::VisibilityLevel::PRIVATE)
end
end
context 'internal visibility level' do
let(:name) { 'internal-public' }
it 'updates the project visibility' do
create_namespace(name, Gitlab::VisibilityLevel::INTERNAL)
create_project(name, Gitlab::VisibilityLevel::PUBLIC)
expect { migrate! }.to change { project.reload.visibility_level }.to(Gitlab::VisibilityLevel::INTERNAL)
end
end
context 'public visibility level' do
let(:name) { 'public-public' }
it 'does not update the project visibility' do
create_namespace(name, Gitlab::VisibilityLevel::PUBLIC)
create_project(name, Gitlab::VisibilityLevel::PUBLIC)
expect { migrate! }.not_to change { project.reload.visibility_level }
end
end
context 'private project visibility level' do
let(:name) { 'public-private' }
it 'does not update the project visibility' do
create_namespace(name, Gitlab::VisibilityLevel::PUBLIC)
create_project(name, Gitlab::VisibilityLevel::PRIVATE)
expect { migrate! }.not_to change { project.reload.visibility_level }
end
end
context 'no namespace' do
let(:name) { 'no-namespace' }
it 'does not update the project visibility' do
create_namespace(name, Gitlab::VisibilityLevel::PRIVATE, type: nil)
create_project(name, Gitlab::VisibilityLevel::PUBLIC)
expect { migrate! }.not_to change { project.reload.visibility_level }
end
end
def create_namespace(name, visibility, options = {})
namespaces.create({
name: name,
path: name,
type: 'Group',
visibility_level: visibility
}.merge(options))
end
def create_project(name, visibility)
projects.create!(namespace_id: namespaces.find_by_name(name).id,
name: name,
path: name,
import_type: 'gitlab_project',
visibility_level: visibility)
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment