gitlab-ce/lib/gitlab/background_migration/backfill_branch_protection_...

136 lines
4.5 KiB
Ruby

# frozen_string_literal: true
module Gitlab
module BackgroundMigration
# This class is used to update the default_branch_protection_defaults column
# for user namespaces of the namespace_settings table.
class BackfillBranchProtectionNamespaceSetting < BatchedMigrationJob
operation_name :set_default_branch_protection_defaults
feature_category :source_code_management
# Migration only version of `namespaces` table
class Namespace < ::ApplicationRecord
self.table_name = 'namespaces'
self.inheritance_column = :_type_disabled
has_one :namespace_setting,
class_name: '::Gitlab::BackgroundMigration::BackfillDefaultBranchProtectionNamespaceSetting::NamespaceSetting'
end
# Migration only version of `namespace_settings` table
class NamespaceSetting < ::ApplicationRecord
self.table_name = 'namespace_settings'
belongs_to :namespace,
class_name: '::Gitlab::BackgroundMigration::BackfillDefaultBranchProtectionNamespaceSetting::Namespace'
end
# Migration only version of Gitlab::Access:BranchProtection application code.
class BranchProtection
attr_reader :level
def initialize(level)
@level = level
end
PROTECTION_NONE = 0
PROTECTION_DEV_CAN_PUSH = 1
PROTECTION_FULL = 2
PROTECTION_DEV_CAN_MERGE = 3
PROTECTION_DEV_CAN_INITIAL_PUSH = 4
DEVELOPER = 30
MAINTAINER = 40
def to_hash
case level
when PROTECTION_NONE
self.class.protection_none
when PROTECTION_DEV_CAN_PUSH
self.class.protection_partial
when PROTECTION_FULL
self.class.protected_fully
when PROTECTION_DEV_CAN_MERGE
self.class.protected_against_developer_pushes
when PROTECTION_DEV_CAN_INITIAL_PUSH
self.class.protected_after_initial_push
end
end
class << self
def protection_none
{
allowed_to_push: [{ 'access_level' => Gitlab::Access::DEVELOPER }],
allowed_to_merge: [{ 'access_level' => Gitlab::Access::DEVELOPER }],
allow_force_push: true
}
end
def protection_partial
{
allowed_to_push: [{ 'access_level' => Gitlab::Access::DEVELOPER }],
allowed_to_merge: [{ 'access_level' => Gitlab::Access::MAINTAINER }],
allow_force_push: false
}
end
def protected_fully
{
allowed_to_push: [{ 'access_level' => Gitlab::Access::MAINTAINER }],
allowed_to_merge: [{ 'access_level' => Gitlab::Access::MAINTAINER }],
allow_force_push: false
}
end
def protected_against_developer_pushes
{
allowed_to_push: [{ 'access_level' => Gitlab::Access::MAINTAINER }],
allowed_to_merge: [{ 'access_level' => Gitlab::Access::DEVELOPER }],
allow_force_push: false
}
end
def protected_after_initial_push
{
allowed_to_push: [{ 'access_level' => Gitlab::Access::MAINTAINER }],
allowed_to_merge: [{ 'access_level' => Gitlab::Access::MAINTAINER }],
allow_force_push: false,
developer_can_initial_push: true
}
end
end
end
def perform
each_sub_batch do |sub_batch|
update_default_protection_branch_defaults(sub_batch)
end
end
private
def update_default_protection_branch_defaults(batch)
namespace_settings = NamespaceSetting.where(namespace_id: batch.pluck(:namespace_id)).includes(:namespace)
values_list = namespace_settings.map do |namespace_setting|
level = namespace_setting.namespace.default_branch_protection.to_i
value = BranchProtection.new(level).to_hash.to_json
"(#{namespace_setting.namespace_id}, '#{value}'::jsonb)"
end.join(", ")
sql = <<~SQL
WITH new_values (namespace_id, default_branch_protection_defaults) AS (
VALUES
#{values_list}
)
UPDATE namespace_settings
SET default_branch_protection_defaults = new_values.default_branch_protection_defaults
FROM new_values
WHERE namespace_settings.namespace_id = new_values.namespace_id;
SQL
connection.execute(sql)
end
end
end
end