Commit d262a196 authored by Peter Leitzen's avatar Peter Leitzen

Merge branch '277162-regexp-support-for-search_files_by_name' into 'master'

Implement wildcard support for file searching in repository

See merge request gitlab-org/gitlab!55871
parents c7e98083 d634a988
...@@ -995,6 +995,12 @@ class Repository ...@@ -995,6 +995,12 @@ class Repository
raw_repository.search_files_by_name(query, ref) raw_repository.search_files_by_name(query, ref)
end end
def search_files_by_wildcard_path(path, ref = 'HEAD')
# We need to use RE2 to match Gitaly's regexp engine
regexp_string = RE2::Regexp.escape(path).gsub('\*', '.*?')
raw_repository.search_files_by_regexp("^#{regexp_string}$", ref)
end
def copy_gitattributes(ref) def copy_gitattributes(ref)
actual_ref = ref || root_ref actual_ref = ref || root_ref
begin begin
......
...@@ -1017,6 +1017,10 @@ module Gitlab ...@@ -1017,6 +1017,10 @@ module Gitlab
gitaly_repository_client.search_files_by_name(ref, safe_query) gitaly_repository_client.search_files_by_name(ref, safe_query)
end end
def search_files_by_regexp(filter, ref = 'HEAD')
gitaly_repository_client.search_files_by_regexp(ref, filter)
end
def find_commits_by_message(query, ref, path, limit, offset) def find_commits_by_message(query, ref, path, limit, offset)
wrapped_gitaly_errors do wrapped_gitaly_errors do
gitaly_commit_client gitaly_commit_client
......
...@@ -339,6 +339,11 @@ module Gitlab ...@@ -339,6 +339,11 @@ module Gitlab
search_results_from_response(response, options) search_results_from_response(response, options)
end end
def search_files_by_regexp(ref, filter)
request = Gitaly::SearchFilesByNameRequest.new(repository: @gitaly_repo, ref: ref, query: '.', filter: filter)
GitalyClient.call(@storage, :repository_service, :search_files_by_name, request, timeout: GitalyClient.fast_timeout).flat_map(&:files)
end
def disconnect_alternates def disconnect_alternates
request = Gitaly::DisconnectGitAlternatesRequest.new( request = Gitaly::DisconnectGitAlternatesRequest.new(
repository: @gitaly_repo repository: @gitaly_repo
......
...@@ -564,6 +564,41 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do ...@@ -564,6 +564,41 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
end end
end end
describe '#search_files_by_regexp' do
let(:ref) { 'master' }
subject(:result) { mutable_repository.search_files_by_regexp(filter, ref) }
context 'when sending a valid regexp' do
let(:filter) { 'files\/.*\/.*\.rb' }
it 'returns matched files' do
expect(result).to contain_exactly('files/links/regex.rb',
'files/ruby/popen.rb',
'files/ruby/regex.rb',
'files/ruby/version_info.rb')
end
end
context 'when sending an ivalid regexp' do
let(:filter) { '*.rb' }
it 'raises error' do
expect { result }.to raise_error(GRPC::InvalidArgument,
/missing argument to repetition operator: `*`/)
end
end
context "when the ref doesn't exist" do
let(:filter) { 'files\/.*\/.*\.rb' }
let(:ref) { 'non-existing-branch' }
it 'returns an empty array' do
expect(result).to eq([])
end
end
end
describe '#find_remote_root_ref' do describe '#find_remote_root_ref' do
it 'gets the remote root ref from GitalyClient' do it 'gets the remote root ref from GitalyClient' do
expect_any_instance_of(Gitlab::GitalyClient::RemoteService) expect_any_instance_of(Gitlab::GitalyClient::RemoteService)
......
...@@ -246,6 +246,21 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do ...@@ -246,6 +246,21 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do
end end
end end
describe '#search_files_by_regexp' do
subject(:result) { client.search_files_by_regexp('master', '.*') }
before do
expect_any_instance_of(Gitaly::RepositoryService::Stub)
.to receive(:search_files_by_name)
.with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
.and_return([double(files: ['file1.txt']), double(files: ['file2.txt'])])
end
it 'sends a search_files_by_name message and returns a flatten array' do
expect(result).to contain_exactly('file1.txt', 'file2.txt')
end
end
describe '#disconnect_alternates' do describe '#disconnect_alternates' do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:repository) { project.repository } let(:repository) { project.repository }
......
...@@ -977,6 +977,57 @@ RSpec.describe Repository do ...@@ -977,6 +977,57 @@ RSpec.describe Repository do
end end
end end
describe '#search_files_by_wildcard_path' do
let(:ref) { 'master' }
subject(:result) { repository.search_files_by_wildcard_path(path, ref) }
context 'when specifying a normal path' do
let(:path) { 'files/images/logo-black.png' }
it 'returns the path' do
expect(result).to eq(['files/images/logo-black.png'])
end
end
context 'when specifying a path with wildcard' do
let(:path) { 'files/*/*.png' }
it 'returns all files matching the path' do
expect(result).to contain_exactly('files/images/logo-black.png',
'files/images/logo-white.png')
end
end
context 'when specifying an extension with wildcard' do
let(:path) { '*.rb' }
it 'returns all files matching the extension' do
expect(result).to contain_exactly('encoding/russian.rb',
'files/ruby/popen.rb',
'files/ruby/regex.rb',
'files/ruby/version_info.rb')
end
end
context 'when sending regexp' do
let(:path) { '.*\.rb' }
it 'ignores the regexp and returns an empty array' do
expect(result).to eq([])
end
end
context 'when sending another ref' do
let(:path) { 'files' }
let(:ref) { 'other-branch' }
it 'returns an empty array' do
expect(result).to eq([])
end
end
end
describe '#async_remove_remote' do describe '#async_remove_remote' do
before do before do
masterrev = repository.find_branch('master').dereferenced_target masterrev = repository.find_branch('master').dereferenced_target
......
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