Commit 4eb9765e authored by Alex Kalderimis's avatar Alex Kalderimis

Refactor identifier parsing

This applies OO principles to simplify indentifier parsing, representing
the two syntaxes with two subclasses of indentifier representation.
parent 6b967a8f
...@@ -43,10 +43,10 @@ module Gitlab ...@@ -43,10 +43,10 @@ module Gitlab
end end
def self.parse(gl_repository) def self.parse(gl_repository)
result = ::Gitlab::GlRepository::Identifier.new(gl_repository) identifier = ::Gitlab::GlRepository::Identifier.parse(gl_repository)
repo_type = result.repo_type repo_type = identifier.repo_type
container = result.fetch_container! container = identifier.container
[container, repo_type.project_for(container), repo_type] [container, repo_type.project_for(container), repo_type]
end end
......
...@@ -3,39 +3,51 @@ ...@@ -3,39 +3,51 @@
module Gitlab module Gitlab
class GlRepository class GlRepository
class Identifier class Identifier
attr_reader :gl_repository, :repo_type IllegalIdentifier = Class.new(ArgumentError)
def initialize(gl_repository) def self.parse(gl_repository_str)
@gl_repository = gl_repository segments = gl_repository_str&.split('-')
@segments = gl_repository.split('-')
# gl_repository can either have 2 or 3 segments:
raise_error if segments.size > 3 # "wiki-1" is the older 2-segment format, where container is implied.
# "group-1-wiki" is the newer 3-segment format, including container information.
@repo_type = find_repo_type #
@container_id = find_container_id # TODO: convert all 2-segment format to 3-segment:
@container_class = find_container_class # https://gitlab.com/gitlab-org/gitlab/-/issues/219192
end case segments&.size
when 2
def fetch_container! TwoPartIdentifier.new(gl_repository_str, *segments)
container_class.find_by_id(container_id) when 3
ThreePartIdentifier.new(gl_repository_str, *segments)
else
raise IllegalIdentifier, %Q(Invalid GL Repository "#{gl_repository_str}")
end
end end
private class TwoPartIdentifier < Identifier
def initialize(gl_repository_str, repo_type_name, container_id_str)
attr_reader :segments, :container_class, :container_id @gl_repository_str = gl_repository_str
@repo_type_name = repo_type_name
@container_id_str = container_id_str
end
def find_repo_type def container_class
type_name = three_segments_format? ? segments.last : segments.first repo_type.container_class
type = Gitlab::GlRepository.types[type_name] end
end
raise_error unless type class ThreePartIdentifier < Identifier
attr_reader :container_type
type def initialize(gl_repository_str, container_type, container_id_str, repo_type_name)
end @gl_repository_str = gl_repository_str
@container_type = container_type
@container_id_str = container_id_str
@repo_type_name = repo_type_name
end
def find_container_class def container_class
if three_segments_format? case container_type
case segments[0]
when 'project' when 'project'
Project Project
when 'group' when 'group'
...@@ -43,31 +55,27 @@ module Gitlab ...@@ -43,31 +55,27 @@ module Gitlab
else else
raise_error raise_error
end end
else
repo_type.container_class
end end
end end
def find_container_id def container
id = Integer(segments[1], 10, exception: false) @container ||= container_class.find_by_id(container_id)
end
raise_error unless id
id def repo_type
@repo_type ||= (Gitlab::GlRepository.types[repo_type_name] || raise_error)
end end
# gl_repository can either have 2 or 3 segments: private
# "wiki-1" is the older 2-segment format, where container is implied.
# "group-1-wiki" is the newer 3-segment format, including container information. attr_reader :gl_repository_str, :container_id_str, :repo_type_name
#
# TODO: convert all 2-segment format to 3-segment: def container_id
# https://gitlab.com/gitlab-org/gitlab/-/issues/219192 Integer(container_id_str, 10, exception: false) || raise_error
def three_segments_format?
segments.size == 3
end end
def raise_error def raise_error
raise ArgumentError, "Invalid GL Repository \"#{gl_repository}\"" raise IllegalIdentifier, %Q(Invalid GL Repository "#{gl_repository_str}")
end end
end end
end end
......
...@@ -54,29 +54,19 @@ describe Gitlab::GlRepository::Identifier do ...@@ -54,29 +54,19 @@ describe Gitlab::GlRepository::Identifier do
end end
end end
describe 'incorrect format' do context 'when the format is incorrect' do
def expect_error_raised_for(identifier) where(:identifier) do
expect { described_class.new(identifier) }.to raise_error(ArgumentError) [
'wiki-noid',
'foo-2',
'snippet-2-wiki',
'snippet',
'project-1-wiki-bar'
]
end end
it 'raises error for incorrect id' do with_them do
expect_error_raised_for('wiki-noid') it_behaves_like 'illegal gl_identifier'
end
it 'raises error for incorrect type' do
expect_error_raised_for('foo-2')
end
it 'raises error for incorrect three-segment container' do
expect_error_raised_for('snippet-2-wiki')
end
it 'raises error for one segment' do
expect_error_raised_for('snippet')
end
it 'raises error for more than three segments' do
expect_error_raised_for('project-1-wiki-bar')
end end
end end
end end
# frozen_string_literal: true # frozen_string_literal: true
RSpec.shared_examples 'parsing gl_repository identifier' do RSpec.shared_examples 'parsing gl_repository identifier' do
subject { described_class.new(identifier) } subject { described_class.parse(identifier) }
it 'returns correct information' do it 'returns correct information' do
aggregate_failures do expect(subject).to have_attributes(
expect(subject.repo_type).to eq(expected_type) repo_type: expected_type,
expect(subject.fetch_container!).to eq(expected_container) container: expected_container
)
end
end
RSpec.shared_examples 'illegal gl_identifier' do
subject do
described_class.parse(identifier).tap do |ident|
ident.repo_type
ident.container
end end
end end
it 'raises an error' do
expect { subject }.to raise_error(described_class::IllegalIdentifier)
end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment