Commit 76a4cbe464a4472e82065c670d1190552db67cc6
Exists in
master
and in
4 other branches
Merge branch 'refactor/gitlab_git'
Showing
72 changed files
with
918 additions
and
836 deletions
Show diff stats
app/contexts/commit_load_context.rb
@@ -12,7 +12,6 @@ class CommitLoadContext < BaseContext | @@ -12,7 +12,6 @@ class CommitLoadContext < BaseContext | ||
12 | commit = project.repository.commit(params[:id]) | 12 | commit = project.repository.commit(params[:id]) |
13 | 13 | ||
14 | if commit | 14 | if commit |
15 | - commit = CommitDecorator.decorate(commit) | ||
16 | line_notes = project.notes.for_commit_id(commit.id).inline | 15 | line_notes = project.notes.for_commit_id(commit.id).inline |
17 | 16 | ||
18 | result[:commit] = commit | 17 | result[:commit] = commit |
app/controllers/blame_controller.rb
@@ -8,7 +8,6 @@ class BlameController < ProjectResourceController | @@ -8,7 +8,6 @@ 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 | - @repo = @project.repo | ||
12 | - @blame = Grit::Blob.blame(@repo, @commit.id, @path) | 11 | + @blame = Gitlab::Git::Blame.new(project.repository, @commit.id, @path) |
13 | end | 12 | end |
14 | end | 13 | end |
app/controllers/commits_controller.rb
@@ -13,7 +13,6 @@ class CommitsController < ProjectResourceController | @@ -13,7 +13,6 @@ class CommitsController < ProjectResourceController | ||
13 | @limit, @offset = (params[:limit] || 40), (params[:offset] || 0) | 13 | @limit, @offset = (params[:limit] || 40), (params[:offset] || 0) |
14 | 14 | ||
15 | @commits = @repo.commits(@ref, @path, @limit, @offset) | 15 | @commits = @repo.commits(@ref, @path, @limit, @offset) |
16 | - @commits = CommitDecorator.decorate_collection(@commits) | ||
17 | 16 | ||
18 | respond_to do |format| | 17 | respond_to do |format| |
19 | format.html # index.html.erb | 18 | format.html # index.html.erb |
app/controllers/compare_controller.rb
@@ -8,15 +8,13 @@ class CompareController < ProjectResourceController | @@ -8,15 +8,13 @@ class CompareController < ProjectResourceController | ||
8 | end | 8 | end |
9 | 9 | ||
10 | def show | 10 | def show |
11 | - result = Commit.compare(project, params[:from], params[:to]) | 11 | + compare = Gitlab::Git::Compare.new(project.repository, params[:from], params[:to]) |
12 | 12 | ||
13 | - @commits = result[:commits] | ||
14 | - @commit = result[:commit] | ||
15 | - @diffs = result[:diffs] | ||
16 | - @refs_are_same = result[:same] | 13 | + @commits = compare.commits |
14 | + @commit = compare.commit | ||
15 | + @diffs = compare.diffs | ||
16 | + @refs_are_same = compare.same | ||
17 | @line_notes = [] | 17 | @line_notes = [] |
18 | - | ||
19 | - @commits = CommitDecorator.decorate_collection(@commits) | ||
20 | end | 18 | end |
21 | 19 | ||
22 | def create | 20 | def create |
app/controllers/merge_requests_controller.rb
@@ -94,12 +94,10 @@ class MergeRequestsController < ProjectResourceController | @@ -94,12 +94,10 @@ class MergeRequestsController < ProjectResourceController | ||
94 | 94 | ||
95 | def branch_from | 95 | def branch_from |
96 | @commit = @repository.commit(params[:ref]) | 96 | @commit = @repository.commit(params[:ref]) |
97 | - @commit = CommitDecorator.decorate(@commit) | ||
98 | end | 97 | end |
99 | 98 | ||
100 | def branch_to | 99 | def branch_to |
101 | @commit = @repository.commit(params[:ref]) | 100 | @commit = @repository.commit(params[:ref]) |
102 | - @commit = CommitDecorator.decorate(@commit) | ||
103 | end | 101 | end |
104 | 102 | ||
105 | def ci_status | 103 | def ci_status |
@@ -143,7 +141,6 @@ class MergeRequestsController < ProjectResourceController | @@ -143,7 +141,6 @@ class MergeRequestsController < ProjectResourceController | ||
143 | # Get commits from repository | 141 | # Get commits from repository |
144 | # or from cache if already merged | 142 | # or from cache if already merged |
145 | @commits = @merge_request.commits | 143 | @commits = @merge_request.commits |
146 | - @commits = CommitDecorator.decorate_collection(@commits) | ||
147 | 144 | ||
148 | @allowed_to_merge = allowed_to_merge? | 145 | @allowed_to_merge = allowed_to_merge? |
149 | @show_merge_controls = @merge_request.opened? && @commits.any? && @allowed_to_merge | 146 | @show_merge_controls = @merge_request.opened? && @commits.any? && @allowed_to_merge |
app/controllers/refs_controller.rb
@@ -34,7 +34,6 @@ class RefsController < ProjectResourceController | @@ -34,7 +34,6 @@ class RefsController < ProjectResourceController | ||
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 |
37 | - last_commit = CommitDecorator.decorate(last_commit) | ||
38 | { | 37 | { |
39 | file_name: content.name, | 38 | file_name: content.name, |
40 | commit: last_commit | 39 | commit: last_commit |
@@ -49,9 +48,7 @@ class RefsController < ProjectResourceController | @@ -49,9 +48,7 @@ class RefsController < ProjectResourceController | ||
49 | 48 | ||
50 | @repo = project.repository | 49 | @repo = project.repository |
51 | @commit = @repo.commit(@ref) | 50 | @commit = @repo.commit(@ref) |
52 | - @commit = CommitDecorator.decorate(@commit) | ||
53 | @tree = Tree.new(@commit.tree, @ref, params[:path]) | 51 | @tree = Tree.new(@commit.tree, @ref, params[:path]) |
54 | - @tree = TreeDecorator.new(@tree) | ||
55 | @hex_path = Digest::SHA1.hexdigest(params[:path] || "") | 52 | @hex_path = Digest::SHA1.hexdigest(params[:path] || "") |
56 | 53 | ||
57 | if params[:path] | 54 | if params[:path] |
app/decorators/commit_decorator.rb
@@ -1,93 +0,0 @@ | @@ -1,93 +0,0 @@ | ||
1 | -class CommitDecorator < ApplicationDecorator | ||
2 | - decorates :commit | ||
3 | - | ||
4 | - # Returns a string describing the commit for use in a link title | ||
5 | - # | ||
6 | - # Example | ||
7 | - # | ||
8 | - # "Commit: Alex Denisov - Project git clone panel" | ||
9 | - def link_title | ||
10 | - "Commit: #{author_name} - #{title}" | ||
11 | - end | ||
12 | - | ||
13 | - # Returns the commits title. | ||
14 | - # | ||
15 | - # Usually, the commit title is the first line of the commit message. | ||
16 | - # In case this first line is longer than 80 characters, it is cut off | ||
17 | - # after 70 characters and ellipses (`&hellp;`) are appended. | ||
18 | - def title | ||
19 | - title = safe_message | ||
20 | - | ||
21 | - return no_commit_message if title.blank? | ||
22 | - | ||
23 | - title_end = title.index(/\n/) | ||
24 | - if (!title_end && title.length > 80) || (title_end && title_end > 80) | ||
25 | - title[0..69] << "…".html_safe | ||
26 | - else | ||
27 | - title.split(/\n/, 2).first | ||
28 | - end | ||
29 | - end | ||
30 | - | ||
31 | - # Returns the commits description | ||
32 | - # | ||
33 | - # cut off, ellipses (`&hellp;`) are prepended to the commit message. | ||
34 | - def description | ||
35 | - description = safe_message | ||
36 | - | ||
37 | - title_end = description.index(/\n/) | ||
38 | - if (!title_end && description.length > 80) || (title_end && title_end > 80) | ||
39 | - "…".html_safe << description[70..-1] | ||
40 | - else | ||
41 | - description.split(/\n/, 2)[1].try(:chomp) | ||
42 | - end | ||
43 | - end | ||
44 | - | ||
45 | - # Returns a link to the commit author. If the author has a matching user and | ||
46 | - # is a member of the current @project it will link to the team member page. | ||
47 | - # Otherwise it will link to the author email as specified in the commit. | ||
48 | - # | ||
49 | - # options: | ||
50 | - # avatar: true will prepend the avatar image | ||
51 | - # size: size of the avatar image in px | ||
52 | - def author_link(options = {}) | ||
53 | - person_link(options.merge source: :author) | ||
54 | - end | ||
55 | - | ||
56 | - # Just like #author_link but for the committer. | ||
57 | - def committer_link(options = {}) | ||
58 | - person_link(options.merge source: :committer) | ||
59 | - end | ||
60 | - | ||
61 | - protected | ||
62 | - | ||
63 | - def no_commit_message | ||
64 | - "--no commit message" | ||
65 | - end | ||
66 | - | ||
67 | - # Private: Returns a link to a person. If the person has a matching user and | ||
68 | - # is a member of the current @project it will link to the team member page. | ||
69 | - # Otherwise it will link to the person email as specified in the commit. | ||
70 | - # | ||
71 | - # options: | ||
72 | - # source: one of :author or :committer | ||
73 | - # avatar: true will prepend the avatar image | ||
74 | - # size: size of the avatar image in px | ||
75 | - def person_link(options = {}) | ||
76 | - source_name = send "#{options[:source]}_name".to_sym | ||
77 | - source_email = send "#{options[:source]}_email".to_sym | ||
78 | - text = if options[:avatar] | ||
79 | - avatar = h.image_tag h.gravatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "" | ||
80 | - %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{source_name}</span>} | ||
81 | - else | ||
82 | - source_name | ||
83 | - end | ||
84 | - | ||
85 | - user = User.where('name like ? or email like ?', source_name, source_email).first | ||
86 | - | ||
87 | - if user.nil? | ||
88 | - h.mail_to(source_email, text.html_safe, class: "commit-#{options[:source]}-link") | ||
89 | - else | ||
90 | - h.link_to(text.html_safe, h.user_path(user), class: "commit-#{options[:source]}-link") | ||
91 | - end | ||
92 | - end | ||
93 | -end |
app/decorators/tree_decorator.rb
@@ -1,33 +0,0 @@ | @@ -1,33 +0,0 @@ | ||
1 | -class TreeDecorator < ApplicationDecorator | ||
2 | - decorates :tree | ||
3 | - | ||
4 | - def breadcrumbs(max_links = 2) | ||
5 | - if path | ||
6 | - part_path = "" | ||
7 | - parts = path.split("\/") | ||
8 | - | ||
9 | - yield('..', nil) if parts.count > max_links | ||
10 | - | ||
11 | - parts.each do |part| | ||
12 | - part_path = File.join(part_path, part) unless part_path.empty? | ||
13 | - part_path = part if part_path.empty? | ||
14 | - | ||
15 | - next unless parts.last(2).include?(part) if parts.count > max_links | ||
16 | - yield(part, h.tree_join(ref, part_path)) | ||
17 | - end | ||
18 | - end | ||
19 | - end | ||
20 | - | ||
21 | - def up_dir? | ||
22 | - path.present? | ||
23 | - end | ||
24 | - | ||
25 | - def up_dir_path | ||
26 | - file = File.join(path, "..") | ||
27 | - h.tree_join(ref, file) | ||
28 | - end | ||
29 | - | ||
30 | - def readme | ||
31 | - @readme ||= contents.find { |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i } | ||
32 | - end | ||
33 | -end |
app/helpers/application_helper.rb
@@ -96,7 +96,7 @@ module ApplicationHelper | @@ -96,7 +96,7 @@ module ApplicationHelper | ||
96 | ] | 96 | ] |
97 | 97 | ||
98 | project_nav = [] | 98 | project_nav = [] |
99 | - if @project && @project.repository && @project.repository.root_ref | 99 | + if @project && @project.repository.exists? && @project.repository.root_ref |
100 | project_nav = [ | 100 | project_nav = [ |
101 | { label: "#{simple_sanitize(@project.name_with_namespace)} - Issues", url: project_issues_path(@project) }, | 101 | { label: "#{simple_sanitize(@project.name_with_namespace)} - Issues", url: project_issues_path(@project) }, |
102 | { label: "#{simple_sanitize(@project.name_with_namespace)} - Commits", url: project_commits_path(@project, @ref || @project.repository.root_ref) }, | 102 | { label: "#{simple_sanitize(@project.name_with_namespace)} - Commits", url: project_commits_path(@project, @ref || @project.repository.root_ref) }, |
app/helpers/commits_helper.rb
1 | module CommitsHelper | 1 | module CommitsHelper |
2 | + # Returns a link to the commit author. If the author has a matching user and | ||
3 | + # is a member of the current @project it will link to the team member page. | ||
4 | + # Otherwise it will link to the author email as specified in the commit. | ||
5 | + # | ||
6 | + # options: | ||
7 | + # avatar: true will prepend the avatar image | ||
8 | + # size: size of the avatar image in px | ||
9 | + def commit_author_link(commit, options = {}) | ||
10 | + commit_person_link(commit, options.merge(source: :author)) | ||
11 | + end | ||
12 | + | ||
13 | + # Just like #author_link but for the committer. | ||
14 | + def commit_committer_link(commit, options = {}) | ||
15 | + commit_person_link(commit, options.merge(source: :committer)) | ||
16 | + end | ||
17 | + | ||
2 | def identification_type(line) | 18 | def identification_type(line) |
3 | if line[0] == "+" | 19 | if line[0] == "+" |
4 | "new" | 20 | "new" |
@@ -93,9 +109,7 @@ module CommitsHelper | @@ -93,9 +109,7 @@ module CommitsHelper | ||
93 | end | 109 | end |
94 | 110 | ||
95 | def commit_to_html commit | 111 | def commit_to_html commit |
96 | - if commit.model | ||
97 | - escape_javascript(render 'commits/commit', commit: commit) | ||
98 | - end | 112 | + escape_javascript(render 'commits/commit', commit: commit) |
99 | end | 113 | end |
100 | 114 | ||
101 | def diff_line_content(line) | 115 | def diff_line_content(line) |
@@ -105,4 +119,58 @@ module CommitsHelper | @@ -105,4 +119,58 @@ module CommitsHelper | ||
105 | line | 119 | line |
106 | end | 120 | end |
107 | end | 121 | end |
122 | + | ||
123 | + # Breadcrumb links for a Project and, if applicable, a tree path | ||
124 | + def commits_breadcrumbs | ||
125 | + return unless @project && @ref | ||
126 | + | ||
127 | + # Add the root project link and the arrow icon | ||
128 | + crumbs = content_tag(:li) do | ||
129 | + content_tag(:span, nil, class: 'arrow') + | ||
130 | + link_to(@project.name, project_commits_path(@project, @ref)) | ||
131 | + end | ||
132 | + | ||
133 | + if @path | ||
134 | + parts = @path.split('/') | ||
135 | + | ||
136 | + parts.each_with_index do |part, i| | ||
137 | + crumbs += content_tag(:span, '/', class: 'divider') | ||
138 | + crumbs += content_tag(:li) do | ||
139 | + # The text is just the individual part, but the link needs all the parts before it | ||
140 | + link_to part, project_commits_path(@project, tree_join(@ref, parts[0..i].join('/'))) | ||
141 | + end | ||
142 | + end | ||
143 | + end | ||
144 | + | ||
145 | + crumbs.html_safe | ||
146 | + end | ||
147 | + | ||
148 | + protected | ||
149 | + | ||
150 | + # Private: Returns a link to a person. If the person has a matching user and | ||
151 | + # is a member of the current @project it will link to the team member page. | ||
152 | + # Otherwise it will link to the person email as specified in the commit. | ||
153 | + # | ||
154 | + # options: | ||
155 | + # source: one of :author or :committer | ||
156 | + # avatar: true will prepend the avatar image | ||
157 | + # size: size of the avatar image in px | ||
158 | + def commit_person_link(commit, options = {}) | ||
159 | + source_name = commit.send "#{options[:source]}_name".to_sym | ||
160 | + source_email = commit.send "#{options[:source]}_email".to_sym | ||
161 | + text = if options[:avatar] | ||
162 | + avatar = image_tag(gravatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "") | ||
163 | + %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{source_name}</span>} | ||
164 | + else | ||
165 | + source_name | ||
166 | + end | ||
167 | + | ||
168 | + user = User.where('name like ? or email like ?', source_name, source_email).first | ||
169 | + | ||
170 | + if user.nil? | ||
171 | + mail_to(source_email, text.html_safe, class: "commit-#{options[:source]}-link") | ||
172 | + else | ||
173 | + link_to(text.html_safe, user_path(user), class: "commit-#{options[:source]}-link") | ||
174 | + end | ||
175 | + end | ||
108 | end | 176 | end |
app/helpers/tree_helper.rb
@@ -70,28 +70,26 @@ module TreeHelper | @@ -70,28 +70,26 @@ module TreeHelper | ||
70 | end | 70 | end |
71 | end | 71 | end |
72 | 72 | ||
73 | - # Breadcrumb links for a Project and, if applicable, a tree path | ||
74 | - def breadcrumbs | ||
75 | - return unless @project && @ref | ||
76 | - | ||
77 | - # Add the root project link and the arrow icon | ||
78 | - crumbs = content_tag(:li) do | ||
79 | - content_tag(:span, nil, class: 'arrow') + | ||
80 | - link_to(@project.name, project_commits_path(@project, @ref)) | ||
81 | - end | 73 | + def tree_breadcrumbs(tree, max_links = 2) |
74 | + if tree.path | ||
75 | + part_path = "" | ||
76 | + parts = tree.path.split("\/") | ||
77 | + | ||
78 | + yield('..', nil) if parts.count > max_links | ||
82 | 79 | ||
83 | - if @path | ||
84 | - parts = @path.split('/') | 80 | + parts.each do |part| |
81 | + part_path = File.join(part_path, part) unless part_path.empty? | ||
82 | + part_path = part if part_path.empty? | ||
85 | 83 | ||
86 | - parts.each_with_index do |part, i| | ||
87 | - crumbs += content_tag(:span, '/', class: 'divider') | ||
88 | - crumbs += content_tag(:li) do | ||
89 | - # The text is just the individual part, but the link needs all the parts before it | ||
90 | - link_to part, project_commits_path(@project, tree_join(@ref, parts[0..i].join('/'))) | ||
91 | - end | 84 | + next unless parts.last(2).include?(part) if parts.count > max_links |
85 | + yield(part, tree_join(tree.ref, part_path)) | ||
92 | end | 86 | end |
93 | end | 87 | end |
88 | + end | ||
94 | 89 | ||
95 | - crumbs.html_safe | 90 | + def up_dir_path tree |
91 | + file = File.join(tree.path, "..") | ||
92 | + tree_join(tree.ref, file) | ||
96 | end | 93 | end |
94 | + | ||
97 | end | 95 | end |
app/mailers/emails/notes.rb
@@ -3,7 +3,6 @@ module Emails | @@ -3,7 +3,6 @@ module Emails | ||
3 | def note_commit_email(recipient_id, note_id) | 3 | def note_commit_email(recipient_id, note_id) |
4 | @note = Note.find(note_id) | 4 | @note = Note.find(note_id) |
5 | @commit = @note.noteable | 5 | @commit = @note.noteable |
6 | - @commit = CommitDecorator.decorate(@commit) | ||
7 | @project = @note.project | 6 | @project = @note.project |
8 | mail(to: recipient(recipient_id), subject: subject("note for commit #{@commit.short_id}", @commit.title)) | 7 | mail(to: recipient(recipient_id), subject: subject("note for commit #{@commit.short_id}", @commit.title)) |
9 | end | 8 | end |
app/models/commit.rb
@@ -8,174 +8,70 @@ class Commit | @@ -8,174 +8,70 @@ class Commit | ||
8 | # | 8 | # |
9 | DIFF_SAFE_SIZE = 100 | 9 | DIFF_SAFE_SIZE = 100 |
10 | 10 | ||
11 | - attr_accessor :commit, :head, :refs | ||
12 | - | ||
13 | - delegate :message, :authored_date, :committed_date, :parents, :sha, | ||
14 | - :date, :committer, :author, :diffs, :tree, :id, :stats, | ||
15 | - :to_patch, to: :commit | ||
16 | - | ||
17 | - class << self | ||
18 | - def find_or_first(repo, commit_id = nil, root_ref) | ||
19 | - commit = if commit_id | ||
20 | - repo.commit(commit_id) | ||
21 | - else | ||
22 | - repo.commits(root_ref).first | ||
23 | - end | ||
24 | - | ||
25 | - Commit.new(commit) if commit | ||
26 | - end | ||
27 | - | ||
28 | - def fresh_commits(repo, n = 10) | ||
29 | - commits = repo.heads.map do |h| | ||
30 | - repo.commits(h.name, n).map { |c| Commit.new(c, h) } | ||
31 | - end.flatten.uniq { |c| c.id } | ||
32 | - | ||
33 | - commits.sort! do |x, y| | ||
34 | - y.committed_date <=> x.committed_date | ||
35 | - end | ||
36 | - | ||
37 | - commits[0...n] | ||
38 | - end | ||
39 | - | ||
40 | - def commits_with_refs(repo, n = 20) | ||
41 | - commits = repo.branches.map { |ref| Commit.new(ref.commit, ref) } | ||
42 | - | ||
43 | - commits.sort! do |x, y| | ||
44 | - y.committed_date <=> x.committed_date | ||
45 | - end | ||
46 | - | ||
47 | - commits[0..n] | ||
48 | - end | ||
49 | - | ||
50 | - def commits_since(repo, date) | ||
51 | - commits = repo.heads.map do |h| | ||
52 | - repo.log(h.name, nil, since: date).each { |c| Commit.new(c, h) } | ||
53 | - end.flatten.uniq { |c| c.id } | ||
54 | - | ||
55 | - commits.sort! do |x, y| | ||
56 | - y.committed_date <=> x.committed_date | ||
57 | - end | ||
58 | - | ||
59 | - commits | ||
60 | - end | ||
61 | - | ||
62 | - def commits(repo, ref, path = nil, limit = nil, offset = nil) | ||
63 | - if path | ||
64 | - repo.log(ref, path, max_count: limit, skip: offset) | ||
65 | - elsif limit && offset | ||
66 | - repo.commits(ref, limit, offset) | ||
67 | - else | ||
68 | - repo.commits(ref) | ||
69 | - end.map{ |c| Commit.new(c) } | ||
70 | - end | ||
71 | - | ||
72 | - def commits_between(repo, from, to) | ||
73 | - repo.commits_between(from, to).map { |c| Commit.new(c) } | ||
74 | - end | ||
75 | - | ||
76 | - def compare(project, from, to) | ||
77 | - result = { | ||
78 | - commits: [], | ||
79 | - diffs: [], | ||
80 | - commit: nil, | ||
81 | - same: false | ||
82 | - } | ||
83 | - | ||
84 | - return result unless from && to | ||
85 | - | ||
86 | - first = project.repository.commit(to.try(:strip)) | ||
87 | - last = project.repository.commit(from.try(:strip)) | ||
88 | - | ||
89 | - if first && last | ||
90 | - result[:same] = (first.id == last.id) | ||
91 | - result[:commits] = project.repo.commits_between(last.id, first.id).map {|c| Commit.new(c)} | ||
92 | - | ||
93 | - # Dont load diff for 100+ commits | ||
94 | - result[:diffs] = if result[:commits].size > 100 | ||
95 | - [] | ||
96 | - else | ||
97 | - project.repo.diff(last.id, first.id) rescue [] | ||
98 | - end | ||
99 | - | ||
100 | - result[:commit] = Commit.new(first) | ||
101 | - end | ||
102 | - | ||
103 | - result | ||
104 | - end | ||
105 | - end | ||
106 | - | ||
107 | - def initialize(raw_commit, head = nil) | ||
108 | - raise "Nil as raw commit passed" unless raw_commit | ||
109 | - | ||
110 | - @commit = raw_commit | ||
111 | - @head = head | ||
112 | - end | ||
113 | - | ||
114 | - def short_id(length = 10) | ||
115 | - id.to_s[0..length] | 11 | + def self.decorate(commits) |
12 | + commits.map { |c| self.new(c) } | ||
116 | end | 13 | end |
117 | 14 | ||
118 | - def safe_message | ||
119 | - @safe_message ||= message | ||
120 | - end | ||
121 | - | ||
122 | - def created_at | ||
123 | - committed_date | ||
124 | - end | 15 | + attr_accessor :raw |
125 | 16 | ||
126 | - def author_email | ||
127 | - author.email | ||
128 | - end | 17 | + def initialize(raw_commit) |
18 | + raise "Nil as raw commit passed" unless raw_commit | ||
129 | 19 | ||
130 | - def author_name | ||
131 | - author.name | 20 | + @raw = raw_commit |
132 | end | 21 | end |
133 | 22 | ||
134 | - # Was this commit committed by a different person than the original author? | ||
135 | - def different_committer? | ||
136 | - author_name != committer_name || author_email != committer_email | 23 | + def id |
24 | + @raw.id | ||
137 | end | 25 | end |
138 | 26 | ||
139 | - def committer_name | ||
140 | - committer.name | 27 | + # Returns a string describing the commit for use in a link title |
28 | + # | ||
29 | + # Example | ||
30 | + # | ||
31 | + # "Commit: Alex Denisov - Project git clone panel" | ||
32 | + def link_title | ||
33 | + "Commit: #{author_name} - #{title}" | ||
141 | end | 34 | end |
142 | 35 | ||
143 | - def committer_email | ||
144 | - committer.email | 36 | + # Returns the commits title. |
37 | + # | ||
38 | + # Usually, the commit title is the first line of the commit message. | ||
39 | + # In case this first line is longer than 80 characters, it is cut off | ||
40 | + # after 70 characters and ellipses (`&hellp;`) are appended. | ||
41 | + def title | ||
42 | + title = safe_message | ||
43 | + | ||
44 | + return no_commit_message if title.blank? | ||
45 | + | ||
46 | + title_end = title.index(/\n/) | ||
47 | + if (!title_end && title.length > 80) || (title_end && title_end > 80) | ||
48 | + title[0..69] << "…".html_safe | ||
49 | + else | ||
50 | + title.split(/\n/, 2).first | ||
51 | + end | ||
145 | end | 52 | end |
146 | 53 | ||
147 | - def prev_commit | ||
148 | - @prev_commit ||= if parents.present? | ||
149 | - Commit.new(parents.first) | ||
150 | - else | ||
151 | - nil | ||
152 | - end | 54 | + # Returns the commits description |
55 | + # | ||
56 | + # cut off, ellipses (`&hellp;`) are prepended to the commit message. | ||
57 | + def description | ||
58 | + description = safe_message | ||
59 | + | ||
60 | + title_end = description.index(/\n/) | ||
61 | + if (!title_end && description.length > 80) || (title_end && title_end > 80) | ||
62 | + "…".html_safe << description[70..-1] | ||
63 | + else | ||
64 | + description.split(/\n/, 2)[1].try(:chomp) | ||
65 | + end | ||
153 | end | 66 | end |
154 | 67 | ||
155 | - def prev_commit_id | ||
156 | - prev_commit.try :id | 68 | + def method_missing(m, *args, &block) |
69 | + @raw.send(m, *args, &block) | ||
157 | end | 70 | end |
158 | 71 | ||
159 | - # Shows the diff between the commit's parent and the commit. | ||
160 | - # | ||
161 | - # Cuts out the header and stats from #to_patch and returns only the diff. | ||
162 | - def to_diff | ||
163 | - # see Grit::Commit#show | ||
164 | - patch = to_patch | ||
165 | - | ||
166 | - # discard lines before the diff | ||
167 | - lines = patch.split("\n") | ||
168 | - while !lines.first.start_with?("diff --git") do | ||
169 | - lines.shift | ||
170 | - end | ||
171 | - lines.pop if lines.last =~ /^[\d.]+$/ # Git version | ||
172 | - lines.pop if lines.last == "-- " # end of diff | ||
173 | - lines.join("\n") | ||
174 | - end | 72 | + def respond_to?(method) |
73 | + return true if @raw.respond_to?(method) | ||
175 | 74 | ||
176 | - def has_zero_stats? | ||
177 | - stats.total.zero? | ||
178 | - rescue | ||
179 | - true | 75 | + super |
180 | end | 76 | end |
181 | end | 77 | end |
app/models/gollum_wiki.rb
@@ -50,7 +50,7 @@ class GollumWiki | @@ -50,7 +50,7 @@ class GollumWiki | ||
50 | # Returns the last 30 Commit objects across the entire | 50 | # Returns the last 30 Commit objects across the entire |
51 | # repository. | 51 | # repository. |
52 | def recent_history | 52 | def recent_history |
53 | - Commit.fresh_commits(wiki.repo, 30) | 53 | + Gitlab::Git::Commit.fresh_commits(wiki.repo, 30) |
54 | end | 54 | end |
55 | 55 | ||
56 | # Finds a page within the repository based on a tile | 56 | # Finds a page within the repository based on a tile |
@@ -90,13 +90,17 @@ class GollumWiki | @@ -90,13 +90,17 @@ class GollumWiki | ||
90 | private | 90 | private |
91 | 91 | ||
92 | def create_repo! | 92 | def create_repo! |
93 | - if gitlab_shell.add_repository(path_with_namespace) | 93 | + if init_repo(path_with_namespace) |
94 | Gollum::Wiki.new(path_to_repo) | 94 | Gollum::Wiki.new(path_to_repo) |
95 | else | 95 | else |
96 | raise CouldNotCreateWikiError | 96 | raise CouldNotCreateWikiError |
97 | end | 97 | end |
98 | end | 98 | end |
99 | 99 | ||
100 | + def init_repo(path_with_namespace) | ||
101 | + gitlab_shell.add_repository(path_with_namespace) | ||
102 | + end | ||
103 | + | ||
100 | def commit_details(action, message = nil, title = nil) | 104 | def commit_details(action, message = nil, title = nil) |
101 | commit_message = message || default_message(action, title) | 105 | commit_message = message || default_message(action, title) |
102 | 106 | ||
@@ -114,5 +118,4 @@ class GollumWiki | @@ -114,5 +118,4 @@ class GollumWiki | ||
114 | def path_to_repo | 118 | def path_to_repo |
115 | @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git") | 119 | @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git") |
116 | end | 120 | end |
117 | - | ||
118 | end | 121 | end |
app/models/merge_request.rb
@@ -152,7 +152,17 @@ class MergeRequest < ActiveRecord::Base | @@ -152,7 +152,17 @@ class MergeRequest < ActiveRecord::Base | ||
152 | end | 152 | end |
153 | 153 | ||
154 | def commits | 154 | def commits |
155 | - st_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 | ||
156 | end | 166 | end |
157 | 167 | ||
158 | def probably_merged? | 168 | def probably_merged? |
@@ -169,9 +179,8 @@ class MergeRequest < ActiveRecord::Base | @@ -169,9 +179,8 @@ class MergeRequest < ActiveRecord::Base | ||
169 | end | 179 | end |
170 | 180 | ||
171 | def unmerged_commits | 181 | def unmerged_commits |
172 | - self.project.repo. | 182 | + self.project.repository. |
173 | commits_between(self.target_branch, self.source_branch). | 183 | commits_between(self.target_branch, self.source_branch). |
174 | - map {|c| Commit.new(c)}. | ||
175 | sort_by(&:created_at). | 184 | sort_by(&:created_at). |
176 | reverse | 185 | reverse |
177 | end | 186 | end |
app/models/network/commit.rb
@@ -8,7 +8,7 @@ module Network | @@ -8,7 +8,7 @@ module Network | ||
8 | attr_accessor :time, :spaces, :parent_spaces | 8 | attr_accessor :time, :spaces, :parent_spaces |
9 | 9 | ||
10 | def initialize(raw_commit, refs) | 10 | def initialize(raw_commit, refs) |
11 | - @commit = ::Commit.new(raw_commit) | 11 | + @commit = Gitlab::Git::Commit.new(raw_commit) |
12 | @time = -1 | 12 | @time = -1 |
13 | @spaces = [] | 13 | @spaces = [] |
14 | @parent_spaces = [] | 14 | @parent_spaces = [] |
app/models/project.rb
@@ -141,13 +141,7 @@ class Project < ActiveRecord::Base | @@ -141,13 +141,7 @@ class Project < ActiveRecord::Base | ||
141 | end | 141 | end |
142 | 142 | ||
143 | def repository | 143 | def repository |
144 | - if path | ||
145 | - @repository ||= Repository.new(path_with_namespace, default_branch) | ||
146 | - else | ||
147 | - nil | ||
148 | - end | ||
149 | - rescue Grit::NoSuchPathError | ||
150 | - nil | 144 | + @repository ||= Repository.new(path_with_namespace, default_branch) |
151 | end | 145 | end |
152 | 146 | ||
153 | def saved? | 147 | def saved? |
@@ -332,14 +326,14 @@ class Project < ActiveRecord::Base | @@ -332,14 +326,14 @@ class Project < ActiveRecord::Base | ||
332 | end | 326 | end |
333 | 327 | ||
334 | def valid_repo? | 328 | def valid_repo? |
335 | - repo | 329 | + repository.exists? |
336 | rescue | 330 | rescue |
337 | errors.add(:path, "Invalid repository path") | 331 | errors.add(:path, "Invalid repository path") |
338 | false | 332 | false |
339 | end | 333 | end |
340 | 334 | ||
341 | def empty_repo? | 335 | def empty_repo? |
342 | - !repository || repository.empty? | 336 | + !repository.exists? || repository.empty? |
343 | end | 337 | end |
344 | 338 | ||
345 | def ensure_satellite_exists | 339 | def ensure_satellite_exists |
@@ -363,7 +357,7 @@ class Project < ActiveRecord::Base | @@ -363,7 +357,7 @@ class Project < ActiveRecord::Base | ||
363 | end | 357 | end |
364 | 358 | ||
365 | def repo_exists? | 359 | def repo_exists? |
366 | - @repo_exists ||= (repository && repository.branches.present?) | 360 | + @repo_exists ||= repository.exists? |
367 | rescue | 361 | rescue |
368 | @repo_exists = false | 362 | @repo_exists = false |
369 | end | 363 | end |
app/models/repository.rb
1 | class Repository | 1 | class Repository |
2 | - include Gitlab::Popen | 2 | + attr_accessor :raw_repository |
3 | 3 | ||
4 | - # Repository directory name with namespace direcotry | ||
5 | - # Examples: | ||
6 | - # gitlab/gitolite | ||
7 | - # diaspora | ||
8 | - # | ||
9 | - attr_accessor :path_with_namespace | ||
10 | - | ||
11 | - # Grit repo object | ||
12 | - attr_accessor :repo | ||
13 | - | ||
14 | - # Default branch in the repository | ||
15 | - attr_accessor :root_ref | ||
16 | - | ||
17 | - def initialize(path_with_namespace, root_ref = 'master') | ||
18 | - @root_ref = root_ref || "master" | ||
19 | - @path_with_namespace = path_with_namespace | ||
20 | - | ||
21 | - # Init grit repo object | ||
22 | - repo | ||
23 | - end | ||
24 | - | ||
25 | - def raw | ||
26 | - repo | ||
27 | - end | ||
28 | - | ||
29 | - def path_to_repo | ||
30 | - @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git") | ||
31 | - end | ||
32 | - | ||
33 | - def repo | ||
34 | - @repo ||= Grit::Repo.new(path_to_repo) | ||
35 | - end | ||
36 | - | ||
37 | - def commit(commit_id = nil) | ||
38 | - Commit.find_or_first(repo, commit_id, root_ref) | 4 | + def initialize(path_with_namespace, default_branch) |
5 | + @raw_repository = Gitlab::Git::Repository.new(path_with_namespace, default_branch) | ||
6 | + rescue Gitlab::Git::Repository::NoRepository | ||
7 | + nil | ||
39 | end | 8 | end |
40 | 9 | ||
41 | - def fresh_commits(n = 10) | ||
42 | - Commit.fresh_commits(repo, n) | 10 | + def exists? |
11 | + raw_repository | ||
43 | end | 12 | end |
44 | 13 | ||
45 | - def commits_with_refs(n = 20) | ||
46 | - Commit.commits_with_refs(repo, n) | 14 | + def empty? |
15 | + raw_repository.empty? | ||
47 | end | 16 | end |
48 | 17 | ||
49 | - def commits_since(date) | ||
50 | - Commit.commits_since(repo, date) | 18 | + def commit(id = nil) |
19 | + commit = raw_repository.commit(id) | ||
20 | + commit = Commit.new(commit) if commit | ||
21 | + commit | ||
51 | end | 22 | end |
52 | 23 | ||
53 | def commits(ref, path = nil, limit = nil, offset = nil) | 24 | def commits(ref, path = nil, limit = nil, offset = nil) |
54 | - Commit.commits(repo, ref, path, limit, offset) | ||
55 | - end | ||
56 | - | ||
57 | - def last_commit_for(ref, path = nil) | ||
58 | - commits(ref, path, 1).first | ||
59 | - end | ||
60 | - | ||
61 | - def commits_between(from, to) | ||
62 | - Commit.commits_between(repo, from, to) | 25 | + commits = raw_repository.commits(ref, path, limit, offset) |
26 | + commits = Commit.decorate(commits) if commits.present? | ||
27 | + commits | ||
63 | end | 28 | end |
64 | 29 | ||
65 | - # Returns an Array of branch names | ||
66 | - # sorted by name ASC | ||
67 | - def branch_names | ||
68 | - branches.map(&:name) | 30 | + def commits_between(target, source) |
31 | + commits = raw_repository.commits_between(target, source) | ||
32 | + commits = Commit.decorate(commits) if commits.present? | ||
33 | + commits | ||
69 | end | 34 | end |
70 | 35 | ||
71 | - # Returns an Array of Branches | ||
72 | - def branches | ||
73 | - repo.branches.sort_by(&:name) | 36 | + def method_missing(m, *args, &block) |
37 | + raw_repository.send(m, *args, &block) | ||
74 | end | 38 | end |
75 | 39 | ||
76 | - # Returns an Array of tag names | ||
77 | - def tag_names | ||
78 | - repo.tags.collect(&:name).sort.reverse | ||
79 | - end | ||
80 | - | ||
81 | - # Returns an Array of Tags | ||
82 | - def tags | ||
83 | - repo.tags.sort_by(&:name).reverse | ||
84 | - end | ||
85 | - | ||
86 | - # Returns an Array of branch and tag names | ||
87 | - def ref_names | ||
88 | - [branch_names + tag_names].flatten | ||
89 | - end | ||
90 | - | ||
91 | - def heads | ||
92 | - @heads ||= repo.heads | ||
93 | - end | ||
94 | - | ||
95 | - def tree(fcommit, path = nil) | ||
96 | - fcommit = commit if fcommit == :head | ||
97 | - tree = fcommit.tree | ||
98 | - path ? (tree / path) : tree | ||
99 | - end | ||
100 | - | ||
101 | - def has_commits? | ||
102 | - !!commit | ||
103 | - rescue Grit::NoSuchPathError | ||
104 | - false | ||
105 | - end | ||
106 | - | ||
107 | - def empty? | ||
108 | - !has_commits? | ||
109 | - end | ||
110 | - | ||
111 | - # Discovers the default branch based on the repository's available branches | ||
112 | - # | ||
113 | - # - If no branches are present, returns nil | ||
114 | - # - If one branch is present, returns its name | ||
115 | - # - If two or more branches are present, returns the one that has a name | ||
116 | - # matching root_ref (default_branch or 'master' if default_branch is nil) | ||
117 | - def discover_default_branch | ||
118 | - if branch_names.length == 0 | ||
119 | - nil | ||
120 | - elsif branch_names.length == 1 | ||
121 | - branch_names.first | ||
122 | - else | ||
123 | - branch_names.select { |v| v == root_ref }.first | ||
124 | - end | ||
125 | - end | ||
126 | - | ||
127 | - # Archive Project to .tar.gz | ||
128 | - # | ||
129 | - # Already packed repo archives stored at | ||
130 | - # app_root/tmp/repositories/project_name/project_name-commit-id.tag.gz | ||
131 | - # | ||
132 | - def archive_repo(ref) | ||
133 | - ref = ref || self.root_ref | ||
134 | - commit = self.commit(ref) | ||
135 | - return nil unless commit | ||
136 | - | ||
137 | - # Build file path | ||
138 | - file_name = self.path_with_namespace.gsub("/","_") + "-" + commit.id.to_s + ".tar.gz" | ||
139 | - storage_path = Rails.root.join("tmp", "repositories") | ||
140 | - file_path = File.join(storage_path, self.path_with_namespace, file_name) | ||
141 | - | ||
142 | - # Put files into a directory before archiving | ||
143 | - prefix = File.basename(self.path_with_namespace) + "/" | ||
144 | - | ||
145 | - # Create file if not exists | ||
146 | - unless File.exists?(file_path) | ||
147 | - FileUtils.mkdir_p File.dirname(file_path) | ||
148 | - file = self.repo.archive_to_file(ref, prefix, file_path) | ||
149 | - end | ||
150 | - | ||
151 | - file_path | ||
152 | - end | ||
153 | - | ||
154 | - # Return repo size in megabytes | ||
155 | - # Cached in redis | ||
156 | - def size | ||
157 | - Rails.cache.fetch(cache_key(:size)) do | ||
158 | - size = popen('du -s', path_to_repo).first.strip.to_i | ||
159 | - (size.to_f / 1024).round(2) | ||
160 | - end | ||
161 | - end | ||
162 | - | ||
163 | - def expire_cache | ||
164 | - Rails.cache.delete(cache_key(:size)) | ||
165 | - end | 40 | + def respond_to?(method) |
41 | + return true if raw_repository.respond_to?(method) | ||
166 | 42 | ||
167 | - def cache_key(type) | ||
168 | - "#{type}:#{path_with_namespace}" | 43 | + super |
169 | end | 44 | end |
170 | end | 45 | end |
app/models/tree.rb
@@ -26,4 +26,12 @@ class Tree | @@ -26,4 +26,12 @@ class Tree | ||
26 | def empty? | 26 | def empty? |
27 | data.blank? | 27 | data.blank? |
28 | end | 28 | end |
29 | + | ||
30 | + def up_dir? | ||
31 | + path.present? | ||
32 | + end | ||
33 | + | ||
34 | + def readme | ||
35 | + @readme ||= contents.find { |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i } | ||
36 | + end | ||
29 | end | 37 | end |
app/models/wiki_page.rb
@@ -79,14 +79,14 @@ class WikiPage | @@ -79,14 +79,14 @@ class WikiPage | ||
79 | def version | 79 | def version |
80 | return nil unless persisted? | 80 | return nil unless persisted? |
81 | 81 | ||
82 | - @version ||= Commit.new(@page.version) | 82 | + @version ||= Commit.new(Gitlab::Git::Commit.new(@page.version)) |
83 | end | 83 | end |
84 | 84 | ||
85 | # Returns an array of Gitlab Commit instances. | 85 | # Returns an array of Gitlab Commit instances. |
86 | def versions | 86 | def versions |
87 | return [] unless persisted? | 87 | return [] unless persisted? |
88 | 88 | ||
89 | - @page.versions.map { |v| Commit.new(v) } | 89 | + @page.versions.map { |v| Commit.new(Gitlab::Git::Commit.new(v)) } |
90 | end | 90 | end |
91 | 91 | ||
92 | # Returns the Date that this latest version was | 92 | # Returns the Date that this latest version was |
app/views/admin/projects/show.html.haml
@@ -46,18 +46,21 @@ | @@ -46,18 +46,21 @@ | ||
46 | %span.light ssh: | 46 | %span.light ssh: |
47 | %strong | 47 | %strong |
48 | = link_to @project.ssh_url_to_repo | 48 | = link_to @project.ssh_url_to_repo |
49 | - %li | ||
50 | - %span.light fs: | ||
51 | - %strong | ||
52 | - = @repository.path_to_repo | 49 | + - if @project.repository.exists? |
50 | + %li | ||
51 | + %span.light fs: | ||
52 | + %strong | ||
53 | + = @repository.path_to_repo | ||
53 | 54 | ||
54 | - %li | ||
55 | - %span.light last commit: | ||
56 | - %strong | ||
57 | - - if @repository | 55 | + %li |
56 | + %span.light last commit: | ||
57 | + %strong | ||
58 | = last_commit(@project) | 58 | = last_commit(@project) |
59 | - - else | ||
60 | - never | 59 | + - else |
60 | + %li | ||
61 | + %span.light repository: | ||
62 | + %strong.cred | ||
63 | + does not exist | ||
61 | 64 | ||
62 | %li | 65 | %li |
63 | %span.light access: | 66 | %span.light access: |
app/views/blame/show.html.haml
@@ -6,7 +6,7 @@ | @@ -6,7 +6,7 @@ | ||
6 | %i.icon-angle-right | 6 | %i.icon-angle-right |
7 | = link_to project_tree_path(@project, @ref) do | 7 | = link_to project_tree_path(@project, @ref) do |
8 | = @project.name | 8 | = @project.name |
9 | - - @tree.breadcrumbs(6) do |link| | 9 | + - tree_breadcrumbs(@tree, 6) do |link| |
10 | \/ | 10 | \/ |
11 | %li= link | 11 | %li= link |
12 | .clear | 12 | .clear |
@@ -22,13 +22,13 @@ | @@ -22,13 +22,13 @@ | ||
22 | %table | 22 | %table |
23 | - current_line = 1 | 23 | - current_line = 1 |
24 | - @blame.each do |commit, lines| | 24 | - @blame.each do |commit, lines| |
25 | - - commit = CommitDecorator.decorate(Commit.new(commit)) | 25 | + - commit = Commit.new(commit) |
26 | %tr | 26 | %tr |
27 | %td.blame-commit | 27 | %td.blame-commit |
28 | %span.commit | 28 | %span.commit |
29 | = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id" | 29 | = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id" |
30 | | 30 | |
31 | - = commit.author_link avatar: true, size: 16 | 31 | + = commit_author_link(commit, avatar: true, size: 16) |
32 | | 32 | |
33 | = link_to_gfm truncate(commit.title, length: 20), project_commit_path(@project, commit.id), class: "row_title" | 33 | = link_to_gfm truncate(commit.title, length: 20), project_commit_path(@project, commit.id), class: "row_title" |
34 | %td.lines.blame-numbers | 34 | %td.lines.blame-numbers |
app/views/commit/_commit_box.html.haml
@@ -24,14 +24,14 @@ | @@ -24,14 +24,14 @@ | ||
24 | .row | 24 | .row |
25 | .span5 | 25 | .span5 |
26 | .author | 26 | .author |
27 | - = @commit.author_link avatar: true, size: 32 | 27 | + = commit_author_link(@commit, avatar: true, size: 32) |
28 | authored | 28 | authored |
29 | %time{title: @commit.authored_date.stamp("Aug 21, 2011 9:23pm")} | 29 | %time{title: @commit.authored_date.stamp("Aug 21, 2011 9:23pm")} |
30 | #{time_ago_in_words(@commit.authored_date)} ago | 30 | #{time_ago_in_words(@commit.authored_date)} ago |
31 | - if @commit.different_committer? | 31 | - if @commit.different_committer? |
32 | .committer | 32 | .committer |
33 | → | 33 | → |
34 | - = @commit.committer_link | 34 | + = commit_committer_link(@commit) |
35 | committed | 35 | committed |
36 | %time{title: @commit.committed_date.stamp("Aug 21, 2011 9:23pm")} | 36 | %time{title: @commit.committed_date.stamp("Aug 21, 2011 9:23pm")} |
37 | #{time_ago_in_words(@commit.committed_date)} ago | 37 | #{time_ago_in_words(@commit.committed_date)} ago |
app/views/commits/_commit.html.haml
@@ -4,7 +4,7 @@ | @@ -4,7 +4,7 @@ | ||
4 | %strong= link_to "Browse Code »", project_tree_path(@project, commit), class: "right" | 4 | %strong= link_to "Browse Code »", project_tree_path(@project, commit), class: "right" |
5 | %p | 5 | %p |
6 | = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id" | 6 | = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id" |
7 | - = commit.author_link avatar: true, size: 24 | 7 | + = commit_author_link(commit, avatar: true, size: 24) |
8 | | 8 | |
9 | = link_to_gfm truncate(commit.title, length: 70), project_commit_path(@project, commit.id), class: "row_title" | 9 | = link_to_gfm truncate(commit.title, length: 70), project_commit_path(@project, commit.id), class: "row_title" |
10 | 10 |
app/views/commits/show.html.haml
app/views/compare/show.html.haml
@@ -16,7 +16,7 @@ | @@ -16,7 +16,7 @@ | ||
16 | %div.ui-box | 16 | %div.ui-box |
17 | %h5.title | 17 | %h5.title |
18 | Commits (#{@commits.count}) | 18 | Commits (#{@commits.count}) |
19 | - %ul.well-list= render @commits | 19 | + %ul.well-list= render Commit.decorate(@commits) |
20 | 20 | ||
21 | - unless @diffs.empty? | 21 | - unless @diffs.empty? |
22 | %h4 Diff | 22 | %h4 Diff |
app/views/events/_commit.html.haml
app/views/projects/_clone_panel.html.haml
@@ -4,7 +4,7 @@ | @@ -4,7 +4,7 @@ | ||
4 | .form-horizontal= render "shared/clone_panel" | 4 | .form-horizontal= render "shared/clone_panel" |
5 | .span4.pull-right | 5 | .span4.pull-right |
6 | .pull-right | 6 | .pull-right |
7 | - - unless @project.empty_repo? | 7 | + - if @project.empty_repo? |
8 | - if can? current_user, :download_code, @project | 8 | - if can? current_user, :download_code, @project |
9 | = link_to archive_project_repository_path(@project), class: "btn-small btn grouped" do | 9 | = link_to archive_project_repository_path(@project), class: "btn-small btn grouped" do |
10 | %i.icon-download-alt | 10 | %i.icon-download-alt |
app/views/repositories/_branch.html.haml
app/views/repositories/_feed.html.haml
app/views/repositories/tags.html.haml
@@ -7,8 +7,7 @@ | @@ -7,8 +7,7 @@ | ||
7 | %th Last commit | 7 | %th Last commit |
8 | %th | 8 | %th |
9 | - @tags.each do |tag| | 9 | - @tags.each do |tag| |
10 | - - commit = Commit.new(tag.commit) | ||
11 | - - commit = CommitDecorator.decorate(commit) | 10 | + - commit = Commit.new(Gitlab::Git::Commit.new(tag.commit)) |
12 | %tr | 11 | %tr |
13 | %td | 12 | %td |
14 | %strong | 13 | %strong |
app/views/tree/_tree.html.haml
@@ -3,7 +3,7 @@ | @@ -3,7 +3,7 @@ | ||
3 | %i.icon-angle-right | 3 | %i.icon-angle-right |
4 | = link_to project_tree_path(@project, @ref) do | 4 | = link_to project_tree_path(@project, @ref) do |
5 | = @project.path | 5 | = @project.path |
6 | - - tree.breadcrumbs(6) do |title, path| | 6 | + - tree_breadcrumbs(tree, 6) do |title, path| |
7 | \/ | 7 | \/ |
8 | %li | 8 | %li |
9 | - if path | 9 | - if path |
@@ -27,7 +27,7 @@ | @@ -27,7 +27,7 @@ | ||
27 | %tr.tree-item | 27 | %tr.tree-item |
28 | %td.tree-item-file-name | 28 | %td.tree-item-file-name |
29 | = image_tag "file_empty.png", size: '16x16' | 29 | = image_tag "file_empty.png", size: '16x16' |
30 | - = link_to "..", project_tree_path(@project, tree.up_dir_path) | 30 | + = link_to "..", project_tree_path(@project, up_dir_path(tree)) |
31 | %td | 31 | %td |
32 | %td | 32 | %td |
33 | %td | 33 | %td |
app/views/tree/_tree_commit_column.html.haml
1 | -%span.tree_author= commit.author_link avatar: true | 1 | +%span.tree_author= commit_author_link(commit, avatar: true) |
2 | = link_to_gfm truncate(commit.title, length: 80), project_commit_path(@project, commit.id), class: "tree-commit-link" | 2 | = link_to_gfm truncate(commit.title, length: 80), project_commit_path(@project, commit.id), class: "tree-commit-link" |
app/views/wikis/history.html.haml
@@ -14,12 +14,13 @@ | @@ -14,12 +14,13 @@ | ||
14 | %th Format | 14 | %th Format |
15 | %tbody | 15 | %tbody |
16 | - @wiki.versions.each do |version| | 16 | - @wiki.versions.each do |version| |
17 | - - commit = CommitDecorator.new(version) | 17 | + - commit = version |
18 | %tr | 18 | %tr |
19 | %td | 19 | %td |
20 | = link_to project_wiki_path(@project, @wiki, version_id: commit.id) do | 20 | = link_to project_wiki_path(@project, @wiki, version_id: commit.id) do |
21 | = commit.short_id | 21 | = commit.short_id |
22 | - %td= commit.author_link avatar: true, size: 24 | 22 | + %td |
23 | + = commit_author_link(commit, avatar: true, size: 24) | ||
23 | %td | 24 | %td |
24 | = commit.title | 25 | = commit.title |
25 | %td | 26 | %td |
app/views/wikis/pages.html.haml
@@ -21,5 +21,5 @@ | @@ -21,5 +21,5 @@ | ||
21 | = wiki_page.created_at.to_s(:short) do | 21 | = wiki_page.created_at.to_s(:short) do |
22 | (#{time_ago_in_words(wiki_page.created_at)} | 22 | (#{time_ago_in_words(wiki_page.created_at)} |
23 | ago) | 23 | ago) |
24 | - - commit = CommitDecorator.decorate(wiki_page.version) | ||
25 | - %td= commit.author_link avatar: true, size: 24 | 24 | + %td |
25 | + = commit_author_link(wiki_page.version, avatar: true, size: 24) |
app/views/wikis/show.html.haml
@@ -13,5 +13,4 @@ | @@ -13,5 +13,4 @@ | ||
13 | = preserve do | 13 | = preserve do |
14 | = render_wiki_content(@wiki) | 14 | = render_wiki_content(@wiki) |
15 | 15 | ||
16 | -- commit = CommitDecorator.new(@wiki.version) | ||
17 | -%p.time Last edited by #{commit.author_link(avatar: true, size: 16)} #{time_ago_in_words @wiki.created_at} ago | 16 | +%p.time Last edited by #{commit_author_link(@wiki.version, avatar: true, size: 16)} #{time_ago_in_words @wiki.created_at} ago |
features/steps/project/project_browse_commits.rb
@@ -15,7 +15,7 @@ class ProjectBrowseCommits < Spinach::FeatureSteps | @@ -15,7 +15,7 @@ class ProjectBrowseCommits < Spinach::FeatureSteps | ||
15 | end | 15 | end |
16 | 16 | ||
17 | Then 'I see commits atom feed' do | 17 | Then 'I see commits atom feed' do |
18 | - commit = CommitDecorator.decorate(@project.repository.commit) | 18 | + commit = @project.repository.commit |
19 | page.response_headers['Content-Type'].should have_content("application/atom+xml") | 19 | page.response_headers['Content-Type'].should have_content("application/atom+xml") |
20 | page.body.should have_selector("title", :text => "Recent commits to #{@project.name}") | 20 | page.body.should have_selector("title", :text => "Recent commits to #{@project.name}") |
21 | page.body.should have_selector("author email", :text => commit.author_email) | 21 | page.body.should have_selector("author email", :text => commit.author_email) |
features/steps/shared/project.rb
@@ -3,14 +3,14 @@ module SharedProject | @@ -3,14 +3,14 @@ module SharedProject | ||
3 | 3 | ||
4 | # Create a project without caring about what it's called | 4 | # Create a project without caring about what it's called |
5 | And "I own a project" do | 5 | And "I own a project" do |
6 | - @project = create(:project) | 6 | + @project = create(:project_with_code) |
7 | @project.team << [@user, :master] | 7 | @project.team << [@user, :master] |
8 | end | 8 | end |
9 | 9 | ||
10 | # Create a specific project called "Shop" | 10 | # Create a specific project called "Shop" |
11 | And 'I own project "Shop"' do | 11 | And 'I own project "Shop"' do |
12 | @project = Project.find_by_name "Shop" | 12 | @project = Project.find_by_name "Shop" |
13 | - @project ||= create(:project, name: "Shop") | 13 | + @project ||= create(:project_with_code, name: "Shop") |
14 | @project.team << [@user, :master] | 14 | @project.team << [@user, :master] |
15 | end | 15 | end |
16 | 16 |
features/steps/userteams/userteams.rb
@@ -132,7 +132,7 @@ class Userteams < Spinach::FeatureSteps | @@ -132,7 +132,7 @@ class Userteams < Spinach::FeatureSteps | ||
132 | team = UserTeam.last | 132 | team = UserTeam.last |
133 | team.projects.each do |project| | 133 | team.projects.each do |project| |
134 | team.members.each do |member| | 134 | team.members.each do |member| |
135 | - 3.times { project.merge_requests << create(:merge_request, assignee: member) } | 135 | + 3.times { create(:merge_request, assignee: member, project: project) } |
136 | end | 136 | end |
137 | end | 137 | end |
138 | end | 138 | end |
@@ -157,7 +157,7 @@ class Userteams < Spinach::FeatureSteps | @@ -157,7 +157,7 @@ class Userteams < Spinach::FeatureSteps | ||
157 | team = UserTeam.last | 157 | team = UserTeam.last |
158 | team.projects.each do |project| | 158 | team.projects.each do |project| |
159 | team.members.each do |member| | 159 | team.members.each do |member| |
160 | - 3.times { project.merge_requests << create(:merge_request, assignee: member) } | 160 | + 3.times { create(:merge_request, assignee: member, project: project) } |
161 | end | 161 | end |
162 | end | 162 | end |
163 | end | 163 | end |
features/support/env.rb
@@ -14,7 +14,7 @@ require 'spinach/capybara' | @@ -14,7 +14,7 @@ require 'spinach/capybara' | ||
14 | require 'sidekiq/testing/inline' | 14 | require 'sidekiq/testing/inline' |
15 | 15 | ||
16 | 16 | ||
17 | -%w(stubbed_repository valid_commit select2_helper).each do |f| | 17 | +%w(valid_commit select2_helper test_env).each do |f| |
18 | require Rails.root.join('spec', 'support', f) | 18 | require Rails.root.join('spec', 'support', f) |
19 | end | 19 | end |
20 | 20 | ||
@@ -35,13 +35,8 @@ Capybara.default_wait_time = 10 | @@ -35,13 +35,8 @@ Capybara.default_wait_time = 10 | ||
35 | DatabaseCleaner.strategy = :truncation | 35 | DatabaseCleaner.strategy = :truncation |
36 | 36 | ||
37 | Spinach.hooks.before_scenario do | 37 | Spinach.hooks.before_scenario do |
38 | - # Use tmp dir for FS manipulations | ||
39 | - Gitlab.config.gitlab_shell.stub(repos_path: Rails.root.join('tmp', 'test-git-base-path')) | ||
40 | - Gitlab::Shell.any_instance.stub(:add_repository) do |path| | ||
41 | - create_temp_repo("#{Rails.root}/tmp/test-git-base-path/#{path}.git") | ||
42 | - end | ||
43 | - FileUtils.rm_rf Gitlab.config.gitlab_shell.repos_path | ||
44 | - FileUtils.mkdir_p Gitlab.config.gitlab_shell.repos_path | 38 | + TestEnv.init |
39 | + | ||
45 | DatabaseCleaner.start | 40 | DatabaseCleaner.start |
46 | end | 41 | end |
47 | 42 | ||
@@ -54,9 +49,3 @@ Spinach.hooks.before_run do | @@ -54,9 +49,3 @@ Spinach.hooks.before_run do | ||
54 | 49 | ||
55 | include FactoryGirl::Syntax::Methods | 50 | include FactoryGirl::Syntax::Methods |
56 | end | 51 | end |
57 | - | ||
58 | -def create_temp_repo(path) | ||
59 | - FileUtils.mkdir_p path | ||
60 | - command = "git init --quiet --bare #{path};" | ||
61 | - system(command) | ||
62 | -end |
lib/api/projects.rb
@@ -372,7 +372,7 @@ module Gitlab | @@ -372,7 +372,7 @@ module Gitlab | ||
372 | ref = params[:ref_name] || user_project.try(:default_branch) || 'master' | 372 | ref = params[:ref_name] || user_project.try(:default_branch) || 'master' |
373 | 373 | ||
374 | commits = user_project.repository.commits(ref, nil, per_page, page * per_page) | 374 | commits = user_project.repository.commits(ref, nil, per_page, page * per_page) |
375 | - present CommitDecorator.decorate(commits), with: Entities::RepoCommit | 375 | + present commits, with: Entities::RepoCommit |
376 | end | 376 | end |
377 | 377 | ||
378 | # Get a project snippets | 378 | # Get a project snippets |
lib/extracts_path.rb
@@ -85,8 +85,8 @@ module ExtractsPath | @@ -85,8 +85,8 @@ module ExtractsPath | ||
85 | # - @id - A string representing the joined ref and path | 85 | # - @id - A string representing the joined ref and path |
86 | # - @ref - A string representing the ref (e.g., the branch, tag, or commit SHA) | 86 | # - @ref - A string representing the ref (e.g., the branch, tag, or commit SHA) |
87 | # - @path - A string representing the filesystem path | 87 | # - @path - A string representing the filesystem path |
88 | - # - @commit - A CommitDecorator representing the commit from the given ref | ||
89 | - # - @tree - A TreeDecorator representing the tree at the given ref/path | 88 | + # - @commit - A Commit representing the commit from the given ref |
89 | + # - @tree - A Tree representing the tree at the given ref/path | ||
90 | # | 90 | # |
91 | # If the :id parameter appears to be requesting a specific response format, | 91 | # If the :id parameter appears to be requesting a specific response format, |
92 | # that will be handled as well. | 92 | # that will be handled as well. |
@@ -100,11 +100,9 @@ module ExtractsPath | @@ -100,11 +100,9 @@ module ExtractsPath | ||
100 | 100 | ||
101 | # It is used "@project.repository.commits(@ref, @path, 1, 0)", | 101 | # It is used "@project.repository.commits(@ref, @path, 1, 0)", |
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 | - commits = @project.repository.commits(@ref, @path, 1, 0) | ||
104 | - @commit = CommitDecorator.decorate(commits.first) | 103 | + @commit = @project.repository.commits(@ref, @path, 1, 0).first |
105 | 104 | ||
106 | @tree = Tree.new(@commit.tree, @ref, @path) | 105 | @tree = Tree.new(@commit.tree, @ref, @path) |
107 | - @tree = TreeDecorator.new(@tree) | ||
108 | 106 | ||
109 | raise InvalidPathError if @tree.invalid? | 107 | raise InvalidPathError if @tree.invalid? |
110 | rescue RuntimeError, NoMethodError, InvalidPathError | 108 | rescue RuntimeError, NoMethodError, InvalidPathError |
@@ -0,0 +1,22 @@ | @@ -0,0 +1,22 @@ | ||
1 | +module Gitlab | ||
2 | + module Git | ||
3 | + class Blame | ||
4 | + | ||
5 | + attr_accessor :repository, :sha, :path | ||
6 | + | ||
7 | + def initialize(repository, sha, path) | ||
8 | + @repository, @sha, @path = repository, sha, path | ||
9 | + | ||
10 | + end | ||
11 | + | ||
12 | + def each | ||
13 | + raw_blame = Grit::Blob.blame(repository.repo, sha, path) | ||
14 | + | ||
15 | + raw_blame.each do |commit, lines| | ||
16 | + commit = Gitlab::Git::Commit.new(commit) | ||
17 | + yield(commit, lines) | ||
18 | + end | ||
19 | + end | ||
20 | + end | ||
21 | + end | ||
22 | +end |
@@ -0,0 +1,153 @@ | @@ -0,0 +1,153 @@ | ||
1 | +# Gitlab::Git::Commit is a wrapper around native Grit::Commit object | ||
2 | +# We dont want to use grit objects inside app/ | ||
3 | +# It helps us easily migrate to rugged in future | ||
4 | +module Gitlab | ||
5 | + module Git | ||
6 | + class Commit | ||
7 | + attr_accessor :raw_commit, :head, :refs | ||
8 | + | ||
9 | + delegate :message, :authored_date, :committed_date, :parents, :sha, | ||
10 | + :date, :committer, :author, :diffs, :tree, :id, :stats, :to_patch, | ||
11 | + to: :raw_commit | ||
12 | + | ||
13 | + class << self | ||
14 | + def find_or_first(repo, commit_id = nil, root_ref) | ||
15 | + commit = if commit_id | ||
16 | + repo.commit(commit_id) | ||
17 | + else | ||
18 | + repo.commits(root_ref).first | ||
19 | + end | ||
20 | + | ||
21 | + Commit.new(commit) if commit | ||
22 | + end | ||
23 | + | ||
24 | + def fresh_commits(repo, n = 10) | ||
25 | + commits = repo.heads.map do |h| | ||
26 | + repo.commits(h.name, n).map { |c| Commit.new(c, h) } | ||
27 | + end.flatten.uniq { |c| c.id } | ||
28 | + | ||
29 | + commits.sort! do |x, y| | ||
30 | + y.committed_date <=> x.committed_date | ||
31 | + end | ||
32 | + | ||
33 | + commits[0...n] | ||
34 | + end | ||
35 | + | ||
36 | + def commits_with_refs(repo, n = 20) | ||
37 | + commits = repo.branches.map { |ref| Commit.new(ref.commit, ref) } | ||
38 | + | ||
39 | + commits.sort! do |x, y| | ||
40 | + y.committed_date <=> x.committed_date | ||
41 | + end | ||
42 | + | ||
43 | + commits[0..n] | ||
44 | + end | ||
45 | + | ||
46 | + def commits_since(repo, date) | ||
47 | + commits = repo.heads.map do |h| | ||
48 | + repo.log(h.name, nil, since: date).each { |c| Commit.new(c, h) } | ||
49 | + end.flatten.uniq { |c| c.id } | ||
50 | + | ||
51 | + commits.sort! do |x, y| | ||
52 | + y.committed_date <=> x.committed_date | ||
53 | + end | ||
54 | + | ||
55 | + commits | ||
56 | + end | ||
57 | + | ||
58 | + def commits(repo, ref, path = nil, limit = nil, offset = nil) | ||
59 | + if path | ||
60 | + repo.log(ref, path, max_count: limit, skip: offset) | ||
61 | + elsif limit && offset | ||
62 | + repo.commits(ref, limit, offset) | ||
63 | + else | ||
64 | + repo.commits(ref) | ||
65 | + end.map{ |c| Commit.new(c) } | ||
66 | + end | ||
67 | + | ||
68 | + def commits_between(repo, from, to) | ||
69 | + repo.commits_between(from, to).map { |c| Commit.new(c) } | ||
70 | + end | ||
71 | + end | ||
72 | + | ||
73 | + def initialize(raw_commit, head = nil) | ||
74 | + raise "Nil as raw commit passed" unless raw_commit | ||
75 | + | ||
76 | + @raw_commit = raw_commit | ||
77 | + @head = head | ||
78 | + end | ||
79 | + | ||
80 | + def short_id(length = 10) | ||
81 | + id.to_s[0..length] | ||
82 | + end | ||
83 | + | ||
84 | + def safe_message | ||
85 | + @safe_message ||= message | ||
86 | + end | ||
87 | + | ||
88 | + def created_at | ||
89 | + committed_date | ||
90 | + end | ||
91 | + | ||
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? | ||
101 | + def different_committer? | ||
102 | + author_name != committer_name || author_email != committer_email | ||
103 | + end | ||
104 | + | ||
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 | ||
123 | + end | ||
124 | + | ||
125 | + # Shows the diff between the commit's parent and the commit. | ||
126 | + # | ||
127 | + # Cuts out the header and stats from #to_patch and returns only the diff. | ||
128 | + def to_diff | ||
129 | + # see Grit::Commit#show | ||
130 | + patch = to_patch | ||
131 | + | ||
132 | + # discard lines before the diff | ||
133 | + lines = patch.split("\n") | ||
134 | + while !lines.first.start_with?("diff --git") do | ||
135 | + lines.shift | ||
136 | + end | ||
137 | + lines.pop if lines.last =~ /^[\d.]+$/ # Git version | ||
138 | + lines.pop if lines.last == "-- " # end of diff | ||
139 | + lines.join("\n") | ||
140 | + end | ||
141 | + | ||
142 | + def has_zero_stats? | ||
143 | + stats.total.zero? | ||
144 | + rescue | ||
145 | + true | ||
146 | + end | ||
147 | + | ||
148 | + def no_commit_message | ||
149 | + "--no commit message" | ||
150 | + end | ||
151 | + end | ||
152 | + end | ||
153 | +end |
@@ -0,0 +1,37 @@ | @@ -0,0 +1,37 @@ | ||
1 | +module Gitlab | ||
2 | + module Git | ||
3 | + class Compare | ||
4 | + attr_accessor :commits, :commit, :diffs, :same | ||
5 | + | ||
6 | + def initialize(repository, from, to) | ||
7 | + @commits, @diffs = [], [] | ||
8 | + @commit = nil | ||
9 | + @same = false | ||
10 | + | ||
11 | + return unless from && to | ||
12 | + | ||
13 | + first = repository.commit(to.try(:strip)) | ||
14 | + last = repository.commit(from.try(:strip)) | ||
15 | + | ||
16 | + return unless first && last | ||
17 | + | ||
18 | + if first.id == last.id | ||
19 | + @same = true | ||
20 | + return | ||
21 | + end | ||
22 | + | ||
23 | + @commit = Commit.new(first) | ||
24 | + | ||
25 | + @commits = repository.commits_between(last.id, first.id) | ||
26 | + @commits = @commits.map { |c| Commit.new(c) } | ||
27 | + | ||
28 | + @diffs = if @commits.size > 100 | ||
29 | + [] | ||
30 | + else | ||
31 | + repository.repo.diff(last.id, first.id) rescue [] | ||
32 | + end | ||
33 | + end | ||
34 | + end | ||
35 | + end | ||
36 | +end | ||
37 | + |
@@ -0,0 +1,185 @@ | @@ -0,0 +1,185 @@ | ||
1 | +# Gitlab::Git::Gitlab::Git::Commit is a wrapper around native Grit::Repository object | ||
2 | +# We dont want to use grit objects inside app/ | ||
3 | +# It helps us easily migrate to rugged in future | ||
4 | +module Gitlab | ||
5 | + module Git | ||
6 | + class Repository | ||
7 | + include Gitlab::Popen | ||
8 | + | ||
9 | + class NoRepository < StandardError; end | ||
10 | + | ||
11 | + # Repository directory name with namespace direcotry | ||
12 | + # Examples: | ||
13 | + # gitlab/gitolite | ||
14 | + # diaspora | ||
15 | + # | ||
16 | + attr_accessor :path_with_namespace | ||
17 | + | ||
18 | + # Grit repo object | ||
19 | + attr_accessor :repo | ||
20 | + | ||
21 | + # Default branch in the repository | ||
22 | + attr_accessor :root_ref | ||
23 | + | ||
24 | + def initialize(path_with_namespace, root_ref = 'master') | ||
25 | + @root_ref = root_ref || "master" | ||
26 | + @path_with_namespace = path_with_namespace | ||
27 | + | ||
28 | + # Init grit repo object | ||
29 | + repo | ||
30 | + end | ||
31 | + | ||
32 | + def raw | ||
33 | + repo | ||
34 | + end | ||
35 | + | ||
36 | + def path_to_repo | ||
37 | + @path_to_repo ||= File.join(repos_path, "#{path_with_namespace}.git") | ||
38 | + end | ||
39 | + | ||
40 | + def repos_path | ||
41 | + Gitlab.config.gitlab_shell.repos_path | ||
42 | + end | ||
43 | + | ||
44 | + def repo | ||
45 | + @repo ||= Grit::Repo.new(path_to_repo) | ||
46 | + rescue Grit::NoSuchPathError | ||
47 | + raise NoRepository.new('no repository for such path') | ||
48 | + end | ||
49 | + | ||
50 | + def commit(commit_id = nil) | ||
51 | + Gitlab::Git::Commit.find_or_first(repo, commit_id, root_ref) | ||
52 | + end | ||
53 | + | ||
54 | + def fresh_commits(n = 10) | ||
55 | + Gitlab::Git::Commit.fresh_commits(repo, n) | ||
56 | + end | ||
57 | + | ||
58 | + def commits_with_refs(n = 20) | ||
59 | + Gitlab::Git::Commit.commits_with_refs(repo, n) | ||
60 | + end | ||
61 | + | ||
62 | + def commits_since(date) | ||
63 | + Gitlab::Git::Commit.commits_since(repo, date) | ||
64 | + end | ||
65 | + | ||
66 | + def commits(ref, path = nil, limit = nil, offset = nil) | ||
67 | + Gitlab::Git::Commit.commits(repo, ref, path, limit, offset) | ||
68 | + end | ||
69 | + | ||
70 | + def last_commit_for(ref, path = nil) | ||
71 | + commits(ref, path, 1).first | ||
72 | + end | ||
73 | + | ||
74 | + def commits_between(from, to) | ||
75 | + Gitlab::Git::Commit.commits_between(repo, from, to) | ||
76 | + end | ||
77 | + | ||
78 | + # Returns an Array of branch names | ||
79 | + # sorted by name ASC | ||
80 | + def branch_names | ||
81 | + branches.map(&:name) | ||
82 | + end | ||
83 | + | ||
84 | + # Returns an Array of Branches | ||
85 | + def branches | ||
86 | + repo.branches.sort_by(&:name) | ||
87 | + end | ||
88 | + | ||
89 | + # Returns an Array of tag names | ||
90 | + def tag_names | ||
91 | + repo.tags.collect(&:name).sort.reverse | ||
92 | + end | ||
93 | + | ||
94 | + # Returns an Array of Tags | ||
95 | + def tags | ||
96 | + repo.tags.sort_by(&:name).reverse | ||
97 | + end | ||
98 | + | ||
99 | + # Returns an Array of branch and tag names | ||
100 | + def ref_names | ||
101 | + [branch_names + tag_names].flatten | ||
102 | + end | ||
103 | + | ||
104 | + def heads | ||
105 | + @heads ||= repo.heads | ||
106 | + end | ||
107 | + | ||
108 | + def tree(fcommit, path = nil) | ||
109 | + fcommit = commit if fcommit == :head | ||
110 | + tree = fcommit.tree | ||
111 | + path ? (tree / path) : tree | ||
112 | + end | ||
113 | + | ||
114 | + def has_commits? | ||
115 | + !!commit | ||
116 | + rescue Grit::NoSuchPathError | ||
117 | + false | ||
118 | + end | ||
119 | + | ||
120 | + def empty? | ||
121 | + !has_commits? | ||
122 | + end | ||
123 | + | ||
124 | + # Discovers the default branch based on the repository's available branches | ||
125 | + # | ||
126 | + # - If no branches are present, returns nil | ||
127 | + # - If one branch is present, returns its name | ||
128 | + # - If two or more branches are present, returns the one that has a name | ||
129 | + # matching root_ref (default_branch or 'master' if default_branch is nil) | ||
130 | + def discover_default_branch | ||
131 | + if branch_names.length == 0 | ||
132 | + nil | ||
133 | + elsif branch_names.length == 1 | ||
134 | + branch_names.first | ||
135 | + else | ||
136 | + branch_names.select { |v| v == root_ref }.first | ||
137 | + end | ||
138 | + end | ||
139 | + | ||
140 | + # Archive Project to .tar.gz | ||
141 | + # | ||
142 | + # Already packed repo archives stored at | ||
143 | + # app_root/tmp/repositories/project_name/project_name-commit-id.tag.gz | ||
144 | + # | ||
145 | + def archive_repo(ref) | ||
146 | + ref = ref || self.root_ref | ||
147 | + commit = self.commit(ref) | ||
148 | + return nil unless commit | ||
149 | + | ||
150 | + # Build file path | ||
151 | + file_name = self.path_with_namespace.gsub("/","_") + "-" + commit.id.to_s + ".tar.gz" | ||
152 | + storage_path = Rails.root.join("tmp", "repositories") | ||
153 | + file_path = File.join(storage_path, self.path_with_namespace, file_name) | ||
154 | + | ||
155 | + # Put files into a directory before archiving | ||
156 | + prefix = File.basename(self.path_with_namespace) + "/" | ||
157 | + | ||
158 | + # Create file if not exists | ||
159 | + unless File.exists?(file_path) | ||
160 | + FileUtils.mkdir_p File.dirname(file_path) | ||
161 | + file = self.repo.archive_to_file(ref, prefix, file_path) | ||
162 | + end | ||
163 | + | ||
164 | + file_path | ||
165 | + end | ||
166 | + | ||
167 | + # Return repo size in megabytes | ||
168 | + # Cached in redis | ||
169 | + def size | ||
170 | + Rails.cache.fetch(cache_key(:size)) do | ||
171 | + size = popen('du -s', path_to_repo).first.strip.to_i | ||
172 | + (size.to_f / 1024).round(2) | ||
173 | + end | ||
174 | + end | ||
175 | + | ||
176 | + def expire_cache | ||
177 | + Rails.cache.delete(cache_key(:size)) | ||
178 | + end | ||
179 | + | ||
180 | + def cache_key(type) | ||
181 | + "#{type}:#{path_with_namespace}" | ||
182 | + end | ||
183 | + end | ||
184 | + end | ||
185 | +end |
lib/gitlab/markdown.rb
@@ -187,7 +187,7 @@ module Gitlab | @@ -187,7 +187,7 @@ module Gitlab | ||
187 | 187 | ||
188 | def reference_commit(identifier) | 188 | def reference_commit(identifier) |
189 | if @project.valid_repo? && commit = @project.repository.commit(identifier) | 189 | if @project.valid_repo? && commit = @project.repository.commit(identifier) |
190 | - link_to(identifier, project_commit_url(@project, commit), html_options.merge(title: CommitDecorator.new(commit).link_title, class: "gfm gfm-commit #{html_options[:class]}")) | 190 | + link_to(identifier, project_commit_url(@project, commit), html_options.merge(title: commit.link_title, class: "gfm gfm-commit #{html_options[:class]}")) |
191 | end | 191 | end |
192 | end | 192 | end |
193 | end | 193 | end |
spec/controllers/commit_controller_spec.rb
1 | require 'spec_helper' | 1 | require 'spec_helper' |
2 | 2 | ||
3 | describe CommitController do | 3 | describe CommitController do |
4 | - let(:project) { create(:project) } | 4 | + let(:project) { create(:project_with_code) } |
5 | let(:user) { create(:user) } | 5 | let(:user) { create(:user) } |
6 | let(:commit) { project.repository.last_commit_for("master") } | 6 | let(:commit) { project.repository.last_commit_for("master") } |
7 | 7 |
spec/controllers/commits_controller_spec.rb
spec/controllers/merge_requests_controller_spec.rb
1 | require 'spec_helper' | 1 | require 'spec_helper' |
2 | 2 | ||
3 | describe MergeRequestsController do | 3 | describe MergeRequestsController do |
4 | - let(:project) { create(:project) } | 4 | + let(:project) { create(:project_with_code) } |
5 | let(:user) { create(:user) } | 5 | let(:user) { create(:user) } |
6 | let(:merge_request) { create(:merge_request_with_diffs, project: project, target_branch: "bcf03b5d~3", source_branch: "bcf03b5d") } | 6 | let(:merge_request) { create(:merge_request_with_diffs, project: project, target_branch: "bcf03b5d~3", source_branch: "bcf03b5d") } |
7 | 7 |
spec/controllers/tree_controller_spec.rb
spec/factories.rb
@@ -34,6 +34,10 @@ FactoryGirl.define do | @@ -34,6 +34,10 @@ FactoryGirl.define do | ||
34 | issues_tracker_id { "project_name_in_redmine" } | 34 | issues_tracker_id { "project_name_in_redmine" } |
35 | end | 35 | end |
36 | 36 | ||
37 | + factory :project_with_code, parent: :project do | ||
38 | + path { 'gitlabhq' } | ||
39 | + end | ||
40 | + | ||
37 | factory :group do | 41 | factory :group do |
38 | sequence(:name) { |n| "group#{n}" } | 42 | sequence(:name) { |n| "group#{n}" } |
39 | path { name.downcase.gsub(/\s/, '_') } | 43 | path { name.downcase.gsub(/\s/, '_') } |
@@ -73,7 +77,7 @@ FactoryGirl.define do | @@ -73,7 +77,7 @@ FactoryGirl.define do | ||
73 | factory :merge_request do | 77 | factory :merge_request do |
74 | title | 78 | title |
75 | author | 79 | author |
76 | - project | 80 | + project factory: :project_with_code |
77 | source_branch "master" | 81 | source_branch "master" |
78 | target_branch "stable" | 82 | target_branch "stable" |
79 | 83 | ||
@@ -82,9 +86,9 @@ FactoryGirl.define do | @@ -82,9 +86,9 @@ FactoryGirl.define do | ||
82 | target_branch "master" # pretend bcf03b5d~3 | 86 | target_branch "master" # pretend bcf03b5d~3 |
83 | source_branch "stable" # pretend bcf03b5d | 87 | source_branch "stable" # pretend bcf03b5d |
84 | st_commits do | 88 | st_commits do |
85 | - [Commit.new(project.repo.commit('bcf03b5d')), | ||
86 | - Commit.new(project.repo.commit('bcf03b5d~1')), | ||
87 | - Commit.new(project.repo.commit('bcf03b5d~2'))] | 89 | + [Commit.new(project.repository.commit('bcf03b5d')), |
90 | + Commit.new(project.repository.commit('bcf03b5d~1')), | ||
91 | + Commit.new(project.repository.commit('bcf03b5d~2'))] | ||
88 | end | 92 | end |
89 | st_diffs do | 93 | st_diffs do |
90 | project.repo.diff("bcf03b5d~3", "bcf03b5d") | 94 | project.repo.diff("bcf03b5d~3", "bcf03b5d") |
@@ -116,6 +120,7 @@ FactoryGirl.define do | @@ -116,6 +120,7 @@ FactoryGirl.define do | ||
116 | factory :note_on_merge_request_diff, traits: [:on_merge_request, :on_diff] | 120 | factory :note_on_merge_request_diff, traits: [:on_merge_request, :on_diff] |
117 | 121 | ||
118 | trait :on_commit do | 122 | trait :on_commit do |
123 | + project factory: :project_with_code | ||
119 | commit_id "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" | 124 | commit_id "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" |
120 | noteable_type "Commit" | 125 | noteable_type "Commit" |
121 | end | 126 | end |
@@ -125,6 +130,7 @@ FactoryGirl.define do | @@ -125,6 +130,7 @@ FactoryGirl.define do | ||
125 | end | 130 | end |
126 | 131 | ||
127 | trait :on_merge_request do | 132 | trait :on_merge_request do |
133 | + project factory: :project_with_code | ||
128 | noteable_id 1 | 134 | noteable_id 1 |
129 | noteable_type "MergeRequest" | 135 | noteable_type "MergeRequest" |
130 | end | 136 | end |
spec/features/gitlab_flavored_markdown_spec.rb
1 | require 'spec_helper' | 1 | require 'spec_helper' |
2 | 2 | ||
3 | describe "Gitlab Flavored Markdown" do | 3 | describe "Gitlab Flavored Markdown" do |
4 | - let(:project) { create(:project) } | 4 | + let(:project) { create(:project_with_code) } |
5 | let(:issue) { create(:issue, project: project) } | 5 | let(:issue) { create(:issue, project: project) } |
6 | let(:merge_request) { create(:merge_request, project: project) } | 6 | let(:merge_request) { create(:merge_request, project: project) } |
7 | let(:fred) do | 7 | let(:fred) do |
spec/features/notes_on_merge_requests_spec.rb
1 | require 'spec_helper' | 1 | require 'spec_helper' |
2 | 2 | ||
3 | describe "On a merge request", js: true do | 3 | describe "On a merge request", js: true do |
4 | - let!(:project) { create(:project) } | 4 | + let!(:project) { create(:project_with_code) } |
5 | let!(:merge_request) { create(:merge_request, project: project) } | 5 | let!(:merge_request) { create(:merge_request, project: project) } |
6 | 6 | ||
7 | before do | 7 | before do |
@@ -83,7 +83,7 @@ end | @@ -83,7 +83,7 @@ end | ||
83 | 83 | ||
84 | 84 | ||
85 | describe "On a merge request diff", js: true, focus: true do | 85 | describe "On a merge request diff", js: true, focus: true do |
86 | - let!(:project) { create(:project) } | 86 | + let!(:project) { create(:project_with_code) } |
87 | let!(:merge_request) { create(:merge_request_with_diffs, project: project) } | 87 | let!(:merge_request) { create(:merge_request_with_diffs, project: project) } |
88 | 88 | ||
89 | before do | 89 | before do |
spec/features/profile_spec.rb
@@ -12,8 +12,9 @@ describe "Profile account page" do | @@ -12,8 +12,9 @@ describe "Profile account page" do | ||
12 | Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) | 12 | Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) |
13 | visit account_profile_path | 13 | visit account_profile_path |
14 | end | 14 | end |
15 | + | ||
15 | it { page.should have_content("Remove account") } | 16 | it { page.should have_content("Remove account") } |
16 | - | 17 | + |
17 | it "should delete the account", js: true do | 18 | it "should delete the account", js: true do |
18 | expect { click_link "Delete account" }.to change {User.count}.by(-1) | 19 | expect { click_link "Delete account" }.to change {User.count}.by(-1) |
19 | current_path.should == new_user_session_path | 20 | current_path.should == new_user_session_path |
@@ -45,4 +46,4 @@ describe "Profile account page" do | @@ -45,4 +46,4 @@ describe "Profile account page" do | ||
45 | current_path.should == account_profile_path | 46 | current_path.should == account_profile_path |
46 | end | 47 | end |
47 | end | 48 | end |
48 | -end | ||
49 | \ No newline at end of file | 49 | \ No newline at end of file |
50 | +end |
spec/features/security/project_access_spec.rb
@@ -14,7 +14,7 @@ describe "Application access" do | @@ -14,7 +14,7 @@ describe "Application access" do | ||
14 | end | 14 | end |
15 | 15 | ||
16 | describe "Project" do | 16 | describe "Project" do |
17 | - let(:project) { create(:project) } | 17 | + let(:project) { create(:project_with_code) } |
18 | 18 | ||
19 | let(:master) { create(:user) } | 19 | let(:master) { create(:user) } |
20 | let(:guest) { create(:user) } | 20 | let(:guest) { create(:user) } |
spec/helpers/gitlab_markdown_helper_spec.rb
@@ -4,10 +4,10 @@ describe GitlabMarkdownHelper do | @@ -4,10 +4,10 @@ describe GitlabMarkdownHelper do | ||
4 | include ApplicationHelper | 4 | include ApplicationHelper |
5 | include IssuesHelper | 5 | include IssuesHelper |
6 | 6 | ||
7 | - let!(:project) { create(:project) } | 7 | + let!(:project) { create(:project_with_code) } |
8 | 8 | ||
9 | let(:user) { create(:user, username: 'gfm') } | 9 | let(:user) { create(:user, username: 'gfm') } |
10 | - let(:commit) { CommitDecorator.decorate(project.repository.commit) } | 10 | + let(:commit) { project.repository.commit } |
11 | let(:issue) { create(:issue, project: project) } | 11 | let(:issue) { create(:issue, project: project) } |
12 | let(:merge_request) { create(:merge_request, project: project) } | 12 | let(:merge_request) { create(:merge_request, project: project) } |
13 | let(:snippet) { create(:snippet, project: project) } | 13 | let(:snippet) { create(:snippet, project: project) } |
@@ -0,0 +1,49 @@ | @@ -0,0 +1,49 @@ | ||
1 | +require "spec_helper" | ||
2 | + | ||
3 | +describe Gitlab::Git::Commit do | ||
4 | + let(:commit) { create(:project_with_code).repository.commit } | ||
5 | + | ||
6 | + describe "Commit info" do | ||
7 | + before do | ||
8 | + @committer = double( | ||
9 | + email: 'mike@smith.com', | ||
10 | + name: 'Mike Smith' | ||
11 | + ) | ||
12 | + | ||
13 | + @author = double( | ||
14 | + email: 'john@smith.com', | ||
15 | + name: 'John Smith' | ||
16 | + ) | ||
17 | + | ||
18 | + @raw_commit = double( | ||
19 | + id: "bcf03b5de6abcf03b5de6c", | ||
20 | + author: @author, | ||
21 | + committer: @committer, | ||
22 | + committed_date: Date.yesterday, | ||
23 | + message: 'Refactoring specs' | ||
24 | + ) | ||
25 | + | ||
26 | + @commit = Gitlab::Git::Commit.new(@raw_commit) | ||
27 | + end | ||
28 | + | ||
29 | + it { @commit.short_id.should == "bcf03b5de6a" } | ||
30 | + it { @commit.safe_message.should == @raw_commit.message } | ||
31 | + it { @commit.created_at.should == @raw_commit.committed_date } | ||
32 | + it { @commit.author_email.should == @author.email } | ||
33 | + it { @commit.author_name.should == @author.name } | ||
34 | + it { @commit.committer_name.should == @committer.name } | ||
35 | + it { @commit.committer_email.should == @committer.email } | ||
36 | + it { @commit.different_committer?.should be_true } | ||
37 | + end | ||
38 | + | ||
39 | + describe "Class methods" do | ||
40 | + subject { Gitlab::Git::Commit } | ||
41 | + | ||
42 | + it { should respond_to(:find_or_first) } | ||
43 | + it { should respond_to(:fresh_commits) } | ||
44 | + it { should respond_to(:commits_with_refs) } | ||
45 | + it { should respond_to(:commits_since) } | ||
46 | + it { should respond_to(:commits_between) } | ||
47 | + it { should respond_to(:commits) } | ||
48 | + end | ||
49 | +end |
@@ -0,0 +1,104 @@ | @@ -0,0 +1,104 @@ | ||
1 | +require "spec_helper" | ||
2 | + | ||
3 | +describe Gitlab::Git::Repository do | ||
4 | + let(:repository) { Gitlab::Git::Repository.new('gitlabhq', 'master') } | ||
5 | + | ||
6 | + describe "Respond to" do | ||
7 | + subject { repository } | ||
8 | + | ||
9 | + it { should respond_to(:repo) } | ||
10 | + it { should respond_to(:tree) } | ||
11 | + it { should respond_to(:root_ref) } | ||
12 | + it { should respond_to(:tags) } | ||
13 | + it { should respond_to(:commit) } | ||
14 | + it { should respond_to(:commits) } | ||
15 | + it { should respond_to(:commits_between) } | ||
16 | + it { should respond_to(:commits_with_refs) } | ||
17 | + it { should respond_to(:commits_since) } | ||
18 | + it { should respond_to(:commits_between) } | ||
19 | + end | ||
20 | + | ||
21 | + | ||
22 | + describe "#discover_default_branch" do | ||
23 | + let(:master) { 'master' } | ||
24 | + let(:stable) { 'stable' } | ||
25 | + | ||
26 | + it "returns 'master' when master exists" do | ||
27 | + repository.should_receive(:branch_names).at_least(:once).and_return([stable, master]) | ||
28 | + repository.discover_default_branch.should == 'master' | ||
29 | + end | ||
30 | + | ||
31 | + it "returns non-master when master exists but default branch is set to something else" do | ||
32 | + repository.root_ref = 'stable' | ||
33 | + repository.should_receive(:branch_names).at_least(:once).and_return([stable, master]) | ||
34 | + repository.discover_default_branch.should == 'stable' | ||
35 | + end | ||
36 | + | ||
37 | + it "returns a non-master branch when only one exists" do | ||
38 | + repository.should_receive(:branch_names).at_least(:once).and_return([stable]) | ||
39 | + repository.discover_default_branch.should == 'stable' | ||
40 | + end | ||
41 | + | ||
42 | + it "returns nil when no branch exists" do | ||
43 | + repository.should_receive(:branch_names).at_least(:once).and_return([]) | ||
44 | + repository.discover_default_branch.should be_nil | ||
45 | + end | ||
46 | + end | ||
47 | + | ||
48 | + describe :commit do | ||
49 | + it "should return first head commit if without params" do | ||
50 | + repository.commit.id.should == repository.repo.commits.first.id | ||
51 | + end | ||
52 | + | ||
53 | + it "should return valid commit" do | ||
54 | + repository.commit(ValidCommit::ID).should be_valid_commit | ||
55 | + end | ||
56 | + | ||
57 | + it "should return nil" do | ||
58 | + repository.commit("+123_4532530XYZ").should be_nil | ||
59 | + end | ||
60 | + end | ||
61 | + | ||
62 | + describe :tree do | ||
63 | + before do | ||
64 | + @commit = repository.commit(ValidCommit::ID) | ||
65 | + end | ||
66 | + | ||
67 | + it "should raise error w/o arguments" do | ||
68 | + lambda { repository.tree }.should raise_error | ||
69 | + end | ||
70 | + | ||
71 | + it "should return root tree for commit" do | ||
72 | + tree = repository.tree(@commit) | ||
73 | + tree.contents.size.should == ValidCommit::FILES_COUNT | ||
74 | + tree.contents.map(&:name).should == ValidCommit::FILES | ||
75 | + end | ||
76 | + | ||
77 | + it "should return root tree for commit with correct path" do | ||
78 | + tree = repository.tree(@commit, ValidCommit::C_FILE_PATH) | ||
79 | + tree.contents.map(&:name).should == ValidCommit::C_FILES | ||
80 | + end | ||
81 | + | ||
82 | + it "should return root tree for commit with incorrect path" do | ||
83 | + repository.tree(@commit, "invalid_path").should be_nil | ||
84 | + end | ||
85 | + end | ||
86 | + | ||
87 | + describe "fresh commits" do | ||
88 | + it { repository.fresh_commits(3).count.should == 3 } | ||
89 | + it { repository.fresh_commits.first.id.should == "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" } | ||
90 | + it { repository.fresh_commits.last.id.should == "f403da73f5e62794a0447aca879360494b08f678" } | ||
91 | + end | ||
92 | + | ||
93 | + describe "commits_between" do | ||
94 | + subject do | ||
95 | + commits = repository.commits_between("3a4b4fb4cde7809f033822a171b9feae19d41fff", | ||
96 | + "8470d70da67355c9c009e4401746b1d5410af2e3") | ||
97 | + commits.map { |c| c.id } | ||
98 | + end | ||
99 | + | ||
100 | + it { should have(3).elements } | ||
101 | + it { should include("f0f14c8eaba69ebddd766498a9d0b0e79becd633") } | ||
102 | + it { should_not include("bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a") } | ||
103 | + end | ||
104 | +end |
spec/mailers/notify_spec.rb
@@ -5,7 +5,7 @@ describe Notify do | @@ -5,7 +5,7 @@ describe Notify do | ||
5 | include EmailSpec::Matchers | 5 | include EmailSpec::Matchers |
6 | 6 | ||
7 | let(:recipient) { create(:user, email: 'recipient@example.com') } | 7 | let(:recipient) { create(:user, email: 'recipient@example.com') } |
8 | - let(:project) { create(:project) } | 8 | + let(:project) { create(:project_with_code) } |
9 | 9 | ||
10 | shared_examples 'a multiple recipients email' do | 10 | shared_examples 'a multiple recipients email' do |
11 | it 'is sent to the given recipient' do | 11 | it 'is sent to the given recipient' do |
@@ -277,14 +277,7 @@ describe Notify do | @@ -277,14 +277,7 @@ describe Notify do | ||
277 | end | 277 | end |
278 | 278 | ||
279 | describe 'on a commit' do | 279 | describe 'on a commit' do |
280 | - let(:commit) do | ||
281 | - mock(:commit).tap do |commit| | ||
282 | - commit.stub(:id).and_return('fauxsha1') | ||
283 | - commit.stub(:project).and_return(project) | ||
284 | - commit.stub(:short_id).and_return('fauxsha1') | ||
285 | - commit.stub(:safe_message).and_return('some message') | ||
286 | - end | ||
287 | - end | 280 | + let(:commit) { project.repository.commit } |
288 | 281 | ||
289 | before(:each) { note.stub(:noteable).and_return(commit) } | 282 | before(:each) { note.stub(:noteable).and_return(commit) } |
290 | 283 | ||
@@ -297,7 +290,7 @@ describe Notify do | @@ -297,7 +290,7 @@ describe Notify do | ||
297 | end | 290 | end |
298 | 291 | ||
299 | it 'contains a link to the commit' do | 292 | it 'contains a link to the commit' do |
300 | - should have_body_text /fauxsha1/ | 293 | + should have_body_text commit.short_id |
301 | end | 294 | end |
302 | end | 295 | end |
303 | 296 |
spec/models/commit_spec.rb
1 | require 'spec_helper' | 1 | require 'spec_helper' |
2 | 2 | ||
3 | describe Commit do | 3 | describe Commit do |
4 | - let(:commit) { create(:project).repository.commit } | 4 | + let(:commit) { create(:project_with_code).repository.commit } |
5 | 5 | ||
6 | - describe CommitDecorator do | ||
7 | - let(:decorator) { CommitDecorator.new(commit) } | ||
8 | 6 | ||
9 | - describe '#title' do | ||
10 | - it "returns no_commit_message when safe_message is blank" do | ||
11 | - decorator.stub(:safe_message).and_return('') | ||
12 | - decorator.title.should == "--no commit message" | ||
13 | - end | ||
14 | - | ||
15 | - it "truncates a message without a newline at 70 characters" do | ||
16 | - message = commit.safe_message * 10 | ||
17 | - | ||
18 | - decorator.stub(:safe_message).and_return(message) | ||
19 | - decorator.title.should == "#{message[0..69]}…" | ||
20 | - end | ||
21 | - | ||
22 | - it "truncates a message with a newline before 80 characters at the newline" do | ||
23 | - message = commit.safe_message.split(" ").first | ||
24 | - | ||
25 | - decorator.stub(:safe_message).and_return(message + "\n" + message) | ||
26 | - decorator.title.should == message | ||
27 | - end | ||
28 | - | ||
29 | - it "truncates a message with a newline after 80 characters at 70 characters" do | ||
30 | - message = (commit.safe_message * 10) + "\n" | ||
31 | - | ||
32 | - decorator.stub(:safe_message).and_return(message) | ||
33 | - decorator.title.should == "#{message[0..69]}…" | ||
34 | - end | 7 | + describe '#title' do |
8 | + it "returns no_commit_message when safe_message is blank" do | ||
9 | + commit.stub(:safe_message).and_return('') | ||
10 | + commit.title.should == "--no commit message" | ||
35 | end | 11 | end |
36 | - end | ||
37 | 12 | ||
38 | - describe "Commit info" do | ||
39 | - before do | ||
40 | - @committer = double( | ||
41 | - email: 'mike@smith.com', | ||
42 | - name: 'Mike Smith' | ||
43 | - ) | 13 | + it "truncates a message without a newline at 70 characters" do |
14 | + message = commit.safe_message * 10 | ||
44 | 15 | ||
45 | - @author = double( | ||
46 | - email: 'john@smith.com', | ||
47 | - name: 'John Smith' | ||
48 | - ) | 16 | + commit.stub(:safe_message).and_return(message) |
17 | + commit.title.should == "#{message[0..69]}…" | ||
18 | + end | ||
49 | 19 | ||
50 | - @raw_commit = double( | ||
51 | - id: "bcf03b5de6abcf03b5de6c", | ||
52 | - author: @author, | ||
53 | - committer: @committer, | ||
54 | - committed_date: Date.yesterday, | ||
55 | - message: 'Refactoring specs' | ||
56 | - ) | 20 | + it "truncates a message with a newline before 80 characters at the newline" do |
21 | + message = commit.safe_message.split(" ").first | ||
57 | 22 | ||
58 | - @commit = Commit.new(@raw_commit) | 23 | + commit.stub(:safe_message).and_return(message + "\n" + message) |
24 | + commit.title.should == message | ||
59 | end | 25 | end |
60 | 26 | ||
61 | - it { @commit.short_id.should == "bcf03b5de6a" } | ||
62 | - it { @commit.safe_message.should == @raw_commit.message } | ||
63 | - it { @commit.created_at.should == @raw_commit.committed_date } | ||
64 | - it { @commit.author_email.should == @author.email } | ||
65 | - it { @commit.author_name.should == @author.name } | ||
66 | - it { @commit.committer_name.should == @committer.name } | ||
67 | - it { @commit.committer_email.should == @committer.email } | ||
68 | - it { @commit.different_committer?.should be_true } | ||
69 | - end | 27 | + it "truncates a message with a newline after 80 characters at 70 characters" do |
28 | + message = (commit.safe_message * 10) + "\n" | ||
70 | 29 | ||
71 | - describe "Class methods" do | ||
72 | - subject { Commit } | ||
73 | - | ||
74 | - it { should respond_to(:find_or_first) } | ||
75 | - it { should respond_to(:fresh_commits) } | ||
76 | - it { should respond_to(:commits_with_refs) } | ||
77 | - it { should respond_to(:commits_since) } | ||
78 | - it { should respond_to(:commits_between) } | ||
79 | - it { should respond_to(:commits) } | ||
80 | - it { should respond_to(:compare) } | 30 | + commit.stub(:safe_message).and_return(message) |
31 | + commit.title.should == "#{message[0..69]}…" | ||
32 | + end | ||
81 | end | 33 | end |
82 | 34 | ||
83 | describe "delegation" do | 35 | describe "delegation" do |
spec/models/gollum_wiki_spec.rb
@@ -81,7 +81,7 @@ describe GollumWiki do | @@ -81,7 +81,7 @@ describe GollumWiki do | ||
81 | end | 81 | end |
82 | 82 | ||
83 | it "raises CouldNotCreateWikiError if it can't create the wiki repository" do | 83 | it "raises CouldNotCreateWikiError if it can't create the wiki repository" do |
84 | - Gitlab::Shell.any_instance.stub(:add_repository).and_return(false) | 84 | + GollumWiki.any_instance.stub(:init_repo).and_return(false) |
85 | expect { GollumWiki.new(project, user).wiki }.to raise_exception(GollumWiki::CouldNotCreateWikiError) | 85 | expect { GollumWiki.new(project, user).wiki }.to raise_exception(GollumWiki::CouldNotCreateWikiError) |
86 | end | 86 | end |
87 | end | 87 | end |
spec/models/project_spec.rb
@@ -119,7 +119,7 @@ describe Project do | @@ -119,7 +119,7 @@ describe Project do | ||
119 | end | 119 | end |
120 | 120 | ||
121 | describe :update_merge_requests do | 121 | describe :update_merge_requests do |
122 | - let(:project) { create(:project) } | 122 | + let(:project) { create(:project_with_code) } |
123 | 123 | ||
124 | before do | 124 | before do |
125 | @merge_request = create(:merge_request, project: project) | 125 | @merge_request = create(:merge_request, project: project) |
@@ -189,10 +189,6 @@ describe Project do | @@ -189,10 +189,6 @@ describe Project do | ||
189 | it "should return valid repo" do | 189 | it "should return valid repo" do |
190 | project.repository.should be_kind_of(Repository) | 190 | project.repository.should be_kind_of(Repository) |
191 | end | 191 | end |
192 | - | ||
193 | - it "should return nil" do | ||
194 | - Project.new(path: "empty").repository.should be_nil | ||
195 | - end | ||
196 | end | 192 | end |
197 | 193 | ||
198 | describe :issue_exists? do | 194 | describe :issue_exists? do |
@@ -249,7 +245,7 @@ describe Project do | @@ -249,7 +245,7 @@ describe Project do | ||
249 | end | 245 | end |
250 | 246 | ||
251 | describe :open_branches do | 247 | describe :open_branches do |
252 | - let(:project) { create(:project) } | 248 | + let(:project) { create(:project_with_code) } |
253 | 249 | ||
254 | before do | 250 | before do |
255 | project.protected_branches.create(name: 'master') | 251 | project.protected_branches.create(name: 'master') |
spec/models/repository_spec.rb
@@ -1,105 +0,0 @@ | @@ -1,105 +0,0 @@ | ||
1 | -require "spec_helper" | ||
2 | - | ||
3 | -describe Repository do | ||
4 | - let(:project) { create(:project) } | ||
5 | - let(:repository) { project.repository } | ||
6 | - | ||
7 | - describe "Respond to" do | ||
8 | - subject { repository } | ||
9 | - | ||
10 | - it { should respond_to(:repo) } | ||
11 | - it { should respond_to(:tree) } | ||
12 | - it { should respond_to(:root_ref) } | ||
13 | - it { should respond_to(:tags) } | ||
14 | - it { should respond_to(:commit) } | ||
15 | - it { should respond_to(:commits) } | ||
16 | - it { should respond_to(:commits_between) } | ||
17 | - it { should respond_to(:commits_with_refs) } | ||
18 | - it { should respond_to(:commits_since) } | ||
19 | - it { should respond_to(:commits_between) } | ||
20 | - end | ||
21 | - | ||
22 | - | ||
23 | - describe "#discover_default_branch" do | ||
24 | - let(:master) { 'master' } | ||
25 | - let(:stable) { 'stable' } | ||
26 | - | ||
27 | - it "returns 'master' when master exists" do | ||
28 | - repository.should_receive(:branch_names).at_least(:once).and_return([stable, master]) | ||
29 | - repository.discover_default_branch.should == 'master' | ||
30 | - end | ||
31 | - | ||
32 | - it "returns non-master when master exists but default branch is set to something else" do | ||
33 | - repository.root_ref = 'stable' | ||
34 | - repository.should_receive(:branch_names).at_least(:once).and_return([stable, master]) | ||
35 | - repository.discover_default_branch.should == 'stable' | ||
36 | - end | ||
37 | - | ||
38 | - it "returns a non-master branch when only one exists" do | ||
39 | - repository.should_receive(:branch_names).at_least(:once).and_return([stable]) | ||
40 | - repository.discover_default_branch.should == 'stable' | ||
41 | - end | ||
42 | - | ||
43 | - it "returns nil when no branch exists" do | ||
44 | - repository.should_receive(:branch_names).at_least(:once).and_return([]) | ||
45 | - repository.discover_default_branch.should be_nil | ||
46 | - end | ||
47 | - end | ||
48 | - | ||
49 | - describe :commit do | ||
50 | - it "should return first head commit if without params" do | ||
51 | - repository.commit.id.should == repository.repo.commits.first.id | ||
52 | - end | ||
53 | - | ||
54 | - it "should return valid commit" do | ||
55 | - repository.commit(ValidCommit::ID).should be_valid_commit | ||
56 | - end | ||
57 | - | ||
58 | - it "should return nil" do | ||
59 | - repository.commit("+123_4532530XYZ").should be_nil | ||
60 | - end | ||
61 | - end | ||
62 | - | ||
63 | - describe :tree do | ||
64 | - before do | ||
65 | - @commit = repository.commit(ValidCommit::ID) | ||
66 | - end | ||
67 | - | ||
68 | - it "should raise error w/o arguments" do | ||
69 | - lambda { repository.tree }.should raise_error | ||
70 | - end | ||
71 | - | ||
72 | - it "should return root tree for commit" do | ||
73 | - tree = repository.tree(@commit) | ||
74 | - tree.contents.size.should == ValidCommit::FILES_COUNT | ||
75 | - tree.contents.map(&:name).should == ValidCommit::FILES | ||
76 | - end | ||
77 | - | ||
78 | - it "should return root tree for commit with correct path" do | ||
79 | - tree = repository.tree(@commit, ValidCommit::C_FILE_PATH) | ||
80 | - tree.contents.map(&:name).should == ValidCommit::C_FILES | ||
81 | - end | ||
82 | - | ||
83 | - it "should return root tree for commit with incorrect path" do | ||
84 | - repository.tree(@commit, "invalid_path").should be_nil | ||
85 | - end | ||
86 | - end | ||
87 | - | ||
88 | - describe "fresh commits" do | ||
89 | - it { repository.fresh_commits(3).count.should == 3 } | ||
90 | - it { repository.fresh_commits.first.id.should == "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" } | ||
91 | - it { repository.fresh_commits.last.id.should == "f403da73f5e62794a0447aca879360494b08f678" } | ||
92 | - end | ||
93 | - | ||
94 | - describe "commits_between" do | ||
95 | - subject do | ||
96 | - commits = repository.commits_between("3a4b4fb4cde7809f033822a171b9feae19d41fff", | ||
97 | - "8470d70da67355c9c009e4401746b1d5410af2e3") | ||
98 | - commits.map { |c| c.id } | ||
99 | - end | ||
100 | - | ||
101 | - it { should have(3).elements } | ||
102 | - it { should include("f0f14c8eaba69ebddd766498a9d0b0e79becd633") } | ||
103 | - it { should_not include("bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a") } | ||
104 | - end | ||
105 | -end |
spec/requests/api/merge_requests_spec.rb
@@ -4,7 +4,7 @@ describe Gitlab::API do | @@ -4,7 +4,7 @@ describe Gitlab::API do | ||
4 | include ApiHelpers | 4 | include ApiHelpers |
5 | 5 | ||
6 | let(:user) { create(:user ) } | 6 | let(:user) { create(:user ) } |
7 | - let!(:project) { create(:project, namespace: user.namespace ) } | 7 | + let!(:project) { create(:project_with_code, creator_id: user.id) } |
8 | let!(:merge_request) { create(:merge_request, author: user, assignee: user, project: project, title: "Test") } | 8 | let!(:merge_request) { create(:merge_request, author: user, assignee: user, project: project, title: "Test") } |
9 | before { project.team << [user, :reporters] } | 9 | before { project.team << [user, :reporters] } |
10 | 10 |
spec/requests/api/projects_spec.rb
@@ -7,7 +7,7 @@ describe Gitlab::API do | @@ -7,7 +7,7 @@ describe Gitlab::API do | ||
7 | let(:user2) { create(:user) } | 7 | let(:user2) { create(:user) } |
8 | let(:user3) { create(:user) } | 8 | let(:user3) { create(:user) } |
9 | let(:admin) { create(:admin) } | 9 | let(:admin) { create(:admin) } |
10 | - let!(:project) { create(:project, namespace: user.namespace ) } | 10 | + let!(:project) { create(:project_with_code, creator_id: user.id) } |
11 | let!(:hook) { create(:project_hook, project: project, url: "http://example.com") } | 11 | let!(:hook) { create(:project_hook, project: project, url: "http://example.com") } |
12 | let!(:snippet) { create(:snippet, author: user, project: project, title: 'example') } | 12 | let!(:snippet) { create(:snippet, author: user, project: project, title: 'example') } |
13 | let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } | 13 | let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } |
spec/services/git_push_service_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper' | @@ -2,7 +2,7 @@ require 'spec_helper' | ||
2 | 2 | ||
3 | describe GitPushService do | 3 | describe GitPushService do |
4 | let (:user) { create :user } | 4 | let (:user) { create :user } |
5 | - let (:project) { create :project } | 5 | + let (:project) { create :project_with_code } |
6 | let (:service) { GitPushService.new } | 6 | let (:service) { GitPushService.new } |
7 | 7 | ||
8 | before do | 8 | before do |
spec/spec_helper.rb
@@ -47,11 +47,7 @@ Spork.prefork do | @@ -47,11 +47,7 @@ Spork.prefork do | ||
47 | config.use_transactional_fixtures = false | 47 | config.use_transactional_fixtures = false |
48 | 48 | ||
49 | config.before do | 49 | config.before do |
50 | - # Use tmp dir for FS manipulations | ||
51 | - temp_repos_path = Rails.root.join('tmp', 'test-git-base-path') | ||
52 | - Gitlab.config.gitlab_shell.stub(repos_path: temp_repos_path) | ||
53 | - FileUtils.rm_rf temp_repos_path | ||
54 | - FileUtils.mkdir_p temp_repos_path | 50 | + TestEnv.init |
55 | end | 51 | end |
56 | end | 52 | end |
57 | end | 53 | end |
spec/support/stubbed_repository.rb
@@ -1,75 +0,0 @@ | @@ -1,75 +0,0 @@ | ||
1 | -require "repository" | ||
2 | -require "project" | ||
3 | -require "merge_request" | ||
4 | -require "shell" | ||
5 | - | ||
6 | -# Stubs out all Git repository access done by models so that specs can run | ||
7 | -# against fake repositories without Grit complaining that they don't exist. | ||
8 | -class Project | ||
9 | - def repository | ||
10 | - if path == "empty" || !path | ||
11 | - nil | ||
12 | - else | ||
13 | - GitLabTestRepo.new(path_with_namespace) | ||
14 | - end | ||
15 | - end | ||
16 | - | ||
17 | - def satellite | ||
18 | - FakeSatellite.new | ||
19 | - end | ||
20 | - | ||
21 | - class FakeSatellite | ||
22 | - def exists? | ||
23 | - true | ||
24 | - end | ||
25 | - | ||
26 | - def destroy | ||
27 | - true | ||
28 | - end | ||
29 | - | ||
30 | - def create | ||
31 | - true | ||
32 | - end | ||
33 | - end | ||
34 | -end | ||
35 | - | ||
36 | -class MergeRequest | ||
37 | - def check_if_can_be_merged | ||
38 | - true | ||
39 | - end | ||
40 | -end | ||
41 | - | ||
42 | -class GitLabTestRepo < Repository | ||
43 | - def repo | ||
44 | - @repo ||= Grit::Repo.new(Rails.root.join('tmp', 'repositories', 'gitlabhq')) | ||
45 | - end | ||
46 | - | ||
47 | - # patch repo size (in mb) | ||
48 | - def size | ||
49 | - 12.45 | ||
50 | - end | ||
51 | -end | ||
52 | - | ||
53 | -module Gitlab | ||
54 | - class Shell | ||
55 | - def add_repository name | ||
56 | - true | ||
57 | - end | ||
58 | - | ||
59 | - def mv_repository name, new_name | ||
60 | - true | ||
61 | - end | ||
62 | - | ||
63 | - def remove_repository name | ||
64 | - true | ||
65 | - end | ||
66 | - | ||
67 | - def add_key id, key | ||
68 | - true | ||
69 | - end | ||
70 | - | ||
71 | - def remove_key id, key | ||
72 | - true | ||
73 | - end | ||
74 | - end | ||
75 | -end |
@@ -0,0 +1,63 @@ | @@ -0,0 +1,63 @@ | ||
1 | +module TestEnv | ||
2 | + extend self | ||
3 | + | ||
4 | + # Test environment | ||
5 | + # | ||
6 | + # all repositories and namespaces stored at | ||
7 | + # RAILS_APP/tmp/test-git-base-path | ||
8 | + # | ||
9 | + # Next shell methods are stubbed and return true | ||
10 | + # - mv_repository | ||
11 | + # - remove_repository | ||
12 | + # - add_key | ||
13 | + # - remove_key | ||
14 | + # | ||
15 | + def init | ||
16 | + # Use tmp dir for FS manipulations | ||
17 | + repos_path = Rails.root.join('tmp', 'test-git-base-path') | ||
18 | + Gitlab.config.gitlab_shell.stub(repos_path: repos_path) | ||
19 | + | ||
20 | + GollumWiki.any_instance.stub(:init_repo) do |path| | ||
21 | + create_temp_repo(File.join(repos_path, "#{path}.git")) | ||
22 | + end | ||
23 | + | ||
24 | + Gitlab::Shell.any_instance.stub( | ||
25 | + add_repository: true, | ||
26 | + mv_repository: true, | ||
27 | + remove_repository: true, | ||
28 | + add_key: true, | ||
29 | + remove_key: true | ||
30 | + ) | ||
31 | + | ||
32 | + Gitlab::Satellite::Satellite.any_instance.stub( | ||
33 | + exists?: true, | ||
34 | + destroy: true, | ||
35 | + create: true | ||
36 | + ) | ||
37 | + | ||
38 | + MergeRequest.any_instance.stub( | ||
39 | + check_if_can_be_merged: true | ||
40 | + ) | ||
41 | + | ||
42 | + Repository.any_instance.stub( | ||
43 | + size: 12.45 | ||
44 | + ) | ||
45 | + | ||
46 | + # Remove tmp/test-git-base-path | ||
47 | + FileUtils.rm_rf Gitlab.config.gitlab_shell.repos_path | ||
48 | + | ||
49 | + # Recreate tmp/test-git-base-path | ||
50 | + FileUtils.mkdir_p Gitlab.config.gitlab_shell.repos_path | ||
51 | + | ||
52 | + # Symlink tmp/repositories/gitlabhq to tmp/test-git-base-path/gitlabhq | ||
53 | + seed_repo = Rails.root.join('tmp', 'repositories', 'gitlabhq') | ||
54 | + target_repo = File.join(repos_path, 'gitlabhq.git') | ||
55 | + system("ln -s #{seed_repo} #{target_repo}") | ||
56 | + end | ||
57 | + | ||
58 | + def create_temp_repo(path) | ||
59 | + FileUtils.mkdir_p path | ||
60 | + command = "git init --quiet --bare #{path};" | ||
61 | + system(command) | ||
62 | + end | ||
63 | +end |
spec/workers/post_receive_spec.rb
@@ -9,7 +9,7 @@ describe PostReceive do | @@ -9,7 +9,7 @@ describe PostReceive do | ||
9 | end | 9 | end |
10 | 10 | ||
11 | context "web hook" do | 11 | context "web hook" do |
12 | - let(:project) { create(:project) } | 12 | + let(:project) { create(:project_with_code) } |
13 | let(:key) { create(:key, user: project.owner) } | 13 | let(:key) { create(:key, user: project.owner) } |
14 | let(:key_id) { key.shell_id } | 14 | let(:key_id) { key.shell_id } |
15 | 15 |