Commit 8cc25e55 authored by Kerri Miller's avatar Kerri Miller

Add #sectional_entry_for_path for path

Additionally extracts tests into shared_examples and standardizes the
response as an array, rather than a bare entry or nil.
parent 69b4dba6
......@@ -19,13 +19,30 @@ module Gitlab
end
def entry_for_path(path)
return sectional_entry_for_path(path) if sectional_codeowners?
path = "/#{path}" unless path.start_with?('/')
matching_pattern = parsed_data.keys.reverse.detect do |pattern|
path_matches?(pattern, path)
end
parsed_data[matching_pattern].dup if matching_pattern
matching_pattern ? [parsed_data[matching_pattern].dup] : []
end
def sectional_entry_for_path(path)
path = "/#{path}" unless path.start_with?('/')
matches = []
parsed_data.each do |_, section_entries|
matching_pattern = section_entries.keys.reverse.detect do |pattern|
path_matches?(pattern, path)
end
matches << section_entries[matching_pattern].dup if matching_pattern
end
matches
end
def path
......
......@@ -143,138 +143,157 @@ describe Gitlab::CodeOwners::File do
end
describe '#entry_for_path' do
context 'for a path without matches' do
let(:file_content) do
<<~CONTENT
# Simulating a CODOWNERS without entries
CONTENT
shared_examples_for "returns expected matches" do
context 'for a path without matches' do
let(:file_content) do
<<~CONTENT
# Simulating a CODOWNERS without entries
CONTENT
end
it 'returns an empty array for an unmatched path' do
entry = file.entry_for_path('no_matches')
expect(entry).to be_a Array
expect(entry).to be_empty
end
end
it 'returns an nil for an unmatched path' do
entry = file.entry_for_path('no_matches')
it 'matches random files to a pattern' do
entry = file.entry_for_path('app/assets/something.vue').first
expect(entry).to be_nil
expect(entry.pattern).to eq('*')
expect(entry.owner_line).to include('default-codeowner')
end
end
it 'matches random files to a pattern' do
entry = file.entry_for_path('app/assets/something.vue')
it 'uses the last pattern if multiple patterns match' do
entry = file.entry_for_path('hello.rb').first
expect(entry.pattern).to eq('*')
expect(entry.owner_line).to include('default-codeowner')
end
expect(entry.pattern).to eq('*.rb')
expect(entry.owner_line).to eq('@ruby-owner')
end
it 'uses the last pattern if multiple patterns match' do
entry = file.entry_for_path('hello.rb')
it 'returns the usernames for a file matching a pattern with a glob' do
entry = file.entry_for_path('app/models/repository.rb').first
expect(entry.pattern).to eq('*.rb')
expect(entry.owner_line).to eq('@ruby-owner')
end
expect(entry.owner_line).to eq('@ruby-owner')
end
it 'returns the usernames for a file matching a pattern with a glob' do
entry = file.entry_for_path('app/models/repository.rb')
it 'allows specifying multiple users' do
entry = file.entry_for_path('CODEOWNERS').first
expect(entry.owner_line).to eq('@ruby-owner')
end
expect(entry.owner_line).to include('multiple', 'owners', 'tab-separated')
end
it 'allows specifying multiple users' do
entry = file.entry_for_path('CODEOWNERS')
it 'returns emails and usernames for a matched pattern' do
entry = file.entry_for_path('LICENSE').first
expect(entry.owner_line).to include('multiple', 'owners', 'tab-separated')
end
expect(entry.owner_line).to include('legal', 'janedoe@gitlab.com')
end
it 'returns emails and usernames for a matched pattern' do
entry = file.entry_for_path('LICENSE')
it 'allows escaping the pound sign used for comments' do
entry = file.entry_for_path('examples/#file_with_pound.rb').first
expect(entry.owner_line).to include('legal', 'janedoe@gitlab.com')
end
expect(entry.owner_line).to include('owner-file-with-pound')
end
it 'allows escaping the pound sign used for comments' do
entry = file.entry_for_path('examples/#file_with_pound.rb')
it 'returns the usernames for a file nested in a directory' do
entry = file.entry_for_path('docs/projects/index.md').first
expect(entry.owner_line).to include('owner-file-with-pound')
end
expect(entry.owner_line).to include('all-docs')
end
it 'returns the usernames for a file nested in a directory' do
entry = file.entry_for_path('docs/projects/index.md')
it 'returns the usernames for a pattern matched with a glob in a folder' do
entry = file.entry_for_path('docs/index.md').first
expect(entry.owner_line).to include('all-docs')
end
expect(entry.owner_line).to include('root-docs')
end
it 'returns the usernames for a pattern matched with a glob in a folder' do
entry = file.entry_for_path('docs/index.md')
it 'allows matching files nested anywhere in the repository', :aggregate_failures do
lib_entry = file.entry_for_path('lib/gitlab/git/repository.rb').first
other_lib_entry = file.entry_for_path('ee/lib/gitlab/git/repository.rb').first
expect(entry.owner_line).to include('root-docs')
end
expect(lib_entry.owner_line).to include('lib-owner')
expect(other_lib_entry.owner_line).to include('lib-owner')
end
it 'allows matching files nested anywhere in the repository', :aggregate_failures do
lib_entry = file.entry_for_path('lib/gitlab/git/repository.rb')
other_lib_entry = file.entry_for_path('ee/lib/gitlab/git/repository.rb')
it 'allows allows limiting the matching files to the root of the repository', :aggregate_failures do
config_entry = file.entry_for_path('config/database.yml').first
other_config_entry = file.entry_for_path('other/config/database.yml').first
expect(lib_entry.owner_line).to include('lib-owner')
expect(other_lib_entry.owner_line).to include('lib-owner')
end
expect(config_entry.owner_line).to include('config-owner')
expect(other_config_entry.owner_line).to eq('@default-codeowner')
end
it 'allows allows limiting the matching files to the root of the repository', :aggregate_failures do
config_entry = file.entry_for_path('config/database.yml')
other_config_entry = file.entry_for_path('other/config/database.yml')
it 'correctly matches paths with spaces' do
entry = file.entry_for_path('path with spaces/README.md').first
expect(config_entry.owner_line).to include('config-owner')
expect(other_config_entry.owner_line).to eq('@default-codeowner')
end
expect(entry.owner_line).to eq('@space-owner')
end
it 'correctly matches paths with spaces' do
entry = file.entry_for_path('path with spaces/README.md')
context 'paths with whitespaces and username lookalikes' do
let(:file_content) do
'a/weird\ path\ with/\ @username\ /\ and-email@lookalikes.com\ / @user-1 email@gitlab.org @user-2'
end
expect(entry.owner_line).to eq('@space-owner')
end
it 'parses correctly' do
entry = file.entry_for_path('a/weird path with/ @username / and-email@lookalikes.com /test.rb').first
context 'paths with whitespaces and username lookalikes' do
let(:file_content) do
'a/weird\ path\ with/\ @username\ /\ and-email@lookalikes.com\ / @user-1 email@gitlab.org @user-2'
expect(entry.owner_line).to include('user-1', 'user-2', 'email@gitlab.org')
expect(entry.owner_line).not_to include('username', 'and-email@lookalikes.com')
end
end
it 'parses correctly' do
entry = file.entry_for_path('a/weird path with/ @username / and-email@lookalikes.com /test.rb')
context 'a glob on the root directory' do
let(:file_content) do
'/* @user-1 @user-2'
end
expect(entry.owner_line).to include('user-1', 'user-2', 'email@gitlab.org')
expect(entry.owner_line).not_to include('username', 'and-email@lookalikes.com')
end
end
it 'matches files in the root directory' do
entry = file.entry_for_path('README.md').first
context 'a glob on the root directory' do
let(:file_content) do
'/* @user-1 @user-2'
end
expect(entry.owner_line).to include('user-1', 'user-2')
end
it 'matches files in the root directory' do
entry = file.entry_for_path('README.md')
it 'does not match nested files' do
entry = file.entry_for_path('nested/path/README.md').first
expect(entry.owner_line).to include('user-1', 'user-2')
end
expect(entry).to be_nil
end
it 'does not match nested files' do
entry = file.entry_for_path('nested/path/README.md')
context 'partial matches' do
let(:file_content) do
'foo/* @user-1 @user-2'
end
it 'does not match a file in a folder that looks the same' do
entry = file.entry_for_path('fufoo/bar').first
expect(entry).to be_nil
end
expect(entry).to be_nil
it 'matches the file in any folder' do
expect(file.entry_for_path('baz/foo/bar').first.owner_line).to include('user-1', 'user-2')
expect(file.entry_for_path('/foo/bar').first.owner_line).to include('user-1', 'user-2')
end
end
end
end
context 'partial matches' do
let(:file_content) do
'foo/* @user-1 @user-2'
context "when feature flag `:sectional_codeowners` is enabled" do
before do
stub_feature_flags(sectional_codeowners: true)
end
it 'does not match a file in a folder that looks the same' do
entry = file.entry_for_path('fufoo/bar')
it_behaves_like "returns expected matches"
end
expect(entry).to be_nil
context "when feature flag `:sectional_codeowners` is disabled" do
before do
stub_feature_flags(sectional_codeowners: false)
end
it 'matches the file in any folder' do
expect(file.entry_for_path('baz/foo/bar').owner_line).to include('user-1', 'user-2')
expect(file.entry_for_path('/foo/bar').owner_line).to include('user-1', 'user-2')
end
it_behaves_like "returns expected matches"
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