diff --git a/app/models/repository.rb b/app/models/repository.rb index 2ffd9558ebc..66869d0539b 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -932,7 +932,7 @@ class Repository return [] if empty? || query.blank? offset = 2 - args = %W(grep -i -I -n --before-context #{offset} --after-context #{offset} -E -e #{Regexp.escape(query)} #{ref || root_ref}) + args = %W(grep -i -I -n -z --before-context #{offset} --after-context #{offset} -E -e #{Regexp.escape(query)} #{ref || root_ref}) run_git(args).first.scrub.split(/^--$/) end diff --git a/changelogs/unreleased/41666-cannot-search-with-keyword-merge.yml b/changelogs/unreleased/41666-cannot-search-with-keyword-merge.yml new file mode 100644 index 00000000000..3a6fa425c9c --- /dev/null +++ b/changelogs/unreleased/41666-cannot-search-with-keyword-merge.yml @@ -0,0 +1,6 @@ +--- +title: Fix file search results when they match file contents with a number between + two colons +merge_request: 16462 +author: +type: fixed diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb index e2662fc362b..7771b15069b 100644 --- a/lib/gitlab/project_search_results.rb +++ b/lib/gitlab/project_search_results.rb @@ -44,25 +44,20 @@ module Gitlab ref = nil filename = nil basename = nil + data = "" startline = 0 - result.each_line.each_with_index do |line, index| - matches = line.match(/^(?[^:]*):(?.*):(?\d+):/) - if matches + result.strip.each_line.each_with_index do |line, index| + prefix ||= line.match(/^(?[^:]*):(?.*)\x00(?\d+)\x00/)&.tap do |matches| ref = matches[:ref] filename = matches[:filename] startline = matches[:startline] startline = startline.to_i - index extname = Regexp.escape(File.extname(filename)) basename = filename.sub(/#{extname}$/, '') - break end - end - data = "" - - result.each_line do |line| - data << line.sub(ref, '').sub(filename, '').sub(/^:-\d+-/, '').sub(/^::\d+:/, '') + data << line.sub(prefix.to_s, '') end FoundBlob.new( diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb index 17937726f2c..1ebb0105cf5 100644 --- a/spec/lib/gitlab/project_search_results_spec.rb +++ b/spec/lib/gitlab/project_search_results_spec.rb @@ -70,15 +70,6 @@ describe Gitlab::ProjectSearchResults do subject { described_class.parse_search_result(search_result) } - it 'can correctly parse filenames including ":"' do - special_char_result = "\nmaster:testdata/project::function1.yaml-1----\nmaster:testdata/project::function1.yaml:2:test: data1\n" - - blob = described_class.parse_search_result(special_char_result) - - expect(blob.ref).to eq('master') - expect(blob.filename).to eq('testdata/project::function1.yaml') - end - it "returns a valid FoundBlob" do is_expected.to be_an Gitlab::SearchResults::FoundBlob expect(subject.id).to be_nil @@ -90,8 +81,32 @@ describe Gitlab::ProjectSearchResults do expect(subject.data.lines[2]).to eq(" - Feature: Replace teams with group membership\n") end + context 'when the matching filename contains a colon' do + let(:search_result) { "\nmaster:testdata/project::function1.yaml\x001\x00---\n" } + + it 'returns a valid FoundBlob' do + expect(subject.filename).to eq('testdata/project::function1.yaml') + expect(subject.basename).to eq('testdata/project::function1') + expect(subject.ref).to eq('master') + expect(subject.startline).to eq(1) + expect(subject.data).to eq('---') + end + end + + context 'when the matching content contains a number surrounded by colons' do + let(:search_result) { "\nmaster:testdata/foo.txt\x001\x00blah:9:blah" } + + it 'returns a valid FoundBlob' do + expect(subject.filename).to eq('testdata/foo.txt') + expect(subject.basename).to eq('testdata/foo') + expect(subject.ref).to eq('master') + expect(subject.startline).to eq(1) + expect(subject.data).to eq('blah:9:blah') + end + end + context "when filename has extension" do - let(:search_result) { "master:CONTRIBUTE.md:5:- [Contribute to GitLab](#contribute-to-gitlab)\n" } + let(:search_result) { "master:CONTRIBUTE.md\x005\x00- [Contribute to GitLab](#contribute-to-gitlab)\n" } it { expect(subject.path).to eq('CONTRIBUTE.md') } it { expect(subject.filename).to eq('CONTRIBUTE.md') } @@ -99,7 +114,7 @@ describe Gitlab::ProjectSearchResults do end context "when file under directory" do - let(:search_result) { "master:a/b/c.md:5:a b c\n" } + let(:search_result) { "master:a/b/c.md\x005\x00a b c\n" } it { expect(subject.path).to eq('a/b/c.md') } it { expect(subject.filename).to eq('a/b/c.md') } @@ -144,7 +159,7 @@ describe Gitlab::ProjectSearchResults do end it 'finds by content' do - expect(results).to include("master:Title.md:1:Content\n") + expect(results).to include("master:Title.md\x001\x00Content\n") end end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index f3456e5b354..7e215e37de3 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -657,7 +657,7 @@ describe Repository do subject { results.first } it { is_expected.to be_an String } - it { expect(subject.lines[2]).to eq("master:CHANGELOG:190: - Feature: Replace teams with group membership\n") } + it { expect(subject.lines[2]).to eq("master:CHANGELOG\x00190\x00 - Feature: Replace teams with group membership\n") } end end