diff --git a/db/post_migrate/20240923090549_fix_inconsistent_organization_id.rb b/db/post_migrate/20240923090549_fix_inconsistent_organization_id.rb new file mode 100644 index 0000000000000000000000000000000000000000..4399d24324f2226fa3a8c2884331e087ba0f3461 --- /dev/null +++ b/db/post_migrate/20240923090549_fix_inconsistent_organization_id.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +class FixInconsistentOrganizationId < Gitlab::Database::Migration[2.2] + milestone '17.5' + + restrict_gitlab_migration gitlab_schema: :gitlab_main_cell + + def process_hierarchy(namespace) + organization_id = namespace['organization_id'] + parent_id = namespace['id'] + + execute(" + UPDATE namespaces + SET organization_id = #{organization_id} + WHERE parent_id = #{parent_id} AND organization_id != #{organization_id} + ") + execute(" + UPDATE projects + SET organization_id = #{organization_id} + WHERE namespace_id = #{parent_id} + AND organization_id != #{organization_id} + ") + + query = "SELECT id, organization_id, type FROM namespaces WHERE parent_id = #{parent_id}" + select_all(query).each do |child| + process_hierarchy(child) + end + end + + def up + query = "SELECT id, organization_id, parent_id FROM namespaces WHERE organization_id > 1 AND parent_id IS NULL" + select_all(query).each do |namespace| + process_hierarchy(namespace) + end + end + + def down + # no-op + end +end diff --git a/db/schema_migrations/20240923090549 b/db/schema_migrations/20240923090549 new file mode 100644 index 0000000000000000000000000000000000000000..de4f319cea1310904c26e6c5d78d31f50986559b --- /dev/null +++ b/db/schema_migrations/20240923090549 @@ -0,0 +1 @@ +35442f00892a8eeb83e52702c57ee1efa083667fb64487c48594b4b92ae3442a \ No newline at end of file diff --git a/spec/migrations/db/post_migrate/20240923090549_fix_inconsistent_organization_id_spec.rb b/spec/migrations/db/post_migrate/20240923090549_fix_inconsistent_organization_id_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..9659b27fac96a826d927d02d0009f89530201736 --- /dev/null +++ b/spec/migrations/db/post_migrate/20240923090549_fix_inconsistent_organization_id_spec.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe FixInconsistentOrganizationId, migration: :gitlab_main, feature_category: :cell do + # Inconsistent data: + let!(:parent_namespace_1) do + table(:namespaces).create!(type: 'Group', name: 'parent', path: 'parent', organization_id: 2) + end + + let!(:namespace_1) do + table(:namespaces).create!(type: 'Group', name: 'child', path: 'child', parent_id: parent_namespace_1.id, + organization_id: 3) + end + + let!(:namespace_2) do + table(:namespaces).create!(type: 'Group', name: 'parent group of project', path: 'parent-group-of-project', + organization_id: 4) + end + + let!(:project_namespace_1) do + table(:namespaces).create!(type: 'Project', name: 'project namespace', path: 'project_namespace', + organization_id: 5) + end + + let!(:project_1) do + table(:projects).create!(namespace_id: namespace_2.id, + project_namespace_id: project_namespace_1.id, organization_id: 5) + end + + let!(:namespace_2_1) do + table(:namespaces).create!(parent_id: namespace_2.id, type: 'Group', name: 'sub-group of project', + path: 'sub-group-of-project', organization_id: 6) + end + + let!(:project_namespace_2_1) do + table(:namespaces).create!(type: 'Project', name: 'project namespace 2 1', path: 'project_namespace-2-1', + organization_id: 7) + end + + let!(:project_2_1) do + table(:projects).create!(namespace_id: namespace_2_1.id, + project_namespace_id: project_namespace_2_1.id, organization_id: 7) + end + + # Valid data + let!(:parent_namespace_2) do + table(:namespaces).create!(type: 'Group', name: 'parent 2', path: 'parent2', organization_id: 8) + end + + let!(:namespace_3) do + table(:namespaces).create!(type: 'Group', name: 'child 2', path: 'child2', parent_id: parent_namespace_2.id, + organization_id: 8) + end + + let!(:namespace_4) do + table(:namespaces).create!(type: 'Group', name: 'parent of project 2', path: 'parent-of-project-2 ', + organization_id: 9) + end + + let!(:project_namespace_2) do + table(:namespaces).create!(type: 'Project', name: 'project namespace 2', path: 'project_namespace_2', + organization_id: 9) + end + + let!(:project_2) do + table(:projects).create!(namespace_id: namespace_4.id, + project_namespace_id: project_namespace_2.id, organization_id: 9) + end + + describe '#up' do + it 'sets organization_id to parent organization if organization_ids do not match' do + migrate! + + expect(namespace_1.reload.organization_id).to eq(2) + expect(project_1.reload.organization_id).to eq(4) + expect(project_2_1.reload.organization_id).to eq(4) + + expect(namespace_3.reload.organization_id).to eq(8) + expect(project_2.reload.organization_id).to eq(9) + end + end +end