Commit 4bbe2b74a85793c06679851706633cbee87ff8ca

Authored by Dmitriy Zaporozhets
2 parents 7af16bbb dfeef6c2

Merge branch 'feature/merge_request_serialize'

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
... ...
app/controllers/raw_controller.rb 0 → 100644
... ... @@ -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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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
... ...
app/views/blob/_actions.html.haml 0 → 100644
... ... @@ -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"
... ...
app/views/blob/_blob.html.haml 0 → 100644
... ... @@ -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
... ...
app/views/blob/_download.html.haml 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +.file_content.blob_file
  2 + %center
  3 + = link_to project_blob_path(@project, @id) do
  4 + %div.padded
  5 + %h4
  6 + %i.icon-download-alt
  7 + %br
  8 + Download (#{number_to_human_size blob.size})
... ...
app/views/blob/_image.html.haml 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 +.file_content.image_file
  2 + %img{ src: "data:#{blob.mime_type};base64,#{Base64.encode64(blob.data)}"}
... ...
app/views/blob/_text.html.haml 0 → 100644
... ... @@ -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
... ...
app/views/blob/show.html.haml 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +%div.tree-ref-holder
  2 + = render 'shared/ref_switcher', destination: 'tree', path: @path
  3 +%div#tree-holder.tree-holder
  4 + = render 'blob', blob: @blob
... ...
app/views/blob/show.js.haml 0 → 100644
... ... @@ -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"
app/views/tree/_blob_item.html.haml 0 → 100644
... ... @@ -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
... ... @@ -1,8 +0,0 @@
1   -.file_content.blob_file
2   - %center
3   - = link_to project_blob_path(@project, @id) do
4   - %div.padded
5   - %h4
6   - %i.icon-download-alt
7   - %br
8   - Download (#{number_to_human_size blob.size})
app/views/tree/blob/_image.html.haml
... ... @@ -1,2 +0,0 @@
1   -.file_content.image_file
2   - %img{ src: "data:#{blob.mime_type};base64,#{Base64.encode64(blob.data)}"}
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
... ...
lib/gitlab/git/blob.rb 0 → 100644
... ... @@ -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 []
... ...
lib/gitlab/git/tree.rb 0 → 100644
... ... @@ -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 +
... ...
spec/controllers/blob_controller_spec.rb 0 → 100644
... ... @@ -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
... ... @@ -20,6 +20,8 @@ describe Gitlab::Git::Commit do
20 20 author: @author,
21 21 committer: @committer,
22 22 committed_date: Date.yesterday,
  23 + authored_date: Date.yesterday,
  24 + parents: [],
23 25 message: 'Refactoring specs'
24 26 )
25 27  
... ...
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  
... ...