diff --git a/db/docs/merge_requests_approval_rules_groups.yml b/db/docs/merge_requests_approval_rules_groups.yml new file mode 100644 index 0000000000000000000000000000000000000000..b8a52e7811f91184d6a280ccaadb6a0e642797d6 --- /dev/null +++ b/db/docs/merge_requests_approval_rules_groups.yml @@ -0,0 +1,12 @@ +--- +table_name: merge_requests_approval_rules_groups +classes: + - MergeRequests::ApprovalRulesGroup +feature_categories: + - code_review_workflow +description: Stores relationship between approval rules v2 and groups +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/179861 +milestone: '17.9' +gitlab_schema: gitlab_main_cell +sharding_key: + group_id: namespaces diff --git a/db/docs/merge_requests_approval_rules_merge_requests.yml b/db/docs/merge_requests_approval_rules_merge_requests.yml new file mode 100644 index 0000000000000000000000000000000000000000..ec7130a8a9ada913a5e403067c16c7cfcdf8bbfc --- /dev/null +++ b/db/docs/merge_requests_approval_rules_merge_requests.yml @@ -0,0 +1,12 @@ +--- +table_name: merge_requests_approval_rules_merge_requests +classes: + - MergeRequests::ApprovalRulesMergeRequest +feature_categories: + - code_review_workflow +description: Stores relationship between approval rules v2 and merge requests +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/179861 +milestone: '17.9' +gitlab_schema: gitlab_main_cell +sharding_key: + project_id: projects diff --git a/db/docs/merge_requests_approval_rules_projects.yml b/db/docs/merge_requests_approval_rules_projects.yml new file mode 100644 index 0000000000000000000000000000000000000000..bbf00b7348c476036452530b3dbb42caed46d7c9 --- /dev/null +++ b/db/docs/merge_requests_approval_rules_projects.yml @@ -0,0 +1,12 @@ +--- +table_name: merge_requests_approval_rules_projects +classes: + - MergeRequests::ApprovalRulesProject +feature_categories: + - code_review_workflow +description: Stores relationship between approval rules v2 and projects +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/179861 +milestone: '17.9' +gitlab_schema: gitlab_main_cell +sharding_key: + project_id: projects diff --git a/db/migrate/20250123151708_create_merge_requests_approval_rules_groups.rb b/db/migrate/20250123151708_create_merge_requests_approval_rules_groups.rb new file mode 100644 index 0000000000000000000000000000000000000000..e873138551f8eabea95ad7430bfa7a918da54ba2 --- /dev/null +++ b/db/migrate/20250123151708_create_merge_requests_approval_rules_groups.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class CreateMergeRequestsApprovalRulesGroups < Gitlab::Database::Migration[2.2] + milestone '17.9' + + def change + create_table :merge_requests_approval_rules_groups do |t| # -- Migration/EnsureFactoryForTable false positive + t.bigint :approval_rule_id, null: false + t.bigint :group_id, null: false + t.index :group_id + t.timestamps_with_timezone null: false + end + + add_index( + :merge_requests_approval_rules_groups, + %i[approval_rule_id group_id], + unique: true, + name: 'index_mrs_ars_groups_on_ar_id_and_group_id' + ) + end +end diff --git a/db/migrate/20250123151726_create_merge_requests_approval_rules_merge_requests.rb b/db/migrate/20250123151726_create_merge_requests_approval_rules_merge_requests.rb new file mode 100644 index 0000000000000000000000000000000000000000..a67fe56a775879b3a8d595e2b20a055bb91ec7bd --- /dev/null +++ b/db/migrate/20250123151726_create_merge_requests_approval_rules_merge_requests.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +class CreateMergeRequestsApprovalRulesMergeRequests < Gitlab::Database::Migration[2.2] + milestone '17.9' + + def change + create_table :merge_requests_approval_rules_merge_requests do |t| # Migration/EnsureFactoryForTable false positive + t.bigint :approval_rule_id, null: false + t.bigint :merge_request_id, null: false + t.bigint :project_id, null: false + t.index :merge_request_id, name: 'index_mrs_approval_rules_mrs_on_mr_id' + t.index :project_id, name: 'index_mrs_approval_rules_mrs_on_project_id' + t.timestamps_with_timezone null: false + end + + add_index( + :merge_requests_approval_rules_merge_requests, + %i[approval_rule_id merge_request_id], + unique: true, + name: 'index_mrs_ars_mrs_on_ar_id_and_mr_id' + ) + end +end diff --git a/db/migrate/20250123151745_create_merge_requests_approval_rules_projects.rb b/db/migrate/20250123151745_create_merge_requests_approval_rules_projects.rb new file mode 100644 index 0000000000000000000000000000000000000000..b87ec1ace48ae046bce324ed2b3c16789093ed3a --- /dev/null +++ b/db/migrate/20250123151745_create_merge_requests_approval_rules_projects.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class CreateMergeRequestsApprovalRulesProjects < Gitlab::Database::Migration[2.2] + milestone '17.9' + + def change + create_table :merge_requests_approval_rules_projects do |t| # -- Migration/EnsureFactoryForTable false positive + t.bigint :approval_rule_id, null: false + t.bigint :project_id, null: false + t.index :project_id, name: 'index_mrs_approval_rules_projects_on_project_id' + t.timestamps_with_timezone null: false + end + + add_index( + :merge_requests_approval_rules_projects, + %i[approval_rule_id project_id], + unique: true, + name: 'index_mrs_ars_projects_on_ar_id_and_project_id' + ) + end +end diff --git a/db/migrate/20250206143903_add_merge_requests_approval_rules_groups_approval_rule_fk.rb b/db/migrate/20250206143903_add_merge_requests_approval_rules_groups_approval_rule_fk.rb new file mode 100644 index 0000000000000000000000000000000000000000..205b9a21c4596a6ecb3c253f23c916d4b376046a --- /dev/null +++ b/db/migrate/20250206143903_add_merge_requests_approval_rules_groups_approval_rule_fk.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddMergeRequestsApprovalRulesGroupsApprovalRuleFk < Gitlab::Database::Migration[2.2] + milestone '17.9' + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :merge_requests_approval_rules_groups, :merge_requests_approval_rules, + column: :approval_rule_id, on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :merge_requests_approval_rules_groups, column: :approval_rule_id + end + end +end diff --git a/db/migrate/20250206143924_add_merge_requests_approval_rules_groups_group_fk.rb b/db/migrate/20250206143924_add_merge_requests_approval_rules_groups_group_fk.rb new file mode 100644 index 0000000000000000000000000000000000000000..35db8abf4702f8b82f2bb624819b7038fe8c7598 --- /dev/null +++ b/db/migrate/20250206143924_add_merge_requests_approval_rules_groups_group_fk.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddMergeRequestsApprovalRulesGroupsGroupFk < Gitlab::Database::Migration[2.2] + milestone '17.9' + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :merge_requests_approval_rules_groups, :namespaces, column: :group_id, + on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :merge_requests_approval_rules_groups, column: :group_id + end + end +end diff --git a/db/migrate/20250206144004_add_merge_requests_approval_rules_projects_approval_rule_fk.rb b/db/migrate/20250206144004_add_merge_requests_approval_rules_projects_approval_rule_fk.rb new file mode 100644 index 0000000000000000000000000000000000000000..740ca025d72897fe7dc8097f3381d1441bada689 --- /dev/null +++ b/db/migrate/20250206144004_add_merge_requests_approval_rules_projects_approval_rule_fk.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddMergeRequestsApprovalRulesProjectsApprovalRuleFk < Gitlab::Database::Migration[2.2] + milestone '17.9' + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :merge_requests_approval_rules_projects, :merge_requests_approval_rules, + column: :approval_rule_id, on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :merge_requests_approval_rules_projects, column: :approval_rule_id + end + end +end diff --git a/db/migrate/20250206144027_add_merge_requests_approval_rules_projects_project_fk.rb b/db/migrate/20250206144027_add_merge_requests_approval_rules_projects_project_fk.rb new file mode 100644 index 0000000000000000000000000000000000000000..70dea81b3e8c42974f1dff12eef6c5a6b3f8c1ab --- /dev/null +++ b/db/migrate/20250206144027_add_merge_requests_approval_rules_projects_project_fk.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddMergeRequestsApprovalRulesProjectsProjectFk < Gitlab::Database::Migration[2.2] + milestone '17.9' + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :merge_requests_approval_rules_projects, :projects, column: :project_id, + on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :merge_requests_approval_rules_projects, column: :project_id + end + end +end diff --git a/db/migrate/20250206144049_add_merge_requests_approval_rules_mrs_approval_rule_fk.rb b/db/migrate/20250206144049_add_merge_requests_approval_rules_mrs_approval_rule_fk.rb new file mode 100644 index 0000000000000000000000000000000000000000..eb877d49cb85a34471c85be909bb26f069825769 --- /dev/null +++ b/db/migrate/20250206144049_add_merge_requests_approval_rules_mrs_approval_rule_fk.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddMergeRequestsApprovalRulesMrsApprovalRuleFk < Gitlab::Database::Migration[2.2] + milestone '17.9' + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :merge_requests_approval_rules_merge_requests, :merge_requests_approval_rules, + column: :approval_rule_id, on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :merge_requests_approval_rules_merge_requests, column: :approval_rule_id + end + end +end diff --git a/db/migrate/20250206144110_add_merge_requests_approval_rules_mrs_mr_fk.rb b/db/migrate/20250206144110_add_merge_requests_approval_rules_mrs_mr_fk.rb new file mode 100644 index 0000000000000000000000000000000000000000..222f73bdce3d2960f3bfe23d09c7929fbc7508b0 --- /dev/null +++ b/db/migrate/20250206144110_add_merge_requests_approval_rules_mrs_mr_fk.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class AddMergeRequestsApprovalRulesMrsMrFk < Gitlab::Database::Migration[2.2] + milestone '17.9' + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :merge_requests_approval_rules_merge_requests, :merge_requests, + column: :merge_request_id, + on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :merge_requests_approval_rules_merge_requests, column: :merge_request_id + end + end +end diff --git a/db/migrate/20250211141110_add_merge_requests_approval_rules_mrs_project_fk.rb b/db/migrate/20250211141110_add_merge_requests_approval_rules_mrs_project_fk.rb new file mode 100644 index 0000000000000000000000000000000000000000..430ff31f2442436513d60fb9410a9061764c319e --- /dev/null +++ b/db/migrate/20250211141110_add_merge_requests_approval_rules_mrs_project_fk.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class AddMergeRequestsApprovalRulesMrsProjectFk < Gitlab::Database::Migration[2.2] + milestone '17.9' + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :merge_requests_approval_rules_merge_requests, :projects, + column: :project_id, + on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :merge_requests_approval_rules_merge_requests, column: :project_id + end + end +end diff --git a/db/schema_migrations/20250123151708 b/db/schema_migrations/20250123151708 new file mode 100644 index 0000000000000000000000000000000000000000..87a1ad0236b30a48f7ae9437fdd1c5b81800bad7 --- /dev/null +++ b/db/schema_migrations/20250123151708 @@ -0,0 +1 @@ +620def37e032e7fa463c4f1ecff0aacde33a5b9bd7a56c2f6ead418b3f4ce828 \ No newline at end of file diff --git a/db/schema_migrations/20250123151726 b/db/schema_migrations/20250123151726 new file mode 100644 index 0000000000000000000000000000000000000000..0d54c5d1bc08d4510c261243d1bf7eb7825ebc72 --- /dev/null +++ b/db/schema_migrations/20250123151726 @@ -0,0 +1 @@ +e5a26f1a31603cf3ac570824874afbeac3bb970ca079bdaaebbf9cbe13155230 \ No newline at end of file diff --git a/db/schema_migrations/20250123151745 b/db/schema_migrations/20250123151745 new file mode 100644 index 0000000000000000000000000000000000000000..2ce7ec05eaa1d5fdfedc100a7d31582067a9e7b6 --- /dev/null +++ b/db/schema_migrations/20250123151745 @@ -0,0 +1 @@ +d6fc925f97583a4509894202b2e529ae64138f2cceef76e0d0c4dcaafe70f45a \ No newline at end of file diff --git a/db/schema_migrations/20250206143903 b/db/schema_migrations/20250206143903 new file mode 100644 index 0000000000000000000000000000000000000000..fc7b302235973f82dddf3e57fd27ff1e27fc1a98 --- /dev/null +++ b/db/schema_migrations/20250206143903 @@ -0,0 +1 @@ +56101662487483f6866c2c1f2cd0ee66d1fa12d08c0da12bd550d389e37f6bf7 \ No newline at end of file diff --git a/db/schema_migrations/20250206143924 b/db/schema_migrations/20250206143924 new file mode 100644 index 0000000000000000000000000000000000000000..724ba0d42f826bc59ab23e8e2768b555b0f8bc77 --- /dev/null +++ b/db/schema_migrations/20250206143924 @@ -0,0 +1 @@ +4b740e775e43ed2143b7060b5e5e1730aeb7309cc83e4d76a5316cc84e80893b \ No newline at end of file diff --git a/db/schema_migrations/20250206144004 b/db/schema_migrations/20250206144004 new file mode 100644 index 0000000000000000000000000000000000000000..8ccb8a71b94f95903a7ac4228c43438e80a3b729 --- /dev/null +++ b/db/schema_migrations/20250206144004 @@ -0,0 +1 @@ +31f9cc1659cd680b16a742eddeb361c4eb059388b1af0136d0d5a648a6fb8cca \ No newline at end of file diff --git a/db/schema_migrations/20250206144027 b/db/schema_migrations/20250206144027 new file mode 100644 index 0000000000000000000000000000000000000000..99653db12ffd2c6ca3720d127088b29ab21df40b --- /dev/null +++ b/db/schema_migrations/20250206144027 @@ -0,0 +1 @@ +08d74afd22511618546821c8cc53473ec3a9f6ec4be3c80a20086e1a2e71da37 \ No newline at end of file diff --git a/db/schema_migrations/20250206144049 b/db/schema_migrations/20250206144049 new file mode 100644 index 0000000000000000000000000000000000000000..3cbc804941579b641604ec52f8e3456ac3c1f795 --- /dev/null +++ b/db/schema_migrations/20250206144049 @@ -0,0 +1 @@ +1611b7751ef4fa7476f9ffeab5263f9e0e85f89ab21e3028b2d5245dd38f31db \ No newline at end of file diff --git a/db/schema_migrations/20250206144110 b/db/schema_migrations/20250206144110 new file mode 100644 index 0000000000000000000000000000000000000000..49eba2314f5c5a4058752b05933b77a5e4b549ea --- /dev/null +++ b/db/schema_migrations/20250206144110 @@ -0,0 +1 @@ +cd304e944ce13f05dc95d6c74a604bca579a04b08d9abf0fd143ae03c00f1390 \ No newline at end of file diff --git a/db/schema_migrations/20250211141110 b/db/schema_migrations/20250211141110 new file mode 100644 index 0000000000000000000000000000000000000000..c1b01af91f496c4f9f956daac558f79e619d617c --- /dev/null +++ b/db/schema_migrations/20250211141110 @@ -0,0 +1 @@ +69fd6b83d6c739006134ada0d7019b9c04ea5d6ae34b3dc4906546a2c3070110 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index a8694caae232ca4c3943a4731b46b92d84c7bec7..fc3c1bee2f851114659eb16c8142a9386774978a 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -16330,6 +16330,23 @@ CREATE TABLE merge_requests_approval_rules ( CONSTRAINT check_c7c36145b7 CHECK ((char_length(name) <= 255)) ); +CREATE TABLE merge_requests_approval_rules_groups ( + id bigint NOT NULL, + approval_rule_id bigint NOT NULL, + group_id bigint NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL +); + +CREATE SEQUENCE merge_requests_approval_rules_groups_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE merge_requests_approval_rules_groups_id_seq OWNED BY merge_requests_approval_rules_groups.id; + CREATE SEQUENCE merge_requests_approval_rules_id_seq START WITH 1 INCREMENT BY 1 @@ -16339,6 +16356,41 @@ CREATE SEQUENCE merge_requests_approval_rules_id_seq ALTER SEQUENCE merge_requests_approval_rules_id_seq OWNED BY merge_requests_approval_rules.id; +CREATE TABLE merge_requests_approval_rules_merge_requests ( + id bigint NOT NULL, + approval_rule_id bigint NOT NULL, + merge_request_id bigint NOT NULL, + project_id bigint NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL +); + +CREATE SEQUENCE merge_requests_approval_rules_merge_requests_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE merge_requests_approval_rules_merge_requests_id_seq OWNED BY merge_requests_approval_rules_merge_requests.id; + +CREATE TABLE merge_requests_approval_rules_projects ( + id bigint NOT NULL, + approval_rule_id bigint NOT NULL, + project_id bigint NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL +); + +CREATE SEQUENCE merge_requests_approval_rules_projects_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE merge_requests_approval_rules_projects_id_seq OWNED BY merge_requests_approval_rules_projects.id; + CREATE TABLE merge_requests_closing_issues ( id bigint NOT NULL, merge_request_id bigint NOT NULL, @@ -25589,6 +25641,12 @@ ALTER TABLE ONLY merge_requests ALTER COLUMN id SET DEFAULT nextval('merge_reque ALTER TABLE ONLY merge_requests_approval_rules ALTER COLUMN id SET DEFAULT nextval('merge_requests_approval_rules_id_seq'::regclass); +ALTER TABLE ONLY merge_requests_approval_rules_groups ALTER COLUMN id SET DEFAULT nextval('merge_requests_approval_rules_groups_id_seq'::regclass); + +ALTER TABLE ONLY merge_requests_approval_rules_merge_requests ALTER COLUMN id SET DEFAULT nextval('merge_requests_approval_rules_merge_requests_id_seq'::regclass); + +ALTER TABLE ONLY merge_requests_approval_rules_projects ALTER COLUMN id SET DEFAULT nextval('merge_requests_approval_rules_projects_id_seq'::regclass); + ALTER TABLE ONLY merge_requests_closing_issues ALTER COLUMN id SET DEFAULT nextval('merge_requests_closing_issues_id_seq'::regclass); ALTER TABLE ONLY merge_requests_compliance_violations ALTER COLUMN id SET DEFAULT nextval('merge_requests_compliance_violations_id_seq'::regclass); @@ -28150,9 +28208,18 @@ ALTER TABLE ONLY merge_request_reviewers ALTER TABLE ONLY merge_request_user_mentions ADD CONSTRAINT merge_request_user_mentions_pkey PRIMARY KEY (id); +ALTER TABLE ONLY merge_requests_approval_rules_groups + ADD CONSTRAINT merge_requests_approval_rules_groups_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY merge_requests_approval_rules_merge_requests + ADD CONSTRAINT merge_requests_approval_rules_merge_requests_pkey PRIMARY KEY (id); + ALTER TABLE ONLY merge_requests_approval_rules ADD CONSTRAINT merge_requests_approval_rules_pkey PRIMARY KEY (id); +ALTER TABLE ONLY merge_requests_approval_rules_projects + ADD CONSTRAINT merge_requests_approval_rules_projects_pkey PRIMARY KEY (id); + ALTER TABLE ONLY merge_requests_closing_issues ADD CONSTRAINT merge_requests_closing_issues_pkey PRIMARY KEY (id); @@ -33556,6 +33623,8 @@ CREATE INDEX index_merge_request_reviewers_on_user_id ON merge_request_reviewers CREATE UNIQUE INDEX index_merge_request_user_mentions_on_note_id ON merge_request_user_mentions USING btree (note_id) WHERE (note_id IS NOT NULL); +CREATE INDEX index_merge_requests_approval_rules_groups_on_group_id ON merge_requests_approval_rules_groups USING btree (group_id); + CREATE INDEX index_merge_requests_approval_rules_on_group_id ON merge_requests_approval_rules USING btree (group_id); CREATE INDEX index_merge_requests_approval_rules_on_project_id ON merge_requests_approval_rules USING btree (project_id); @@ -33734,6 +33803,18 @@ CREATE INDEX index_mr_metrics_on_target_project_id_merged_at_nulls_last ON merge CREATE INDEX index_mr_metrics_on_target_project_id_merged_at_time_to_merge ON merge_request_metrics USING btree (target_project_id, merged_at, created_at) WHERE (merged_at > created_at); +CREATE INDEX index_mrs_approval_rules_mrs_on_mr_id ON merge_requests_approval_rules_merge_requests USING btree (merge_request_id); + +CREATE INDEX index_mrs_approval_rules_mrs_on_project_id ON merge_requests_approval_rules_merge_requests USING btree (project_id); + +CREATE INDEX index_mrs_approval_rules_projects_on_project_id ON merge_requests_approval_rules_projects USING btree (project_id); + +CREATE UNIQUE INDEX index_mrs_ars_groups_on_ar_id_and_group_id ON merge_requests_approval_rules_groups USING btree (approval_rule_id, group_id); + +CREATE UNIQUE INDEX index_mrs_ars_mrs_on_ar_id_and_mr_id ON merge_requests_approval_rules_merge_requests USING btree (approval_rule_id, merge_request_id); + +CREATE UNIQUE INDEX index_mrs_ars_projects_on_ar_id_and_project_id ON merge_requests_approval_rules_projects USING btree (approval_rule_id, project_id); + CREATE INDEX index_namespace_admin_notes_on_namespace_id ON namespace_admin_notes USING btree (namespace_id); CREATE UNIQUE INDEX index_namespace_aggregation_schedules_on_namespace_id ON namespace_aggregation_schedules USING btree (namespace_id); @@ -38603,6 +38684,9 @@ ALTER TABLE ONLY observability_traces_issues_connections ALTER TABLE ONLY merge_request_assignment_events ADD CONSTRAINT fk_08f7602bfd FOREIGN KEY (merge_request_id) REFERENCES merge_requests(id) ON DELETE CASCADE; +ALTER TABLE ONLY merge_requests_approval_rules_groups + ADD CONSTRAINT fk_094b4086a3 FOREIGN KEY (approval_rule_id) REFERENCES merge_requests_approval_rules(id) ON DELETE CASCADE; + ALTER TABLE ONLY catalog_resource_component_last_usages ADD CONSTRAINT fk_094c686785 FOREIGN KEY (component_project_id) REFERENCES projects(id) ON DELETE CASCADE; @@ -38762,6 +38846,9 @@ ALTER TABLE ONLY agent_project_authorizations ALTER TABLE ONLY ai_agent_version_attachments ADD CONSTRAINT fk_1d4253673b FOREIGN KEY (ai_vectorizable_file_id) REFERENCES ai_vectorizable_files(id) ON DELETE CASCADE; +ALTER TABLE ONLY merge_requests_approval_rules_merge_requests + ADD CONSTRAINT fk_1d49645a27 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; + ALTER TABLE ONLY design_management_versions ADD CONSTRAINT fk_1dccb304f8 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE; @@ -39083,6 +39170,9 @@ ALTER TABLE ONLY incident_management_timeline_events ALTER TABLE ONLY todos ADD CONSTRAINT fk_45054f9c45 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; +ALTER TABLE ONLY merge_requests_approval_rules_projects + ADD CONSTRAINT fk_451a9dfe93 FOREIGN KEY (approval_rule_id) REFERENCES merge_requests_approval_rules(id) ON DELETE CASCADE; + ALTER TABLE ONLY security_policy_requirements ADD CONSTRAINT fk_458f7f5ad5 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE; @@ -39200,6 +39290,9 @@ ALTER TABLE ONLY approval_merge_request_rules ALTER TABLE ONLY deploy_keys_projects ADD CONSTRAINT fk_58a901ca7e FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; +ALTER TABLE ONLY merge_requests_approval_rules_groups + ADD CONSTRAINT fk_59068f09e5 FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE; + ALTER TABLE ONLY oauth_access_grants ADD CONSTRAINT fk_59cdb2323c FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE; @@ -39233,6 +39326,9 @@ ALTER TABLE ONLY dast_scanner_profiles_builds ALTER TABLE ONLY protected_environment_deploy_access_levels ADD CONSTRAINT fk_5d9b05a7e9 FOREIGN KEY (protected_environment_project_id) REFERENCES projects(id) ON DELETE CASCADE; +ALTER TABLE ONLY merge_requests_approval_rules_merge_requests + ADD CONSTRAINT fk_5ddc4a2f7b FOREIGN KEY (approval_rule_id) REFERENCES merge_requests_approval_rules(id) ON DELETE CASCADE; + ALTER TABLE ONLY issue_assignees ADD CONSTRAINT fk_5e0c8d9154 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; @@ -39374,6 +39470,9 @@ ALTER TABLE ONLY index_statuses ALTER TABLE ONLY abuse_report_notes ADD CONSTRAINT fk_74e1990397 FOREIGN KEY (abuse_report_id) REFERENCES abuse_reports(id) ON DELETE CASCADE; +ALTER TABLE ONLY merge_requests_approval_rules_merge_requests + ADD CONSTRAINT fk_74e3466397 FOREIGN KEY (merge_request_id) REFERENCES merge_requests(id) ON DELETE CASCADE; + ALTER TABLE ONLY software_license_policies ADD CONSTRAINT fk_74f6d8328a FOREIGN KEY (custom_software_license_id) REFERENCES custom_software_licenses(id) ON DELETE CASCADE; @@ -39818,6 +39917,9 @@ ALTER TABLE ONLY ml_experiments ALTER TABLE ONLY merge_request_metrics ADD CONSTRAINT fk_ae440388cc FOREIGN KEY (latest_closed_by_id) REFERENCES users(id) ON DELETE SET NULL; +ALTER TABLE ONLY merge_requests_approval_rules_projects + ADD CONSTRAINT fk_af4078336f FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; + ALTER TABLE ONLY analytics_cycle_analytics_group_stages ADD CONSTRAINT fk_analytics_cycle_analytics_group_stages_group_value_stream_id FOREIGN KEY (group_value_stream_id) REFERENCES analytics_cycle_analytics_group_value_streams(id) ON DELETE CASCADE; diff --git a/ee/app/models/ee/group.rb b/ee/app/models/ee/group.rb index 16024c44236e4e9975ce6f5159a85d7b8642c13a..82faa88634223f607759b3665040bb648818cfa3 100644 --- a/ee/app/models/ee/group.rb +++ b/ee/app/models/ee/group.rb @@ -99,6 +99,10 @@ module Group has_many :security_exclusions, class_name: 'Security::GroupSecurityExclusion' + # WIP v2 approval rules as part of https://gitlab.com/groups/gitlab-org/-/epics/12955 + has_many :v2_approval_rules_groups, class_name: 'MergeRequests::ApprovalRulesGroup', inverse_of: :group + has_many :v2_approval_rules, through: :v2_approval_rules_groups, class_name: 'MergeRequests::ApprovalRule', source: :approval_rule + delegate :deleting_user, :marked_for_deletion_on, to: :deletion_schedule, allow_nil: true delegate :repository_read_only, diff --git a/ee/app/models/ee/merge_request.rb b/ee/app/models/ee/merge_request.rb index fcbf51d524998fcbd25c83e9a8a2a2a9f94c3d3b..83dcc54275cddcafab32fce1a3594caa34167928 100644 --- a/ee/app/models/ee/merge_request.rb +++ b/ee/app/models/ee/merge_request.rb @@ -101,6 +101,12 @@ def set_applicable_when_copying_rules(applicable_ids) has_many :merge_request_stage_events, class_name: 'Analytics::CycleAnalytics::MergeRequestStageEvent' + # WIP v2 approval rules as part of https://gitlab.com/groups/gitlab-org/-/epics/12955 + has_many :v2_approval_rules_merge_requests, class_name: 'MergeRequests::ApprovalRulesMergeRequest', + inverse_of: :merge_request + has_many :v2_approval_rules, through: :v2_approval_rules_merge_requests, + class_name: 'MergeRequests::ApprovalRule', source: :approval_rule + delegate :sha, to: :head_pipeline, prefix: :head_pipeline, allow_nil: true delegate :sha, to: :base_pipeline, prefix: :base_pipeline, allow_nil: true delegate :wrapped_approval_rules, :invalid_approvers_rules, to: :approval_state diff --git a/ee/app/models/ee/project.rb b/ee/app/models/ee/project.rb index 8a392295d9e97f6716e384d0990f9f52484f4409..7785ce7520238e0aa077f2760fdae33503b3198e 100644 --- a/ee/app/models/ee/project.rb +++ b/ee/app/models/ee/project.rb @@ -217,6 +217,10 @@ def lock_for_confirmation!(id) has_many :project_control_compliance_statuses, class_name: 'ComplianceManagement::ComplianceFramework::ProjectControlComplianceStatus' + # WIP v2 approval rules as part of https://gitlab.com/groups/gitlab-org/-/epics/12955 + has_many :v2_approval_rules_projects, class_name: 'MergeRequests::ApprovalRulesProject', inverse_of: :project + has_many :v2_approval_rules, through: :v2_approval_rules_projects, class_name: 'MergeRequests::ApprovalRule', source: :approval_rule + elastic_index_dependant_association :issues, on_change: :visibility_level elastic_index_dependant_association :issues, on_change: :archived elastic_index_dependant_association :work_items, on_change: :visibility_level diff --git a/ee/app/models/merge_requests/approval_rule.rb b/ee/app/models/merge_requests/approval_rule.rb index 46538828aea773d3fd9b8e9d0a87d563089eb6e0..8f002d21655a8e084036c2a4b5a9b99308d79e5f 100644 --- a/ee/app/models/merge_requests/approval_rule.rb +++ b/ee/app/models/merge_requests/approval_rule.rb @@ -4,6 +4,30 @@ module MergeRequests class ApprovalRule < ApplicationRecord self.table_name = 'merge_requests_approval_rules' + # If we allow overriding in subgroups there can be multiple groups + has_many :approval_rules_groups + has_many :groups, through: :approval_rules_groups + + # When this originated from group there is only one group + has_one :approval_rules_group, inverse_of: :approval_rule + has_one :group, through: :approval_rules_group + + # When this originated from group there are multiple projects + has_many :approval_rules_projects + has_many :projects, through: :approval_rules_projects + + # When this originated from project there is only one project + has_one :approval_rules_project + has_one :project, through: :approval_rules_project + + # When this originated from group or project there are multiple merge_requests + has_many :approval_rules_merge_requests + has_many :merge_requests, through: :approval_rules_merge_requests + + # When this originated from merge_request there is only one merge_request + has_one :approval_rules_merge_request, inverse_of: :approval_rule + has_one :merge_request, through: :approval_rules_merge_request + validate :ensure_single_sharding_key with_options validate: true do diff --git a/ee/app/models/merge_requests/approval_rules_group.rb b/ee/app/models/merge_requests/approval_rules_group.rb new file mode 100644 index 0000000000000000000000000000000000000000..2f5b08c306cdb5b9fd8c7d0c327cf7836e776977 --- /dev/null +++ b/ee/app/models/merge_requests/approval_rules_group.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module MergeRequests + class ApprovalRulesGroup < ApplicationRecord + self.table_name = 'merge_requests_approval_rules_groups' + + belongs_to :approval_rule, class_name: 'MergeRequests::ApprovalRule' + belongs_to :group + + validates :group_id, uniqueness: { scope: :approval_rule_id } + end +end diff --git a/ee/app/models/merge_requests/approval_rules_merge_request.rb b/ee/app/models/merge_requests/approval_rules_merge_request.rb new file mode 100644 index 0000000000000000000000000000000000000000..add783e2d3d6cfb031ce6d3a2c24b915cad952ef --- /dev/null +++ b/ee/app/models/merge_requests/approval_rules_merge_request.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module MergeRequests + class ApprovalRulesMergeRequest < ApplicationRecord + self.table_name = 'merge_requests_approval_rules_merge_requests' + + belongs_to :approval_rule, class_name: 'MergeRequests::ApprovalRule' + belongs_to :merge_request, class_name: 'MergeRequest' + + validates :merge_request_id, uniqueness: { scope: :approval_rule_id } + before_create :set_project_id + + private + + def set_project_id + self.project_id = merge_request.source_project.id + end + end +end diff --git a/ee/app/models/merge_requests/approval_rules_project.rb b/ee/app/models/merge_requests/approval_rules_project.rb new file mode 100644 index 0000000000000000000000000000000000000000..dbe99c628f2daf6b7595fa0a23a2057467f86134 --- /dev/null +++ b/ee/app/models/merge_requests/approval_rules_project.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module MergeRequests + class ApprovalRulesProject < ApplicationRecord + self.table_name = 'merge_requests_approval_rules_projects' + + belongs_to :approval_rule, class_name: 'MergeRequests::ApprovalRule' + belongs_to :project + + validates :project_id, uniqueness: { scope: :approval_rule_id } + end +end diff --git a/ee/spec/factories/merge_requests/approval_rules_groups.rb b/ee/spec/factories/merge_requests/approval_rules_groups.rb new file mode 100644 index 0000000000000000000000000000000000000000..fb8212dd5ea6cce4a3284bf88a2db073cdfb04eb --- /dev/null +++ b/ee/spec/factories/merge_requests/approval_rules_groups.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :merge_requests_approval_rules_group, class: 'MergeRequests::ApprovalRulesGroup' do + association :approval_rule, factory: :merge_requests_approval_rule + association :group, factory: :group + end +end diff --git a/ee/spec/factories/merge_requests/approval_rules_merge_requests.rb b/ee/spec/factories/merge_requests/approval_rules_merge_requests.rb new file mode 100644 index 0000000000000000000000000000000000000000..b221902638aaa6cacc2f30682e4d69005cadf3b6 --- /dev/null +++ b/ee/spec/factories/merge_requests/approval_rules_merge_requests.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :merge_requests_approval_rules_merge_request, class: 'MergeRequests::ApprovalRulesMergeRequest' do + association :approval_rule, factory: :merge_requests_approval_rule + association :merge_request, factory: :merge_request + end +end diff --git a/ee/spec/factories/merge_requests/approval_rules_projects.rb b/ee/spec/factories/merge_requests/approval_rules_projects.rb new file mode 100644 index 0000000000000000000000000000000000000000..de9d478f357fffcd592a0c795ae95a6c29d63eff --- /dev/null +++ b/ee/spec/factories/merge_requests/approval_rules_projects.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :merge_requests_approval_rules_project, class: 'MergeRequests::ApprovalRulesProject' do + association :approval_rule, factory: :merge_requests_approval_rule + association :project, factory: :project + end +end diff --git a/ee/spec/models/merge_requests/approval_rules_group_spec.rb b/ee/spec/models/merge_requests/approval_rules_group_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..870caa6b9799d7292185ed167d66a8e7de8ca039 --- /dev/null +++ b/ee/spec/models/merge_requests/approval_rules_group_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe MergeRequests::ApprovalRulesGroup, type: :model, feature_category: :code_review_workflow do + describe 'associations' do + it { is_expected.to belong_to(:approval_rule) } + it { is_expected.to belong_to(:group) } + end + + describe 'validations' do + context 'when adding the same group to an approval rule' do + let(:group) { create(:group) } + let(:approval_rule) { create(:merge_requests_approval_rule, group_id: group.id) } + + before do + create(:merge_requests_approval_rules_group, approval_rule: approval_rule, group: group) + end + + it 'is not valid' do + duplicate_approval_rules_group = build(:merge_requests_approval_rules_group, approval_rule: approval_rule, + group_id: group.id) + expect(duplicate_approval_rules_group).not_to be_valid + expect(duplicate_approval_rules_group.errors[:group_id]).to include('has already been taken') + end + end + end +end diff --git a/ee/spec/models/merge_requests/approval_rules_merge_request_spec.rb b/ee/spec/models/merge_requests/approval_rules_merge_request_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..c2d0ebf27bc8a0224d93ce9f479e955e9c868627 --- /dev/null +++ b/ee/spec/models/merge_requests/approval_rules_merge_request_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe MergeRequests::ApprovalRulesMergeRequest, type: :model, feature_category: :code_review_workflow do + describe 'associations' do + it { is_expected.to belong_to(:approval_rule) } + it { is_expected.to belong_to(:merge_request) } + end + + describe 'validations' do + context 'when adding the same merge request to an approval rule' do + let(:merge_request) { create(:merge_request) } + let(:group) { create(:group) } + let(:approval_rule) { create(:merge_requests_approval_rule, group_id: group.id) } + + before do + create(:merge_requests_approval_rules_merge_request, approval_rule: approval_rule, + merge_request: merge_request, project_id: merge_request.project_id) + end + + it 'is not valid' do + duplicate_approval_rules_merge_request = build(:merge_requests_approval_rules_merge_request, + approval_rule: approval_rule, merge_request_id: merge_request.id, project_id: merge_request.project_id) + expect(duplicate_approval_rules_merge_request).not_to be_valid + expect(duplicate_approval_rules_merge_request.errors[:merge_request_id]).to include('has already been taken') + end + end + end +end diff --git a/ee/spec/models/merge_requests/approval_rules_project_spec.rb b/ee/spec/models/merge_requests/approval_rules_project_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..eeb9ee379d6da7e542d5623632c85c68fb39a88d --- /dev/null +++ b/ee/spec/models/merge_requests/approval_rules_project_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe MergeRequests::ApprovalRulesProject, type: :model, feature_category: :code_review_workflow do + describe 'associations' do + it { is_expected.to belong_to(:approval_rule) } + it { is_expected.to belong_to(:project) } + end + + describe 'validations' do + context 'when adding the same project to an approval rule' do + let_it_be(:project) { create(:project) } + let(:approval_rule) { create(:merge_requests_approval_rule, project_id: project.id) } + + before do + create(:merge_requests_approval_rules_project, approval_rule: approval_rule, project: project) + end + + it 'is not valid' do + duplicate_approval_rules_project = build(:merge_requests_approval_rules_project, approval_rule: approval_rule, + project_id: project.id) + expect(duplicate_approval_rules_project).not_to be_valid + expect(duplicate_approval_rules_project.errors[:project_id]).to include('has already been taken') + end + end + end +end diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index dcd711a26ca37aa8b59361c25f329711c56e35ec..e9da7b7abfb56126dc954ae389b365c3eb5b9a00 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -256,6 +256,9 @@ merge_requests: - approver_users - approver_groups - approved_by_users +- v2_approval_rules +- v2_approval_rules_projects +- v2_approval_rules_merge_requests - draft_notes - merge_train_car - blocks_as_blocker @@ -770,6 +773,9 @@ project: - approval_merge_request_rules - approval_merge_request_rule_sources - approval_project_rules +- v2_approval_rules +- v2_approval_rules_projects +- v2_approval_rules_merge_requests - approvers - approver_users - audit_events