diff --git a/app/models/organizations/organization.rb b/app/models/organizations/organization.rb index 489fd6e0da7c19871df14f43689ab3bb1fa1518d..893b08d7872a9b89be860f0b7af54c1ccd446724 100644 --- a/app/models/organizations/organization.rb +++ b/app/models/organizations/organization.rb @@ -10,6 +10,7 @@ class Organization < ApplicationRecord has_many :namespaces has_many :groups + has_many :projects has_one :settings, class_name: "OrganizationSetting" diff --git a/app/models/project.rb b/app/models/project.rb index cb1468a8d0c76277908b458466a46a94f452dcaf..4e69cdeff13326ccde18ed7a849a45e255e3d13e 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -165,6 +165,7 @@ class Project < ApplicationRecord # Relations belongs_to :pool_repository belongs_to :creator, class_name: 'User' + belongs_to :organization, class_name: 'Organizations::Organization' belongs_to :group, -> { where(type: Group.sti_name) }, foreign_key: 'namespace_id' belongs_to :namespace # Sync deletion via DB Trigger to ensure we do not have diff --git a/config/gitlab_loose_foreign_keys.yml b/config/gitlab_loose_foreign_keys.yml index 6bd6f99a1344979567174bf7080c3b3d9ca366f7..c12a2dfda7bf5b32c17a2b75445767500c7fea13 100644 --- a/config/gitlab_loose_foreign_keys.yml +++ b/config/gitlab_loose_foreign_keys.yml @@ -287,6 +287,10 @@ pages_deployments: - table: p_ci_builds column: ci_build_id on_delete: async_nullify +projects: + - table: organizations + column: organization_id + on_delete: async_nullify requirements_management_test_reports: - table: ci_builds column: build_id diff --git a/db/migrate/20230822064649_add_organization_id_to_project.rb b/db/migrate/20230822064649_add_organization_id_to_project.rb new file mode 100644 index 0000000000000000000000000000000000000000..9607f711981b3302178ee9140d620fdde70667d5 --- /dev/null +++ b/db/migrate/20230822064649_add_organization_id_to_project.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class AddOrganizationIdToProject < Gitlab::Database::Migration[2.1] + DEFAULT_ORGANIZATION_ID = 1 + + enable_lock_retries! + + def change + add_column :projects, :organization_id, :bigint, default: DEFAULT_ORGANIZATION_ID, null: true # rubocop:disable Migration/AddColumnsToWideTables + end +end diff --git a/db/post_migrate/20230822064841_prepare_index_for_org_id_on_projects.rb b/db/post_migrate/20230822064841_prepare_index_for_org_id_on_projects.rb new file mode 100644 index 0000000000000000000000000000000000000000..1f822a440a40677bb71e272856e5b4cb41484e97 --- /dev/null +++ b/db/post_migrate/20230822064841_prepare_index_for_org_id_on_projects.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class PrepareIndexForOrgIdOnProjects < Gitlab::Database::Migration[2.1] + INDEX_NAME = 'index_projects_on_organization_id' + + def up + prepare_async_index :projects, :organization_id, name: INDEX_NAME + end + + def down + unprepare_async_index :projects, :organization_id, name: INDEX_NAME + end +end diff --git a/db/schema_migrations/20230822064649 b/db/schema_migrations/20230822064649 new file mode 100644 index 0000000000000000000000000000000000000000..449dd984431776a00363c982875ae221ff5ef7a0 --- /dev/null +++ b/db/schema_migrations/20230822064649 @@ -0,0 +1 @@ +b892940441125e854d08e24906e4b6287f8359b4ad374be5b141b43cfdcc1354 \ No newline at end of file diff --git a/db/schema_migrations/20230822064841 b/db/schema_migrations/20230822064841 new file mode 100644 index 0000000000000000000000000000000000000000..2922af9c57334991bf8adf1392e5cd247e5f13f2 --- /dev/null +++ b/db/schema_migrations/20230822064841 @@ -0,0 +1 @@ +e025eb64ab8b9ece1a18c845024db272a1859757734948609c134f6dfee93884 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 9c1fc3b5500c3aa5b0f8b844d4d85427b4205536..805745d44709ccabbd0dc64ecb58e74a8073c7e4 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -21836,7 +21836,8 @@ CREATE TABLE projects ( autoclose_referenced_issues boolean, suggestion_commit_message character varying(255), project_namespace_id bigint, - hidden boolean DEFAULT false NOT NULL + hidden boolean DEFAULT false NOT NULL, + organization_id bigint DEFAULT 1 ); CREATE SEQUENCE projects_id_seq diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb index 04a83a1f6ab7d4020d9587b0f638804a9563580e..fea3c5b77a130174384eb8dabf06db7fd40eca97 100644 --- a/spec/db/schema_spec.rb +++ b/spec/db/schema_spec.rb @@ -15,7 +15,8 @@ search_namespace_index_assignments: [%w[search_index_id index_type]], slack_integrations_scopes: [%w[slack_api_scope_id]], notes: %w[namespace_id], # this index is added in an async manner, hence it needs to be ignored in the first phase. - vulnerabilities: [%w[finding_id]] # index will be created in https://gitlab.com/gitlab-org/gitlab/-/issues/423541 + vulnerabilities: [%w[finding_id]], # index will be created in https://gitlab.com/gitlab-org/gitlab/-/issues/423541 + projects: %w[organization_id] # this index is added in an async manner, hence it needs to be ignored in the first phase. }.with_indifferent_access.freeze TABLE_PARTITIONS = %w[ci_builds_metadata].freeze diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 99e871e5255693f6b2725c25076cac14109a2d7a..de3f28a5b90641d311be5b101f4f4b25b841d2f4 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -823,6 +823,7 @@ project: - project_state - security_policy_bots - target_branch_rules +- organization award_emoji: - awardable - user diff --git a/spec/models/organizations/organization_spec.rb b/spec/models/organizations/organization_spec.rb index 7838fc1c5a4fceb4a6a1dc0fed2f635f22575d67..2f9f04fd3e64546fa35c23c89528bb7e0794a3e2 100644 --- a/spec/models/organizations/organization_spec.rb +++ b/spec/models/organizations/organization_spec.rb @@ -11,6 +11,7 @@ it { is_expected.to have_many :groups } it { is_expected.to have_many(:users).through(:organization_users).inverse_of(:organizations) } it { is_expected.to have_many(:organization_users).inverse_of(:organization) } + it { is_expected.to have_many :projects } end describe 'validations' do diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 657c7d5dee8bbd1fa518aaae82d4bdc039b96fd5..5312ca0ef7024b805ada755f6a62c006f16cb2ac 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -17,6 +17,7 @@ it_behaves_like 'ensures runners_token is prefixed', :project describe 'associations' do + it { is_expected.to belong_to(:organization) } it { is_expected.to belong_to(:group) } it { is_expected.to belong_to(:namespace) } it { is_expected.to belong_to(:project_namespace).class_name('Namespaces::ProjectNamespace').with_foreign_key('project_namespace_id').inverse_of(:project) } @@ -9189,6 +9190,13 @@ def create_hook end end + context 'with loose foreign key on organization_id' do + it_behaves_like 'cleanup by a loose foreign key' do + let_it_be(:parent) { create(:organization) } + let_it_be(:model) { create(:project, organization: parent) } + end + end + private def finish_job(export_job) diff --git a/spec/requests/api/project_attributes.yml b/spec/requests/api/project_attributes.yml index 1055c1a6968620166345a7bf66e4b1d24ccab570..677cb243a7cab02f383a0fd89f0d9ed85b1d98c1 100644 --- a/spec/requests/api/project_attributes.yml +++ b/spec/requests/api/project_attributes.yml @@ -44,6 +44,7 @@ itself: # project - storage_version - topic_list - verification_checksum + - organization_id remapped_attributes: avatar: avatar_url build_allow_git_fetch: build_git_strategy