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
| @@ -268,6 +268,13 @@ img.avatar { | @@ -268,6 +268,13 @@ img.avatar { | ||
| 268 | -webkit-border-radius: 4px; | 268 | -webkit-border-radius: 4px; |
| 269 | -moz-border-radius: 4px; | 269 | -moz-border-radius: 4px; |
| 270 | border-radius: 4px; | 270 | border-radius: 4px; |
| 271 | + | ||
| 272 | + &.s16 { | ||
| 273 | + width:16px; | ||
| 274 | + } | ||
| 275 | + &.s24 { | ||
| 276 | + width:24px; | ||
| 277 | + } | ||
| 271 | } | 278 | } |
| 272 | 279 | ||
| 273 | img.lil_av { | 280 | img.lil_av { |
app/assets/stylesheets/tree.scss
| @@ -53,6 +53,11 @@ | @@ -53,6 +53,11 @@ | ||
| 53 | padding: 9px 10px; | 53 | padding: 9px 10px; |
| 54 | height:18px; | 54 | height:18px; |
| 55 | 55 | ||
| 56 | + .options { | ||
| 57 | + float:right; | ||
| 58 | + margin-top: -5px; | ||
| 59 | + } | ||
| 60 | + | ||
| 56 | .file_name { | 61 | .file_name { |
| 57 | color:$style_color; | 62 | color:$style_color; |
| 58 | font-size:14px; | 63 | font-size:14px; |
| @@ -220,3 +225,27 @@ | @@ -220,3 +225,27 @@ | ||
| 220 | margin:0; | 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,7 +8,7 @@ class RefsController < ApplicationController | ||
| 8 | before_filter :require_non_empty_project | 8 | before_filter :require_non_empty_project |
| 9 | 9 | ||
| 10 | before_filter :ref | 10 | before_filter :ref |
| 11 | - before_filter :define_tree_vars, :only => [:tree, :blob] | 11 | + before_filter :define_tree_vars, :only => [:tree, :blob, :blame] |
| 12 | before_filter :render_full_content | 12 | before_filter :render_full_content |
| 13 | 13 | ||
| 14 | layout "project" | 14 | layout "project" |
| @@ -62,6 +62,10 @@ class RefsController < ApplicationController | @@ -62,6 +62,10 @@ class RefsController < ApplicationController | ||
| 62 | return render_404 | 62 | return render_404 |
| 63 | end | 63 | end |
| 64 | 64 | ||
| 65 | + def blame | ||
| 66 | + @blame = Grit::Blob.blame(@repo, @commit.id, params[:path]) | ||
| 67 | + end | ||
| 68 | + | ||
| 65 | protected | 69 | protected |
| 66 | 70 | ||
| 67 | def define_tree_vars | 71 | def define_tree_vars |
| @@ -0,0 +1,10 @@ | @@ -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 | .view_file | 1 | .view_file |
| 3 | .view_file_header | 2 | .view_file_header |
| 4 | %i.icon-file | 3 | %i.icon-file |
| 5 | %span.file_name | 4 | %span.file_name |
| 6 | = name | 5 | = name |
| 7 | %small #{file.mode} | 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 | - if file.text? | 11 | - if file.text? |
| 12 | - if name =~ /\.(md|markdown)$/i | 12 | - if name =~ /\.(md|markdown)$/i |
| 13 | #tree-readme-holder | 13 | #tree-readme-holder |
| @@ -0,0 +1,46 @@ | @@ -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 | #tree-holder= render :partial => "tree", :locals => {:repo => @repo, :commit => @commit, :tree => @tree} | 2 | #tree-holder= render :partial => "tree", :locals => {:repo => @repo, :commit => @commit, :tree => @tree} |
| 12 | 3 | ||
| 13 | :javascript | 4 | :javascript |
config/routes.rb
| @@ -94,6 +94,14 @@ Gitlab::Application.routes.draw do | @@ -94,6 +94,14 @@ Gitlab::Application.routes.draw do | ||
| 94 | :id => /[a-zA-Z.0-9\/_\-]+/, | 94 | :id => /[a-zA-Z.0-9\/_\-]+/, |
| 95 | :path => /.*/ | 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 | end | 105 | end |
| 98 | end | 106 | end |
| 99 | 107 |
| @@ -0,0 +1,25 @@ | @@ -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 |