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 |