Add ability to search wiki titles
This commit is contained in:
parent
0b4f9ff406
commit
7350eb1fa8
14 changed files with 159 additions and 107 deletions
|
@ -25,14 +25,22 @@ module SearchHelper
|
|||
return unless collection.count > 0
|
||||
|
||||
from = collection.offset_value + 1
|
||||
to = collection.offset_value + collection.length
|
||||
to = collection.offset_value + collection.count
|
||||
count = collection.total_count
|
||||
|
||||
"Showing #{from} - #{to} of #{count} #{scope.humanize(capitalize: false)} for \"#{term}\""
|
||||
end
|
||||
|
||||
def find_project_for_result_blob(result)
|
||||
@project
|
||||
end
|
||||
|
||||
def parse_search_result(result)
|
||||
Gitlab::ProjectSearchResults.parse_search_result(result)
|
||||
result
|
||||
end
|
||||
|
||||
def search_blob_title(project, filename)
|
||||
filename
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -140,10 +140,6 @@ class ProjectWiki
|
|||
[title, title_array.join("/")]
|
||||
end
|
||||
|
||||
def search_files(query)
|
||||
repository.search_files_by_content(query, default_branch)
|
||||
end
|
||||
|
||||
def repository
|
||||
@repository ||= Repository.new(full_path, @project, disk_path: disk_path, is_wiki: true)
|
||||
end
|
||||
|
|
|
@ -1,13 +1,5 @@
|
|||
- file_name, blob = blob
|
||||
.blob-result
|
||||
.file-holder
|
||||
.js-file-title.file-title
|
||||
- ref = @search_results.repository_ref
|
||||
- blob_link = project_blob_path(@project, tree_join(ref, file_name))
|
||||
= link_to blob_link do
|
||||
%i.fa.fa-file
|
||||
%strong
|
||||
= file_name
|
||||
- if blob
|
||||
.file-content.code.term
|
||||
= render 'shared/file_highlight', blob: blob, first_line_number: blob.startline, blob_link: blob_link
|
||||
- project = find_project_for_result_blob(blob)
|
||||
- file_name, blob = parse_search_result(blob)
|
||||
- blob_link = project_blob_path(project, tree_join(blob.ref, file_name))
|
||||
|
||||
= render partial: 'search/results/blob_data', locals: { blob: blob, project: project, file_name: file_name, blob_link: blob_link }
|
||||
|
|
9
app/views/search/results/_blob_data.html.haml
Normal file
9
app/views/search/results/_blob_data.html.haml
Normal file
|
@ -0,0 +1,9 @@
|
|||
.blob-result
|
||||
.file-holder
|
||||
.js-file-title.file-title
|
||||
= link_to blob_link do
|
||||
%i.fa.fa-file
|
||||
= search_blob_title(project, file_name)
|
||||
- if blob.data
|
||||
.file-content.code.term
|
||||
= render 'shared/file_highlight', blob: blob, first_line_number: blob.startline
|
|
@ -1,10 +1,5 @@
|
|||
- wiki_blob = parse_search_result(wiki_blob)
|
||||
.blob-result
|
||||
.file-holder
|
||||
.js-file-title.file-title
|
||||
= link_to project_wiki_path(@project, wiki_blob.basename) do
|
||||
%i.fa.fa-file
|
||||
%strong
|
||||
= wiki_blob.basename
|
||||
.file-content.code.term
|
||||
= render 'shared/file_highlight', blob: wiki_blob, first_line_number: wiki_blob.startline
|
||||
- project = find_project_for_result_blob(wiki_blob)
|
||||
- file_name, wiki_blob = parse_search_result(wiki_blob)
|
||||
- wiki_blob_link = project_wiki_path(project, wiki_blob.basename)
|
||||
|
||||
= render partial: 'search/results/blob_data', locals: { blob: wiki_blob, project: project, file_name: file_name, blob_link: wiki_blob_link }
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Added ability to search by wiki titles
|
||||
merge_request: 19112
|
||||
author:
|
||||
type: added
|
|
@ -34,9 +34,7 @@ module API
|
|||
|
||||
def process_results(results)
|
||||
case params[:scope]
|
||||
when 'wiki_blobs'
|
||||
paginate(results).map { |blob| Gitlab::ProjectSearchResults.parse_search_result(blob, user_project) }
|
||||
when 'blobs'
|
||||
when 'blobs', 'wiki_blobs'
|
||||
paginate(results).map { |blob| blob[1] }
|
||||
else
|
||||
paginate(results)
|
||||
|
|
|
@ -32,17 +32,13 @@ module Gitlab
|
|||
end
|
||||
|
||||
def find_by_filename(query, except: [])
|
||||
filenames = repository.search_files_by_name(query, ref).first(BATCH_SIZE)
|
||||
filenames.delete_if { |filename| except.include?(filename) } unless except.empty?
|
||||
filenames = search_filenames(query, except)
|
||||
|
||||
blob_refs = filenames.map { |filename| [ref, filename] }
|
||||
blobs = Gitlab::Git::Blob.batch(repository, blob_refs, blob_size_limit: 1024)
|
||||
|
||||
blobs.map do |blob|
|
||||
blobs(filenames).map do |blob|
|
||||
Gitlab::SearchResults::FoundBlob.new(
|
||||
id: blob.id,
|
||||
filename: blob.path,
|
||||
basename: File.basename(blob.path),
|
||||
basename: File.basename(blob.path, File.extname(blob.path)),
|
||||
ref: ref,
|
||||
startline: 1,
|
||||
data: blob.data,
|
||||
|
@ -50,5 +46,21 @@ module Gitlab
|
|||
)
|
||||
end
|
||||
end
|
||||
|
||||
def search_filenames(query, except)
|
||||
filenames = repository.search_files_by_name(query, ref).first(BATCH_SIZE)
|
||||
|
||||
filenames.delete_if { |filename| except.include?(filename) } unless except.empty?
|
||||
|
||||
filenames
|
||||
end
|
||||
|
||||
def blob_refs(filenames)
|
||||
filenames.map { |filename| [ref, filename] }
|
||||
end
|
||||
|
||||
def blobs(filenames)
|
||||
Gitlab::Git::Blob.batch(repository, blob_refs(filenames), blob_size_limit: 1024)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -106,7 +106,8 @@ module Gitlab
|
|||
project_wiki = ProjectWiki.new(project)
|
||||
|
||||
unless project_wiki.empty?
|
||||
project_wiki.search_files(query)
|
||||
ref = repository_ref || project.wiki.default_branch
|
||||
Gitlab::WikiFileFinder.new(project, ref).find(query)
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
|
23
lib/gitlab/wiki_file_finder.rb
Normal file
23
lib/gitlab/wiki_file_finder.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
module Gitlab
|
||||
class WikiFileFinder < FileFinder
|
||||
attr_reader :repository
|
||||
|
||||
def initialize(project, ref)
|
||||
@project = project
|
||||
@ref = ref
|
||||
@repository = project.wiki.repository
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def search_filenames(query, except)
|
||||
safe_query = Regexp.escape(query.tr(' ', '-'))
|
||||
safe_query = Regexp.new(safe_query, Regexp::IGNORECASE)
|
||||
filenames = repository.ls_files(ref)
|
||||
|
||||
filenames.delete_if { |filename| except.include?(filename) } unless except.empty?
|
||||
|
||||
filenames.grep(safe_query).first(BATCH_SIZE)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,27 +3,11 @@ require 'spec_helper'
|
|||
describe Gitlab::FileFinder do
|
||||
describe '#find' do
|
||||
let(:project) { create(:project, :public, :repository) }
|
||||
let(:finder) { described_class.new(project, project.default_branch) }
|
||||
|
||||
it 'finds by name' do
|
||||
results = finder.find('files')
|
||||
|
||||
filename, blob = results.find { |_, blob| blob.filename == 'files/images/wm.svg' }
|
||||
expect(filename).to eq('files/images/wm.svg')
|
||||
expect(blob).to be_a(Gitlab::SearchResults::FoundBlob)
|
||||
expect(blob.ref).to eq(finder.ref)
|
||||
expect(blob.data).not_to be_empty
|
||||
end
|
||||
|
||||
it 'finds by content' do
|
||||
results = finder.find('files')
|
||||
|
||||
filename, blob = results.find { |_, blob| blob.filename == 'CHANGELOG' }
|
||||
|
||||
expect(filename).to eq('CHANGELOG')
|
||||
expect(blob).to be_a(Gitlab::SearchResults::FoundBlob)
|
||||
expect(blob.ref).to eq(finder.ref)
|
||||
expect(blob.data).not_to be_empty
|
||||
it_behaves_like 'file finder' do
|
||||
subject { described_class.new(project, project.default_branch) }
|
||||
let(:expected_file_by_name) { 'files/images/wm.svg' }
|
||||
let(:expected_file_by_content) { 'CHANGELOG' }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -22,47 +22,57 @@ describe Gitlab::ProjectSearchResults do
|
|||
it { expect(results.query).to eq('hello world') }
|
||||
end
|
||||
|
||||
describe 'blob search' do
|
||||
let(:project) { create(:project, :public, :repository) }
|
||||
shared_examples 'general blob search' do |entity_type, blob_kind|
|
||||
let(:query) { 'files' }
|
||||
subject(:results) { described_class.new(user, project, query).objects(blob_type) }
|
||||
|
||||
subject(:results) { described_class.new(user, project, 'files').objects('blobs') }
|
||||
|
||||
context 'when repository is disabled' do
|
||||
let(:project) { create(:project, :public, :repository, :repository_disabled) }
|
||||
|
||||
it 'hides blobs from members' do
|
||||
context "when #{entity_type} is disabled" do
|
||||
let(:project) { disabled_project }
|
||||
it "hides #{blob_kind} from members" do
|
||||
project.add_reporter(user)
|
||||
|
||||
is_expected.to be_empty
|
||||
end
|
||||
|
||||
it 'hides blobs from non-members' do
|
||||
it "hides #{blob_kind} from non-members" do
|
||||
is_expected.to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'when repository is internal' do
|
||||
let(:project) { create(:project, :public, :repository, :repository_private) }
|
||||
context "when #{entity_type} is internal" do
|
||||
let(:project) { private_project }
|
||||
|
||||
it 'finds blobs for members' do
|
||||
it "finds #{blob_kind} for members" do
|
||||
project.add_reporter(user)
|
||||
|
||||
is_expected.not_to be_empty
|
||||
end
|
||||
|
||||
it 'hides blobs from non-members' do
|
||||
it "hides #{blob_kind} from non-members" do
|
||||
is_expected.to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
it 'finds by name' do
|
||||
expect(results.map(&:first)).to include('files/images/wm.svg')
|
||||
expect(results.map(&:first)).to include(expected_file_by_name)
|
||||
end
|
||||
|
||||
it 'finds by content' do
|
||||
blob = results.select { |result| result.first == "CHANGELOG" }.flatten.last
|
||||
blob = results.select { |result| result.first == expected_file_by_content }.flatten.last
|
||||
|
||||
expect(blob.filename).to eq("CHANGELOG")
|
||||
expect(blob.filename).to eq(expected_file_by_content)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'blob search' do
|
||||
let(:project) { create(:project, :public, :repository) }
|
||||
|
||||
it_behaves_like 'general blob search', 'repository', 'blobs' do
|
||||
let(:blob_type) { 'blobs' }
|
||||
let(:disabled_project) { create(:project, :public, :repository, :repository_disabled) }
|
||||
let(:private_project) { create(:project, :public, :repository, :repository_private) }
|
||||
let(:expected_file_by_name) { 'files/images/wm.svg' }
|
||||
let(:expected_file_by_content) { 'CHANGELOG' }
|
||||
end
|
||||
|
||||
describe 'parsing results' do
|
||||
|
@ -189,40 +199,18 @@ describe Gitlab::ProjectSearchResults do
|
|||
describe 'wiki search' do
|
||||
let(:project) { create(:project, :public, :wiki_repo) }
|
||||
let(:wiki) { build(:project_wiki, project: project) }
|
||||
let!(:wiki_page) { wiki.create_page('Title', 'Content') }
|
||||
|
||||
subject(:results) { described_class.new(user, project, 'Content').objects('wiki_blobs') }
|
||||
|
||||
context 'when wiki is disabled' do
|
||||
let(:project) { create(:project, :public, :wiki_repo, :wiki_disabled) }
|
||||
|
||||
it 'hides wiki blobs from members' do
|
||||
project.add_reporter(user)
|
||||
|
||||
is_expected.to be_empty
|
||||
end
|
||||
|
||||
it 'hides wiki blobs from non-members' do
|
||||
is_expected.to be_empty
|
||||
end
|
||||
before do
|
||||
wiki.create_page('Files/Title', 'Content')
|
||||
wiki.create_page('CHANGELOG', 'Files example')
|
||||
end
|
||||
|
||||
context 'when wiki is internal' do
|
||||
let(:project) { create(:project, :public, :wiki_repo, :wiki_private) }
|
||||
|
||||
it 'finds wiki blobs for guest' do
|
||||
project.add_guest(user)
|
||||
|
||||
is_expected.not_to be_empty
|
||||
end
|
||||
|
||||
it 'hides wiki blobs from non-members' do
|
||||
is_expected.to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
it 'finds by content' do
|
||||
expect(results).to include("master:Title.md\x001\x00Content\n")
|
||||
it_behaves_like 'general blob search', 'wiki', 'wiki blobs' do
|
||||
let(:blob_type) { 'wiki_blobs' }
|
||||
let(:disabled_project) { create(:project, :public, :wiki_repo, :wiki_disabled) }
|
||||
let(:private_project) { create(:project, :public, :wiki_repo, :wiki_private) }
|
||||
let(:expected_file_by_name) { 'Files/Title.md' }
|
||||
let(:expected_file_by_content) { 'CHANGELOG.md' }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
20
spec/lib/gitlab/wiki_file_finder_spec.rb
Normal file
20
spec/lib/gitlab/wiki_file_finder_spec.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::WikiFileFinder do
|
||||
describe '#find' do
|
||||
let(:project) { create(:project, :public, :wiki_repo) }
|
||||
let(:wiki) { build(:project_wiki, project: project) }
|
||||
|
||||
before do
|
||||
wiki.create_page('Files/Title', 'Content')
|
||||
wiki.create_page('CHANGELOG', 'Files example')
|
||||
end
|
||||
|
||||
it_behaves_like 'file finder' do
|
||||
subject { described_class.new(project, project.wiki.default_branch) }
|
||||
|
||||
let(:expected_file_by_name) { 'Files/Title.md' }
|
||||
let(:expected_file_by_content) { 'CHANGELOG.md' }
|
||||
end
|
||||
end
|
||||
end
|
21
spec/support/shared_examples/file_finder.rb
Normal file
21
spec/support/shared_examples/file_finder.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
shared_examples 'file finder' do
|
||||
let(:query) { 'files' }
|
||||
let(:search_results) { subject.find(query) }
|
||||
|
||||
it 'finds by name' do
|
||||
filename, blob = search_results.find { |_, blob| blob.filename == expected_file_by_name }
|
||||
expect(filename).to eq(expected_file_by_name)
|
||||
expect(blob).to be_a(Gitlab::SearchResults::FoundBlob)
|
||||
expect(blob.ref).to eq(subject.ref)
|
||||
expect(blob.data).not_to be_empty
|
||||
end
|
||||
|
||||
it 'finds by content' do
|
||||
filename, blob = search_results.find { |_, blob| blob.filename == expected_file_by_content }
|
||||
|
||||
expect(filename).to eq(expected_file_by_content)
|
||||
expect(blob).to be_a(Gitlab::SearchResults::FoundBlob)
|
||||
expect(blob.ref).to eq(subject.ref)
|
||||
expect(blob.data).not_to be_empty
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue