Commit 7f57fe5034f6fdfbdd4e29745b50e7bfa1576bf5
Committed by
Dmitriy Zaporozhets
1 parent
4353babe
Exists in
master
and in
4 other branches
Implemented code search feature
Showing
11 changed files
with
98 additions
and
7 deletions
Show diff stats
.travis.yml
Gemfile
| ... | ... | @@ -23,7 +23,7 @@ gem 'omniauth-github' |
| 23 | 23 | |
| 24 | 24 | # Extracting information from a git repository |
| 25 | 25 | # We cannot use original git since some bugs |
| 26 | -gem "grit", '~> 2.5.0', git: 'https://github.com/gitlabhq/grit.git', ref: '42297cdcee16284d2e4eff23d41377f52fc28b9d' | |
| 26 | +gem "grit", '~> 2.5.0', git: 'https://github.com/gitlabhq/grit.git' | |
| 27 | 27 | gem 'gitlab_git', '~> 1.0.6' |
| 28 | 28 | |
| 29 | 29 | # Ruby/Rack Git Smart-HTTP Server Handler | ... | ... |
Gemfile.lock
| ... | ... | @@ -8,8 +8,7 @@ GIT |
| 8 | 8 | |
| 9 | 9 | GIT |
| 10 | 10 | remote: https://github.com/gitlabhq/grit.git |
| 11 | - revision: 42297cdcee16284d2e4eff23d41377f52fc28b9d | |
| 12 | - ref: 42297cdcee16284d2e4eff23d41377f52fc28b9d | |
| 11 | + revision: e873bb84ac3c4f8249311490d6a7c6ac9127625f | |
| 13 | 12 | specs: |
| 14 | 13 | grit (2.5.0) |
| 15 | 14 | diff-lcs (~> 1.1) | ... | ... |
app/contexts/search_context.rb
| ... | ... | @@ -10,7 +10,11 @@ class SearchContext |
| 10 | 10 | |
| 11 | 11 | return result unless query.present? |
| 12 | 12 | |
| 13 | - result[:projects] = Project.where(id: project_ids).search(query).limit(10) | |
| 13 | + projects = Project.where(id: project_ids) | |
| 14 | + result[:projects] = projects.search(query).limit(10) | |
| 15 | + if projects.length == 1 | |
| 16 | + result[:snippets] = projects.first.files(query, params[:branch_ref]) | |
| 17 | + end | |
| 14 | 18 | result[:merge_requests] = MergeRequest.where(project_id: project_ids).search(query).limit(10) |
| 15 | 19 | result[:issues] = Issue.where(project_id: project_ids).search(query).limit(10) |
| 16 | 20 | result[:wiki_pages] = [] |
| ... | ... | @@ -22,7 +26,8 @@ class SearchContext |
| 22 | 26 | projects: [], |
| 23 | 27 | merge_requests: [], |
| 24 | 28 | issues: [], |
| 25 | - wiki_pages: [] | |
| 29 | + wiki_pages: [], | |
| 30 | + snippets: [] | |
| 26 | 31 | } |
| 27 | 32 | end |
| 28 | 33 | end | ... | ... |
app/controllers/search_controller.rb
app/models/project.rb
| ... | ... | @@ -411,4 +411,15 @@ class Project < ActiveRecord::Base |
| 411 | 411 | !(forked_project_link.nil? || forked_project_link.forked_from_project.nil?) |
| 412 | 412 | end |
| 413 | 413 | |
| 414 | + def files(query, treeish) | |
| 415 | + snippets = [] | |
| 416 | + tree = treeish.present? ? treeish : default_branch | |
| 417 | + if repository && !tree.nil? | |
| 418 | + greps = repository.repo.grep(query, 3, tree) | |
| 419 | + greps.each do |g| | |
| 420 | + snippets << Gitlab::BlobSnippet.new(self, tree, g.content, g.startline, g.filename) | |
| 421 | + end | |
| 422 | + end | |
| 423 | + snippets | |
| 424 | + end | |
| 414 | 425 | end | ... | ... |
app/views/layouts/_search.html.haml
| ... | ... | @@ -3,4 +3,13 @@ |
| 3 | 3 | = text_field_tag "search", nil, placeholder: "Search", class: "search-input" |
| 4 | 4 | = hidden_field_tag :group_id, @group.try(:id) |
| 5 | 5 | = hidden_field_tag :project_id, @project.try(:id) |
| 6 | - .search-autocomplete-json.hide{:'data-autocomplete-opts' => search_autocomplete_source } | |
| 6 | + - if @ref | |
| 7 | + - @branch_ref = @ref | |
| 8 | + - else | |
| 9 | + - @branch_ref = @project.try(:default_branch) | |
| 10 | + - if @branch_ref.blank? | |
| 11 | + - @branch_ref = 'master' | |
| 12 | + = hidden_field_tag :branch_ref, @branch_ref | |
| 13 | + - if ENV['RAILS_ENV'] == 'test' | |
| 14 | + = submit_tag 'Go' | |
| 15 | + .search-autocomplete-json.hide{:'data-autocomplete-opts' => search_autocomplete_source } | |
| 7 | 16 | \ No newline at end of file | ... | ... |
app/views/search/_result.html.haml
| ... | ... | @@ -32,6 +32,15 @@ |
| 32 | 32 | %strong.term |
| 33 | 33 | = truncate wiki_page.title, length: 50 |
| 34 | 34 | %span.light (#{wiki_page.project.name_with_namespace}) |
| 35 | + - @snippets.each do |snippet| | |
| 36 | + %li | |
| 37 | + code: | |
| 38 | + = link_to project_blob_path(snippet.project, tree_join(snippet.tree, snippet.filename), :anchor => "L" + snippet.startline.to_s) do | |
| 39 | + %strong.term | |
| 40 | + = snippet.filename | |
| 41 | + .file_content.code | |
| 42 | + %div{class: user_color_scheme_class} | |
| 43 | + = raw snippet.colorize( formatter: :gitlab, options: { first_line_number: snippet.startline } ) | |
| 35 | 44 | |
| 36 | 45 | :javascript |
| 37 | 46 | $(function() { | ... | ... |
| ... | ... | @@ -0,0 +1,9 @@ |
| 1 | +Feature: Project Search code | |
| 2 | + Background: | |
| 3 | + Given I sign in as a user | |
| 4 | + And I own project "Shop" | |
| 5 | + Given I visit project source page | |
| 6 | + | |
| 7 | + Scenario: Search for term "Welcome to Gitlab" | |
| 8 | + When I search for term "Welcome to Gitlab" | |
| 9 | + Then I should see files from repository containing "Welcome to Gitlab" | ... | ... |
| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | +class ProjectSearchCode < Spinach::FeatureSteps | |
| 2 | + include SharedAuthentication | |
| 3 | + include SharedProject | |
| 4 | + include SharedPaths | |
| 5 | + | |
| 6 | + When 'I search for term "Welcome to Gitlab"' do | |
| 7 | + fill_in "search", with: "Welcome to Gitlab" | |
| 8 | + click_button "Go" | |
| 9 | + end | |
| 10 | + | |
| 11 | + Then 'I should see files from repository containing "Welcome to Gitlab"' do | |
| 12 | + page.should have_content "Welcome to Gitlab" | |
| 13 | + page.should have_content "GitLab is a free project and repository management application" | |
| 14 | + end | |
| 15 | + | |
| 16 | +end | ... | ... |
| ... | ... | @@ -0,0 +1,32 @@ |
| 1 | +module Gitlab | |
| 2 | + class BlobSnippet | |
| 3 | + include Linguist::BlobHelper | |
| 4 | + | |
| 5 | + attr_accessor :project | |
| 6 | + attr_accessor :tree | |
| 7 | + attr_accessor :lines | |
| 8 | + attr_accessor :filename | |
| 9 | + attr_accessor :startline | |
| 10 | + | |
| 11 | + def initialize(project, tree, lines, startline, filename) | |
| 12 | + @project, @tree, @lines, @startline, @filename = project, tree, lines, startline, filename | |
| 13 | + end | |
| 14 | + | |
| 15 | + def data | |
| 16 | + lines.join("\n") | |
| 17 | + end | |
| 18 | + | |
| 19 | + def name | |
| 20 | + filename | |
| 21 | + end | |
| 22 | + | |
| 23 | + def size | |
| 24 | + data.length | |
| 25 | + end | |
| 26 | + | |
| 27 | + def mode | |
| 28 | + nil | |
| 29 | + end | |
| 30 | + | |
| 31 | + end | |
| 32 | +end | |
| 0 | 33 | \ No newline at end of file | ... | ... |