From b4d95da46b7016fcf97b174356f595688e932807 Mon Sep 17 00:00:00 2001 From: Tan Le Date: Tue, 30 Mar 2021 19:21:16 +1100 Subject: [PATCH] Add tables and models for group approval rules This commit introduces some DB tables and domain models to allows managing group approval rules: - approval_group_rules - approval_group_rules_users - approval_group_rules_groups --- .../325646-group-approval-rules-post-api.yml | 5 ++ ...20210329124955_add_approval_group_rules.rb | 31 +++++++ ...064326_add_approval_groups_rules_groups.rb | 18 ++++ ...0064433_add_approval_groups_rules_users.rb | 18 ++++ ...oval_rule_on_approval_group_rules_users.rb | 18 ++++ ...k_to_user_on_approval_group_rules_users.rb | 17 ++++ ...val_rule_on_approval_group_rules_groups.rb | 18 ++++ ...to_group_on_approval_group_rules_groups.rb | 17 ++++ db/schema_migrations/20210329124955 | 1 + db/schema_migrations/20210330064326 | 1 + db/schema_migrations/20210330064433 | 1 + db/schema_migrations/20210331051716 | 1 + db/schema_migrations/20210331051807 | 1 + db/schema_migrations/20210331051844 | 1 + db/schema_migrations/20210331052026 | 1 + db/structure.sql | 88 +++++++++++++++++++ .../approval_rules/approval_group_rule.rb | 23 +++++ ee/app/models/ee/group.rb | 1 + ee/spec/factories/approval_rules.rb | 6 ++ .../approval_group_rule_spec.rb | 34 +++++++ ee/spec/models/ee/group_spec.rb | 1 + locale/gitlab.pot | 3 + 22 files changed, 305 insertions(+) create mode 100644 changelogs/unreleased/325646-group-approval-rules-post-api.yml create mode 100644 db/migrate/20210329124955_add_approval_group_rules.rb create mode 100644 db/migrate/20210330064326_add_approval_groups_rules_groups.rb create mode 100644 db/migrate/20210330064433_add_approval_groups_rules_users.rb create mode 100644 db/migrate/20210331051716_add_fk_to_approval_rule_on_approval_group_rules_users.rb create mode 100644 db/migrate/20210331051807_add_fk_to_user_on_approval_group_rules_users.rb create mode 100644 db/migrate/20210331051844_add_fk_to_approval_rule_on_approval_group_rules_groups.rb create mode 100644 db/migrate/20210331052026_add_fk_to_group_on_approval_group_rules_groups.rb create mode 100644 db/schema_migrations/20210329124955 create mode 100644 db/schema_migrations/20210330064326 create mode 100644 db/schema_migrations/20210330064433 create mode 100644 db/schema_migrations/20210331051716 create mode 100644 db/schema_migrations/20210331051807 create mode 100644 db/schema_migrations/20210331051844 create mode 100644 db/schema_migrations/20210331052026 create mode 100644 ee/app/models/approval_rules/approval_group_rule.rb create mode 100644 ee/spec/models/approval_rules/approval_group_rule_spec.rb diff --git a/changelogs/unreleased/325646-group-approval-rules-post-api.yml b/changelogs/unreleased/325646-group-approval-rules-post-api.yml new file mode 100644 index 00000000000000..b9a97de913d883 --- /dev/null +++ b/changelogs/unreleased/325646-group-approval-rules-post-api.yml @@ -0,0 +1,5 @@ +--- +title: Add supported tables for group approval rules +merge_request: 57800 +author: +type: added diff --git a/db/migrate/20210329124955_add_approval_group_rules.rb b/db/migrate/20210329124955_add_approval_group_rules.rb new file mode 100644 index 00000000000000..3bf8f171c94ea9 --- /dev/null +++ b/db/migrate/20210329124955_add_approval_group_rules.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +class AddApprovalGroupRules < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + INDEX_GROUP_ID_TYPE_NAME = 'idx_on_approval_group_rules_group_id_type_name' + INDEX_ANY_APPROVER_TYPE = 'idx_on_approval_group_rules_any_approver_type' + + disable_ddl_transaction! + + def up + create_table_with_constraints :approval_group_rules do |t| + t.timestamps_with_timezone + t.references :group, references: :namespaces, null: false, + foreign_key: { to_table: :namespaces, on_delete: :cascade }, index: false + t.integer :approvals_required, limit: 2, null: false, default: 0 + t.integer :rule_type, limit: 2, null: false, default: 1 + t.text :name, null: false + + t.text_limit :name, 255 + t.index [:group_id, :rule_type, :name], unique: true, name: INDEX_GROUP_ID_TYPE_NAME + t.index :id, where: 'rule_type = 4', name: INDEX_ANY_APPROVER_TYPE + end + end + + def down + with_lock_retries do + drop_table :approval_group_rules + end + end +end diff --git a/db/migrate/20210330064326_add_approval_groups_rules_groups.rb b/db/migrate/20210330064326_add_approval_groups_rules_groups.rb new file mode 100644 index 00000000000000..36ab7ddd941849 --- /dev/null +++ b/db/migrate/20210330064326_add_approval_groups_rules_groups.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class AddApprovalGroupsRulesGroups < ActiveRecord::Migration[6.0] + INDEX_RULE_GROUP = 'idx_on_approval_group_rules_groups_rule_group' + + def up + create_table :approval_group_rules_groups do |t| + t.bigint :approval_group_rule_id, null: false + t.bigint :group_id, null: false + + t.index [:approval_group_rule_id, :group_id], unique: true, name: INDEX_RULE_GROUP + end + end + + def down + drop_table :approval_group_rules_groups + end +end diff --git a/db/migrate/20210330064433_add_approval_groups_rules_users.rb b/db/migrate/20210330064433_add_approval_groups_rules_users.rb new file mode 100644 index 00000000000000..745245a4c7b40e --- /dev/null +++ b/db/migrate/20210330064433_add_approval_groups_rules_users.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class AddApprovalGroupsRulesUsers < ActiveRecord::Migration[6.0] + INDEX_RULE_USER = 'idx_on_approval_group_rules_users_rule_user' + + def up + create_table :approval_group_rules_users do |t| + t.bigint :approval_group_rule_id, null: false + t.bigint :user_id, null: false + + t.index [:approval_group_rule_id, :user_id], unique: true, name: INDEX_RULE_USER + end + end + + def down + drop_table :approval_group_rules_users + end +end diff --git a/db/migrate/20210331051716_add_fk_to_approval_rule_on_approval_group_rules_users.rb b/db/migrate/20210331051716_add_fk_to_approval_rule_on_approval_group_rules_users.rb new file mode 100644 index 00000000000000..2e7d50f13dfbf3 --- /dev/null +++ b/db/migrate/20210331051716_add_fk_to_approval_rule_on_approval_group_rules_users.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class AddFkToApprovalRuleOnApprovalGroupRulesUsers < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :approval_group_rules_users, :approval_group_rules, column: :approval_group_rule_id, + on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :approval_group_rules_users, column: :approval_group_rule_id + end + end +end diff --git a/db/migrate/20210331051807_add_fk_to_user_on_approval_group_rules_users.rb b/db/migrate/20210331051807_add_fk_to_user_on_approval_group_rules_users.rb new file mode 100644 index 00000000000000..fabbd1e3f796ad --- /dev/null +++ b/db/migrate/20210331051807_add_fk_to_user_on_approval_group_rules_users.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddFkToUserOnApprovalGroupRulesUsers < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :approval_group_rules_users, :users, column: :user_id, on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :approval_group_rules_users, column: :user_id + end + end +end diff --git a/db/migrate/20210331051844_add_fk_to_approval_rule_on_approval_group_rules_groups.rb b/db/migrate/20210331051844_add_fk_to_approval_rule_on_approval_group_rules_groups.rb new file mode 100644 index 00000000000000..6c85f470cfd7b3 --- /dev/null +++ b/db/migrate/20210331051844_add_fk_to_approval_rule_on_approval_group_rules_groups.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class AddFkToApprovalRuleOnApprovalGroupRulesGroups < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :approval_group_rules_groups, :approval_group_rules, column: :approval_group_rule_id, + on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :approval_group_rules_groups, column: :approval_group_rule_id + end + end +end diff --git a/db/migrate/20210331052026_add_fk_to_group_on_approval_group_rules_groups.rb b/db/migrate/20210331052026_add_fk_to_group_on_approval_group_rules_groups.rb new file mode 100644 index 00000000000000..bd7a38003977c4 --- /dev/null +++ b/db/migrate/20210331052026_add_fk_to_group_on_approval_group_rules_groups.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddFkToGroupOnApprovalGroupRulesGroups < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :approval_group_rules_groups, :namespaces, column: :group_id, on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :approval_group_rules_groups, column: :group_id + end + end +end diff --git a/db/schema_migrations/20210329124955 b/db/schema_migrations/20210329124955 new file mode 100644 index 00000000000000..cf366c334c651f --- /dev/null +++ b/db/schema_migrations/20210329124955 @@ -0,0 +1 @@ +08d000ecd3d6830e8fffbc9676600930448ac62684ff401f86a0f5ef0389e7e5 \ No newline at end of file diff --git a/db/schema_migrations/20210330064326 b/db/schema_migrations/20210330064326 new file mode 100644 index 00000000000000..0b7439586deb5a --- /dev/null +++ b/db/schema_migrations/20210330064326 @@ -0,0 +1 @@ +c3699551bfb4a918def67f7bcb2b6f098aa24b169e60f884dd4f4aea088464da \ No newline at end of file diff --git a/db/schema_migrations/20210330064433 b/db/schema_migrations/20210330064433 new file mode 100644 index 00000000000000..3e36ccb71c80c1 --- /dev/null +++ b/db/schema_migrations/20210330064433 @@ -0,0 +1 @@ +b66e689656511dcfe434d7af48c7d41fb7ffef1eee9ef1abb156a990db8a54e4 \ No newline at end of file diff --git a/db/schema_migrations/20210331051716 b/db/schema_migrations/20210331051716 new file mode 100644 index 00000000000000..592dd559a620b9 --- /dev/null +++ b/db/schema_migrations/20210331051716 @@ -0,0 +1 @@ +18fe378710f6bafdd72708a0998d337412adfe1c9668e2586acddb6f70fcd644 \ No newline at end of file diff --git a/db/schema_migrations/20210331051807 b/db/schema_migrations/20210331051807 new file mode 100644 index 00000000000000..374eca572c640b --- /dev/null +++ b/db/schema_migrations/20210331051807 @@ -0,0 +1 @@ +0b1b90b80fd1b5ae7e4a8af7fdd562ab5cf20a2c25f53a48eb43d23653001771 \ No newline at end of file diff --git a/db/schema_migrations/20210331051844 b/db/schema_migrations/20210331051844 new file mode 100644 index 00000000000000..f84afdaac37f89 --- /dev/null +++ b/db/schema_migrations/20210331051844 @@ -0,0 +1 @@ +183c01fdb397e8e6a1f373a498b048b98ebeb1554f237ea2c09a4a24a0c643cf \ No newline at end of file diff --git a/db/schema_migrations/20210331052026 b/db/schema_migrations/20210331052026 new file mode 100644 index 00000000000000..cc8f4927b467e2 --- /dev/null +++ b/db/schema_migrations/20210331052026 @@ -0,0 +1 @@ +adfd8c52083da4ccac00d843881ab71647bcda543188f920be9b6221eec0f8ba \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index ad34d16bbda13d..0344dd29ded081 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -9473,6 +9473,56 @@ CREATE SEQUENCE application_settings_id_seq ALTER SEQUENCE application_settings_id_seq OWNED BY application_settings.id; +CREATE TABLE approval_group_rules ( + id bigint NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL, + group_id bigint NOT NULL, + approvals_required smallint DEFAULT 0 NOT NULL, + rule_type smallint DEFAULT 1 NOT NULL, + name text NOT NULL, + CONSTRAINT check_25d42add43 CHECK ((char_length(name) <= 255)) +); + +CREATE TABLE approval_group_rules_groups ( + id bigint NOT NULL, + approval_group_rule_id bigint NOT NULL, + group_id bigint NOT NULL +); + +CREATE SEQUENCE approval_group_rules_groups_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE approval_group_rules_groups_id_seq OWNED BY approval_group_rules_groups.id; + +CREATE SEQUENCE approval_group_rules_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE approval_group_rules_id_seq OWNED BY approval_group_rules.id; + +CREATE TABLE approval_group_rules_users ( + id bigint NOT NULL, + approval_group_rule_id bigint NOT NULL, + user_id bigint NOT NULL +); + +CREATE SEQUENCE approval_group_rules_users_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE approval_group_rules_users_id_seq OWNED BY approval_group_rules_users.id; + CREATE TABLE approval_merge_request_rule_sources ( id bigint NOT NULL, approval_merge_request_rule_id bigint NOT NULL, @@ -19068,6 +19118,12 @@ ALTER TABLE ONLY application_setting_terms ALTER COLUMN id SET DEFAULT nextval(' ALTER TABLE ONLY application_settings ALTER COLUMN id SET DEFAULT nextval('application_settings_id_seq'::regclass); +ALTER TABLE ONLY approval_group_rules ALTER COLUMN id SET DEFAULT nextval('approval_group_rules_id_seq'::regclass); + +ALTER TABLE ONLY approval_group_rules_groups ALTER COLUMN id SET DEFAULT nextval('approval_group_rules_groups_id_seq'::regclass); + +ALTER TABLE ONLY approval_group_rules_users ALTER COLUMN id SET DEFAULT nextval('approval_group_rules_users_id_seq'::regclass); + ALTER TABLE ONLY approval_merge_request_rule_sources ALTER COLUMN id SET DEFAULT nextval('approval_merge_request_rule_sources_id_seq'::regclass); ALTER TABLE ONLY approval_merge_request_rules ALTER COLUMN id SET DEFAULT nextval('approval_merge_request_rules_id_seq'::regclass); @@ -20138,6 +20194,15 @@ ALTER TABLE ONLY application_setting_terms ALTER TABLE ONLY application_settings ADD CONSTRAINT application_settings_pkey PRIMARY KEY (id); +ALTER TABLE ONLY approval_group_rules_groups + ADD CONSTRAINT approval_group_rules_groups_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY approval_group_rules + ADD CONSTRAINT approval_group_rules_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY approval_group_rules_users + ADD CONSTRAINT approval_group_rules_users_pkey PRIMARY KEY (id); + ALTER TABLE ONLY approval_merge_request_rule_sources ADD CONSTRAINT approval_merge_request_rule_sources_pkey PRIMARY KEY (id); @@ -21772,6 +21837,14 @@ CREATE INDEX idx_mr_cc_diff_files_on_mr_cc_id_and_sha ON merge_request_context_c CREATE INDEX idx_mrs_on_target_id_and_created_at_and_state_id ON merge_requests USING btree (target_project_id, state_id, created_at, id); +CREATE INDEX idx_on_approval_group_rules_any_approver_type ON approval_group_rules USING btree (id) WHERE (rule_type = 4); + +CREATE UNIQUE INDEX idx_on_approval_group_rules_group_id_type_name ON approval_group_rules USING btree (group_id, rule_type, name); + +CREATE UNIQUE INDEX idx_on_approval_group_rules_groups_rule_group ON approval_group_rules_groups USING btree (approval_group_rule_id, group_id); + +CREATE UNIQUE INDEX idx_on_approval_group_rules_users_rule_user ON approval_group_rules_users USING btree (approval_group_rule_id, user_id); + CREATE UNIQUE INDEX idx_on_compliance_management_frameworks_namespace_id_name ON compliance_management_frameworks USING btree (namespace_id, name); CREATE UNIQUE INDEX idx_on_external_approval_rules_project_id_external_url ON external_approval_rules USING btree (project_id, external_url); @@ -24869,6 +24942,9 @@ ALTER TABLE ONLY geo_event_log ALTER TABLE ONLY ci_build_trace_sections ADD CONSTRAINT fk_4ebe41f502 FOREIGN KEY (build_id) REFERENCES ci_builds(id) ON DELETE CASCADE; +ALTER TABLE ONLY approval_group_rules_groups + ADD CONSTRAINT fk_50edc8134e FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE; + ALTER TABLE ONLY alert_management_alerts ADD CONSTRAINT fk_51ab4b6089 FOREIGN KEY (prometheus_alert_id) REFERENCES prometheus_alerts(id) ON DELETE CASCADE; @@ -25016,6 +25092,9 @@ ALTER TABLE ONLY ci_builds ALTER TABLE ONLY experiment_subjects ADD CONSTRAINT fk_88489af1b1 FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE; +ALTER TABLE ONLY approval_group_rules_users + ADD CONSTRAINT fk_888a0df3b7 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; + ALTER TABLE ONLY vulnerabilities ADD CONSTRAINT fk_88b4d546ef FOREIGN KEY (start_date_sourcing_milestone_id) REFERENCES milestones(id) ON DELETE SET NULL; @@ -25067,6 +25146,9 @@ ALTER TABLE ONLY protected_branch_merge_access_levels ALTER TABLE ONLY notes ADD CONSTRAINT fk_99e097b079 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; +ALTER TABLE ONLY approval_group_rules_users + ADD CONSTRAINT fk_9a4b673183 FOREIGN KEY (approval_group_rule_id) REFERENCES approval_group_rules(id) ON DELETE CASCADE; + ALTER TABLE ONLY geo_event_log ADD CONSTRAINT fk_9b9afb1916 FOREIGN KEY (repository_created_event_id) REFERENCES geo_repository_created_events(id) ON DELETE CASCADE; @@ -25337,6 +25419,9 @@ ALTER TABLE ONLY events ALTER TABLE ONLY vulnerabilities ADD CONSTRAINT fk_efb96ab1e2 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; +ALTER TABLE ONLY approval_group_rules_groups + ADD CONSTRAINT fk_efff219a48 FOREIGN KEY (approval_group_rule_id) REFERENCES approval_group_rules(id) ON DELETE CASCADE; + ALTER TABLE ONLY emails ADD CONSTRAINT fk_emails_user_id FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; @@ -26051,6 +26136,9 @@ ALTER TABLE ONLY namespace_admin_notes ALTER TABLE ONLY web_hook_logs ADD CONSTRAINT fk_rails_666826e111 FOREIGN KEY (web_hook_id) REFERENCES web_hooks(id) ON DELETE CASCADE; +ALTER TABLE ONLY approval_group_rules + ADD CONSTRAINT fk_rails_6727675176 FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE; + ALTER TABLE ONLY jira_imports ADD CONSTRAINT fk_rails_675d38c03b FOREIGN KEY (label_id) REFERENCES labels(id) ON DELETE SET NULL; diff --git a/ee/app/models/approval_rules/approval_group_rule.rb b/ee/app/models/approval_rules/approval_group_rule.rb new file mode 100644 index 00000000000000..90db909b065ef2 --- /dev/null +++ b/ee/app/models/approval_rules/approval_group_rule.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module ApprovalRules + class ApprovalGroupRule < ApplicationRecord + include ApprovalRuleLike + + enum rule_type: { + regular: 1, + code_owner: 2, + report_approver: 3, + any_approver: 4 + } + + belongs_to :group, inverse_of: :approval_rules + + validates :group, presence: true + validates :name, uniqueness: { scope: [:group_id, :rule_type] } + validates :rule_type, uniqueness: { + scope: :group_id, + message: proc { _('any-approver for the group already exists') } + }, if: :any_approver? + end +end diff --git a/ee/app/models/ee/group.rb b/ee/app/models/ee/group.rb index b6bbcd52b64d30..bb973d08410321 100644 --- a/ee/app/models/ee/group.rb +++ b/ee/app/models/ee/group.rb @@ -58,6 +58,7 @@ module Group belongs_to :file_template_project, class_name: "Project" belongs_to :push_rule, inverse_of: :group + has_many :approval_rules, class_name: 'ApprovalRules::ApprovalGroupRule', inverse_of: :group # Use +checked_file_template_project+ instead, which implements important # visibility checks diff --git a/ee/spec/factories/approval_rules.rb b/ee/spec/factories/approval_rules.rb index 250bfc1981fe56..f8e9872498b289 100644 --- a/ee/spec/factories/approval_rules.rb +++ b/ee/spec/factories/approval_rules.rb @@ -62,4 +62,10 @@ rule_type { :report_approver } end end + + factory :approval_group_rule, class: 'ApprovalRules::ApprovalGroupRule' do + group + sequence(:name) { |n| "#{ApprovalRuleLike::DEFAULT_NAME}-#{n}" } + rule_type { :regular } + end end diff --git a/ee/spec/models/approval_rules/approval_group_rule_spec.rb b/ee/spec/models/approval_rules/approval_group_rule_spec.rb new file mode 100644 index 00000000000000..5afec4896190de --- /dev/null +++ b/ee/spec/models/approval_rules/approval_group_rule_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ApprovalRules::ApprovalGroupRule do + subject { build(:approval_group_rule) } + + describe 'validations' do + it { is_expected.to validate_presence_of(:group) } + it { is_expected.to validate_presence_of(:name) } + it { is_expected.to validate_uniqueness_of(:name).scoped_to([:group_id, :rule_type]) } + it { is_expected.to validate_numericality_of(:approvals_required).is_less_than_or_equal_to(100) } + it { is_expected.to validate_numericality_of(:approvals_required).is_greater_than_or_equal_to(0) } + end + + describe 'associations' do + it { is_expected.to belong_to(:group).inverse_of(:approval_rules) } + it { is_expected.to have_and_belong_to_many(:users) } + it { is_expected.to have_and_belong_to_many(:groups) } + end + + describe 'any_approver rules' do + let_it_be(:group) { create(:group) } + + let(:rule) { build(:approval_group_rule, group: group, rule_type: :any_approver) } + + it 'allows to create only one any_approver rule', :aggregate_failures do + create(:approval_group_rule, group: group, rule_type: :any_approver) + + expect(rule).not_to be_valid + expect(rule.errors.messages).to eq(rule_type: ['any-approver for the group already exists']) + end + end +end diff --git a/ee/spec/models/ee/group_spec.rb b/ee/spec/models/ee/group_spec.rb index c1f26313533985..34d7cf3f2d9bc0 100644 --- a/ee/spec/models/ee/group_spec.rb +++ b/ee/spec/models/ee/group_spec.rb @@ -30,6 +30,7 @@ it { is_expected.to have_many(:repository_storage_moves) } it { is_expected.to have_many(:iterations) } it { is_expected.to have_many(:iterations_cadences) } + it { is_expected.to have_many(:approval_rules).class_name('ApprovalRules::ApprovalGroupRule').inverse_of(:group) } it_behaves_like 'model with wiki' do let(:container) { create(:group, :nested, :wiki_repo) } diff --git a/locale/gitlab.pot b/locale/gitlab.pot index f70ad89876ad14..6135ea89c02944 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -36674,6 +36674,9 @@ msgstr "" msgid "and" msgstr "" +msgid "any-approver for the group already exists" +msgstr "" + msgid "any-approver for the merge request already exists" msgstr "" -- GitLab