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 | 8 | before_filter :require_non_empty_project |
| 9 | 9 | |
| 10 | 10 | def show |
| 11 | + @blob = Gitlab::Git::Blob.new(@repository, @commit.id, @ref, @path) | |
| 11 | 12 | @blame = Gitlab::Git::Blame.new(project.repository, @commit.id, @path) |
| 12 | 13 | end |
| 13 | 14 | end | ... | ... |
app/controllers/blob_controller.rb
| ... | ... | @@ -8,15 +8,6 @@ class BlobController < ProjectResourceController |
| 8 | 8 | before_filter :require_non_empty_project |
| 9 | 9 | |
| 10 | 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 | 12 | end |
| 22 | 13 | end | ... | ... |
| ... | ... | @@ -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 | 30 | end |
| 31 | 31 | |
| 32 | 32 | def logs_tree |
| 33 | - contents = @tree.contents | |
| 33 | + contents = @tree.entries | |
| 34 | 34 | @logs = contents.map do |content| |
| 35 | 35 | file = params[:path] ? File.join(params[:path], content.name) : content.name |
| 36 | 36 | last_commit = @repo.commits(@commit.id, file, 1).last |
| ... | ... | @@ -48,7 +48,7 @@ class RefsController < ProjectResourceController |
| 48 | 48 | |
| 49 | 49 | @repo = project.repository |
| 50 | 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 | 52 | @hex_path = Digest::SHA1.hexdigest(params[:path] || "") |
| 53 | 53 | |
| 54 | 54 | if params[:path] | ... | ... |
app/helpers/tree_helper.rb
| ... | ... | @@ -3,9 +3,9 @@ module TreeHelper |
| 3 | 3 | # their corresponding partials |
| 4 | 4 | # |
| 5 | 5 | # contents - A Grit::Tree object for the current tree |
| 6 | - def render_tree(contents) | |
| 6 | + def render_tree(tree) | |
| 7 | 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 | 10 | tree = "" |
| 11 | 11 | |
| ... | ... | @@ -18,7 +18,7 @@ module TreeHelper |
| 18 | 18 | render partial: 'tree/submodule_item', object: f |
| 19 | 19 | else |
| 20 | 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 | 22 | end |
| 23 | 23 | |
| 24 | 24 | tree += html if html.present? |
| ... | ... | @@ -91,5 +91,4 @@ module TreeHelper |
| 91 | 91 | file = File.join(tree.path, "..") |
| 92 | 92 | tree_join(tree.ref, file) |
| 93 | 93 | end |
| 94 | - | |
| 95 | 94 | end | ... | ... |
app/models/merge_request.rb
| ... | ... | @@ -152,17 +152,7 @@ class MergeRequest < ActiveRecord::Base |
| 152 | 152 | end |
| 153 | 153 | |
| 154 | 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 | 156 | end |
| 167 | 157 | |
| 168 | 158 | def probably_merged? |
| ... | ... | @@ -172,13 +162,7 @@ class MergeRequest < ActiveRecord::Base |
| 172 | 162 | |
| 173 | 163 | def reloaded_commits |
| 174 | 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 | 166 | save |
| 183 | 167 | end |
| 184 | 168 | commits |
| ... | ... | @@ -228,4 +212,14 @@ class MergeRequest < ActiveRecord::Base |
| 228 | 212 | def last_commit_short_sha |
| 229 | 213 | @last_commit_short_sha ||= last_commit.sha[0..10] |
| 230 | 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 | 225 | end | ... | ... |
app/models/tree.rb
| 1 | 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 | 6 | end |
| 21 | 7 | |
| 22 | - def invalid? | |
| 23 | - tree.nil? | |
| 8 | + def method_missing(m, *args, &block) | |
| 9 | + @raw.send(m, *args, &block) | |
| 24 | 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 | 16 | end |
| 37 | 17 | end | ... | ... |
app/services/git_push_service.rb
| ... | ... | @@ -104,7 +104,7 @@ class GitPushService |
| 104 | 104 | data[:commits] << { |
| 105 | 105 | id: commit.id, |
| 106 | 106 | message: commit.safe_message, |
| 107 | - timestamp: commit.date.xmlschema, | |
| 107 | + timestamp: commit.committed_date.xmlschema, | |
| 108 | 108 | url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/#{commit.id}", |
| 109 | 109 | author: { |
| 110 | 110 | name: commit.author_name, | ... | ... |
app/views/blame/show.html.haml
| ... | ... | @@ -15,9 +15,9 @@ |
| 15 | 15 | .file_title |
| 16 | 16 | %i.icon-file |
| 17 | 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 | 21 | .file_content.blame |
| 22 | 22 | %table |
| 23 | 23 | - current_line = 1 | ... | ... |
| ... | ... | @@ -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 @@ |
| 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 @@ |
| 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 @@ |
| 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 | - unless @suppress_diff |
| 17 | 17 | - diffs.each_with_index do |diff, i| |
| 18 | 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 | 21 | - next unless file |
| 22 | 22 | .file{id: "diff-#{i}"} |
| 23 | 23 | .header |
| 24 | 24 | - if diff.deleted_file |
| 25 | 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 | 29 | View file @ |
| 30 | 30 | %span.commit-short-id= @commit.short_id(6) |
| 31 | 31 | - else |
| ... | ... | @@ -43,7 +43,7 @@ |
| 43 | 43 | - if file.text? |
| 44 | 44 | = render "commits/text_file", diff: diff, index: i |
| 45 | 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 | 47 | = render "commits/image", diff: diff, old_file: old_file, file: file, index: i |
| 48 | 48 | - else |
| 49 | 49 | %p.nothing_here_message No preview for this file type | ... | ... |
app/views/graph/show.json.erb
| ... | ... | @@ -7,9 +7,9 @@ |
| 7 | 7 | { |
| 8 | 8 | parents: parents_zip_spaces(c.parents(@graph.map), c.parent_spaces), |
| 9 | 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 | 14 | time: c.time, |
| 15 | 15 | space: c.spaces.first, | ... | ... |
app/views/tree/_blob.html.haml
| ... | ... | @@ -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 | -.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 @@ |
| 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 | 12 | = link_to title, '#' |
| 13 | 13 | |
| 14 | 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 | 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 | -- 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 | 23 | |
| 24 | 24 | user = if identifier.blank? |
| 25 | 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 | 27 | User.find_by_email(email) if email |
| 28 | 28 | |
| 29 | 29 | elsif identifier =~ /\Auser-\d+\Z/ | ... | ... |
config/routes.rb
| ... | ... | @@ -170,6 +170,7 @@ Gitlab::Application.routes.draw do |
| 170 | 170 | end |
| 171 | 171 | |
| 172 | 172 | resources :blob, only: [:show], constraints: {id: /.+/} |
| 173 | + resources :raw, only: [:show], constraints: {id: /.+/} | |
| 173 | 174 | resources :tree, only: [:show], constraints: {id: /.+/, format: /(html|js)/ } |
| 174 | 175 | resources :edit_tree, only: [:show, :update], constraints: {id: /.+/}, path: 'edit' |
| 175 | 176 | resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/} | ... | ... |
features/steps/shared/paths.rb
| ... | ... | @@ -205,7 +205,7 @@ module SharedPaths |
| 205 | 205 | end |
| 206 | 206 | |
| 207 | 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 | 209 | end |
| 210 | 210 | |
| 211 | 211 | Given 'I visit project source page for "8470d70"' do | ... | ... |
lib/api/projects.rb
| ... | ... | @@ -493,14 +493,16 @@ module Gitlab |
| 493 | 493 | |
| 494 | 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 | 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 | 506 | end |
| 505 | 507 | |
| 506 | 508 | # Get a specific project's keys | ... | ... |
lib/extracts_path.rb
| ... | ... | @@ -102,9 +102,9 @@ module ExtractsPath |
| 102 | 102 | # because "@project.repository.commit(@ref)" returns wrong commit when @ref is tag name. |
| 103 | 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 | 108 | rescue RuntimeError, NoMethodError, InvalidPathError |
| 109 | 109 | not_found! |
| 110 | 110 | end | ... | ... |
| ... | ... | @@ -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 | 4 | module Gitlab |
| 5 | 5 | module Git |
| 6 | 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 | 13 | to: :raw_commit |
| 12 | 14 | |
| 13 | 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 | 20 | def find_or_first(repo, commit_id = nil, root_ref) |
| 15 | 21 | commit = if commit_id |
| 16 | 22 | repo.commit(commit_id) |
| ... | ... | @@ -73,10 +79,19 @@ module Gitlab |
| 73 | 79 | def initialize(raw_commit, head = nil) |
| 74 | 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 | 88 | @head = head |
| 78 | 89 | end |
| 79 | 90 | |
| 91 | + def sha | |
| 92 | + id | |
| 93 | + end | |
| 94 | + | |
| 80 | 95 | def short_id(length = 10) |
| 81 | 96 | id.to_s[0..length] |
| 82 | 97 | end |
| ... | ... | @@ -89,37 +104,13 @@ module Gitlab |
| 89 | 104 | committed_date |
| 90 | 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 | 107 | # Was this commit committed by a different person than the original author? |
| 101 | 108 | def different_committer? |
| 102 | 109 | author_name != committer_name || author_email != committer_email |
| 103 | 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 | 114 | end |
| 124 | 115 | |
| 125 | 116 | # Shows the diff between the commit's parent and the commit. |
| ... | ... | @@ -148,6 +139,43 @@ module Gitlab |
| 148 | 139 | def no_commit_message |
| 149 | 140 | "--no commit message" |
| 150 | 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 | 179 | end |
| 152 | 180 | end |
| 153 | 181 | end | ... | ... |
lib/gitlab/git/compare.rb
| ... | ... | @@ -20,10 +20,8 @@ module Gitlab |
| 20 | 20 | return |
| 21 | 21 | end |
| 22 | 22 | |
| 23 | - @commit = Commit.new(first) | |
| 24 | - | |
| 23 | + @commit = first | |
| 25 | 24 | @commits = repository.commits_between(last.id, first.id) |
| 26 | - @commits = @commits.map { |c| Commit.new(c) } | |
| 27 | 25 | |
| 28 | 26 | @diffs = if @commits.size > 100 |
| 29 | 27 | [] | ... | ... |
| ... | ... | @@ -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 @@ |
| 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 | 26 | end |
| 27 | 27 | |
| 28 | 28 | context "valid branch, valid path" do |
| 29 | - let(:id) { 'master/README.md' } | |
| 29 | + let(:id) { 'master/app/' } | |
| 30 | 30 | it { should respond_with(:success) } |
| 31 | 31 | end |
| 32 | 32 | |
| 33 | 33 | context "valid branch, invalid path" do |
| 34 | - let(:id) { 'master/invalid-path.rb' } | |
| 34 | + let(:id) { 'master/invalid-path/' } | |
| 35 | 35 | it { should respond_with(:not_found) } |
| 36 | 36 | end |
| 37 | 37 | |
| 38 | 38 | context "invalid branch, valid path" do |
| 39 | - let(:id) { 'invalid-branch/README.md' } | |
| 39 | + let(:id) { 'invalid-branch/app/' } | |
| 40 | 40 | it { should respond_with(:not_found) } |
| 41 | 41 | end |
| 42 | 42 | end | ... | ... |
spec/factories.rb
| ... | ... | @@ -86,9 +86,11 @@ FactoryGirl.define do |
| 86 | 86 | target_branch "master" # pretend bcf03b5d~3 |
| 87 | 87 | source_branch "stable" # pretend bcf03b5d |
| 88 | 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 | 94 | end |
| 93 | 95 | st_diffs do |
| 94 | 96 | project.repo.diff("bcf03b5d~3", "bcf03b5d") | ... | ... |
spec/lib/git/commit_spec.rb
spec/models/commit_spec.rb
| ... | ... | @@ -38,10 +38,10 @@ describe Commit do |
| 38 | 38 | it { should respond_to(:message) } |
| 39 | 39 | it { should respond_to(:authored_date) } |
| 40 | 40 | it { should respond_to(:committed_date) } |
| 41 | + it { should respond_to(:committer_email) } | |
| 42 | + it { should respond_to(:author_email) } | |
| 41 | 43 | it { should respond_to(:parents) } |
| 42 | 44 | it { should respond_to(:date) } |
| 43 | - it { should respond_to(:committer) } | |
| 44 | - it { should respond_to(:author) } | |
| 45 | 45 | it { should respond_to(:diffs) } |
| 46 | 46 | it { should respond_to(:tree) } |
| 47 | 47 | it { should respond_to(:id) } | ... | ... |
spec/support/matchers.rb
| ... | ... | @@ -3,7 +3,7 @@ RSpec::Matchers.define :be_valid_commit do |
| 3 | 3 | actual != nil |
| 4 | 4 | actual.id == ValidCommit::ID |
| 5 | 5 | actual.message == ValidCommit::MESSAGE |
| 6 | - actual.author.name == ValidCommit::AUTHOR_FULL_NAME | |
| 6 | + actual.author_name == ValidCommit::AUTHOR_FULL_NAME | |
| 7 | 7 | end |
| 8 | 8 | end |
| 9 | 9 | ... | ... |