diff options
Diffstat (limited to 'db/post_migrate/20201005094331_migrate_compliance_framework_enum_to_database_framework_record.rb')
-rw-r--r-- | db/post_migrate/20201005094331_migrate_compliance_framework_enum_to_database_framework_record.rb | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/db/post_migrate/20201005094331_migrate_compliance_framework_enum_to_database_framework_record.rb b/db/post_migrate/20201005094331_migrate_compliance_framework_enum_to_database_framework_record.rb new file mode 100644 index 00000000000..5e261637d46 --- /dev/null +++ b/db/post_migrate/20201005094331_migrate_compliance_framework_enum_to_database_framework_record.rb @@ -0,0 +1,104 @@ +# frozen_string_literal: true + +class MigrateComplianceFrameworkEnumToDatabaseFrameworkRecord < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + class TmpComplianceFramework < ActiveRecord::Base + self.table_name = 'compliance_management_frameworks' + end + + class TmpProjectSettings < ActiveRecord::Base + # Maps data between ComplianceManagement::ComplianceFramework::FRAMEWORKS(enum) and new ComplianceManagement::Framework model + ENUM_FRAMEWORK_MAPPING = { + 1 => { + name: 'GDPR', + description: 'General Data Protection Regulation', + color: '#1aaa55' + }.freeze, + 2 => { + name: 'HIPAA', + description: 'Health Insurance Portability and Accountability Act', + color: '#1f75cb' + }.freeze, + 3 => { + name: 'PCI-DSS', + description: 'Payment Card Industry-Data Security Standard', + color: '#6666c4' + }.freeze, + 4 => { + name: 'SOC 2', + description: 'Service Organization Control 2', + color: '#dd2b0e' + }.freeze, + 5 => { + name: 'SOX', + description: 'Sarbanes-Oxley', + color: '#fc9403' + }.freeze + }.freeze + + self.table_name = 'project_compliance_framework_settings' + + include EachBatch + + def raw_compliance_framework + # Because we have an `enum` definition in ComplianceManagement::ComplianceFramework::ProjectSettings, this is very unlikely to fail. + ENUM_FRAMEWORK_MAPPING.fetch(framework).merge(namespace_id: root_namespace_id) + end + end + + def up + return unless Gitlab.ee? + + TmpComplianceFramework.reset_column_information + TmpProjectSettings.reset_column_information + + # This is our standard recursive namespace query, we use it to determine the root_namespace_id in the same query. + lateral_join = <<~SQL + INNER JOIN LATERAL ( + WITH RECURSIVE "base_and_ancestors" AS ( + ( + SELECT "ns".* FROM "namespaces" as ns WHERE "ns"."id" = projects.namespace_id + ) UNION + ( + SELECT "ns".* FROM "namespaces" as ns, "base_and_ancestors" WHERE "ns"."id" = "base_and_ancestors"."parent_id" + ) + ) SELECT "namespaces".* FROM "base_and_ancestors" AS "namespaces" WHERE parent_id IS NULL LIMIT 1) AS root_namespaces ON TRUE + SQL + + TmpProjectSettings.each_batch(of: 100) do |query| + project_settings_with_root_group = query + .select(:project_id, :framework, 'root_namespaces.id as root_namespace_id') + .from("(SELECT * FROM project_compliance_framework_settings) as project_compliance_framework_settings") # this is needed for the LATERAL JOIN + .joins("INNER JOIN projects on projects.id = project_compliance_framework_settings.project_id") + .joins(lateral_join) + .to_a + + ActiveRecord::Base.transaction do + raw_frameworks = project_settings_with_root_group.map(&:raw_compliance_framework) + TmpComplianceFramework.insert_all(raw_frameworks.uniq) # Create compliance frameworks per group + + unique_namespace_ids = project_settings_with_root_group.map(&:root_namespace_id).uniq + + framework_records = TmpComplianceFramework.select(:id, :namespace_id, :name).where(namespace_id: unique_namespace_ids) + + project_settings_with_root_group.each do |project_setting| + framework = framework_records.find do |record| + # name is unique within a group + record.name == project_setting.raw_compliance_framework[:name] && record[:namespace_id] == project_setting.raw_compliance_framework[:namespace_id] + end + + project_setting.update_column(:framework_id, framework.id) + end + end + end + end + + def down + # data migration, no-op + end +end |