diff --git a/db/docs/jira_connect_installations.yml b/db/docs/jira_connect_installations.yml index f5c4bd7d8a2667bb48918edc2c983b4a3663d4ab..a245b15ad6acdc5aa756c104299c4d29ce2f26e7 100644 --- a/db/docs/jira_connect_installations.yml +++ b/db/docs/jira_connect_installations.yml @@ -8,5 +8,6 @@ description: GitLab for Jira Cloud app installation data, formerly Jira Connect introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/9593 milestone: '11.9' gitlab_schema: gitlab_main_org -sharding_key_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/560334 table_size: small +sharding_key: + organization_id: organizations diff --git a/db/post_migrate/20250924101346_backfill_jira_connect_installations_organization_id.rb b/db/post_migrate/20250924101346_backfill_jira_connect_installations_organization_id.rb new file mode 100644 index 0000000000000000000000000000000000000000..5afaa86747f4de5d498c94bb30f6473073c46cd0 --- /dev/null +++ b/db/post_migrate/20250924101346_backfill_jira_connect_installations_organization_id.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class BackfillJiraConnectInstallationsOrganizationId < Gitlab::Database::Migration[2.3] + milestone '18.5' + disable_ddl_transaction! + restrict_gitlab_migration gitlab_schema: :gitlab_main_org + + BATCH_SIZE = 1000 + DEFAULT_ORGANIZATION_ID = 1 + + def up + define_batchable_model('jira_connect_installations') + .where(organization_id: nil) + .each_batch(of: BATCH_SIZE) do |batch| + batch.update_all(organization_id: DEFAULT_ORGANIZATION_ID) + end + end + + def down + # no-op + end +end diff --git a/db/post_migrate/20250924103022_validate_jira_connect_installations_not_null_constraint_on_organization_id.rb b/db/post_migrate/20250924103022_validate_jira_connect_installations_not_null_constraint_on_organization_id.rb new file mode 100644 index 0000000000000000000000000000000000000000..4f09dc8dbd3761d7b14c855f86a8e46920ef894a --- /dev/null +++ b/db/post_migrate/20250924103022_validate_jira_connect_installations_not_null_constraint_on_organization_id.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class ValidateJiraConnectInstallationsNotNullConstraintOnOrganizationId < Gitlab::Database::Migration[2.3] + milestone '18.5' + disable_ddl_transaction! + + TABLE_NAME = :jira_connect_installations + COLUMN_NAME = :organization_id + CONSTRAINT_NAME = :check_dc0d039821 + + def up + validate_not_null_constraint :jira_connect_installations, :organization_id + end + + def down + # no-op + end +end diff --git a/db/schema_migrations/20250924101346 b/db/schema_migrations/20250924101346 new file mode 100644 index 0000000000000000000000000000000000000000..34c444368bd3eab5e999565b8dcb5558d1eb86ec --- /dev/null +++ b/db/schema_migrations/20250924101346 @@ -0,0 +1 @@ +1ecd4544179e900e28c6c9b46db385709ffc7ab345971e762ed9af0298117454 \ No newline at end of file diff --git a/db/schema_migrations/20250924103022 b/db/schema_migrations/20250924103022 new file mode 100644 index 0000000000000000000000000000000000000000..c8250baaed23238248e1ae10b8b43995a87ba873 --- /dev/null +++ b/db/schema_migrations/20250924103022 @@ -0,0 +1 @@ +fca38d0a69134a7cf8222bb4e2723c9630f29fd5612b43228580bb0eb61528a5 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 73340652aedb470b4445c2974b78903e3a5a1499..a3a5d76f2b64fda2daa9cf666f393e3874696b48 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -18565,7 +18565,8 @@ CREATE TABLE jira_connect_installations ( base_url character varying, instance_url text, organization_id bigint, - CONSTRAINT check_4c6abed669 CHECK ((char_length(instance_url) <= 255)) + CONSTRAINT check_4c6abed669 CHECK ((char_length(instance_url) <= 255)), + CONSTRAINT check_dc0d039821 CHECK ((organization_id IS NOT NULL)) ); CREATE SEQUENCE jira_connect_installations_id_seq @@ -32836,9 +32837,6 @@ ALTER TABLE work_item_custom_statuses ALTER TABLE packages_packages ADD CONSTRAINT check_d6301aedeb CHECK ((char_length(status_message) <= 255)) NOT VALID; -ALTER TABLE jira_connect_installations - ADD CONSTRAINT check_dc0d039821 CHECK ((organization_id IS NOT NULL)) NOT VALID; - ALTER TABLE sprints ADD CONSTRAINT check_df3816aed7 CHECK ((due_date IS NOT NULL)) NOT VALID; diff --git a/spec/migrations/backfill_jira_connect_installations_organization_id_spec.rb b/spec/migrations/backfill_jira_connect_installations_organization_id_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..40cf41e9c5f6443dc77370a9cf7a08012b62ef51 --- /dev/null +++ b/spec/migrations/backfill_jira_connect_installations_organization_id_spec.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe BackfillJiraConnectInstallationsOrganizationId, feature_category: :integrations do + let(:organizations) { table(:organizations) } + let(:installations) { table(:jira_connect_installations) } + let(:organization) { organizations.create!(id: 1, name: 'Default', path: 'default') } + + let(:installation_without_organization) do + installations.create!( + client_key: 'foo', + base_url: 'https://example.com', + instance_url: 'https://example.com' + ) + end + + let(:another_installation_without_organization) do + installations.create!( + client_key: 'bar', + base_url: 'https://example.com', + instance_url: 'https://example.com' + ) + end + + let(:installation_with_organization) do + installations.create!( + client_key: 'baz', + base_url: 'https://example.com', + instance_url: 'https://example.com', + organization_id: organization.id + ) + end + + before do + ApplicationRecord + .connection + .execute('ALTER TABLE jira_connect_installations DROP CONSTRAINT IF EXISTS check_dc0d039821;') + end + + after do + ApplicationRecord + .connection + .execute( + 'ALTER TABLE jira_connect_installations ADD CONSTRAINT check_dc0d039821 ' \ + 'CHECK ((organization_id IS NOT NULL)) NOT VALID;' + ) + end + + describe "#up" do + it 'sets organization_id sharding key for records that do not have it' do + expect(installation_without_organization.organization_id).to be_nil + expect(another_installation_without_organization.organization_id).to be_nil + expect(installation_with_organization.organization_id).to eq(organization.id) + + migrate! + + expect(installation_without_organization.reload.organization_id).to eq(organization.id) + expect(another_installation_without_organization.reload.organization_id).to eq(organization.id) + expect(installation_with_organization.reload.organization_id).to eq(organization.id) + end + end +end