Commit 4bbe2b74a85793c06679851706633cbee87ff8ca
Exists in
master
and in
4 other branches
Merge branch 'feature/merge_request_serialize'
Showing
40 changed files
with
388 additions
and
201 deletions
Show diff stats
app/controllers/blame_controller.rb
| @@ -8,6 +8,7 @@ class BlameController < ProjectResourceController | @@ -8,6 +8,7 @@ class BlameController < ProjectResourceController | ||
| 8 | before_filter :require_non_empty_project | 8 | before_filter :require_non_empty_project |
| 9 | 9 | ||
| 10 | def show | 10 | def show |
| 11 | + @blob = Gitlab::Git::Blob.new(@repository, @commit.id, @ref, @path) | ||
| 11 | @blame = Gitlab::Git::Blame.new(project.repository, @commit.id, @path) | 12 | @blame = Gitlab::Git::Blame.new(project.repository, @commit.id, @path) |
| 12 | end | 13 | end |
| 13 | end | 14 | end |
app/controllers/blob_controller.rb
| @@ -8,15 +8,6 @@ class BlobController < ProjectResourceController | @@ -8,15 +8,6 @@ class BlobController < ProjectResourceController | ||
| 8 | before_filter :require_non_empty_project | 8 | before_filter :require_non_empty_project |
| 9 | 9 | ||
| 10 | def show | 10 | def show |
| 11 | - if @tree.is_blob? | ||
| 12 | - send_data( | ||
| 13 | - @tree.data, | ||
| 14 | - type: @tree.mime_type, | ||
| 15 | - disposition: 'inline', | ||
| 16 | - filename: @tree.name | ||
| 17 | - ) | ||
| 18 | - else | ||
| 19 | - not_found! | ||
| 20 | - end | 11 | + @blob = Gitlab::Git::Blob.new(@repository, @commit.id, @ref, @path) |
| 21 | end | 12 | end |
| 22 | end | 13 | end |
| @@ -0,0 +1,25 @@ | @@ -0,0 +1,25 @@ | ||
| 1 | +# Controller for viewing a file's raw | ||
| 2 | +class RawController < ProjectResourceController | ||
| 3 | + include ExtractsPath | ||
| 4 | + | ||
| 5 | + # Authorize | ||
| 6 | + before_filter :authorize_read_project! | ||
| 7 | + before_filter :authorize_code_access! | ||
| 8 | + before_filter :require_non_empty_project | ||
| 9 | + | ||
| 10 | + def show | ||
| 11 | + @blob = Gitlab::Git::Blob.new(@repository, @commit.id, @ref, @path) | ||
| 12 | + | ||
| 13 | + if @blob.exists? | ||
| 14 | + send_data( | ||
| 15 | + @blob.data, | ||
| 16 | + type: @blob.mime_type, | ||
| 17 | + disposition: 'inline', | ||
| 18 | + filename: @blob.name | ||
| 19 | + ) | ||
| 20 | + else | ||
| 21 | + not_found! | ||
| 22 | + end | ||
| 23 | + end | ||
| 24 | +end | ||
| 25 | + |
app/controllers/refs_controller.rb
| @@ -30,7 +30,7 @@ class RefsController < ProjectResourceController | @@ -30,7 +30,7 @@ class RefsController < ProjectResourceController | ||
| 30 | end | 30 | end |
| 31 | 31 | ||
| 32 | def logs_tree | 32 | def logs_tree |
| 33 | - contents = @tree.contents | 33 | + contents = @tree.entries |
| 34 | @logs = contents.map do |content| | 34 | @logs = contents.map do |content| |
| 35 | file = params[:path] ? File.join(params[:path], content.name) : content.name | 35 | file = params[:path] ? File.join(params[:path], content.name) : content.name |
| 36 | last_commit = @repo.commits(@commit.id, file, 1).last | 36 | last_commit = @repo.commits(@commit.id, file, 1).last |
| @@ -48,7 +48,7 @@ class RefsController < ProjectResourceController | @@ -48,7 +48,7 @@ class RefsController < ProjectResourceController | ||
| 48 | 48 | ||
| 49 | @repo = project.repository | 49 | @repo = project.repository |
| 50 | @commit = @repo.commit(@ref) | 50 | @commit = @repo.commit(@ref) |
| 51 | - @tree = Tree.new(@commit.tree, @ref, params[:path]) | 51 | + @tree = Tree.new(@repo, @commit.id, @ref, params[:path]) |
| 52 | @hex_path = Digest::SHA1.hexdigest(params[:path] || "") | 52 | @hex_path = Digest::SHA1.hexdigest(params[:path] || "") |
| 53 | 53 | ||
| 54 | if params[:path] | 54 | if params[:path] |
app/helpers/tree_helper.rb
| @@ -3,9 +3,9 @@ module TreeHelper | @@ -3,9 +3,9 @@ module TreeHelper | ||
| 3 | # their corresponding partials | 3 | # their corresponding partials |
| 4 | # | 4 | # |
| 5 | # contents - A Grit::Tree object for the current tree | 5 | # contents - A Grit::Tree object for the current tree |
| 6 | - def render_tree(contents) | 6 | + def render_tree(tree) |
| 7 | # Render Folders before Files/Submodules | 7 | # Render Folders before Files/Submodules |
| 8 | - folders, files = contents.partition { |v| v.kind_of?(Grit::Tree) } | 8 | + folders, files = tree.trees, tree.blobs |
| 9 | 9 | ||
| 10 | tree = "" | 10 | tree = "" |
| 11 | 11 | ||
| @@ -18,7 +18,7 @@ module TreeHelper | @@ -18,7 +18,7 @@ module TreeHelper | ||
| 18 | render partial: 'tree/submodule_item', object: f | 18 | render partial: 'tree/submodule_item', object: f |
| 19 | else | 19 | else |
| 20 | # Object is a Blob | 20 | # Object is a Blob |
| 21 | - render partial: 'tree/tree_item', object: f, locals: {type: 'file'} | 21 | + render partial: 'tree/blob_item', object: f, locals: {type: 'file'} |
| 22 | end | 22 | end |
| 23 | 23 | ||
| 24 | tree += html if html.present? | 24 | tree += html if html.present? |
| @@ -91,5 +91,4 @@ module TreeHelper | @@ -91,5 +91,4 @@ module TreeHelper | ||
| 91 | file = File.join(tree.path, "..") | 91 | file = File.join(tree.path, "..") |
| 92 | tree_join(tree.ref, file) | 92 | tree_join(tree.ref, file) |
| 93 | end | 93 | end |
| 94 | - | ||
| 95 | end | 94 | end |
app/models/merge_request.rb
| @@ -152,17 +152,7 @@ class MergeRequest < ActiveRecord::Base | @@ -152,17 +152,7 @@ class MergeRequest < ActiveRecord::Base | ||
| 152 | end | 152 | end |
| 153 | 153 | ||
| 154 | def commits | 154 | def commits |
| 155 | - if st_commits.present? | ||
| 156 | - # check if merge request commits are valid | ||
| 157 | - if st_commits.first.respond_to?(:short_id) | ||
| 158 | - st_commits | ||
| 159 | - else | ||
| 160 | - # if commits are invalid - simply reload it from repo | ||
| 161 | - reloaded_commits | ||
| 162 | - end | ||
| 163 | - else | ||
| 164 | - [] | ||
| 165 | - end | 155 | + load_commits(st_commits || []) |
| 166 | end | 156 | end |
| 167 | 157 | ||
| 168 | def probably_merged? | 158 | def probably_merged? |
| @@ -172,13 +162,7 @@ class MergeRequest < ActiveRecord::Base | @@ -172,13 +162,7 @@ class MergeRequest < ActiveRecord::Base | ||
| 172 | 162 | ||
| 173 | def reloaded_commits | 163 | def reloaded_commits |
| 174 | if opened? && unmerged_commits.any? | 164 | if opened? && unmerged_commits.any? |
| 175 | - # we need to reset st_commits field first | ||
| 176 | - # in order to prevent internal rails comparison | ||
| 177 | - self.st_commits = [] | ||
| 178 | - save | ||
| 179 | - | ||
| 180 | - # Then we can safely write unmerged commits | ||
| 181 | - self.st_commits = unmerged_commits | 165 | + self.st_commits = dump_commits(unmerged_commits) |
| 182 | save | 166 | save |
| 183 | end | 167 | end |
| 184 | commits | 168 | commits |
| @@ -228,4 +212,14 @@ class MergeRequest < ActiveRecord::Base | @@ -228,4 +212,14 @@ class MergeRequest < ActiveRecord::Base | ||
| 228 | def last_commit_short_sha | 212 | def last_commit_short_sha |
| 229 | @last_commit_short_sha ||= last_commit.sha[0..10] | 213 | @last_commit_short_sha ||= last_commit.sha[0..10] |
| 230 | end | 214 | end |
| 215 | + | ||
| 216 | + private | ||
| 217 | + | ||
| 218 | + def dump_commits(commits) | ||
| 219 | + commits.map(&:to_hash) | ||
| 220 | + end | ||
| 221 | + | ||
| 222 | + def load_commits(array) | ||
| 223 | + array.map { |hash| Commit.new(Gitlab::Git::Commit.new(hash)) } | ||
| 224 | + end | ||
| 231 | end | 225 | end |
app/models/tree.rb
| 1 | class Tree | 1 | class Tree |
| 2 | - include Linguist::BlobHelper | 2 | + attr_accessor :raw |
| 3 | 3 | ||
| 4 | - attr_accessor :path, :tree, :ref | ||
| 5 | - | ||
| 6 | - delegate :contents, :basename, :name, :data, :mime_type, | ||
| 7 | - :mode, :size, :text?, :colorize, to: :tree | ||
| 8 | - | ||
| 9 | - def initialize(raw_tree, ref = nil, path = nil) | ||
| 10 | - @ref, @path = ref, path | ||
| 11 | - @tree = if path.present? | ||
| 12 | - raw_tree / path | ||
| 13 | - else | ||
| 14 | - raw_tree | ||
| 15 | - end | ||
| 16 | - end | ||
| 17 | - | ||
| 18 | - def is_blob? | ||
| 19 | - tree.is_a?(Grit::Blob) | 4 | + def initialize(repository, sha, ref = nil, path = nil) |
| 5 | + @raw = Gitlab::Git::Tree.new(repository, sha, ref, path) | ||
| 20 | end | 6 | end |
| 21 | 7 | ||
| 22 | - def invalid? | ||
| 23 | - tree.nil? | 8 | + def method_missing(m, *args, &block) |
| 9 | + @raw.send(m, *args, &block) | ||
| 24 | end | 10 | end |
| 25 | 11 | ||
| 26 | - def empty? | ||
| 27 | - data.blank? | ||
| 28 | - end | ||
| 29 | - | ||
| 30 | - def up_dir? | ||
| 31 | - path.present? | ||
| 32 | - end | 12 | + def respond_to?(method) |
| 13 | + return true if @raw.respond_to?(method) | ||
| 33 | 14 | ||
| 34 | - def readme | ||
| 35 | - @readme ||= contents.find { |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i } | 15 | + super |
| 36 | end | 16 | end |
| 37 | end | 17 | end |
app/services/git_push_service.rb
| @@ -104,7 +104,7 @@ class GitPushService | @@ -104,7 +104,7 @@ class GitPushService | ||
| 104 | data[:commits] << { | 104 | data[:commits] << { |
| 105 | id: commit.id, | 105 | id: commit.id, |
| 106 | message: commit.safe_message, | 106 | message: commit.safe_message, |
| 107 | - timestamp: commit.date.xmlschema, | 107 | + timestamp: commit.committed_date.xmlschema, |
| 108 | url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/#{commit.id}", | 108 | url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/#{commit.id}", |
| 109 | author: { | 109 | author: { |
| 110 | name: commit.author_name, | 110 | name: commit.author_name, |
app/views/blame/show.html.haml
| @@ -15,9 +15,9 @@ | @@ -15,9 +15,9 @@ | ||
| 15 | .file_title | 15 | .file_title |
| 16 | %i.icon-file | 16 | %i.icon-file |
| 17 | %span.file_name | 17 | %span.file_name |
| 18 | - = @tree.name | ||
| 19 | - %small= number_to_human_size @tree.size | ||
| 20 | - %span.options= render "tree/blob_actions" | 18 | + = @blob.name |
| 19 | + %small= number_to_human_size @blob.size | ||
| 20 | + %span.options= render "blob/actions" | ||
| 21 | .file_content.blame | 21 | .file_content.blame |
| 22 | %table | 22 | %table |
| 23 | - current_line = 1 | 23 | - current_line = 1 |
| @@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
| 1 | +.btn-group.tree-btn-group | ||
| 2 | + -# only show edit link for text files | ||
| 3 | + - if @blob.text? | ||
| 4 | + = link_to "edit", project_edit_tree_path(@project, @id), class: "btn btn-tiny", disabled: !allowed_tree_edit? | ||
| 5 | + = link_to "raw", project_raw_path(@project, @id), class: "btn btn-tiny", target: "_blank" | ||
| 6 | + -# only show normal/blame view links for text files | ||
| 7 | + - if @blob.text? | ||
| 8 | + - if current_page? project_blame_path(@project, @id) | ||
| 9 | + = link_to "normal view", project_blob_path(@project, @id), class: "btn btn-tiny" | ||
| 10 | + - else | ||
| 11 | + = link_to "blame", project_blame_path(@project, @id), class: "btn btn-tiny" | ||
| 12 | + = link_to "history", project_commits_path(@project, @id), class: "btn btn-tiny" |
| @@ -0,0 +1,27 @@ | @@ -0,0 +1,27 @@ | ||
| 1 | +%ul.breadcrumb | ||
| 2 | + %li | ||
| 3 | + %i.icon-angle-right | ||
| 4 | + = link_to project_tree_path(@project, @ref) do | ||
| 5 | + = @project.path | ||
| 6 | + - tree_breadcrumbs(@tree, 6) do |title, path| | ||
| 7 | + \/ | ||
| 8 | + %li | ||
| 9 | + - if path | ||
| 10 | + = link_to truncate(title, length: 40), project_tree_path(@project, path) | ||
| 11 | + - else | ||
| 12 | + = link_to title, '#' | ||
| 13 | + | ||
| 14 | +%div#tree-content-holder.tree-content-holder | ||
| 15 | + .file_holder | ||
| 16 | + .file_title | ||
| 17 | + %i.icon-file | ||
| 18 | + %span.file_name | ||
| 19 | + = blob.name | ||
| 20 | + %small= number_to_human_size blob.size | ||
| 21 | + %span.options= render "actions" | ||
| 22 | + - if blob.text? | ||
| 23 | + = render "text", blob: blob | ||
| 24 | + - elsif blob.image? | ||
| 25 | + = render "image", blob: blob | ||
| 26 | + - else | ||
| 27 | + = render "download", blob: blob |
| @@ -0,0 +1,14 @@ | @@ -0,0 +1,14 @@ | ||
| 1 | +- if gitlab_markdown?(blob.name) | ||
| 2 | + .file_content.wiki | ||
| 3 | + = preserve do | ||
| 4 | + = markdown(blob.data) | ||
| 5 | +- elsif markup?(blob.name) | ||
| 6 | + .file_content.wiki | ||
| 7 | + = raw GitHub::Markup.render(blob.name, blob.data) | ||
| 8 | +- else | ||
| 9 | + .file_content.code | ||
| 10 | + - unless blob.empty? | ||
| 11 | + %div{class: user_color_scheme_class} | ||
| 12 | + = raw blob.colorize(formatter: :gitlab) | ||
| 13 | + - else | ||
| 14 | + %p.nothing_here_message Empty file |
| @@ -0,0 +1,10 @@ | @@ -0,0 +1,10 @@ | ||
| 1 | +:plain | ||
| 2 | + // Load Files list | ||
| 3 | + $("#tree-holder").html("#{escape_javascript(render(partial: "blob", locals: {blob: @blob}))}"); | ||
| 4 | + $("#tree-content-holder").show("slide", { direction: "right" }, 400); | ||
| 5 | + $('.project-refs-form #path').val("#{@path}"); | ||
| 6 | + | ||
| 7 | + // Load last commit log for each file in tree | ||
| 8 | + $('#tree-slider').waitForImages(function() { | ||
| 9 | + ajaxGet('#{@logs_path}'); | ||
| 10 | + }); |
app/views/commits/_diffs.html.haml
| @@ -16,16 +16,16 @@ | @@ -16,16 +16,16 @@ | ||
| 16 | - unless @suppress_diff | 16 | - unless @suppress_diff |
| 17 | - diffs.each_with_index do |diff, i| | 17 | - diffs.each_with_index do |diff, i| |
| 18 | - next if diff.diff.empty? | 18 | - next if diff.diff.empty? |
| 19 | - - file = (@commit.tree / diff.new_path) | ||
| 20 | - - file = (@commit.prev_commit.tree / diff.old_path) unless file | 19 | + - file = Gitlab::Git::Blob.new(@repository, @commit.id, @ref, diff.new_path) |
| 20 | + - file = Gitlab::Git::Blob.new(@repository, @commit.parent_id, @ref, diff.old_path) unless file.exists? | ||
| 21 | - next unless file | 21 | - next unless file |
| 22 | .file{id: "diff-#{i}"} | 22 | .file{id: "diff-#{i}"} |
| 23 | .header | 23 | .header |
| 24 | - if diff.deleted_file | 24 | - if diff.deleted_file |
| 25 | %span= diff.old_path | 25 | %span= diff.old_path |
| 26 | 26 | ||
| 27 | - - if @commit.prev_commit | ||
| 28 | - = link_to project_tree_path(@project, tree_join(@commit.prev_commit_id, diff.new_path)), {:class => 'btn btn-tiny pull-right view-file'} do | 27 | + - if @commit.parent_ids.present? |
| 28 | + = link_to project_tree_path(@project, tree_join(@commit.parent_id, diff.new_path)), {:class => 'btn btn-tiny pull-right view-file'} do | ||
| 29 | View file @ | 29 | View file @ |
| 30 | %span.commit-short-id= @commit.short_id(6) | 30 | %span.commit-short-id= @commit.short_id(6) |
| 31 | - else | 31 | - else |
| @@ -43,7 +43,7 @@ | @@ -43,7 +43,7 @@ | ||
| 43 | - if file.text? | 43 | - if file.text? |
| 44 | = render "commits/text_file", diff: diff, index: i | 44 | = render "commits/text_file", diff: diff, index: i |
| 45 | - elsif file.image? | 45 | - elsif file.image? |
| 46 | - - old_file = (@commit.prev_commit.tree / diff.old_path) if !@commit.prev_commit.nil? | 46 | + - old_file = Gitlab::Git::Blob.new(@repository, @commit.parent_id, @ref, diff.old_path) if @commit.parent_id |
| 47 | = render "commits/image", diff: diff, old_file: old_file, file: file, index: i | 47 | = render "commits/image", diff: diff, old_file: old_file, file: file, index: i |
| 48 | - else | 48 | - else |
| 49 | %p.nothing_here_message No preview for this file type | 49 | %p.nothing_here_message No preview for this file type |
app/views/graph/show.json.erb
| @@ -7,9 +7,9 @@ | @@ -7,9 +7,9 @@ | ||
| 7 | { | 7 | { |
| 8 | parents: parents_zip_spaces(c.parents(@graph.map), c.parent_spaces), | 8 | parents: parents_zip_spaces(c.parents(@graph.map), c.parent_spaces), |
| 9 | author: { | 9 | author: { |
| 10 | - name: c.author.name, | ||
| 11 | - email: c.author.email, | ||
| 12 | - icon: gravatar_icon(c.author.email, 20) | 10 | + name: c.author_name, |
| 11 | + email: c.author_email, | ||
| 12 | + icon: gravatar_icon(c.author_email, 20) | ||
| 13 | }, | 13 | }, |
| 14 | time: c.time, | 14 | time: c.time, |
| 15 | space: c.spaces.first, | 15 | space: c.spaces.first, |
app/views/tree/_blob.html.haml
| @@ -1,13 +0,0 @@ | @@ -1,13 +0,0 @@ | ||
| 1 | -.file_holder | ||
| 2 | - .file_title | ||
| 3 | - %i.icon-file | ||
| 4 | - %span.file_name | ||
| 5 | - = blob.name | ||
| 6 | - %small= number_to_human_size blob.size | ||
| 7 | - %span.options= render "tree/blob_actions" | ||
| 8 | - - if blob.text? | ||
| 9 | - = render "tree/blob/text", blob: blob | ||
| 10 | - - elsif blob.image? | ||
| 11 | - = render "tree/blob/image", blob: blob | ||
| 12 | - - else | ||
| 13 | - = render "tree/blob/download", blob: blob |
app/views/tree/_blob_actions.html.haml
| @@ -1,12 +0,0 @@ | @@ -1,12 +0,0 @@ | ||
| 1 | -.btn-group.tree-btn-group | ||
| 2 | - -# only show edit link for text files | ||
| 3 | - - if @tree.text? | ||
| 4 | - = link_to "edit", project_edit_tree_path(@project, @id), class: "btn btn-tiny", disabled: !allowed_tree_edit? | ||
| 5 | - = link_to "raw", project_blob_path(@project, @id), class: "btn btn-tiny", target: "_blank" | ||
| 6 | - -# only show normal/blame view links for text files | ||
| 7 | - - if @tree.text? | ||
| 8 | - - if current_page? project_blame_path(@project, @id) | ||
| 9 | - = link_to "normal view", project_tree_path(@project, @id), class: "btn btn-tiny" | ||
| 10 | - - else | ||
| 11 | - = link_to "blame", project_blame_path(@project, @id), class: "btn btn-tiny" | ||
| 12 | - = link_to "history", project_commits_path(@project, @id), class: "btn btn-tiny" |
| @@ -0,0 +1,9 @@ | @@ -0,0 +1,9 @@ | ||
| 1 | +%tr{ class: "tree-item #{tree_hex_class(blob_item)}" } | ||
| 2 | + %td.tree-item-file-name | ||
| 3 | + = tree_icon(type) | ||
| 4 | + %strong= link_to truncate(blob_item.name, length: 40), project_blob_path(@project, tree_join(@id || @commit.id, blob_item.name)) | ||
| 5 | + %td.tree_time_ago.cgray | ||
| 6 | + %span.log_loading.hide | ||
| 7 | + Loading commit data... | ||
| 8 | + = image_tag "ajax_loader_tree.gif", width: 14 | ||
| 9 | + %td.tree_commit{ colspan: 2 } |
app/views/tree/_tree.html.haml
| @@ -12,36 +12,32 @@ | @@ -12,36 +12,32 @@ | ||
| 12 | = link_to title, '#' | 12 | = link_to title, '#' |
| 13 | 13 | ||
| 14 | %div#tree-content-holder.tree-content-holder | 14 | %div#tree-content-holder.tree-content-holder |
| 15 | - - if tree.is_blob? | ||
| 16 | - = render "tree/blob", blob: tree | ||
| 17 | - - else | ||
| 18 | - %table#tree-slider{class: "table_#{@hex_path} tree-table" } | ||
| 19 | - %thead | ||
| 20 | - %tr | ||
| 21 | - %th Name | ||
| 22 | - %th Last Update | ||
| 23 | - %th Last Commit | ||
| 24 | - %th= link_to "history", project_commits_path(@project, @id), class: "btn btn-tiny pull-right" | 15 | + %table#tree-slider{class: "table_#{@hex_path} tree-table" } |
| 16 | + %thead | ||
| 17 | + %tr | ||
| 18 | + %th Name | ||
| 19 | + %th Last Update | ||
| 20 | + %th Last Commit | ||
| 21 | + %th= link_to "history", project_commits_path(@project, @id), class: "btn btn-tiny pull-right" | ||
| 25 | 22 | ||
| 26 | - - if tree.up_dir? | ||
| 27 | - %tr.tree-item | ||
| 28 | - %td.tree-item-file-name | ||
| 29 | - = image_tag "file_empty.png", size: '16x16' | ||
| 30 | - = link_to "..", project_tree_path(@project, up_dir_path(tree)) | ||
| 31 | - %td | ||
| 32 | - %td | ||
| 33 | - %td | 23 | + - if tree.up_dir? |
| 24 | + %tr.tree-item | ||
| 25 | + %td.tree-item-file-name | ||
| 26 | + = image_tag "file_empty.png", size: '16x16' | ||
| 27 | + = link_to "..", project_tree_path(@project, up_dir_path(tree)) | ||
| 28 | + %td | ||
| 29 | + %td | ||
| 30 | + %td | ||
| 34 | 31 | ||
| 35 | - = render_tree(tree.contents) | 32 | + = render_tree(tree) |
| 36 | 33 | ||
| 37 | - - if tree.readme | ||
| 38 | - = render "tree/readme", readme: tree.readme | 34 | + - if tree.readme |
| 35 | + = render "tree/readme", readme: tree.readme | ||
| 39 | 36 | ||
| 40 | %div.tree_progress | 37 | %div.tree_progress |
| 41 | 38 | ||
| 42 | -- unless tree.is_blob? | ||
| 43 | - :javascript | ||
| 44 | - // Load last commit log for each file in tree | ||
| 45 | - $(window).load(function(){ | ||
| 46 | - ajaxGet('#{@logs_path}'); | ||
| 47 | - }); | 39 | +:javascript |
| 40 | + // Load last commit log for each file in tree | ||
| 41 | + $(window).load(function(){ | ||
| 42 | + ajaxGet('#{@logs_path}'); | ||
| 43 | + }); |
app/views/tree/blob/_download.html.haml
app/views/tree/blob/_image.html.haml
app/views/tree/blob/_text.html.haml
| @@ -1,14 +0,0 @@ | @@ -1,14 +0,0 @@ | ||
| 1 | -- if gitlab_markdown?(blob.name) | ||
| 2 | - .file_content.wiki | ||
| 3 | - = preserve do | ||
| 4 | - = markdown(blob.data) | ||
| 5 | -- elsif markup?(blob.name) | ||
| 6 | - .file_content.wiki | ||
| 7 | - = raw GitHub::Markup.render(blob.name, blob.data) | ||
| 8 | -- else | ||
| 9 | - .file_content.code | ||
| 10 | - - unless blob.empty? | ||
| 11 | - %div{class: user_color_scheme_class} | ||
| 12 | - = raw blob.colorize(formatter: :gitlab) | ||
| 13 | - - else | ||
| 14 | - %p.nothing_here_message Empty file |
app/workers/post_receive.rb
| @@ -23,7 +23,7 @@ class PostReceive | @@ -23,7 +23,7 @@ class PostReceive | ||
| 23 | 23 | ||
| 24 | user = if identifier.blank? | 24 | user = if identifier.blank? |
| 25 | # Local push from gitlab | 25 | # Local push from gitlab |
| 26 | - email = project.repository.commit(newrev).author.email rescue nil | 26 | + email = project.repository.commit(newrev).author_email rescue nil |
| 27 | User.find_by_email(email) if email | 27 | User.find_by_email(email) if email |
| 28 | 28 | ||
| 29 | elsif identifier =~ /\Auser-\d+\Z/ | 29 | elsif identifier =~ /\Auser-\d+\Z/ |
config/routes.rb
| @@ -170,6 +170,7 @@ Gitlab::Application.routes.draw do | @@ -170,6 +170,7 @@ Gitlab::Application.routes.draw do | ||
| 170 | end | 170 | end |
| 171 | 171 | ||
| 172 | resources :blob, only: [:show], constraints: {id: /.+/} | 172 | resources :blob, only: [:show], constraints: {id: /.+/} |
| 173 | + resources :raw, only: [:show], constraints: {id: /.+/} | ||
| 173 | resources :tree, only: [:show], constraints: {id: /.+/, format: /(html|js)/ } | 174 | resources :tree, only: [:show], constraints: {id: /.+/, format: /(html|js)/ } |
| 174 | resources :edit_tree, only: [:show, :update], constraints: {id: /.+/}, path: 'edit' | 175 | resources :edit_tree, only: [:show, :update], constraints: {id: /.+/}, path: 'edit' |
| 175 | resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/} | 176 | resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/} |
features/steps/shared/paths.rb
| @@ -205,7 +205,7 @@ module SharedPaths | @@ -205,7 +205,7 @@ module SharedPaths | ||
| 205 | end | 205 | end |
| 206 | 206 | ||
| 207 | Given 'I visit blob file from repo' do | 207 | Given 'I visit blob file from repo' do |
| 208 | - visit project_tree_path(@project, File.join(ValidCommit::ID, ValidCommit::BLOB_FILE_PATH)) | 208 | + visit project_blob_path(@project, File.join(ValidCommit::ID, ValidCommit::BLOB_FILE_PATH)) |
| 209 | end | 209 | end |
| 210 | 210 | ||
| 211 | Given 'I visit project source page for "8470d70"' do | 211 | Given 'I visit project source page for "8470d70"' do |
lib/api/projects.rb
| @@ -493,14 +493,16 @@ module Gitlab | @@ -493,14 +493,16 @@ module Gitlab | ||
| 493 | 493 | ||
| 494 | ref = params[:sha] | 494 | ref = params[:sha] |
| 495 | 495 | ||
| 496 | - commit = user_project.repository.commit ref | 496 | + repo = user_project.repository |
| 497 | + | ||
| 498 | + commit = repo.commit(ref) | ||
| 497 | not_found! "Commit" unless commit | 499 | not_found! "Commit" unless commit |
| 498 | 500 | ||
| 499 | - tree = Tree.new commit.tree, ref, params[:filepath] | ||
| 500 | - not_found! "File" unless tree.try(:tree) | 501 | + blob = Gitlab::Git::Blob.new(repo, commit.id, ref, params[:filepath]) |
| 502 | + not_found! "File" unless blob.exists? | ||
| 501 | 503 | ||
| 502 | - content_type tree.mime_type | ||
| 503 | - present tree.data | 504 | + content_type blob.mime_type |
| 505 | + present blob.data | ||
| 504 | end | 506 | end |
| 505 | 507 | ||
| 506 | # Get a specific project's keys | 508 | # Get a specific project's keys |
lib/extracts_path.rb
| @@ -102,9 +102,9 @@ module ExtractsPath | @@ -102,9 +102,9 @@ module ExtractsPath | ||
| 102 | # because "@project.repository.commit(@ref)" returns wrong commit when @ref is tag name. | 102 | # because "@project.repository.commit(@ref)" returns wrong commit when @ref is tag name. |
| 103 | @commit = @project.repository.commits(@ref, @path, 1, 0).first | 103 | @commit = @project.repository.commits(@ref, @path, 1, 0).first |
| 104 | 104 | ||
| 105 | - @tree = Tree.new(@commit.tree, @ref, @path) | 105 | + @tree = Tree.new(@project.repository, @commit.id, @ref, @path) |
| 106 | 106 | ||
| 107 | - raise InvalidPathError if @tree.invalid? | 107 | + raise InvalidPathError unless @tree.exists? |
| 108 | rescue RuntimeError, NoMethodError, InvalidPathError | 108 | rescue RuntimeError, NoMethodError, InvalidPathError |
| 109 | not_found! | 109 | not_found! |
| 110 | end | 110 | end |
| @@ -0,0 +1,42 @@ | @@ -0,0 +1,42 @@ | ||
| 1 | +module Gitlab | ||
| 2 | + module Git | ||
| 3 | + class Blob | ||
| 4 | + include Linguist::BlobHelper | ||
| 5 | + | ||
| 6 | + attr_accessor :raw_blob | ||
| 7 | + | ||
| 8 | + delegate :name, to: :raw_blob | ||
| 9 | + | ||
| 10 | + def initialize(repository, sha, ref, path) | ||
| 11 | + @repository, @sha, @ref = repository, sha, ref | ||
| 12 | + | ||
| 13 | + @commit = @repository.commit(sha) | ||
| 14 | + @raw_blob = @repository.tree(@commit, path) | ||
| 15 | + end | ||
| 16 | + | ||
| 17 | + def data | ||
| 18 | + if raw_blob | ||
| 19 | + raw_blob.data | ||
| 20 | + else | ||
| 21 | + nil | ||
| 22 | + end | ||
| 23 | + end | ||
| 24 | + | ||
| 25 | + def exists? | ||
| 26 | + raw_blob | ||
| 27 | + end | ||
| 28 | + | ||
| 29 | + def empty? | ||
| 30 | + data.blank? | ||
| 31 | + end | ||
| 32 | + | ||
| 33 | + def mode | ||
| 34 | + raw_blob.mode | ||
| 35 | + end | ||
| 36 | + | ||
| 37 | + def size | ||
| 38 | + raw_blob.size | ||
| 39 | + end | ||
| 40 | + end | ||
| 41 | + end | ||
| 42 | +end |
lib/gitlab/git/commit.rb
| @@ -4,13 +4,19 @@ | @@ -4,13 +4,19 @@ | ||
| 4 | module Gitlab | 4 | module Gitlab |
| 5 | module Git | 5 | module Git |
| 6 | class Commit | 6 | class Commit |
| 7 | - attr_accessor :raw_commit, :head, :refs | 7 | + attr_accessor :raw_commit, :head, :refs, |
| 8 | + :id, :authored_date, :committed_date, :message, | ||
| 9 | + :author_name, :author_email, :parent_ids, | ||
| 10 | + :committer_name, :committer_email | ||
| 8 | 11 | ||
| 9 | - delegate :message, :authored_date, :committed_date, :parents, :sha, | ||
| 10 | - :date, :committer, :author, :diffs, :tree, :id, :stats, :to_patch, | 12 | + delegate :parents, :diffs, :tree, :stats, :to_patch, |
| 11 | to: :raw_commit | 13 | to: :raw_commit |
| 12 | 14 | ||
| 13 | class << self | 15 | class << self |
| 16 | + def serialize_keys | ||
| 17 | + %w(id authored_date committed_date author_name author_email committer_name committer_email message parent_ids) | ||
| 18 | + end | ||
| 19 | + | ||
| 14 | def find_or_first(repo, commit_id = nil, root_ref) | 20 | def find_or_first(repo, commit_id = nil, root_ref) |
| 15 | commit = if commit_id | 21 | commit = if commit_id |
| 16 | repo.commit(commit_id) | 22 | repo.commit(commit_id) |
| @@ -73,10 +79,19 @@ module Gitlab | @@ -73,10 +79,19 @@ module Gitlab | ||
| 73 | def initialize(raw_commit, head = nil) | 79 | def initialize(raw_commit, head = nil) |
| 74 | raise "Nil as raw commit passed" unless raw_commit | 80 | raise "Nil as raw commit passed" unless raw_commit |
| 75 | 81 | ||
| 76 | - @raw_commit = raw_commit | 82 | + if raw_commit.is_a?(Hash) |
| 83 | + init_from_hash(raw_commit) | ||
| 84 | + else | ||
| 85 | + init_from_grit(raw_commit) | ||
| 86 | + end | ||
| 87 | + | ||
| 77 | @head = head | 88 | @head = head |
| 78 | end | 89 | end |
| 79 | 90 | ||
| 91 | + def sha | ||
| 92 | + id | ||
| 93 | + end | ||
| 94 | + | ||
| 80 | def short_id(length = 10) | 95 | def short_id(length = 10) |
| 81 | id.to_s[0..length] | 96 | id.to_s[0..length] |
| 82 | end | 97 | end |
| @@ -89,37 +104,13 @@ module Gitlab | @@ -89,37 +104,13 @@ module Gitlab | ||
| 89 | committed_date | 104 | committed_date |
| 90 | end | 105 | end |
| 91 | 106 | ||
| 92 | - def author_email | ||
| 93 | - author.email | ||
| 94 | - end | ||
| 95 | - | ||
| 96 | - def author_name | ||
| 97 | - author.name | ||
| 98 | - end | ||
| 99 | - | ||
| 100 | # Was this commit committed by a different person than the original author? | 107 | # Was this commit committed by a different person than the original author? |
| 101 | def different_committer? | 108 | def different_committer? |
| 102 | author_name != committer_name || author_email != committer_email | 109 | author_name != committer_name || author_email != committer_email |
| 103 | end | 110 | end |
| 104 | 111 | ||
| 105 | - def committer_name | ||
| 106 | - committer.name | ||
| 107 | - end | ||
| 108 | - | ||
| 109 | - def committer_email | ||
| 110 | - committer.email | ||
| 111 | - end | ||
| 112 | - | ||
| 113 | - def prev_commit | ||
| 114 | - @prev_commit ||= if parents.present? | ||
| 115 | - Commit.new(parents.first) | ||
| 116 | - else | ||
| 117 | - nil | ||
| 118 | - end | ||
| 119 | - end | ||
| 120 | - | ||
| 121 | - def prev_commit_id | ||
| 122 | - prev_commit.try :id | 112 | + def parent_id |
| 113 | + parent_ids.first | ||
| 123 | end | 114 | end |
| 124 | 115 | ||
| 125 | # Shows the diff between the commit's parent and the commit. | 116 | # Shows the diff between the commit's parent and the commit. |
| @@ -148,6 +139,43 @@ module Gitlab | @@ -148,6 +139,43 @@ module Gitlab | ||
| 148 | def no_commit_message | 139 | def no_commit_message |
| 149 | "--no commit message" | 140 | "--no commit message" |
| 150 | end | 141 | end |
| 142 | + | ||
| 143 | + def to_hash | ||
| 144 | + hash = {} | ||
| 145 | + | ||
| 146 | + keys = Commit.serialize_keys | ||
| 147 | + | ||
| 148 | + keys.each do |key| | ||
| 149 | + hash[key] = send(key) | ||
| 150 | + end | ||
| 151 | + | ||
| 152 | + hash | ||
| 153 | + end | ||
| 154 | + | ||
| 155 | + def date | ||
| 156 | + committed_date | ||
| 157 | + end | ||
| 158 | + | ||
| 159 | + private | ||
| 160 | + | ||
| 161 | + def init_from_grit(grit) | ||
| 162 | + @raw_commit = grit | ||
| 163 | + @id = grit.id | ||
| 164 | + @message = grit.message | ||
| 165 | + @authored_date = grit.authored_date | ||
| 166 | + @committed_date = grit.committed_date | ||
| 167 | + @author_name = grit.author.name | ||
| 168 | + @author_email = grit.author.email | ||
| 169 | + @committer_name = grit.committer.name | ||
| 170 | + @committer_email = grit.committer.email | ||
| 171 | + @parent_ids = grit.parents.map(&:id) | ||
| 172 | + end | ||
| 173 | + | ||
| 174 | + def init_from_hash(hash) | ||
| 175 | + Commit.serialize_keys.each do |key| | ||
| 176 | + send(:"#{key}=", hash[key]) | ||
| 177 | + end | ||
| 178 | + end | ||
| 151 | end | 179 | end |
| 152 | end | 180 | end |
| 153 | end | 181 | end |
lib/gitlab/git/compare.rb
| @@ -20,10 +20,8 @@ module Gitlab | @@ -20,10 +20,8 @@ module Gitlab | ||
| 20 | return | 20 | return |
| 21 | end | 21 | end |
| 22 | 22 | ||
| 23 | - @commit = Commit.new(first) | ||
| 24 | - | 23 | + @commit = first |
| 25 | @commits = repository.commits_between(last.id, first.id) | 24 | @commits = repository.commits_between(last.id, first.id) |
| 26 | - @commits = @commits.map { |c| Commit.new(c) } | ||
| 27 | 25 | ||
| 28 | @diffs = if @commits.size > 100 | 26 | @diffs = if @commits.size > 100 |
| 29 | [] | 27 | [] |
| @@ -0,0 +1,52 @@ | @@ -0,0 +1,52 @@ | ||
| 1 | +module Gitlab | ||
| 2 | + module Git | ||
| 3 | + class Tree | ||
| 4 | + attr_accessor :repository, :sha, :path, :ref, :raw_tree, :id | ||
| 5 | + | ||
| 6 | + def initialize(repository, sha, ref = nil, path = nil) | ||
| 7 | + @repository, @sha, @ref, @path = repository, sha, ref, path | ||
| 8 | + | ||
| 9 | + @path = nil if @path.blank? | ||
| 10 | + | ||
| 11 | + # Load tree from repository | ||
| 12 | + @commit = @repository.commit(@sha) | ||
| 13 | + @raw_tree = @repository.tree(@commit, @path) | ||
| 14 | + end | ||
| 15 | + | ||
| 16 | + def exists? | ||
| 17 | + raw_tree | ||
| 18 | + end | ||
| 19 | + | ||
| 20 | + def empty? | ||
| 21 | + data.blank? | ||
| 22 | + end | ||
| 23 | + | ||
| 24 | + def trees | ||
| 25 | + entries.select { |t| t.is_a?(Grit::Tree) } | ||
| 26 | + end | ||
| 27 | + | ||
| 28 | + def blobs | ||
| 29 | + entries.select { |t| t.is_a?(Grit::Blob) } | ||
| 30 | + end | ||
| 31 | + | ||
| 32 | + def is_blob? | ||
| 33 | + raw_tree.is_a?(Grit::Blob) | ||
| 34 | + end | ||
| 35 | + | ||
| 36 | + def up_dir? | ||
| 37 | + path.present? | ||
| 38 | + end | ||
| 39 | + | ||
| 40 | + def readme | ||
| 41 | + @readme ||= entries.find { |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i } | ||
| 42 | + end | ||
| 43 | + | ||
| 44 | + protected | ||
| 45 | + | ||
| 46 | + def entries | ||
| 47 | + raw_tree.contents | ||
| 48 | + end | ||
| 49 | + end | ||
| 50 | + end | ||
| 51 | +end | ||
| 52 | + |
| @@ -0,0 +1,37 @@ | @@ -0,0 +1,37 @@ | ||
| 1 | +require 'spec_helper' | ||
| 2 | + | ||
| 3 | +describe BlobController do | ||
| 4 | + let(:project) { create(:project_with_code) } | ||
| 5 | + let(:user) { create(:user) } | ||
| 6 | + | ||
| 7 | + before do | ||
| 8 | + sign_in(user) | ||
| 9 | + | ||
| 10 | + project.team << [user, :master] | ||
| 11 | + | ||
| 12 | + project.stub(:branches).and_return(['master', 'foo/bar/baz']) | ||
| 13 | + project.stub(:tags).and_return(['v1.0.0', 'v2.0.0']) | ||
| 14 | + controller.instance_variable_set(:@project, project) | ||
| 15 | + end | ||
| 16 | + | ||
| 17 | + describe "GET show" do | ||
| 18 | + render_views | ||
| 19 | + | ||
| 20 | + before { get :show, project_id: project.code, id: id } | ||
| 21 | + | ||
| 22 | + context "valid branch, valid file" do | ||
| 23 | + let(:id) { 'master/README.md' } | ||
| 24 | + it { should respond_with(:success) } | ||
| 25 | + end | ||
| 26 | + | ||
| 27 | + context "valid branch, invalid file" do | ||
| 28 | + let(:id) { 'master/invalid-path.rb' } | ||
| 29 | + it { should respond_with(:not_found) } | ||
| 30 | + end | ||
| 31 | + | ||
| 32 | + context "invalid branch, valid file" do | ||
| 33 | + let(:id) { 'invalid-branch/README.md' } | ||
| 34 | + it { should respond_with(:not_found) } | ||
| 35 | + end | ||
| 36 | + end | ||
| 37 | +end |
spec/controllers/tree_controller_spec.rb
| @@ -26,17 +26,17 @@ describe TreeController do | @@ -26,17 +26,17 @@ describe TreeController do | ||
| 26 | end | 26 | end |
| 27 | 27 | ||
| 28 | context "valid branch, valid path" do | 28 | context "valid branch, valid path" do |
| 29 | - let(:id) { 'master/README.md' } | 29 | + let(:id) { 'master/app/' } |
| 30 | it { should respond_with(:success) } | 30 | it { should respond_with(:success) } |
| 31 | end | 31 | end |
| 32 | 32 | ||
| 33 | context "valid branch, invalid path" do | 33 | context "valid branch, invalid path" do |
| 34 | - let(:id) { 'master/invalid-path.rb' } | 34 | + let(:id) { 'master/invalid-path/' } |
| 35 | it { should respond_with(:not_found) } | 35 | it { should respond_with(:not_found) } |
| 36 | end | 36 | end |
| 37 | 37 | ||
| 38 | context "invalid branch, valid path" do | 38 | context "invalid branch, valid path" do |
| 39 | - let(:id) { 'invalid-branch/README.md' } | 39 | + let(:id) { 'invalid-branch/app/' } |
| 40 | it { should respond_with(:not_found) } | 40 | it { should respond_with(:not_found) } |
| 41 | end | 41 | end |
| 42 | end | 42 | end |
spec/factories.rb
| @@ -86,9 +86,11 @@ FactoryGirl.define do | @@ -86,9 +86,11 @@ FactoryGirl.define do | ||
| 86 | target_branch "master" # pretend bcf03b5d~3 | 86 | target_branch "master" # pretend bcf03b5d~3 |
| 87 | source_branch "stable" # pretend bcf03b5d | 87 | source_branch "stable" # pretend bcf03b5d |
| 88 | st_commits do | 88 | st_commits do |
| 89 | - [Commit.new(project.repository.commit('bcf03b5d')), | ||
| 90 | - Commit.new(project.repository.commit('bcf03b5d~1')), | ||
| 91 | - Commit.new(project.repository.commit('bcf03b5d~2'))] | 89 | + [ |
| 90 | + project.repository.commit('bcf03b5d').to_hash, | ||
| 91 | + project.repository.commit('bcf03b5d~1').to_hash, | ||
| 92 | + project.repository.commit('bcf03b5d~2').to_hash | ||
| 93 | + ] | ||
| 92 | end | 94 | end |
| 93 | st_diffs do | 95 | st_diffs do |
| 94 | project.repo.diff("bcf03b5d~3", "bcf03b5d") | 96 | project.repo.diff("bcf03b5d~3", "bcf03b5d") |
spec/lib/git/commit_spec.rb
| @@ -20,6 +20,8 @@ describe Gitlab::Git::Commit do | @@ -20,6 +20,8 @@ describe Gitlab::Git::Commit do | ||
| 20 | author: @author, | 20 | author: @author, |
| 21 | committer: @committer, | 21 | committer: @committer, |
| 22 | committed_date: Date.yesterday, | 22 | committed_date: Date.yesterday, |
| 23 | + authored_date: Date.yesterday, | ||
| 24 | + parents: [], | ||
| 23 | message: 'Refactoring specs' | 25 | message: 'Refactoring specs' |
| 24 | ) | 26 | ) |
| 25 | 27 |
spec/models/commit_spec.rb
| @@ -38,10 +38,10 @@ describe Commit do | @@ -38,10 +38,10 @@ describe Commit do | ||
| 38 | it { should respond_to(:message) } | 38 | it { should respond_to(:message) } |
| 39 | it { should respond_to(:authored_date) } | 39 | it { should respond_to(:authored_date) } |
| 40 | it { should respond_to(:committed_date) } | 40 | it { should respond_to(:committed_date) } |
| 41 | + it { should respond_to(:committer_email) } | ||
| 42 | + it { should respond_to(:author_email) } | ||
| 41 | it { should respond_to(:parents) } | 43 | it { should respond_to(:parents) } |
| 42 | it { should respond_to(:date) } | 44 | it { should respond_to(:date) } |
| 43 | - it { should respond_to(:committer) } | ||
| 44 | - it { should respond_to(:author) } | ||
| 45 | it { should respond_to(:diffs) } | 45 | it { should respond_to(:diffs) } |
| 46 | it { should respond_to(:tree) } | 46 | it { should respond_to(:tree) } |
| 47 | it { should respond_to(:id) } | 47 | it { should respond_to(:id) } |
spec/support/matchers.rb
| @@ -3,7 +3,7 @@ RSpec::Matchers.define :be_valid_commit do | @@ -3,7 +3,7 @@ RSpec::Matchers.define :be_valid_commit do | ||
| 3 | actual != nil | 3 | actual != nil |
| 4 | actual.id == ValidCommit::ID | 4 | actual.id == ValidCommit::ID |
| 5 | actual.message == ValidCommit::MESSAGE | 5 | actual.message == ValidCommit::MESSAGE |
| 6 | - actual.author.name == ValidCommit::AUTHOR_FULL_NAME | 6 | + actual.author_name == ValidCommit::AUTHOR_FULL_NAME |
| 7 | end | 7 | end |
| 8 | end | 8 | end |
| 9 | 9 |