Commit 574d75cb authored by Valery Sizov's avatar Valery Sizov

Merge branch 'es_global_search' into 'master'

ES: Global code search

- [x] Basic implementation of blobs search
- [x] Basic implementation of commits search
- [x] Fix pagination for commits. Do paginating on ES level instead of resulting array
- [x] Refactoring. The `gitlab-elastcsearch-git` gem should not know anything specific to GitLab application structure.
- [ ] Backport changes to CE
   - [ ] Search result parsers (after review this MR)
   - [x] Removing `total_count` (https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/6216)
- [x] Make rake tasks pass parent id
- [x] Test database search afterwards
- [x] Mention somewhere that ES should be updated to 2.4.0
- [x] Specs
- [x] Address TODO in the code
- [x] Add project name to search results

Related MR for `gitlab-elasticsearch-git` gem (https://gitlab.com/gitlab-org/gitlab-elasticsearch-git/merge_requests/18)

Screenshots:

![Screen_Shot_2016-09-06_at_16.07.30](/uploads/dca09ee14b9c728ab22b902ed471a071/Screen_Shot_2016-09-06_at_16.07.30.png)

Closes https://gitlab.com/gitlab-org/gitlab-ee/issues/556

See merge request !699
parents 84ff13a8 18a45c9a
......@@ -5,6 +5,7 @@ v 8.12.0 (Unreleased)
- Request only the LDAP attributes we need
- [ES] Instrument other Gitlab::Elastic classes
- [ES] Fix: Elasticsearch does not find partial matches in project names
- [ES] Global code search
v 8.11.6
- Exclude blocked users from potential MR approvers
......
......@@ -108,7 +108,7 @@ gem 'seed-fu', '~> 2.3.5'
# Search
gem 'elasticsearch-model'
gem 'elasticsearch-rails'
gem 'gitlab-elasticsearch-git', '~> 0.0.17', require: "elasticsearch/git"
gem 'gitlab-elasticsearch-git', '~> 1.0.0', require: "elasticsearch/git"
# Markdown and HTML processing
gem 'html-pipeline', '~> 1.11.0'
......
......@@ -283,7 +283,7 @@ GEM
mime-types (>= 1.19)
rugged (>= 0.23.0b)
github-markup (1.4.0)
gitlab-elasticsearch-git (0.0.17)
gitlab-elasticsearch-git (1.0.0)
activemodel (~> 4.2)
activesupport (~> 4.2)
charlock_holmes (~> 0.7)
......@@ -886,7 +886,7 @@ DEPENDENCIES
gemojione (~> 3.0)
github-linguist (~> 4.7.0)
github-markup (~> 1.4)
gitlab-elasticsearch-git (~> 0.0.17)
gitlab-elasticsearch-git (~> 1.0.0)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-license (~> 1.0)
gitlab_git (~> 10.6.3)
......
......@@ -38,9 +38,10 @@ class SearchController < ApplicationController
Search::SnippetService.new(current_user, params).execute
else
unless %w(projects issues merge_requests milestones).include?(@scope)
unless %w(projects issues merge_requests milestones blobs commits).include?(@scope)
@scope = 'projects'
end
Search::GlobalService.new(current_user, params).execute
end
......
......@@ -30,6 +30,92 @@ module SearchHelper
"Showing #{from} - #{to} of #{count} #{scope.humanize(capitalize: false)} for \"#{term}\""
end
def parse_search_result(result)
if result.is_a?(String)
parse_search_result_from_grep(result)
else
parse_search_result_from_elastic(result)
end
end
def parse_search_result_from_elastic(result)
ref = result["_source"]["blob"]["commit_sha"]
filename = result["_source"]["blob"]["path"]
extname = File.extname(filename)
basename = filename.sub(/#{extname}$/, '')
content = result["_source"]["blob"]["content"]
total_lines = content.lines.size
highlighted_content = result["highlight"]["blob.content"]
term = highlighted_content && highlighted_content[0].match(/gitlabelasticsearch→(.*?)←gitlabelasticsearch/)[1]
found_line_number = 0
content.each_line.each_with_index do |line, index|
if term && line.include?(term)
found_line_number = index
break
end
end
from = if found_line_number >= 2
found_line_number - 2
else
found_line_number
end
to = if (total_lines - found_line_number) > 3
found_line_number + 2
else
found_line_number
end
data = content.lines[from..to]
OpenStruct.new(
filename: filename,
basename: basename,
ref: ref,
startline: from + 1,
data: data.join
)
end
def parse_search_result_from_grep(result)
ref = nil
filename = nil
basename = nil
startline = 0
result.each_line.each_with_index do |line, index|
if line =~ /^.*:.*:\d+:/
ref, filename, startline = line.split(':')
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+:/, '')
end
OpenStruct.new(
filename: filename,
basename: basename,
ref: ref,
startline: startline,
data: data
)
end
def find_project_for_blob(blob)
Project.find(blob['_parent'])
end
private
# Autocomplete results for various settings pages
......
......@@ -11,8 +11,8 @@ module Elastic
project.id
end
def self.repositories_count
Project.cached_count
def project_id
project.id
end
def client_for_indexing
......@@ -27,6 +27,40 @@ module Elastic
end
end
end
def find_commits_by_message_with_elastic(query, page: 1, per_page: 20)
response = project.repository.search(query, type: :commit, page: page, per: per_page)[:commits][:results]
commits = response.map do |result|
commit result["_source"]["commit"]["sha"]
end
# Before "map" we had a paginated array so we need to recover it
offset = per_page * ((page || 1) - 1)
Kaminari.paginate_array(commits, total_count: response.total_count, limit: per_page, offset: offset)
end
end
class_methods do
def find_commits_by_message_with_elastic(query, page: 1, per_page: 20, options: {})
response = Repository.search(
query,
type: :commit,
page: page,
per: per_page,
options: options
)[:commits][:results]
commits = response.map do |result|
sha = result["_source"]["commit"]["sha"]
project = Project.find(result["_source"]["commit"]["rid"])
project.commit(sha)
end
# Before "map" we had a paginated array so we need to recover it
offset = per_page * ((page || 1) - 1)
Kaminari.paginate_array(commits, total_count: response.total_count, limit: per_page, offset: offset)
end
end
end
end
......@@ -11,8 +11,8 @@ module Elastic
"wiki_#{project.id}"
end
def self.repositories_count
Project.with_wiki_enabled.count
def project_id
project.id
end
def client_for_indexing
......
......@@ -131,12 +131,6 @@ class Repository
commits
end
def find_commits_by_message_with_elastic(query)
project.repository.search(query, type: :commit)[:commits][:results].map do |result|
commit result["_source"]["commit"]["sha"]
end
end
def find_branch(name, fresh_repo: true)
# Since the Repository object may have in-memory index changes, invalidating the memoized Repository object may
# cause unintended side effects. Because finding a branch is a read-only operation, we can safely instantiate
......@@ -1146,88 +1140,6 @@ class Repository
Gitlab::Popen.popen(args, path_to_repo).first.scrub.split(/^--$/)
end
def parse_search_result(result)
if result.is_a?(String)
parse_search_result_from_grep(result)
else
parse_search_result_from_elastic(result)
end
end
def parse_search_result_from_elastic(result)
ref = result["_source"]["blob"]["commit_sha"]
filename = result["_source"]["blob"]["path"]
extname = File.extname(filename)
basename = filename.sub(/#{extname}$/, '')
content = result["_source"]["blob"]["content"]
total_lines = content.lines.size
highlighted_content = result["highlight"]["blob.content"]
term = highlighted_content && highlighted_content[0].match(/gitlabelasticsearch→(.*?)←gitlabelasticsearch/)[1]
found_line_number = 0
content.each_line.each_with_index do |line, index|
if term && line.include?(term)
found_line_number = index
break
end
end
from = if found_line_number >= 2
found_line_number - 2
else
found_line_number
end
to = if (total_lines - found_line_number) > 3
found_line_number + 2
else
found_line_number
end
data = content.lines[from..to]
OpenStruct.new(
filename: filename,
basename: basename,
ref: ref,
startline: from + 1,
data: data.join
)
end
def parse_search_result_from_grep(result)
ref = nil
filename = nil
basename = nil
startline = 0
result.each_line.each_with_index do |line, index|
if line =~ /^.*:.*:\d+:/
ref, filename, startline = line.split(':')
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+:/, '')
end
OpenStruct.new(
filename: filename,
basename: basename,
ref: ref,
startline: startline,
data: data
)
end
def fetch_ref(source_path, source_ref, target_ref)
args = %W(#{Gitlab.config.git.bin_path} fetch --no-tags -f #{source_path} #{source_ref}:#{target_ref})
Gitlab::Popen.popen(args, path_to_repo)
......
......@@ -14,6 +14,8 @@
.commit-info-block
.commit-row-title
%span.item-title
- unless @project
#{project.name_with_namespace}:
= link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message"
%span.commit-row-message.visible-xs-inline
&middot;
......
......@@ -69,3 +69,14 @@
Milestones
%span.badge
= @search_results.milestones_count
- if current_application_settings.elasticsearch_search?
%li{class: ("active" if @scope == 'blobs')}
= link_to search_filter_path(scope: 'blobs') do
Code
%span.badge
= @search_results.blobs_count
%li{class: ("active" if @scope == 'commits')}
= link_to search_filter_path(scope: 'commits') do
Commits
%span.badge
= @search_results.commits_count
- blob = @project.repository.parse_search_result(blob)
- parsed_blob = parse_search_result(blob)
- project = @project || find_project_for_blob(blob)
- blob_link = namespace_project_blob_path(project.namespace, project, tree_join(parsed_blob.ref, parsed_blob.filename))
.blob-result
.file-holder
.file-title
- blob_link = namespace_project_blob_path(@project.namespace, @project, tree_join(blob.ref, blob.filename))
= link_to blob_link do
%i.fa.fa-file
= icon('fa-file')
%strong
= blob.filename
- if @project
= parsed_blob.filename
- else
#{project.name_with_namespace}:
%i= parsed_blob.filename
.file-content.code.term
= render 'shared/file_highlight', blob: blob, first_line_number: blob.startline, blob_link: blob_link
= render 'shared/file_highlight', blob: parsed_blob, first_line_number: parsed_blob.startline, blob_link: blob_link
.search-result-row
= render 'projects/commits/commit', project: @project, commit: commit
= render 'projects/commits/commit', project: commit.project, commit: commit
- wiki_blob = @project.repository.parse_search_result(wiki_blob)
- wiki_blob = parse_search_result(wiki_blob)
.blob-result
.file-holder
.file-title
......
......@@ -41,6 +41,10 @@ class Repository
PROJECT_ID
end
def project_id
PROJECT_ID
end
def path_to_repo
REPO_PATH
end
......
......@@ -31,7 +31,7 @@ is installed or on a separate server.
These are the minimum requirements needed for Elasticsearch to work:
- GitLab 8.4+
- Elasticsearch 2.0+ (with [Delete By Query Plugin](https://www.elastic.co/guide/en/elasticsearch/plugins/2.0/plugins-delete-by-query.html) installed)
- Elasticsearch 2.4+ (with [Delete By Query Plugin](https://www.elastic.co/guide/en/elasticsearch/plugins/2.4/plugins-delete-by-query.html) installed)
## Install Elasticsearch
......
......@@ -182,6 +182,35 @@ To make sure you didn't miss anything run a more thorough check:
If all items are green, then congratulations, the upgrade is complete!
### 11. Elasticsearch index update (if you currently use Elasticsearch)
In 8.12 release we changed the index mapping and this is why the whole index should be removed and built from scratch. Also the Elasticsearch 2.3.* contains a bug that causes to fail all queries that use highlight feature and Parent Child relationship at once, so we recommend to use the version 2.4 and newer. After updating your Elasticsearch server, please re-create your index by using one of two ways listed below:
1. Re-create the index. The following command is acceptable for not very big GitLab instances (storage size no more than few gigabytes).
```
# Omnibus installations
sudo gitlab-rake gitlab:elastic:index
# Installations from source
bundle exec rake gitlab:elastic:index
```
1. For very big GitLab instances you have to remove index first. Note: Consider disabling ES search feature (**Admin > Settings**) before removing the index, in order to allow your users to use regular search while you recreate the Elasticsearch index.
```
# Omnibus installations
sudo gitlab-rake gitlab:elastic:delete_indexes
sudo gitlab-rake gitlab:elastic:clear_index_status
# Installations from source
bundle exec rake gitlab:elastic:delete_indexes
bundle exec rake gitlab:elastic:clear_index_status
```
Then we recommend to follow [Add GitLab's data to the Elasticsearch index](../integration/elasticsearch.md#add-gitlabs-data-to-the-elasticsearch-index).
## Things went south? Revert to previous version (8.11)
### 1. Revert the code to the previous version
......
......@@ -28,17 +28,12 @@ module Gitlab
when 'wiki_blobs'
wiki_blobs.page(page).per(per_page)
when 'commits'
Kaminari.paginate_array(commits).page(page).per(per_page)
commits(page: page, per_page: per_page)
else
super
end
end
def total_count
@total_count ||= issues_count + merge_requests_count + blobs_count +
notes_count + wiki_blobs_count + commits_count
end
def blobs_count
@blobs_count ||= blobs.total_count
end
......@@ -52,7 +47,7 @@ module Gitlab
end
def commits_count
@commits_count ||= commits.count
@commits_count ||= commits.total_count
end
private
......@@ -98,17 +93,19 @@ module Gitlab
Note.elastic_search(query, options: opt)
end
def commits
def commits(page: 1, per_page: 20)
if project.empty_repo? || query.blank?
Kaminari.paginate_array([])
else
# We use elastic for default branch only
if root_ref?
project.repository.find_commits_by_message_with_elastic(query)
project.repository.find_commits_by_message_with_elastic(
query,
page: (page || 1).to_i,
per_page: per_page
)
else
Kaminari.paginate_array(
project.repository.find_commits_by_message(query).compact
)
end
end
end
......
......@@ -24,19 +24,27 @@ module Gitlab
merge_requests.page(page).per(per_page).records
when 'milestones'
milestones.page(page).per(per_page).records
when 'blobs'
blobs.page(page).per(per_page)
when 'commits'
commits(page: page, per_page: per_page)
else
Kaminari.paginate_array([])
end
end
def total_count
@total_count ||= projects_count + issues_count + merge_requests_count + milestones_count
end
def projects_count
@projects_count ||= projects.total_count
end
def blobs_count
@blobs_count ||= blobs.total_count
end
def commits_count
@commits_count ||= commits.total_count
end
def issues_count
@issues_count ||= issues.total_count
end
......@@ -49,10 +57,6 @@ module Gitlab
@milestones_count ||= milestones.total_count
end
def empty?
total_count.zero?
end
private
def projects
......@@ -92,6 +96,64 @@ module Gitlab
MergeRequest.elastic_search(query, options: opt)
end
def blobs
if query.blank?
Kaminari.paginate_array([])
else
opt = {
additional_filter: build_filter_by_project(limit_project_ids, @public_and_internal_projects)
}
Repository.search(
query,
type: :blob,
options: opt.merge({ highlight: true })
)[:blobs][:results].response
end
end
def commits(page: 1, per_page: 20)
if query.blank?
Kaminari.paginate_array([])
else
options = {
additional_filter: build_filter_by_project(limit_project_ids, @public_and_internal_projects)
}
Repository.find_commits_by_message_with_elastic(
query,
page: (page || 1).to_i,
per_page: per_page,
options: options
)
end
end
def build_filter_by_project(project_ids, public_and_internal_projects)
conditions = [{ terms: { id: project_ids } }]
if public_and_internal_projects
conditions << {
term: { visibility_level: Project::PUBLIC }
}
conditions << {
term: { visibility_level: Project::INTERNAL }
}
end
{
has_parent: {
parent_type: 'project',
query: {
bool: {
should: conditions
}
}
}
}
end
def default_scope
'projects'
end
......
......@@ -69,6 +69,7 @@ module Gitlab
def merge_requests
merge_requests = MergeRequest.in_projects(project_ids_relation)
if query =~ /[#!](\d+)\z/
merge_requests = merge_requests.where(iid: $1)
else
......
......@@ -34,4 +34,41 @@ feature 'Global elastic search', feature: true do
expect(page).to have_selector('.gl-pagination .page', count: 2)
end
end
describe 'I search through the blobs' do
before do
project.repository.index_blobs
Gitlab::Elastic::Helper.refresh_index
end
it "finds files" do
visit dashboard_projects_path
fill_in "search", with: "def"
click_button "Go"
select_filter("Code")
expect(page).to have_selector('.file-content .code')
end
end
describe 'I search through the commits' do
before do
project.repository.index_commits
Gitlab::Elastic::Helper.refresh_index
end
it "finds commits" do
visit dashboard_projects_path
fill_in "search", with: "add"
click_button "Go"
select_filter("Commits")
expect(page).to have_selector('.commit-row-description')
end
end
end
......@@ -6,6 +6,71 @@ describe SearchHelper do
str
end
describe 'parsing result' do
let(:project) { create(:project) }
let(:repository) { project.repository }
let(:results) { repository.search_files('feature', 'master') }
let(:search_result) { results.first }
subject { helper.parse_search_result(search_result) }
it "returns a valid OpenStruct object" do
is_expected.to be_an OpenStruct
expect(subject.filename).to eq('CHANGELOG')
expect(subject.basename).to eq('CHANGELOG')
expect(subject.ref).to eq('master')
expect(subject.startline).to eq(186)
expect(subject.data.lines[2]).to eq(" - Feature: Replace teams with group membership\n")
end
context "when filename has extension" do
let(:search_result) { "master:CONTRIBUTE.md:5:- [Contribute to GitLab](#contribute-to-gitlab)\n" }
it { expect(subject.filename).to eq('CONTRIBUTE.md') }
it { expect(subject.basename).to eq('CONTRIBUTE') }
end
context "when file under directory" do
let(:search_result) { "master:a/b/c.md:5:a b c\n" }
it { expect(subject.filename).to eq('a/b/c.md') }
it { expect(subject.basename).to eq('a/b/c') }
end
end
describe '#parse_search_result_from_elastic' do
before do
stub_application_setting(elasticsearch_search: true, elasticsearch_indexing: true)
Gitlab::Elastic::Helper.create_empty_index
end
after do
Gitlab::Elastic::Helper.delete_index
stub_application_setting(elasticsearch_search: false, elasticsearch_indexing: false)
end
it "returns parsed result" do
project = create :project
project.repository.index_blobs
Gitlab::Elastic::Helper.refresh_index
result = project.repository.search(
'def popen',
type: :blob,
options: { highlight: true }
)[:blobs][:results][0]
parsed_result = helper.parse_search_result_from_elastic(result)
expect(parsed_result.ref). to eq('5937ac0a7beb003549fc5fd26fc247adbce4a52e')
expect(parsed_result.filename).to eq('files/ruby/popen.rb')
expect(parsed_result.startline).to eq(2)
expect(parsed_result.data).to include("Popen")
end
end
describe 'search_autocomplete_source' do
context "with no current user" do
before do
......
......@@ -41,7 +41,7 @@ describe Gitlab::Elastic::SearchResults, lib: true do
Gitlab::Elastic::Helper.refresh_index
end
it 'lists issues that title or description contain the query' do
it 'lists found issues' do
results = described_class.new(user, 'hello world', limit_project_ids)
issues = results.objects('issues')
......@@ -51,7 +51,7 @@ describe Gitlab::Elastic::SearchResults, lib: true do
expect(results.issues_count).to eq 2
end
it 'returns empty list when issues title or description does not contain the query' do
it 'returns empty list when issues are not found' do
results = described_class.new(user, 'security', limit_project_ids)
expect(results.objects('issues')).to be_empty
......@@ -297,7 +297,7 @@ describe Gitlab::Elastic::SearchResults, lib: true do
Gitlab::Elastic::Helper.refresh_index
end
it 'lists merge requests that title or description contain the query' do
it 'lists found merge requests' do
results = described_class.new(user, 'hello world', limit_project_ids)
merge_requests = results.objects('merge_requests')
......@@ -307,7 +307,7 @@ describe Gitlab::Elastic::SearchResults, lib: true do
expect(results.merge_requests_count).to eq 2
end
it 'returns empty list when merge requests title or description does not contain the query' do
it 'returns empty list when merge requests are not found' do
results = described_class.new(user, 'security', limit_project_ids)
expect(results.objects('merge_requests')).to be_empty
......@@ -366,4 +366,72 @@ describe Gitlab::Elastic::SearchResults, lib: true do
expect(result.projects_count).to eq(1)
end
end
describe 'Blobs' do
before do
project_1.repository.index_blobs
Gitlab::Elastic::Helper.refresh_index
end
it 'founds blobs' do
results = described_class.new(user, 'def', limit_project_ids)
blobs = results.objects('blobs')
expect(blobs.first["_source"]["blob"]["content"]).to include("def")
expect(results.blobs_count).to eq 4
end
it 'founds blobs from public projects only' do
project_2 = create :project, :private
project_2.repository.index_blobs
Gitlab::Elastic::Helper.refresh_index
results = described_class.new(user, 'def', [project_1.id])
expect(results.blobs_count).to eq 4
results = described_class.new(user, 'def', [project_1.id, project_2.id])
expect(results.blobs_count).to eq 8
end
it 'returns zero when blobs are not found' do
results = described_class.new(user, 'asdfg', limit_project_ids)
expect(results.blobs_count).to eq 0
end
end
describe 'Commits' do
before do
project_1.repository.index_commits
Gitlab::Elastic::Helper.refresh_index
end
it 'founds commits' do
results = described_class.new(user, 'add', limit_project_ids)
commits = results.objects('commits')
expect(commits.first.message).to include("add")
expect(results.commits_count).to eq 5
end
it 'founds commits from public projects only' do
project_2 = create :project, :private
project_2.repository.index_commits
Gitlab::Elastic::Helper.refresh_index
results = described_class.new(user, 'add', [project_1.id])
expect(results.commits_count).to eq 5
results = described_class.new(user, 'add', [project_1.id, project_2.id])
expect(results.commits_count).to eq 10
end
it 'returns zero when commits are not found' do
results = described_class.new(user, 'asdfg', limit_project_ids)
expect(results.commits_count).to eq 0
end
end
end
......@@ -24,4 +24,34 @@ describe Repository, elastic: true do
expect(project.repository.search('def popen')[:blobs][:total_count]).to eq(1)
expect(project.repository.search('initial')[:commits][:total_count]).to eq(1)
end
describe "class method find_commits_by_message_with_elastic" do
it "returns commits" do
project = create :project
project1 = create :project
project.repository.index_commits
project1.repository.index_commits
Gitlab::Elastic::Helper.refresh_index
expect(Repository.find_commits_by_message_with_elastic('initial').first).to be_a(Commit)
expect(Repository.find_commits_by_message_with_elastic('initial').count).to eq(2)
expect(Repository.find_commits_by_message_with_elastic('initial').total_count).to eq(2)
end
end
describe "find_commits_by_message_with_elastic" do
it "returns commits" do
project = create :project
project.repository.index_commits
Gitlab::Elastic::Helper.refresh_index
expect(project.repository.find_commits_by_message_with_elastic('initial').first).to be_a(Commit)
expect(project.repository.find_commits_by_message_with_elastic('initial').count).to eq(1)
expect(project.repository.find_commits_by_message_with_elastic('initial').total_count).to eq(1)
end
end
end
......@@ -132,7 +132,7 @@ describe Repository, models: true do
end
end
describe :commit_file do
describe 'commit_file' do
it 'commits change to a file successfully' do
expect do
repository.commit_file(user, 'CHANGELOG', 'Changelog!',
......@@ -146,7 +146,7 @@ describe Repository, models: true do
end
end
describe :update_file do
describe 'update_file' do
it 'updates filename successfully' do
expect do
repository.update_file(user, 'NEWLICENSE', 'Copyright!',
......@@ -186,32 +186,6 @@ describe Repository, models: true do
it { is_expected.to be_an String }
it { expect(subject.lines[2]).to eq("master:CHANGELOG:188: - Feature: Replace teams with group membership\n") }
end
describe 'parsing result' do
subject { repository.parse_search_result(search_result) }
let(:search_result) { results.first }
it { is_expected.to be_an OpenStruct }
it { expect(subject.filename).to eq('CHANGELOG') }
it { expect(subject.basename).to eq('CHANGELOG') }
it { expect(subject.ref).to eq('master') }
it { expect(subject.startline).to eq(186) }
it { expect(subject.data.lines[2]).to eq(" - Feature: Replace teams with group membership\n") }
context "when filename has extension" do
let(:search_result) { "master:CONTRIBUTE.md:5:- [Contribute to GitLab](#contribute-to-gitlab)\n" }
it { expect(subject.filename).to eq('CONTRIBUTE.md') }
it { expect(subject.basename).to eq('CONTRIBUTE') }
end
context "when file under directory" do
let(:search_result) { "master:a/b/c.md:5:a b c\n" }
it { expect(subject.filename).to eq('a/b/c.md') }
it { expect(subject.basename).to eq('a/b/c') }
end
end
end
describe "#changelog" do
......@@ -761,7 +735,7 @@ describe Repository, models: true do
end
end
describe :skip_merged_commit do
describe 'skip_merged_commit' do
subject { repository.commits(Gitlab::Git::BRANCH_REF_PREFIX + "'test'", limit: 100, skip_merges: true).map{ |k| k.id } }
it { is_expected.not_to include('e56497bb5f03a90a51293fc6d516788730953899') }
......@@ -1068,39 +1042,33 @@ describe Repository, models: true do
stub_application_setting(elasticsearch_search: false, elasticsearch_indexing: false)
end
describe :find_commits_by_message_with_elastic do
describe "class method find_commits_by_message_with_elastic" do
it "returns commits" do
project = create :project
project1 = create :project
project.repository.index_commits
project1.repository.index_commits
Gitlab::Elastic::Helper.refresh_index
expect(project.repository.find_commits_by_message_with_elastic('initial').first).to be_a(Commit)
expect(project.repository.find_commits_by_message_with_elastic('initial').count).to eq(1)
expect(described_class.find_commits_by_message_with_elastic('initial').first).to be_a(Commit)
expect(described_class.find_commits_by_message_with_elastic('initial').count).to eq(2)
expect(described_class.find_commits_by_message_with_elastic('initial').total_count).to eq(2)
end
end
describe :parse_search_result_from_elastic do
it "returns parsed result" do
describe "find_commits_by_message_with_elastic" do
it "returns commits" do
project = create :project
project.repository.index_blobs
project.repository.index_commits
Gitlab::Elastic::Helper.refresh_index
result = project.repository.search(
'def popen',
type: :blob,
options: { highlight: true }
)[:blobs][:results][0]
parsed_result = project.repository.parse_search_result_from_elastic(result)
expect(parsed_result.ref). to eq('5937ac0a7beb003549fc5fd26fc247adbce4a52e')
expect(parsed_result.filename).to eq('files/ruby/popen.rb')
expect(parsed_result.startline).to eq(2)
expect(parsed_result.data).to include("Popen")
expect(project.repository.find_commits_by_message_with_elastic('initial').first).to be_a(Commit)
expect(project.repository.find_commits_by_message_with_elastic('initial').count).to eq(1)
expect(project.repository.find_commits_by_message_with_elastic('initial').total_count).to eq(1)
end
end
end
......
require 'webmock'
require 'webmock/rspec'
WebMock.disable_net_connect!(allow_localhost: true, allow: 'elasticsearch')
WebMock.disable_net_connect!(allow_localhost: true, allow: 'registry.gitlab.com-gitlab-org-test-elastic-image')
WebMock.disable_net_connect!(
allow_localhost: true,
allow: ['elasticsearch', 'registry.gitlab.com-gitlab-org-test-elastic-image']
)
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