Commit 9cd8f7b08296d73532c66f06581ff47dab9720a3
1 parent
2e54ac17
Exists in
master
and in
4 other branches
New Feature: Git Blame for file
Showing
9 changed files
with
135 additions
and
15 deletions
Show diff stats
app/assets/stylesheets/gitlab_bootstrap.scss
app/assets/stylesheets/tree.scss
| ... | ... | @@ -53,6 +53,11 @@ |
| 53 | 53 | padding: 9px 10px; |
| 54 | 54 | height:18px; |
| 55 | 55 | |
| 56 | + .options { | |
| 57 | + float:right; | |
| 58 | + margin-top: -5px; | |
| 59 | + } | |
| 60 | + | |
| 56 | 61 | .file_name { |
| 57 | 62 | color:$style_color; |
| 58 | 63 | font-size:14px; |
| ... | ... | @@ -220,3 +225,27 @@ |
| 220 | 225 | margin:0; |
| 221 | 226 | } |
| 222 | 227 | } |
| 228 | + | |
| 229 | +.blame_file { | |
| 230 | + .view_file_content { | |
| 231 | + tr { | |
| 232 | + border-bottom: 1px solid #eee; | |
| 233 | + } | |
| 234 | + td { | |
| 235 | + padding:5px; | |
| 236 | + } | |
| 237 | + .author, | |
| 238 | + .commit { | |
| 239 | + background:#f5f5f5; | |
| 240 | + vertical-align:top; | |
| 241 | + } | |
| 242 | + .lines { | |
| 243 | + pre { | |
| 244 | + padding:0; | |
| 245 | + margin:0; | |
| 246 | + background:none; | |
| 247 | + border:none; | |
| 248 | + } | |
| 249 | + } | |
| 250 | + } | |
| 251 | +} | ... | ... |
app/controllers/refs_controller.rb
| ... | ... | @@ -8,7 +8,7 @@ class RefsController < ApplicationController |
| 8 | 8 | before_filter :require_non_empty_project |
| 9 | 9 | |
| 10 | 10 | before_filter :ref |
| 11 | - before_filter :define_tree_vars, :only => [:tree, :blob] | |
| 11 | + before_filter :define_tree_vars, :only => [:tree, :blob, :blame] | |
| 12 | 12 | before_filter :render_full_content |
| 13 | 13 | |
| 14 | 14 | layout "project" |
| ... | ... | @@ -62,6 +62,10 @@ class RefsController < ApplicationController |
| 62 | 62 | return render_404 |
| 63 | 63 | end |
| 64 | 64 | |
| 65 | + def blame | |
| 66 | + @blame = Grit::Blob.blame(@repo, @commit.id, params[:path]) | |
| 67 | + end | |
| 68 | + | |
| 65 | 69 | protected |
| 66 | 70 | |
| 67 | 71 | def define_tree_vars | ... | ... |
| ... | ... | @@ -0,0 +1,10 @@ |
| 1 | +%ul.nav.nav-tabs | |
| 2 | + %li | |
| 3 | + = form_tag switch_project_refs_path(@project), :method => :get, :class => "project-refs-form", :remote => true do | |
| 4 | + = select_tag "ref", grouped_options_refs, :onchange => "$(this.form).trigger('submit');", :class => "project-refs-select" | |
| 5 | + = hidden_field_tag :destination, "tree" | |
| 6 | + = hidden_field_tag :path, params[:path] | |
| 7 | + %li{:class => "#{'active' if (controller.controller_name == "refs") }"} | |
| 8 | + = link_to tree_project_ref_path(@project, @ref) do | |
| 9 | + Code | |
| 10 | + | ... | ... |
app/views/refs/_tree_file.html.haml
| 1 | -:css | |
| 2 | 1 | .view_file |
| 3 | 2 | .view_file_header |
| 4 | 3 | %i.icon-file |
| 5 | 4 | %span.file_name |
| 6 | 5 | = name |
| 7 | 6 | %small #{file.mode} |
| 8 | - %span.right | |
| 9 | - = link_to "raw", blob_project_ref_path(@project, @ref, :path => params[:path]), :class => "right", :target => "_blank" | |
| 10 | - = link_to "history", project_commits_path(@project, :path => params[:path], :ref => @ref), :class => "right", :style => "margin-right:10px;" | |
| 7 | + %span.options | |
| 8 | + = link_to "raw", blob_project_ref_path(@project, @ref, :path => params[:path]), :class => "btn very_small", :target => "_blank" | |
| 9 | + = link_to "history", project_commits_path(@project, :path => params[:path], :ref => @ref), :class => "btn very_small" | |
| 10 | + = link_to "blame", blame_file_project_ref_path(@project, @ref, :path => params[:path]), :class => "btn very_small" | |
| 11 | 11 | - if file.text? |
| 12 | 12 | - if name =~ /\.(md|markdown)$/i |
| 13 | 13 | #tree-readme-holder | ... | ... |
| ... | ... | @@ -0,0 +1,46 @@ |
| 1 | += render "head" | |
| 2 | + | |
| 3 | +#tree-holder | |
| 4 | + %ul.breadcrumb | |
| 5 | + %li | |
| 6 | + %span.arrow | |
| 7 | + = link_to tree_project_ref_path(@project, @ref, :path => nil) do | |
| 8 | + = @project.name | |
| 9 | + - @tree.breadcrumbs(6) do |link| | |
| 10 | + \/ | |
| 11 | + %li= link | |
| 12 | + .clear | |
| 13 | + | |
| 14 | + .view_file.blame_file | |
| 15 | + .view_file_header | |
| 16 | + %i.icon-file | |
| 17 | + %span.file_name | |
| 18 | + = @tree.name | |
| 19 | + %small blame | |
| 20 | + %span.options | |
| 21 | + = link_to "raw", blob_project_ref_path(@project, @ref, :path => params[:path]), :class => "btn very_small", :target => "_blank" | |
| 22 | + = link_to "history", project_commits_path(@project, :path => params[:path], :ref => @ref), :class => "btn very_small" | |
| 23 | + = link_to "source", tree_file_project_ref_path(@project, @ref, :path => params[:path]), :class => "btn very_small" | |
| 24 | + .view_file_content | |
| 25 | + %table | |
| 26 | + - @blame.each do |commit, lines| | |
| 27 | + - commit = Commit.new(commit) | |
| 28 | + %tr | |
| 29 | + %td.author | |
| 30 | + = image_tag gravatar_icon(commit.author_email, 16) | |
| 31 | + = commit.author_name | |
| 32 | + %td.commit | |
| 33 | + | |
| 34 | + = link_to project_commit_path(@project, :id => commit.id) do | |
| 35 | + %code= commit.id.to_s[0..10] | |
| 36 | + %span.row_title= truncate(commit.safe_message, :length => 30) rescue "--broken encoding" | |
| 37 | + %td.lines | |
| 38 | + = preserve do | |
| 39 | + %pre | |
| 40 | + - lines.each do |line| | |
| 41 | + = line | |
| 42 | + | |
| 43 | +:javascript | |
| 44 | + $(function(){ | |
| 45 | + $('.project-refs-select').chosen(); | |
| 46 | + }); | ... | ... |
app/views/refs/tree.html.haml
| 1 | -%ul.nav.nav-tabs | |
| 2 | - %li | |
| 3 | - = form_tag switch_project_refs_path(@project), :method => :get, :class => "project-refs-form", :remote => true do | |
| 4 | - = select_tag "ref", grouped_options_refs, :onchange => "$(this.form).trigger('submit');", :class => "project-refs-select" | |
| 5 | - = hidden_field_tag :destination, "tree" | |
| 6 | - = hidden_field_tag :path, params[:path] | |
| 7 | - %li{:class => "#{'active' if (controller.controller_name == "refs") }"} | |
| 8 | - = link_to tree_project_ref_path(@project, @ref) do | |
| 9 | - Code | |
| 10 | - | |
| 1 | += render "head" | |
| 11 | 2 | #tree-holder= render :partial => "tree", :locals => {:repo => @repo, :commit => @commit, :tree => @tree} |
| 12 | 3 | |
| 13 | 4 | :javascript | ... | ... |
config/routes.rb
| ... | ... | @@ -94,6 +94,14 @@ Gitlab::Application.routes.draw do |
| 94 | 94 | :id => /[a-zA-Z.0-9\/_\-]+/, |
| 95 | 95 | :path => /.*/ |
| 96 | 96 | } |
| 97 | + | |
| 98 | + # blame | |
| 99 | + get "blame/:path" => "refs#blame", | |
| 100 | + :as => :blame_file, | |
| 101 | + :constraints => { | |
| 102 | + :id => /[a-zA-Z.0-9\/_\-]+/, | |
| 103 | + :path => /.*/ | |
| 104 | + } | |
| 97 | 105 | end |
| 98 | 106 | end |
| 99 | 107 | ... | ... |
| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | +require 'spec_helper' | |
| 2 | + | |
| 3 | +describe "Blame file" do | |
| 4 | + before { login_as :user } | |
| 5 | + | |
| 6 | + describe "GET /:projectname/:commit/blob/Gemfile" do | |
| 7 | + before do | |
| 8 | + @project = Factory :project | |
| 9 | + @project.add_access(@user, :read) | |
| 10 | + | |
| 11 | + visit tree_project_ref_path(@project, @project.root_ref, :path => "Gemfile") | |
| 12 | + click_link "blame" | |
| 13 | + end | |
| 14 | + | |
| 15 | + it "should be correct path" do | |
| 16 | + current_path.should == blame_file_project_ref_path(@project, @project.root_ref, :path => "Gemfile") | |
| 17 | + end | |
| 18 | + | |
| 19 | + it "should contain file view" do | |
| 20 | + page.should have_content("rubygems.org") | |
| 21 | + page.should have_content("Dmitriy Zaporozhets") | |
| 22 | + page.should have_content("bc3735004cb Moving to rails 3.2") | |
| 23 | + end | |
| 24 | + end | |
| 25 | +end | ... | ... |