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 | ... | ... |