diff --git a/.rubocop_todo/gitlab/namespaced_class.yml b/.rubocop_todo/gitlab/namespaced_class.yml index eec55aa7bbecfafe183b7095cc59e84f075591a1..d1257e3ffac1bf3a166a068a958cb95bd38b9cbe 100644 --- a/.rubocop_todo/gitlab/namespaced_class.yml +++ b/.rubocop_todo/gitlab/namespaced_class.yml @@ -133,7 +133,6 @@ Gitlab/NamespacedClass: - 'app/models/commit_status.rb' - 'app/models/commit_user_mention.rb' - 'app/models/compare.rb' - - 'app/models/concerns/uniquify.rb' - 'app/models/container_expiration_policy.rb' - 'app/models/container_repository.rb' - 'app/models/context_commits_diff.rb' diff --git a/.rubocop_todo/layout/space_in_lambda_literal.yml b/.rubocop_todo/layout/space_in_lambda_literal.yml index 3abff1e8788ae9d8f344c2dbb04bb04ea4865024..362d9b20eb19380dda90e7bc7c67f92dc310c55e 100644 --- a/.rubocop_todo/layout/space_in_lambda_literal.yml +++ b/.rubocop_todo/layout/space_in_lambda_literal.yml @@ -400,7 +400,6 @@ Layout/SpaceInLambdaLiteral: - 'spec/models/ability_spec.rb' - 'spec/models/broadcast_message_spec.rb' - 'spec/models/concerns/participable_spec.rb' - - 'spec/models/concerns/uniquify_spec.rb' - 'spec/models/merge_request_spec.rb' - 'spec/support/shared_examples/lib/cache_helpers_shared_examples.rb' - 'spec/support/shared_examples/workers/batched_background_migration_worker_shared_examples.rb' diff --git a/.rubocop_todo/lint/unused_block_argument.yml b/.rubocop_todo/lint/unused_block_argument.yml index f226f04445a1b6c3c8635db8551826695e3de10f..188b57db7a76da2e949a3a25998170cf8aa14d56 100644 --- a/.rubocop_todo/lint/unused_block_argument.yml +++ b/.rubocop_todo/lint/unused_block_argument.yml @@ -376,7 +376,6 @@ Lint/UnusedBlockArgument: - 'spec/models/concerns/ci/partitionable/switch_spec.rb' - 'spec/models/concerns/ci/partitionable_spec.rb' - 'spec/models/concerns/each_batch_spec.rb' - - 'spec/models/concerns/uniquify_spec.rb' - 'spec/models/container_repository_spec.rb' - 'spec/models/network/graph_spec.rb' - 'spec/models/packages/debian/file_metadatum_spec.rb' diff --git a/.rubocop_todo/rspec/missing_feature_category.yml b/.rubocop_todo/rspec/missing_feature_category.yml index b40b311591325b0f31e5c9921124d0305accab1b..9ceeab0404984ca64981feb6d81641eadcd57fa3 100644 --- a/.rubocop_todo/rspec/missing_feature_category.yml +++ b/.rubocop_todo/rspec/missing_feature_category.yml @@ -5954,7 +5954,6 @@ RSpec/MissingFeatureCategory: - 'spec/models/concerns/token_authenticatable_strategies/encryption_helper_spec.rb' - 'spec/models/concerns/transactions_spec.rb' - 'spec/models/concerns/triggerable_hooks_spec.rb' - - 'spec/models/concerns/uniquify_spec.rb' - 'spec/models/concerns/usage_statistics_spec.rb' - 'spec/models/concerns/vulnerability_finding_helpers_spec.rb' - 'spec/models/concerns/vulnerability_finding_signature_helpers_spec.rb' diff --git a/app/models/concerns/has_unique_internal_users.rb b/app/models/concerns/has_unique_internal_users.rb index 4d60cfa03b075833f806c10f54993f811da30757..25b56f6d70f6d39e31986c9cfbf0a33009f5438e 100644 --- a/app/models/concerns/has_unique_internal_users.rb +++ b/app/models/concerns/has_unique_internal_users.rb @@ -28,7 +28,7 @@ def create_unique_internal(scope, username, email_pattern, &creation_block) existing_user = uncached { scope.first } return existing_user if existing_user.present? - uniquify = Uniquify.new + uniquify = Gitlab::Utils::Uniquify.new username = uniquify.string(username) { |s| User.find_by_username(s) } diff --git a/app/models/concerns/uniquify.rb b/app/models/concerns/uniquify.rb deleted file mode 100644 index 382e826ec584f466e589158b3643c92e63be1a2b..0000000000000000000000000000000000000000 --- a/app/models/concerns/uniquify.rb +++ /dev/null @@ -1,40 +0,0 @@ -# frozen_string_literal: true - -# Uniquify -# -# Return a version of the given 'base' string that is unique -# by appending a counter to it. Uniqueness is determined by -# repeated calls to the passed block. -# -# You can pass an initial value for the counter, if not given -# counting starts from 1. -# -# If `base` is a function/proc, we expect that calling it with a -# candidate counter returns a string to test/return. -class Uniquify - def initialize(counter = nil) - @counter = counter - end - - def string(base) - @base = base - - increment_counter! while yield(base_string) - base_string - end - - private - - def base_string - if @base.respond_to?(:call) - @base.call(@counter) - else - "#{@base}#{@counter}" - end - end - - def increment_counter! - @counter ||= 0 - @counter += 1 - end -end diff --git a/app/models/issue.rb b/app/models/issue.rb index bea86168c8ddafed775fc6c2e848a379a642269b..483bfca259ccfd489381e89062338214c7d005b4 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -463,7 +463,7 @@ def suggested_branch_name "#{to_branch_name}-#{suffix}" end - Uniquify.new(start_counting_from).string(branch_name_generator) do |suggested_branch_name| + Gitlab::Utils::Uniquify.new(start_counting_from).string(branch_name_generator) do |suggested_branch_name| project.repository.branch_exists?(suggested_branch_name) end end diff --git a/app/models/namespace.rb b/app/models/namespace.rb index c3bff24cb1af96ec65add83eb85ca9333486eb14..252fb9aa3088840b87043cba77e7d69cfc3b66fe 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -244,7 +244,7 @@ def search(query, include_parents: false) def clean_path(path, limited_to: Namespace.all) slug = Gitlab::Slug::Path.new(path).generate path = Namespaces::RandomizedSuffixPath.new(slug) - Uniquify.new.string(path) { |s| limited_to.find_by_path_or_name(s) } + Gitlab::Utils::Uniquify.new.string(path) { |s| limited_to.find_by_path_or_name(s) } end def clean_name(value) diff --git a/app/services/resource_access_tokens/create_service.rb b/app/services/resource_access_tokens/create_service.rb index c6948536053cec993dd1c7254e7ad9889fc985fc..f122fea6967c9d4d078c7b28876c1f0c08ad5ada 100644 --- a/app/services/resource_access_tokens/create_service.rb +++ b/app/services/resource_access_tokens/create_service.rb @@ -85,7 +85,7 @@ def generate_email end def uniquify - Uniquify.new + Gitlab::Utils::Uniquify.new end def create_personal_access_token(user) diff --git a/ee/app/controllers/groups/sso_controller.rb b/ee/app/controllers/groups/sso_controller.rb index 77f65858ff2c804f7cbd72992923edf040add904..c713e0ae03bb8a3901a32fce8e24cc8cdefbea6e 100644 --- a/ee/app/controllers/groups/sso_controller.rb +++ b/ee/app/controllers/groups/sso_controller.rb @@ -95,7 +95,7 @@ def new_user_params def generate_unique_username username = ::Namespace.clean_path(oauth_data.username) - Uniquify.new.string(username) { |s| !NamespacePathValidator.valid_path?(s) } + ::Gitlab::Utils::Uniquify.new.string(username) { |s| !NamespacePathValidator.valid_path?(s) } end def check_oauth_data diff --git a/ee/lib/ee/gitlab/scim/base_provisioning_service.rb b/ee/lib/ee/gitlab/scim/base_provisioning_service.rb index d3c5a6d594d880de4b99345802c9a633b3402b12..b6552b796a166a660031864ef538046beb5eed4d 100644 --- a/ee/lib/ee/gitlab/scim/base_provisioning_service.rb +++ b/ee/lib/ee/gitlab/scim/base_provisioning_service.rb @@ -35,7 +35,7 @@ def random_password def valid_username clean_username = ::Namespace.clean_path(@parsed_hash[:username]) - Uniquify.new.string(clean_username) { |s| !NamespacePathValidator.valid_path?(s) } + ::Gitlab::Utils::Uniquify.new.string(clean_username) { |s| !NamespacePathValidator.valid_path?(s) } end def missing_params diff --git a/lib/bulk_imports/groups/transformers/group_attributes_transformer.rb b/lib/bulk_imports/groups/transformers/group_attributes_transformer.rb index 19993629ff5a9702414f2f3c6371df6a07e8e569..18ef460385c5d867c336eb5765e2b7746faad519 100644 --- a/lib/bulk_imports/groups/transformers/group_attributes_transformer.rb +++ b/lib/bulk_imports/groups/transformers/group_attributes_transformer.rb @@ -65,9 +65,10 @@ def group_name(namespace, data) namespace_children_names = namespace.children.pluck(:name) # rubocop: disable CodeReuse/ActiveRecord if namespace_children_names.include?(data['name']) - data['name'] = Uniquify.new(1).string(-> (counter) { "#{data['name']}(#{counter})" }) do |base| - namespace_children_names.include?(base) - end + data['name'] = + Gitlab::Utils::Uniquify.new(1).string(-> (counter) { "#{data['name']}(#{counter})" }) do |base| + namespace_children_names.include?(base) + end end end diff --git a/lib/gitlab/auth/o_auth/user.rb b/lib/gitlab/auth/o_auth/user.rb index 01e126ec2f59431d084982c21fdd6d6e131ae166..bb47b4236fb919d49ae40b28e8eea88d57b55ea4 100644 --- a/lib/gitlab/auth/o_auth/user.rb +++ b/lib/gitlab/auth/o_auth/user.rb @@ -233,7 +233,7 @@ def user_attributes email ||= auth_hash.email valid_username = ::Namespace.clean_path(username) - valid_username = Uniquify.new.string(valid_username) { |s| !NamespacePathValidator.valid_path?(s) } + valid_username = Gitlab::Utils::Uniquify.new.string(valid_username) { |s| !NamespacePathValidator.valid_path?(s) } { name: name.strip.presence || valid_username, diff --git a/lib/gitlab/utils/uniquify.rb b/lib/gitlab/utils/uniquify.rb new file mode 100644 index 0000000000000000000000000000000000000000..b5908d181035d85e6ed31690f8151c01a359e6f6 --- /dev/null +++ b/lib/gitlab/utils/uniquify.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +# Uniquify +# +# Return a version of the given 'base' string that is unique +# by appending a counter to it. Uniqueness is determined by +# repeated calls to the passed block. +# +# You can pass an initial value for the counter, if not given +# counting starts from 1. +# +# If `base` is a function/proc, we expect that calling it with a +# candidate counter returns a string to test/return. + +module Gitlab + module Utils + class Uniquify + def initialize(counter = nil) + @counter = counter + end + + def string(base) + @base = base + + increment_counter! while yield(base_string) + base_string + end + + private + + def base_string + if @base.respond_to?(:call) + @base.call(@counter) + else + "#{@base}#{@counter}" + end + end + + def increment_counter! + @counter ||= 0 + @counter += 1 + end + end + end +end diff --git a/spec/models/concerns/uniquify_spec.rb b/spec/lib/gitlab/utils/uniquify_spec.rb similarity index 79% rename from spec/models/concerns/uniquify_spec.rb rename to spec/lib/gitlab/utils/uniquify_spec.rb index 9b79e4d415438bbc4aef01d6fecd30a802283a5b..df02fbe8c82970f30b5ca64fa1c4dc6307ae764d 100644 --- a/spec/models/concerns/uniquify_spec.rb +++ b/spec/lib/gitlab/utils/uniquify_spec.rb @@ -1,13 +1,13 @@ # frozen_string_literal: true -require 'spec_helper' +require 'fast_spec_helper' -RSpec.describe Uniquify do - let(:uniquify) { described_class.new } +RSpec.describe Gitlab::Utils::Uniquify, feature_category: :shared do + subject(:uniquify) { described_class.new } describe "#string" do it 'returns the given string if it does not exist' do - result = uniquify.string('test_string') { |s| false } + result = uniquify.string('test_string') { |_s| false } expect(result).to eq('test_string') end @@ -34,7 +34,7 @@ end it 'allows passing in a base function that defines the location of the counter' do - result = uniquify.string(-> (counter) { "test_#{counter}_string" }) do |s| + result = uniquify.string(->(counter) { "test_#{counter}_string" }) do |s| s == 'test__string' end diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml index 7aa7d8e8abd3bc98ae8d1de5d39b4dc302132c81..d6c310d25f25c0ef32be146d0df8866463b6ebd9 100644 --- a/spec/support/rspec_order_todo.yml +++ b/spec/support/rspec_order_todo.yml @@ -7956,7 +7956,6 @@ - './spec/models/concerns/token_authenticatable_strategies/encryption_helper_spec.rb' - './spec/models/concerns/transactions_spec.rb' - './spec/models/concerns/triggerable_hooks_spec.rb' -- './spec/models/concerns/uniquify_spec.rb' - './spec/models/concerns/usage_statistics_spec.rb' - './spec/models/concerns/vulnerability_finding_helpers_spec.rb' - './spec/models/concerns/vulnerability_finding_signature_helpers_spec.rb'