Skip to content
代码片段 群组 项目
提交 9c315784 编辑于 作者: Jan Provaznik's avatar Jan Provaznik 提交者: Diogo Frazão
浏览文件

Add default hierarchy restrictions

Adds restrictions for predefined types.

Changelog: added
上级 6233e6fb
No related branches found
No related tags found
无相关合并请求
显示
258 个添加7 个删除
......@@ -10,17 +10,29 @@ class Type < ApplicationRecord
include CacheMarkdownField
# type name is used in restrictions DB seeder to assure restrictions for
# default types are pre-filled
TYPE_NAMES = {
issue: 'Issue',
incident: 'Incident',
test_case: 'Test Case',
requirement: 'Requirement',
task: 'Task',
objective: 'Objective',
key_result: 'Key Result'
}.freeze
# Base types need to exist on the DB on app startup
# This constant is used by the DB seeder
# TODO - where to add new icon names created?
BASE_TYPES = {
issue: { name: 'Issue', icon_name: 'issue-type-issue', enum_value: 0 },
incident: { name: 'Incident', icon_name: 'issue-type-incident', enum_value: 1 },
test_case: { name: 'Test Case', icon_name: 'issue-type-test-case', enum_value: 2 }, ## EE-only
requirement: { name: 'Requirement', icon_name: 'issue-type-requirements', enum_value: 3 }, ## EE-only
task: { name: 'Task', icon_name: 'issue-type-task', enum_value: 4 },
objective: { name: 'Objective', icon_name: 'issue-type-objective', enum_value: 5 }, ## EE-only
key_result: { name: 'Key Result', icon_name: 'issue-type-keyresult', enum_value: 6 } ## EE-only
issue: { name: TYPE_NAMES[:issue], icon_name: 'issue-type-issue', enum_value: 0 },
incident: { name: TYPE_NAMES[:incident], icon_name: 'issue-type-incident', enum_value: 1 },
test_case: { name: TYPE_NAMES[:test_case], icon_name: 'issue-type-test-case', enum_value: 2 }, ## EE-only
requirement: { name: TYPE_NAMES[:requirement], icon_name: 'issue-type-requirements', enum_value: 3 }, ## EE-only
task: { name: TYPE_NAMES[:task], icon_name: 'issue-type-task', enum_value: 4 },
objective: { name: TYPE_NAMES[:objective], icon_name: 'issue-type-objective', enum_value: 5 }, ## EE-only
key_result: { name: TYPE_NAMES[:key_result], icon_name: 'issue-type-keyresult', enum_value: 6 } ## EE-only
}.freeze
WIDGETS_FOR_TYPE = {
......@@ -66,6 +78,7 @@ def self.default_by_type(type)
return found_type if found_type
Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter.upsert_types
Gitlab::DatabaseImporters::WorkItems::HierarchyRestrictionsImporter.upsert_restrictions
find_by(namespace_id: nil, base_type: type)
end
......
# frozen_string_literal: true
Gitlab::Seeder.quiet do
Gitlab::DatabaseImporters::WorkItems::HierarchyRestrictionsImporter.upsert_restrictions
end
# frozen_string_literal: true
Gitlab::Seeder.quiet do
Gitlab::DatabaseImporters::WorkItems::HierarchyRestrictionsImporter.upsert_restrictions
end
# frozen_string_literal: true
class AddOkrHierarchyRestrictions < Gitlab::Database::Migration[2.0]
class WorkItemType < MigrationRecord
self.table_name = 'work_item_types'
end
class HierarchyRestriction < MigrationRecord
self.table_name = 'work_item_hierarchy_restrictions'
end
restrict_gitlab_migration gitlab_schema: :gitlab_main
disable_ddl_transaction!
def up
objective = WorkItemType.find_by_name_and_namespace_id('Objective', nil)
key_result = WorkItemType.find_by_name_and_namespace_id('Key Result', nil)
issue = WorkItemType.find_by_name_and_namespace_id('Issue', nil)
task = WorkItemType.find_by_name_and_namespace_id('Task', nil)
incident = WorkItemType.find_by_name_and_namespace_id('Incident', nil)
# work item default types should be filled, if this is not the case
# then restrictions will be created together with work item types
unless objective && key_result && issue && task && incident
Gitlab::AppLogger.warn('default types are missing, not adding restrictions')
return
end
restrictions = [
{ parent_type_id: objective.id, child_type_id: objective.id, maximum_depth: 9 },
{ parent_type_id: objective.id, child_type_id: key_result.id, maximum_depth: 1 },
{ parent_type_id: issue.id, child_type_id: task.id, maximum_depth: 1 },
{ parent_type_id: incident.id, child_type_id: task.id, maximum_depth: 1 }
]
HierarchyRestriction.upsert_all(
restrictions,
unique_by: :index_work_item_hierarchy_restrictions_on_parent_and_child
)
end
def down
# so far restrictions table was empty so we can delete all records when
# migrating down
HierarchyRestriction.delete_all
end
end
a6caf06dd18f096219d5ce0752c956ef099a92df71899c1b9164d3a16f6ef0ba
\ No newline at end of file
# frozen_string_literal: true
module Gitlab
module DatabaseImporters
module WorkItems
module HierarchyRestrictionsImporter
def self.upsert_restrictions
objective = find_or_create_type(::WorkItems::Type::TYPE_NAMES[:objective])
key_result = find_or_create_type(::WorkItems::Type::TYPE_NAMES[:key_result])
issue = find_or_create_type(::WorkItems::Type::TYPE_NAMES[:issue])
task = find_or_create_type(::WorkItems::Type::TYPE_NAMES[:task])
incident = find_or_create_type(::WorkItems::Type::TYPE_NAMES[:incident])
restrictions = [
{ parent_type_id: objective.id, child_type_id: objective.id, maximum_depth: 9 },
{ parent_type_id: objective.id, child_type_id: key_result.id, maximum_depth: 1 },
{ parent_type_id: issue.id, child_type_id: task.id, maximum_depth: 1 },
{ parent_type_id: incident.id, child_type_id: task.id, maximum_depth: 1 }
]
::WorkItems::HierarchyRestriction.upsert_all(
restrictions,
unique_by: :index_work_item_hierarchy_restrictions_on_parent_and_child
)
end
def self.find_or_create_type(name)
type = ::WorkItems::Type.find_by_name_and_namespace_id(name, nil)
return type if type
Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter.upsert_types
::WorkItems::Type.find_by_name_and_namespace_id(name, nil)
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Create work item hierarchy restrictions in development', feature_category: :portfolio_management do
subject { load Rails.root.join('db/fixtures/development/50_create_work_item_hierarchy_restrictions.rb') }
it_behaves_like 'work item hierarchy restrictions importer'
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Create work item hierarchy restrictions in production', feature_category: :portfolio_management do
subject { load Rails.root.join('db/fixtures/production/020_create_work_item_hierarchy_restrictions.rb') }
it_behaves_like 'work item hierarchy restrictions importer'
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::DatabaseImporters::WorkItems::HierarchyRestrictionsImporter,
feature_category: :portfolio_management do
subject { described_class.upsert_restrictions }
it_behaves_like 'work item hierarchy restrictions importer'
end
# frozen_string_literal: true
require 'spec_helper'
require_migration!
RSpec.describe AddOkrHierarchyRestrictions, :migration, feature_category: :portfolio_management do
include MigrationHelpers::WorkItemTypesHelper
let_it_be(:restrictions) { table(:work_item_hierarchy_restrictions) }
let_it_be(:work_item_types) { table(:work_item_types) }
it 'creates default restrictions' do
restrictions.delete_all
reversible_migration do |migration|
migration.before -> {
expect(restrictions.count).to eq(0)
}
migration.after -> {
expect(restrictions.count).to eq(4)
}
end
end
context 'when work items are missing' do
before do
work_item_types.delete_all
end
it 'does nothing' do
expect { migrate! }.not_to change { restrictions.count }
end
end
end
......@@ -75,6 +75,32 @@
end
end
describe '.default_by_type' do
let(:default_issue_type) { described_class.find_by(namespace_id: nil, base_type: :issue) }
subject { described_class.default_by_type(:issue) }
it 'returns default work item type by base type without calling importer' do
expect(Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter).not_to receive(:upsert_types)
expect(Gitlab::DatabaseImporters::WorkItems::HierarchyRestrictionsImporter).not_to receive(:upsert_restrictions)
expect(subject).to eq(default_issue_type)
end
context 'when default types are missing' do
before do
described_class.delete_all
end
it 'creates types and restrictions and returns default work item type by base type' do
expect(Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter).to receive(:upsert_types)
expect(Gitlab::DatabaseImporters::WorkItems::HierarchyRestrictionsImporter).to receive(:upsert_restrictions)
expect(subject).to eq(default_issue_type)
end
end
end
describe '#default?' do
subject { build(:work_item_type, namespace: namespace).default? }
......
# frozen_string_literal: true
RSpec.shared_examples 'work item hierarchy restrictions importer' do
shared_examples_for 'adds restrictions' do
it "adds all restrictions if they don't exist" do
expect { subject }.to change { WorkItems::HierarchyRestriction.count }.from(0).to(4)
end
end
it_behaves_like 'adds restrictions'
context 'when base types are missing' do
before do
WorkItems::Type.delete_all
end
it_behaves_like 'adds restrictions'
end
context 'when restrictions already exist' do
before do
Gitlab::DatabaseImporters::WorkItems::HierarchyRestrictionsImporter.upsert_restrictions
end
it 'upserts restrictions' do
restriction = WorkItems::HierarchyRestriction.first
depth = restriction.maximum_depth
restriction.update!(maximum_depth: depth + 1)
expect do
subject
restriction.reload
end.to not_change { WorkItems::HierarchyRestriction.count }.and(
change { restriction.maximum_depth }.from(depth + 1).to(depth)
)
end
end
context 'when some restrictions are missing' do
before do
Gitlab::DatabaseImporters::WorkItems::HierarchyRestrictionsImporter.upsert_restrictions
WorkItems::HierarchyRestriction.limit(1).delete_all
end
it 'inserts missing restrictions and does nothing if some already existed' do
expect { subject }.to make_queries_matching(/INSERT/, 1).and(
change { WorkItems::HierarchyRestriction.count }.by(1)
)
expect(WorkItems::HierarchyRestriction.count).to eq(4)
end
end
end
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册