##// END OF EJS Templates
Merged r4710 and r4714 from trunk....
Toshi MARUYAMA -
r4596:6188b9eddba7
parent child
Show More
@@ -1,335 +1,335
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2009 Jean-Philippe Lang
2 # Copyright (C) 2006-2009 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require 'SVG/Graph/Bar'
18 require 'SVG/Graph/Bar'
19 require 'SVG/Graph/BarHorizontal'
19 require 'SVG/Graph/BarHorizontal'
20 require 'digest/sha1'
20 require 'digest/sha1'
21
21
22 class ChangesetNotFound < Exception; end
22 class ChangesetNotFound < Exception; end
23 class InvalidRevisionParam < Exception; end
23 class InvalidRevisionParam < Exception; end
24
24
25 class RepositoriesController < ApplicationController
25 class RepositoriesController < ApplicationController
26 menu_item :repository
26 menu_item :repository
27 menu_item :settings, :only => :edit
27 menu_item :settings, :only => :edit
28 default_search_scope :changesets
28 default_search_scope :changesets
29
29
30 before_filter :find_repository, :except => :edit
30 before_filter :find_repository, :except => :edit
31 before_filter :find_project, :only => :edit
31 before_filter :find_project, :only => :edit
32 before_filter :authorize
32 before_filter :authorize
33 accept_key_auth :revisions
33 accept_key_auth :revisions
34
34
35 rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed
35 rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed
36
36
37 def edit
37 def edit
38 @repository = @project.repository
38 @repository = @project.repository
39 if !@repository
39 if !@repository
40 @repository = Repository.factory(params[:repository_scm])
40 @repository = Repository.factory(params[:repository_scm])
41 @repository.project = @project if @repository
41 @repository.project = @project if @repository
42 end
42 end
43 if request.post? && @repository
43 if request.post? && @repository
44 @repository.attributes = params[:repository]
44 @repository.attributes = params[:repository]
45 @repository.save
45 @repository.save
46 end
46 end
47 render(:update) do |page|
47 render(:update) do |page|
48 page.replace_html "tab-content-repository", :partial => 'projects/settings/repository'
48 page.replace_html "tab-content-repository", :partial => 'projects/settings/repository'
49 if @repository && !@project.repository
49 if @repository && !@project.repository
50 @project.reload #needed to reload association
50 @project.reload #needed to reload association
51 page.replace_html "main-menu", render_main_menu(@project)
51 page.replace_html "main-menu", render_main_menu(@project)
52 end
52 end
53 end
53 end
54 end
54 end
55
55
56 def committers
56 def committers
57 @committers = @repository.committers
57 @committers = @repository.committers
58 @users = @project.users
58 @users = @project.users
59 additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id)
59 additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id)
60 @users += User.find_all_by_id(additional_user_ids) unless additional_user_ids.empty?
60 @users += User.find_all_by_id(additional_user_ids) unless additional_user_ids.empty?
61 @users.compact!
61 @users.compact!
62 @users.sort!
62 @users.sort!
63 if request.post? && params[:committers].is_a?(Hash)
63 if request.post? && params[:committers].is_a?(Hash)
64 # Build a hash with repository usernames as keys and corresponding user ids as values
64 # Build a hash with repository usernames as keys and corresponding user ids as values
65 @repository.committer_ids = params[:committers].values.inject({}) {|h, c| h[c.first] = c.last; h}
65 @repository.committer_ids = params[:committers].values.inject({}) {|h, c| h[c.first] = c.last; h}
66 flash[:notice] = l(:notice_successful_update)
66 flash[:notice] = l(:notice_successful_update)
67 redirect_to :action => 'committers', :id => @project
67 redirect_to :action => 'committers', :id => @project
68 end
68 end
69 end
69 end
70
70
71 def destroy
71 def destroy
72 @repository.destroy
72 @repository.destroy
73 redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'repository'
73 redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'repository'
74 end
74 end
75
75
76 def show
76 def show
77 @repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty?
77 @repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty?
78
78
79 @entries = @repository.entries(@path, @rev)
79 @entries = @repository.entries(@path, @rev)
80 if request.xhr?
80 if request.xhr?
81 @entries ? render(:partial => 'dir_list_content') : render(:nothing => true)
81 @entries ? render(:partial => 'dir_list_content') : render(:nothing => true)
82 else
82 else
83 (show_error_not_found; return) unless @entries
83 (show_error_not_found; return) unless @entries
84 @changesets = @repository.latest_changesets(@path, @rev)
84 @changesets = @repository.latest_changesets(@path, @rev)
85 @properties = @repository.properties(@path, @rev)
85 @properties = @repository.properties(@path, @rev)
86 render :action => 'show'
86 render :action => 'show'
87 end
87 end
88 end
88 end
89
89
90 alias_method :browse, :show
90 alias_method :browse, :show
91
91
92 def changes
92 def changes
93 @entry = @repository.entry(@path, @rev)
93 @entry = @repository.entry(@path, @rev)
94 (show_error_not_found; return) unless @entry
94 (show_error_not_found; return) unless @entry
95 @changesets = @repository.latest_changesets(@path, @rev, Setting.repository_log_display_limit.to_i)
95 @changesets = @repository.latest_changesets(@path, @rev, Setting.repository_log_display_limit.to_i)
96 @properties = @repository.properties(@path, @rev)
96 @properties = @repository.properties(@path, @rev)
97 end
97 end
98
98
99 def revisions
99 def revisions
100 @changeset_count = @repository.changesets.count
100 @changeset_count = @repository.changesets.count
101 @changeset_pages = Paginator.new self, @changeset_count,
101 @changeset_pages = Paginator.new self, @changeset_count,
102 per_page_option,
102 per_page_option,
103 params['page']
103 params['page']
104 @changesets = @repository.changesets.find(:all,
104 @changesets = @repository.changesets.find(:all,
105 :limit => @changeset_pages.items_per_page,
105 :limit => @changeset_pages.items_per_page,
106 :offset => @changeset_pages.current.offset,
106 :offset => @changeset_pages.current.offset,
107 :include => [:user, :repository])
107 :include => [:user, :repository])
108
108
109 respond_to do |format|
109 respond_to do |format|
110 format.html { render :layout => false if request.xhr? }
110 format.html { render :layout => false if request.xhr? }
111 format.atom { render_feed(@changesets, :title => "#{@project.name}: #{l(:label_revision_plural)}") }
111 format.atom { render_feed(@changesets, :title => "#{@project.name}: #{l(:label_revision_plural)}") }
112 end
112 end
113 end
113 end
114
114
115 def entry
115 def entry
116 @entry = @repository.entry(@path, @rev)
116 @entry = @repository.entry(@path, @rev)
117 (show_error_not_found; return) unless @entry
117 (show_error_not_found; return) unless @entry
118
118
119 # If the entry is a dir, show the browser
119 # If the entry is a dir, show the browser
120 (show; return) if @entry.is_dir?
120 (show; return) if @entry.is_dir?
121
121
122 @content = @repository.cat(@path, @rev)
122 @content = @repository.cat(@path, @rev)
123 (show_error_not_found; return) unless @content
123 (show_error_not_found; return) unless @content
124 if 'raw' == params[:format] || @content.is_binary_data? || (@entry.size && @entry.size > Setting.file_max_size_displayed.to_i.kilobyte)
124 if 'raw' == params[:format] || @content.is_binary_data? || (@entry.size && @entry.size > Setting.file_max_size_displayed.to_i.kilobyte)
125 # Force the download
125 # Force the download
126 send_data @content, :filename => @path.split('/').last
126 send_data @content, :filename => @path.split('/').last
127 else
127 else
128 # Prevent empty lines when displaying a file with Windows style eol
128 # Prevent empty lines when displaying a file with Windows style eol
129 @content.gsub!("\r\n", "\n")
129 @content.gsub!("\r\n", "\n")
130 end
130 end
131 end
131 end
132
132
133 def annotate
133 def annotate
134 @entry = @repository.entry(@path, @rev)
134 @entry = @repository.entry(@path, @rev)
135 (show_error_not_found; return) unless @entry
135 (show_error_not_found; return) unless @entry
136
136
137 @annotate = @repository.scm.annotate(@path, @rev)
137 @annotate = @repository.scm.annotate(@path, @rev)
138 (render_error l(:error_scm_annotate); return) if @annotate.nil? || @annotate.empty?
138 (render_error l(:error_scm_annotate); return) if @annotate.nil? || @annotate.empty?
139 end
139 end
140
140
141 def revision
141 def revision
142 raise ChangesetNotFound if @rev.nil? || @rev.empty?
142 raise ChangesetNotFound if @rev.nil? || @rev.empty?
143 @changeset = @repository.find_changeset_by_name(@rev)
143 @changeset = @repository.find_changeset_by_name(@rev)
144 raise ChangesetNotFound unless @changeset
144 raise ChangesetNotFound unless @changeset
145
145
146 respond_to do |format|
146 respond_to do |format|
147 format.html
147 format.html
148 format.js {render :layout => false}
148 format.js {render :layout => false}
149 end
149 end
150 rescue ChangesetNotFound
150 rescue ChangesetNotFound
151 show_error_not_found
151 show_error_not_found
152 end
152 end
153
153
154 def diff
154 def diff
155 if params[:format] == 'diff'
155 if params[:format] == 'diff'
156 @diff = @repository.diff(@path, @rev, @rev_to)
156 @diff = @repository.diff(@path, @rev, @rev_to)
157 (show_error_not_found; return) unless @diff
157 (show_error_not_found; return) unless @diff
158 filename = "changeset_r#{@rev}"
158 filename = "changeset_r#{@rev}"
159 filename << "_r#{@rev_to}" if @rev_to
159 filename << "_r#{@rev_to}" if @rev_to
160 send_data @diff.join, :filename => "#{filename}.diff",
160 send_data @diff.join, :filename => "#{filename}.diff",
161 :type => 'text/x-patch',
161 :type => 'text/x-patch',
162 :disposition => 'attachment'
162 :disposition => 'attachment'
163 else
163 else
164 @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline'
164 @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline'
165 @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type)
165 @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type)
166
166
167 # Save diff type as user preference
167 # Save diff type as user preference
168 if User.current.logged? && @diff_type != User.current.pref[:diff_type]
168 if User.current.logged? && @diff_type != User.current.pref[:diff_type]
169 User.current.pref[:diff_type] = @diff_type
169 User.current.pref[:diff_type] = @diff_type
170 User.current.preference.save
170 User.current.preference.save
171 end
171 end
172
172
173 @cache_key = "repositories/diff/#{@repository.id}/" + Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}")
173 @cache_key = "repositories/diff/#{@repository.id}/" + Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}")
174 unless read_fragment(@cache_key)
174 unless read_fragment(@cache_key)
175 @diff = @repository.diff(@path, @rev, @rev_to)
175 @diff = @repository.diff(@path, @rev, @rev_to)
176 show_error_not_found unless @diff
176 show_error_not_found unless @diff
177 end
177 end
178
178
179 @changeset = @repository.find_changeset_by_name(@rev)
179 @changeset = @repository.find_changeset_by_name(@rev)
180 @changeset_to = @rev_to ? @repository.find_changeset_by_name(@rev_to) : nil
180 @changeset_to = @rev_to ? @repository.find_changeset_by_name(@rev_to) : nil
181 end
181 end
182 end
182 end
183
183
184 def stats
184 def stats
185 end
185 end
186
186
187 def graph
187 def graph
188 data = nil
188 data = nil
189 case params[:graph]
189 case params[:graph]
190 when "commits_per_month"
190 when "commits_per_month"
191 data = graph_commits_per_month(@repository)
191 data = graph_commits_per_month(@repository)
192 when "commits_per_author"
192 when "commits_per_author"
193 data = graph_commits_per_author(@repository)
193 data = graph_commits_per_author(@repository)
194 end
194 end
195 if data
195 if data
196 headers["Content-Type"] = "image/svg+xml"
196 headers["Content-Type"] = "image/svg+xml"
197 send_data(data, :type => "image/svg+xml", :disposition => "inline")
197 send_data(data, :type => "image/svg+xml", :disposition => "inline")
198 else
198 else
199 render_404
199 render_404
200 end
200 end
201 end
201 end
202
202
203 private
203 private
204
204
205 REV_PARAM_RE = %r{\A[a-f0-9]*\Z}i
205 REV_PARAM_RE = %r{\A[a-f0-9]*\Z}i
206
206
207 def find_repository
207 def find_repository
208 @project = Project.find(params[:id])
208 @project = Project.find(params[:id])
209 @repository = @project.repository
209 @repository = @project.repository
210 (render_404; return false) unless @repository
210 (render_404; return false) unless @repository
211 @path = params[:path].join('/') unless params[:path].nil?
211 @path = params[:path].join('/') unless params[:path].nil?
212 @path ||= ''
212 @path ||= ''
213 @rev = params[:rev].blank? ? @repository.default_branch : params[:rev].strip
213 @rev = params[:rev].blank? ? @repository.default_branch : params[:rev].strip
214 @rev_to = params[:rev_to]
214 @rev_to = params[:rev_to]
215
215
216 unless @rev.to_s.match(REV_PARAM_RE) && @rev.to_s.match(REV_PARAM_RE)
216 unless @rev.to_s.match(REV_PARAM_RE) && @rev.to_s.match(REV_PARAM_RE)
217 if @repository.branches.blank?
217 if @repository.branches.blank?
218 raise InvalidRevisionParam
218 raise InvalidRevisionParam
219 end
219 end
220 end
220 end
221 rescue ActiveRecord::RecordNotFound
221 rescue ActiveRecord::RecordNotFound
222 render_404
222 render_404
223 rescue InvalidRevisionParam
223 rescue InvalidRevisionParam
224 show_error_not_found
224 show_error_not_found
225 end
225 end
226
226
227 def show_error_not_found
227 def show_error_not_found
228 render_error l(:error_scm_not_found)
228 render_error :message => l(:error_scm_not_found), :status => 404
229 end
229 end
230
230
231 # Handler for Redmine::Scm::Adapters::CommandFailed exception
231 # Handler for Redmine::Scm::Adapters::CommandFailed exception
232 def show_error_command_failed(exception)
232 def show_error_command_failed(exception)
233 render_error l(:error_scm_command_failed, exception.message)
233 render_error l(:error_scm_command_failed, exception.message)
234 end
234 end
235
235
236 def graph_commits_per_month(repository)
236 def graph_commits_per_month(repository)
237 @date_to = Date.today
237 @date_to = Date.today
238 @date_from = @date_to << 11
238 @date_from = @date_to << 11
239 @date_from = Date.civil(@date_from.year, @date_from.month, 1)
239 @date_from = Date.civil(@date_from.year, @date_from.month, 1)
240 commits_by_day = repository.changesets.count(:all, :group => :commit_date, :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
240 commits_by_day = repository.changesets.count(:all, :group => :commit_date, :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
241 commits_by_month = [0] * 12
241 commits_by_month = [0] * 12
242 commits_by_day.each {|c| commits_by_month[c.first.to_date.months_ago] += c.last }
242 commits_by_day.each {|c| commits_by_month[c.first.to_date.months_ago] += c.last }
243
243
244 changes_by_day = repository.changes.count(:all, :group => :commit_date, :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
244 changes_by_day = repository.changes.count(:all, :group => :commit_date, :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
245 changes_by_month = [0] * 12
245 changes_by_month = [0] * 12
246 changes_by_day.each {|c| changes_by_month[c.first.to_date.months_ago] += c.last }
246 changes_by_day.each {|c| changes_by_month[c.first.to_date.months_ago] += c.last }
247
247
248 fields = []
248 fields = []
249 12.times {|m| fields << month_name(((Date.today.month - 1 - m) % 12) + 1)}
249 12.times {|m| fields << month_name(((Date.today.month - 1 - m) % 12) + 1)}
250
250
251 graph = SVG::Graph::Bar.new(
251 graph = SVG::Graph::Bar.new(
252 :height => 300,
252 :height => 300,
253 :width => 800,
253 :width => 800,
254 :fields => fields.reverse,
254 :fields => fields.reverse,
255 :stack => :side,
255 :stack => :side,
256 :scale_integers => true,
256 :scale_integers => true,
257 :step_x_labels => 2,
257 :step_x_labels => 2,
258 :show_data_values => false,
258 :show_data_values => false,
259 :graph_title => l(:label_commits_per_month),
259 :graph_title => l(:label_commits_per_month),
260 :show_graph_title => true
260 :show_graph_title => true
261 )
261 )
262
262
263 graph.add_data(
263 graph.add_data(
264 :data => commits_by_month[0..11].reverse,
264 :data => commits_by_month[0..11].reverse,
265 :title => l(:label_revision_plural)
265 :title => l(:label_revision_plural)
266 )
266 )
267
267
268 graph.add_data(
268 graph.add_data(
269 :data => changes_by_month[0..11].reverse,
269 :data => changes_by_month[0..11].reverse,
270 :title => l(:label_change_plural)
270 :title => l(:label_change_plural)
271 )
271 )
272
272
273 graph.burn
273 graph.burn
274 end
274 end
275
275
276 def graph_commits_per_author(repository)
276 def graph_commits_per_author(repository)
277 commits_by_author = repository.changesets.count(:all, :group => :committer)
277 commits_by_author = repository.changesets.count(:all, :group => :committer)
278 commits_by_author.to_a.sort! {|x, y| x.last <=> y.last}
278 commits_by_author.to_a.sort! {|x, y| x.last <=> y.last}
279
279
280 changes_by_author = repository.changes.count(:all, :group => :committer)
280 changes_by_author = repository.changes.count(:all, :group => :committer)
281 h = changes_by_author.inject({}) {|o, i| o[i.first] = i.last; o}
281 h = changes_by_author.inject({}) {|o, i| o[i.first] = i.last; o}
282
282
283 fields = commits_by_author.collect {|r| r.first}
283 fields = commits_by_author.collect {|r| r.first}
284 commits_data = commits_by_author.collect {|r| r.last}
284 commits_data = commits_by_author.collect {|r| r.last}
285 changes_data = commits_by_author.collect {|r| h[r.first] || 0}
285 changes_data = commits_by_author.collect {|r| h[r.first] || 0}
286
286
287 fields = fields + [""]*(10 - fields.length) if fields.length<10
287 fields = fields + [""]*(10 - fields.length) if fields.length<10
288 commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10
288 commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10
289 changes_data = changes_data + [0]*(10 - changes_data.length) if changes_data.length<10
289 changes_data = changes_data + [0]*(10 - changes_data.length) if changes_data.length<10
290
290
291 # Remove email adress in usernames
291 # Remove email adress in usernames
292 fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') }
292 fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') }
293
293
294 graph = SVG::Graph::BarHorizontal.new(
294 graph = SVG::Graph::BarHorizontal.new(
295 :height => 400,
295 :height => 400,
296 :width => 800,
296 :width => 800,
297 :fields => fields,
297 :fields => fields,
298 :stack => :side,
298 :stack => :side,
299 :scale_integers => true,
299 :scale_integers => true,
300 :show_data_values => false,
300 :show_data_values => false,
301 :rotate_y_labels => false,
301 :rotate_y_labels => false,
302 :graph_title => l(:label_commits_per_author),
302 :graph_title => l(:label_commits_per_author),
303 :show_graph_title => true
303 :show_graph_title => true
304 )
304 )
305
305
306 graph.add_data(
306 graph.add_data(
307 :data => commits_data,
307 :data => commits_data,
308 :title => l(:label_revision_plural)
308 :title => l(:label_revision_plural)
309 )
309 )
310
310
311 graph.add_data(
311 graph.add_data(
312 :data => changes_data,
312 :data => changes_data,
313 :title => l(:label_change_plural)
313 :title => l(:label_change_plural)
314 )
314 )
315
315
316 graph.burn
316 graph.burn
317 end
317 end
318
318
319 end
319 end
320
320
321 class Date
321 class Date
322 def months_ago(date = Date.today)
322 def months_ago(date = Date.today)
323 (date.year - self.year)*12 + (date.month - self.month)
323 (date.year - self.year)*12 + (date.month - self.month)
324 end
324 end
325
325
326 def weeks_ago(date = Date.today)
326 def weeks_ago(date = Date.today)
327 (date.year - self.year)*52 + (date.cweek - self.cweek)
327 (date.year - self.year)*52 + (date.cweek - self.cweek)
328 end
328 end
329 end
329 end
330
330
331 class String
331 class String
332 def with_leading_slash
332 def with_leading_slash
333 starts_with?('/') ? self : "/#{self}"
333 starts_with?('/') ? self : "/#{self}"
334 end
334 end
335 end
335 end
@@ -1,203 +1,203
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19 require 'repositories_controller'
19 require 'repositories_controller'
20
20
21 # Re-raise errors caught by the controller.
21 # Re-raise errors caught by the controller.
22 class RepositoriesController; def rescue_action(e) raise e end; end
22 class RepositoriesController; def rescue_action(e) raise e end; end
23
23
24 class RepositoriesGitControllerTest < ActionController::TestCase
24 class RepositoriesGitControllerTest < ActionController::TestCase
25 fixtures :projects, :users, :roles, :members, :member_roles, :repositories, :enabled_modules
25 fixtures :projects, :users, :roles, :members, :member_roles, :repositories, :enabled_modules
26
26
27 # No '..' in the repository path
27 # No '..' in the repository path
28 REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/git_repository'
28 REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/git_repository'
29 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
29 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
30
30
31 def setup
31 def setup
32 @controller = RepositoriesController.new
32 @controller = RepositoriesController.new
33 @request = ActionController::TestRequest.new
33 @request = ActionController::TestRequest.new
34 @response = ActionController::TestResponse.new
34 @response = ActionController::TestResponse.new
35 User.current = nil
35 User.current = nil
36 @repository = Repository::Git.create(:project => Project.find(3), :url => REPOSITORY_PATH)
36 @repository = Repository::Git.create(:project => Project.find(3), :url => REPOSITORY_PATH)
37 assert @repository
37 assert @repository
38 end
38 end
39
39
40 if File.directory?(REPOSITORY_PATH)
40 if File.directory?(REPOSITORY_PATH)
41 def test_show
41 def test_show
42 get :show, :id => 3
42 get :show, :id => 3
43 assert_response :success
43 assert_response :success
44 assert_template 'show'
44 assert_template 'show'
45 assert_not_nil assigns(:entries)
45 assert_not_nil assigns(:entries)
46 assert_not_nil assigns(:changesets)
46 assert_not_nil assigns(:changesets)
47 end
47 end
48
48
49 def test_browse_root
49 def test_browse_root
50 get :show, :id => 3
50 get :show, :id => 3
51 assert_response :success
51 assert_response :success
52 assert_template 'show'
52 assert_template 'show'
53 assert_not_nil assigns(:entries)
53 assert_not_nil assigns(:entries)
54 assert_equal 9, assigns(:entries).size
54 assert_equal 9, assigns(:entries).size
55 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
55 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
56 assert assigns(:entries).detect {|e| e.name == 'this_is_a_really_long_and_verbose_directory_name' && e.kind == 'dir'}
56 assert assigns(:entries).detect {|e| e.name == 'this_is_a_really_long_and_verbose_directory_name' && e.kind == 'dir'}
57 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
57 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
58 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
58 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
59 assert assigns(:entries).detect {|e| e.name == 'copied_README' && e.kind == 'file'}
59 assert assigns(:entries).detect {|e| e.name == 'copied_README' && e.kind == 'file'}
60 assert assigns(:entries).detect {|e| e.name == 'new_file.txt' && e.kind == 'file'}
60 assert assigns(:entries).detect {|e| e.name == 'new_file.txt' && e.kind == 'file'}
61 assert assigns(:entries).detect {|e| e.name == 'renamed_test.txt' && e.kind == 'file'}
61 assert assigns(:entries).detect {|e| e.name == 'renamed_test.txt' && e.kind == 'file'}
62 assert assigns(:entries).detect {|e| e.name == 'filemane with spaces.txt' && e.kind == 'file'}
62 assert assigns(:entries).detect {|e| e.name == 'filemane with spaces.txt' && e.kind == 'file'}
63 assert assigns(:entries).detect {|e| e.name == ' filename with a leading space.txt ' && e.kind == 'file'}
63 assert assigns(:entries).detect {|e| e.name == ' filename with a leading space.txt ' && e.kind == 'file'}
64 end
64 end
65
65
66 def test_browse_branch
66 def test_browse_branch
67 get :show, :id => 3, :rev => 'test_branch'
67 get :show, :id => 3, :rev => 'test_branch'
68 assert_response :success
68 assert_response :success
69 assert_template 'show'
69 assert_template 'show'
70 assert_not_nil assigns(:entries)
70 assert_not_nil assigns(:entries)
71 assert_equal 4, assigns(:entries).size
71 assert_equal 4, assigns(:entries).size
72 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
72 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
73 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
73 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
74 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
74 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
75 assert assigns(:entries).detect {|e| e.name == 'test.txt' && e.kind == 'file'}
75 assert assigns(:entries).detect {|e| e.name == 'test.txt' && e.kind == 'file'}
76 end
76 end
77
77
78 def test_browse_directory
78 def test_browse_directory
79 get :show, :id => 3, :path => ['images']
79 get :show, :id => 3, :path => ['images']
80 assert_response :success
80 assert_response :success
81 assert_template 'show'
81 assert_template 'show'
82 assert_not_nil assigns(:entries)
82 assert_not_nil assigns(:entries)
83 assert_equal ['edit.png'], assigns(:entries).collect(&:name)
83 assert_equal ['edit.png'], assigns(:entries).collect(&:name)
84 entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
84 entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
85 assert_not_nil entry
85 assert_not_nil entry
86 assert_equal 'file', entry.kind
86 assert_equal 'file', entry.kind
87 assert_equal 'images/edit.png', entry.path
87 assert_equal 'images/edit.png', entry.path
88 end
88 end
89
89
90 def test_browse_at_given_revision
90 def test_browse_at_given_revision
91 get :show, :id => 3, :path => ['images'], :rev => '7234cb2750b63f47bff735edc50a1c0a433c2518'
91 get :show, :id => 3, :path => ['images'], :rev => '7234cb2750b63f47bff735edc50a1c0a433c2518'
92 assert_response :success
92 assert_response :success
93 assert_template 'show'
93 assert_template 'show'
94 assert_not_nil assigns(:entries)
94 assert_not_nil assigns(:entries)
95 assert_equal ['delete.png'], assigns(:entries).collect(&:name)
95 assert_equal ['delete.png'], assigns(:entries).collect(&:name)
96 end
96 end
97
97
98 def test_changes
98 def test_changes
99 get :changes, :id => 3, :path => ['images', 'edit.png']
99 get :changes, :id => 3, :path => ['images', 'edit.png']
100 assert_response :success
100 assert_response :success
101 assert_template 'changes'
101 assert_template 'changes'
102 assert_tag :tag => 'h2', :content => 'edit.png'
102 assert_tag :tag => 'h2', :content => 'edit.png'
103 end
103 end
104
104
105 def test_entry_show
105 def test_entry_show
106 get :entry, :id => 3, :path => ['sources', 'watchers_controller.rb']
106 get :entry, :id => 3, :path => ['sources', 'watchers_controller.rb']
107 assert_response :success
107 assert_response :success
108 assert_template 'entry'
108 assert_template 'entry'
109 # Line 19
109 # Line 19
110 assert_tag :tag => 'th',
110 assert_tag :tag => 'th',
111 :content => /11/,
111 :content => /11/,
112 :attributes => { :class => /line-num/ },
112 :attributes => { :class => /line-num/ },
113 :sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ }
113 :sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ }
114 end
114 end
115
115
116 def test_entry_download
116 def test_entry_download
117 get :entry, :id => 3, :path => ['sources', 'watchers_controller.rb'], :format => 'raw'
117 get :entry, :id => 3, :path => ['sources', 'watchers_controller.rb'], :format => 'raw'
118 assert_response :success
118 assert_response :success
119 # File content
119 # File content
120 assert @response.body.include?('WITHOUT ANY WARRANTY')
120 assert @response.body.include?('WITHOUT ANY WARRANTY')
121 end
121 end
122
122
123 def test_directory_entry
123 def test_directory_entry
124 get :entry, :id => 3, :path => ['sources']
124 get :entry, :id => 3, :path => ['sources']
125 assert_response :success
125 assert_response :success
126 assert_template 'show'
126 assert_template 'show'
127 assert_not_nil assigns(:entry)
127 assert_not_nil assigns(:entry)
128 assert_equal 'sources', assigns(:entry).name
128 assert_equal 'sources', assigns(:entry).name
129 end
129 end
130
130
131 def test_diff
131 def test_diff
132 @repository.fetch_changesets
132 @repository.fetch_changesets
133 @repository.reload
133 @repository.reload
134
134
135 # Full diff of changeset 2f9c0091
135 # Full diff of changeset 2f9c0091
136 get :diff, :id => 3, :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
136 get :diff, :id => 3, :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
137 assert_response :success
137 assert_response :success
138 assert_template 'diff'
138 assert_template 'diff'
139 # Line 22 removed
139 # Line 22 removed
140 assert_tag :tag => 'th',
140 assert_tag :tag => 'th',
141 :content => /22/,
141 :content => /22/,
142 :sibling => { :tag => 'td',
142 :sibling => { :tag => 'td',
143 :attributes => { :class => /diff_out/ },
143 :attributes => { :class => /diff_out/ },
144 :content => /def remove/ }
144 :content => /def remove/ }
145 assert_tag :tag => 'h2', :content => /2f9c0091/
145 assert_tag :tag => 'h2', :content => /2f9c0091/
146 end
146 end
147
147
148 def test_diff_two_revs
148 def test_diff_two_revs
149 @repository.fetch_changesets
149 @repository.fetch_changesets
150 @repository.reload
150 @repository.reload
151
151
152 get :diff, :id => 3, :rev => '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
152 get :diff, :id => 3, :rev => '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
153 :rev_to => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
153 :rev_to => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
154 assert_response :success
154 assert_response :success
155 assert_template 'diff'
155 assert_template 'diff'
156
156
157 diff = assigns(:diff)
157 diff = assigns(:diff)
158 assert_not_nil diff
158 assert_not_nil diff
159 assert_tag :tag => 'h2', :content => /2f9c0091:61b685fb/
159 assert_tag :tag => 'h2', :content => /2f9c0091:61b685fb/
160 end
160 end
161
161
162 def test_annotate
162 def test_annotate
163 get :annotate, :id => 3, :path => ['sources', 'watchers_controller.rb']
163 get :annotate, :id => 3, :path => ['sources', 'watchers_controller.rb']
164 assert_response :success
164 assert_response :success
165 assert_template 'annotate'
165 assert_template 'annotate'
166 # Line 23, changeset 2f9c0091
166 # Line 23, changeset 2f9c0091
167 assert_tag :tag => 'th', :content => /24/,
167 assert_tag :tag => 'th', :content => /24/,
168 :sibling => { :tag => 'td', :child => { :tag => 'a', :content => /2f9c0091/ } },
168 :sibling => { :tag => 'td', :child => { :tag => 'a', :content => /2f9c0091/ } },
169 :sibling => { :tag => 'td', :content => /jsmith/ },
169 :sibling => { :tag => 'td', :content => /jsmith/ },
170 :sibling => { :tag => 'td', :content => /watcher =/ }
170 :sibling => { :tag => 'td', :content => /watcher =/ }
171 end
171 end
172
172
173 def test_annotate_binary_file
173 def test_annotate_binary_file
174 get :annotate, :id => 3, :path => ['images', 'edit.png']
174 get :annotate, :id => 3, :path => ['images', 'edit.png']
175 assert_response 500
175 assert_response 500
176 assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ },
176 assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ },
177 :content => /can not be annotated/
177 :content => /can not be annotated/
178 end
178 end
179
179
180 def test_revision
180 def test_revision
181 @repository.fetch_changesets
181 @repository.fetch_changesets
182 @repository.reload
182 @repository.reload
183 ['61b685fbe55ab05b5ac68402d5720c1a6ac973d1', '61b685f'].each do |r|
183 ['61b685fbe55ab05b5ac68402d5720c1a6ac973d1', '61b685f'].each do |r|
184 get :revision, :id => 3, :rev => r
184 get :revision, :id => 3, :rev => r
185 assert_response :success
185 assert_response :success
186 assert_template 'revision'
186 assert_template 'revision'
187 end
187 end
188 end
188 end
189
189
190 def test_empty_revision
190 def test_empty_revision
191 @repository.fetch_changesets
191 @repository.fetch_changesets
192 @repository.reload
192 @repository.reload
193 ['', ' ', nil].each do |r|
193 ['', ' ', nil].each do |r|
194 get :revision, :id => 1, :rev => r
194 get :revision, :id => 1, :rev => r
195 assert_response 500
195 assert_response 404
196 assert_error_tag :content => /was not found/
196 assert_error_tag :content => /was not found/
197 end
197 end
198 end
198 end
199 else
199 else
200 puts "Git test repository NOT FOUND. Skipping functional tests !!!"
200 puts "Git test repository NOT FOUND. Skipping functional tests !!!"
201 def test_fake; assert true end
201 def test_fake; assert true end
202 end
202 end
203 end
203 end
@@ -1,171 +1,182
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19 require 'repositories_controller'
19 require 'repositories_controller'
20
20
21 # Re-raise errors caught by the controller.
21 # Re-raise errors caught by the controller.
22 class RepositoriesController; def rescue_action(e) raise e end; end
22 class RepositoriesController; def rescue_action(e) raise e end; end
23
23
24 class RepositoriesMercurialControllerTest < ActionController::TestCase
24 class RepositoriesMercurialControllerTest < ActionController::TestCase
25 fixtures :projects, :users, :roles, :members, :member_roles, :repositories, :enabled_modules
25 fixtures :projects, :users, :roles, :members, :member_roles, :repositories, :enabled_modules
26
26
27 # No '..' in the repository path
27 # No '..' in the repository path
28 REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/mercurial_repository'
28 REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/mercurial_repository'
29
29
30 def setup
30 def setup
31 @controller = RepositoriesController.new
31 @controller = RepositoriesController.new
32 @request = ActionController::TestRequest.new
32 @request = ActionController::TestRequest.new
33 @response = ActionController::TestResponse.new
33 @response = ActionController::TestResponse.new
34 User.current = nil
34 User.current = nil
35 Repository::Mercurial.create(:project => Project.find(3), :url => REPOSITORY_PATH)
35 @repository = Repository::Mercurial.create(:project => Project.find(3), :url => REPOSITORY_PATH)
36 assert @repository
36 end
37 end
37
38
38 if File.directory?(REPOSITORY_PATH)
39 if File.directory?(REPOSITORY_PATH)
39 def test_show
40 def test_show
40 get :show, :id => 3
41 get :show, :id => 3
41 assert_response :success
42 assert_response :success
42 assert_template 'show'
43 assert_template 'show'
43 assert_not_nil assigns(:entries)
44 assert_not_nil assigns(:entries)
44 assert_not_nil assigns(:changesets)
45 assert_not_nil assigns(:changesets)
45 end
46 end
46
47
47 def test_show_root
48 def test_show_root
48 get :show, :id => 3
49 get :show, :id => 3
49 assert_response :success
50 assert_response :success
50 assert_template 'show'
51 assert_template 'show'
51 assert_not_nil assigns(:entries)
52 assert_not_nil assigns(:entries)
52 assert_equal 4, assigns(:entries).size
53 assert_equal 4, assigns(:entries).size
53 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
54 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
54 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
55 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
55 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
56 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
56 end
57 end
57
58
58 def test_show_directory
59 def test_show_directory
59 get :show, :id => 3, :path => ['images']
60 get :show, :id => 3, :path => ['images']
60 assert_response :success
61 assert_response :success
61 assert_template 'show'
62 assert_template 'show'
62 assert_not_nil assigns(:entries)
63 assert_not_nil assigns(:entries)
63 assert_equal ['delete.png', 'edit.png'], assigns(:entries).collect(&:name)
64 assert_equal ['delete.png', 'edit.png'], assigns(:entries).collect(&:name)
64 entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
65 entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
65 assert_not_nil entry
66 assert_not_nil entry
66 assert_equal 'file', entry.kind
67 assert_equal 'file', entry.kind
67 assert_equal 'images/edit.png', entry.path
68 assert_equal 'images/edit.png', entry.path
68 end
69 end
69
70
70 def test_show_at_given_revision
71 def test_show_at_given_revision
71 get :show, :id => 3, :path => ['images'], :rev => 0
72 get :show, :id => 3, :path => ['images'], :rev => 0
72 assert_response :success
73 assert_response :success
73 assert_template 'show'
74 assert_template 'show'
74 assert_not_nil assigns(:entries)
75 assert_not_nil assigns(:entries)
75 assert_equal ['delete.png'], assigns(:entries).collect(&:name)
76 assert_equal ['delete.png'], assigns(:entries).collect(&:name)
76 end
77 end
77
78
78 def test_show_directory_sql_escape_percent
79 def test_show_directory_sql_escape_percent
79 get :show, :id => 3, :path => ['sql_escape', 'percent%dir'], :rev => 13
80 get :show, :id => 3, :path => ['sql_escape', 'percent%dir'], :rev => 13
80 assert_response :success
81 assert_response :success
81 assert_template 'show'
82 assert_template 'show'
82
83
83 assert_not_nil assigns(:entries)
84 assert_not_nil assigns(:entries)
84 assert_equal ['percent%file1.txt', 'percentfile1.txt'], assigns(:entries).collect(&:name)
85 assert_equal ['percent%file1.txt', 'percentfile1.txt'], assigns(:entries).collect(&:name)
85 changesets = assigns(:changesets)
86 changesets = assigns(:changesets)
86
87
87 ## This is not yet implemented.
88 ## This is not yet implemented.
88 # assert_not_nil changesets
89 # assert_not_nil changesets
89 # assert_equal %w(13 11 10 9), changesets.collect(&:revision)
90 # assert_equal %w(13 11 10 9), changesets.collect(&:revision)
90 end
91 end
91
92
92 def test_changes
93 def test_changes
93 get :changes, :id => 3, :path => ['images', 'edit.png']
94 get :changes, :id => 3, :path => ['images', 'edit.png']
94 assert_response :success
95 assert_response :success
95 assert_template 'changes'
96 assert_template 'changes'
96 assert_tag :tag => 'h2', :content => 'edit.png'
97 assert_tag :tag => 'h2', :content => 'edit.png'
97 end
98 end
98
99
99 def test_entry_show
100 def test_entry_show
100 get :entry, :id => 3, :path => ['sources', 'watchers_controller.rb']
101 get :entry, :id => 3, :path => ['sources', 'watchers_controller.rb']
101 assert_response :success
102 assert_response :success
102 assert_template 'entry'
103 assert_template 'entry'
103 # Line 10
104 # Line 10
104 assert_tag :tag => 'th',
105 assert_tag :tag => 'th',
105 :content => '10',
106 :content => '10',
106 :attributes => { :class => 'line-num' },
107 :attributes => { :class => 'line-num' },
107 :sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ }
108 :sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ }
108 end
109 end
109
110
110 def test_entry_download
111 def test_entry_download
111 get :entry, :id => 3, :path => ['sources', 'watchers_controller.rb'], :format => 'raw'
112 get :entry, :id => 3, :path => ['sources', 'watchers_controller.rb'], :format => 'raw'
112 assert_response :success
113 assert_response :success
113 # File content
114 # File content
114 assert @response.body.include?('WITHOUT ANY WARRANTY')
115 assert @response.body.include?('WITHOUT ANY WARRANTY')
115 end
116 end
116
117
117 def test_directory_entry
118 def test_directory_entry
118 get :entry, :id => 3, :path => ['sources']
119 get :entry, :id => 3, :path => ['sources']
119 assert_response :success
120 assert_response :success
120 assert_template 'show'
121 assert_template 'show'
121 assert_not_nil assigns(:entry)
122 assert_not_nil assigns(:entry)
122 assert_equal 'sources', assigns(:entry).name
123 assert_equal 'sources', assigns(:entry).name
123 end
124 end
124
125
125 def test_diff
126 def test_diff
126 # Full diff of changeset 4
127 # Full diff of changeset 4
127 get :diff, :id => 3, :rev => 4
128 get :diff, :id => 3, :rev => 4
128 assert_response :success
129 assert_response :success
129 assert_template 'diff'
130 assert_template 'diff'
130 # Line 22 removed
131 # Line 22 removed
131 assert_tag :tag => 'th',
132 assert_tag :tag => 'th',
132 :content => '22',
133 :content => '22',
133 :sibling => { :tag => 'td',
134 :sibling => { :tag => 'td',
134 :attributes => { :class => /diff_out/ },
135 :attributes => { :class => /diff_out/ },
135 :content => /def remove/ }
136 :content => /def remove/ }
136 end
137 end
137
138
138 def test_annotate
139 def test_annotate
139 get :annotate, :id => 3, :path => ['sources', 'watchers_controller.rb']
140 get :annotate, :id => 3, :path => ['sources', 'watchers_controller.rb']
140 assert_response :success
141 assert_response :success
141 assert_template 'annotate'
142 assert_template 'annotate'
142 # Line 23, revision 4:def6d2f1254a
143 # Line 23, revision 4:def6d2f1254a
143 assert_tag :tag => 'th',
144 assert_tag :tag => 'th',
144 :content => '23',
145 :content => '23',
145 :attributes => { :class => 'line-num' },
146 :attributes => { :class => 'line-num' },
146 :sibling =>
147 :sibling =>
147 {
148 {
148 :tag => 'td',
149 :tag => 'td',
149 :attributes => { :class => 'revision' },
150 :attributes => { :class => 'revision' },
150 :child => { :tag => 'a', :content => '4' }
151 :child => { :tag => 'a', :content => '4' }
151 # :child => { :tag => 'a', :content => /4:def6d2f1/ }
152 # :child => { :tag => 'a', :content => /4:def6d2f1/ }
152 }
153 }
153 assert_tag :tag => 'th',
154 assert_tag :tag => 'th',
154 :content => '23',
155 :content => '23',
155 :attributes => { :class => 'line-num' },
156 :attributes => { :class => 'line-num' },
156 :sibling =>
157 :sibling =>
157 {
158 {
158 :tag => 'td' ,
159 :tag => 'td' ,
159 :content => 'jsmith' ,
160 :content => 'jsmith' ,
160 :attributes => { :class => 'author' },
161 :attributes => { :class => 'author' },
161 }
162 }
162 assert_tag :tag => 'th',
163 assert_tag :tag => 'th',
163 :content => '23',
164 :content => '23',
164 :attributes => { :class => 'line-num' },
165 :attributes => { :class => 'line-num' },
165 :sibling => { :tag => 'td', :content => /watcher =/ }
166 :sibling => { :tag => 'td', :content => /watcher =/ }
166 end
167 end
168
169 def test_empty_revision
170 @repository.fetch_changesets
171 @repository.reload
172 ['', ' ', nil].each do |r|
173 get :revision, :id => 3, :rev => r
174 assert_response 404
175 assert_error_tag :content => /was not found/
176 end
177 end
167 else
178 else
168 puts "Mercurial test repository NOT FOUND. Skipping functional tests !!!"
179 puts "Mercurial test repository NOT FOUND. Skipping functional tests !!!"
169 def test_fake; assert true end
180 def test_fake; assert true end
170 end
181 end
171 end
182 end
@@ -1,235 +1,235
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19 require 'repositories_controller'
19 require 'repositories_controller'
20
20
21 # Re-raise errors caught by the controller.
21 # Re-raise errors caught by the controller.
22 class RepositoriesController; def rescue_action(e) raise e end; end
22 class RepositoriesController; def rescue_action(e) raise e end; end
23
23
24 class RepositoriesSubversionControllerTest < ActionController::TestCase
24 class RepositoriesSubversionControllerTest < ActionController::TestCase
25 fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules,
25 fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules,
26 :repositories, :issues, :issue_statuses, :changesets, :changes,
26 :repositories, :issues, :issue_statuses, :changesets, :changes,
27 :issue_categories, :enumerations, :custom_fields, :custom_values, :trackers
27 :issue_categories, :enumerations, :custom_fields, :custom_values, :trackers
28
28
29 def setup
29 def setup
30 @controller = RepositoriesController.new
30 @controller = RepositoriesController.new
31 @request = ActionController::TestRequest.new
31 @request = ActionController::TestRequest.new
32 @response = ActionController::TestResponse.new
32 @response = ActionController::TestResponse.new
33 Setting.default_language = 'en'
33 Setting.default_language = 'en'
34 User.current = nil
34 User.current = nil
35 end
35 end
36
36
37 if repository_configured?('subversion')
37 if repository_configured?('subversion')
38 def test_show
38 def test_show
39 get :show, :id => 1
39 get :show, :id => 1
40 assert_response :success
40 assert_response :success
41 assert_template 'show'
41 assert_template 'show'
42 assert_not_nil assigns(:entries)
42 assert_not_nil assigns(:entries)
43 assert_not_nil assigns(:changesets)
43 assert_not_nil assigns(:changesets)
44 end
44 end
45
45
46 def test_browse_root
46 def test_browse_root
47 get :show, :id => 1
47 get :show, :id => 1
48 assert_response :success
48 assert_response :success
49 assert_template 'show'
49 assert_template 'show'
50 assert_not_nil assigns(:entries)
50 assert_not_nil assigns(:entries)
51 entry = assigns(:entries).detect {|e| e.name == 'subversion_test'}
51 entry = assigns(:entries).detect {|e| e.name == 'subversion_test'}
52 assert_equal 'dir', entry.kind
52 assert_equal 'dir', entry.kind
53 end
53 end
54
54
55 def test_browse_directory
55 def test_browse_directory
56 get :show, :id => 1, :path => ['subversion_test']
56 get :show, :id => 1, :path => ['subversion_test']
57 assert_response :success
57 assert_response :success
58 assert_template 'show'
58 assert_template 'show'
59 assert_not_nil assigns(:entries)
59 assert_not_nil assigns(:entries)
60 assert_equal ['[folder_with_brackets]', 'folder', '.project', 'helloworld.c', 'textfile.txt'], assigns(:entries).collect(&:name)
60 assert_equal ['[folder_with_brackets]', 'folder', '.project', 'helloworld.c', 'textfile.txt'], assigns(:entries).collect(&:name)
61 entry = assigns(:entries).detect {|e| e.name == 'helloworld.c'}
61 entry = assigns(:entries).detect {|e| e.name == 'helloworld.c'}
62 assert_equal 'file', entry.kind
62 assert_equal 'file', entry.kind
63 assert_equal 'subversion_test/helloworld.c', entry.path
63 assert_equal 'subversion_test/helloworld.c', entry.path
64 assert_tag :a, :content => 'helloworld.c', :attributes => { :class => /text\-x\-c/ }
64 assert_tag :a, :content => 'helloworld.c', :attributes => { :class => /text\-x\-c/ }
65 end
65 end
66
66
67 def test_browse_at_given_revision
67 def test_browse_at_given_revision
68 get :show, :id => 1, :path => ['subversion_test'], :rev => 4
68 get :show, :id => 1, :path => ['subversion_test'], :rev => 4
69 assert_response :success
69 assert_response :success
70 assert_template 'show'
70 assert_template 'show'
71 assert_not_nil assigns(:entries)
71 assert_not_nil assigns(:entries)
72 assert_equal ['folder', '.project', 'helloworld.c', 'helloworld.rb', 'textfile.txt'], assigns(:entries).collect(&:name)
72 assert_equal ['folder', '.project', 'helloworld.c', 'helloworld.rb', 'textfile.txt'], assigns(:entries).collect(&:name)
73 end
73 end
74
74
75 def test_file_changes
75 def test_file_changes
76 get :changes, :id => 1, :path => ['subversion_test', 'folder', 'helloworld.rb' ]
76 get :changes, :id => 1, :path => ['subversion_test', 'folder', 'helloworld.rb' ]
77 assert_response :success
77 assert_response :success
78 assert_template 'changes'
78 assert_template 'changes'
79
79
80 changesets = assigns(:changesets)
80 changesets = assigns(:changesets)
81 assert_not_nil changesets
81 assert_not_nil changesets
82 assert_equal %w(6 3 2), changesets.collect(&:revision)
82 assert_equal %w(6 3 2), changesets.collect(&:revision)
83
83
84 # svn properties displayed with svn >= 1.5 only
84 # svn properties displayed with svn >= 1.5 only
85 if Redmine::Scm::Adapters::SubversionAdapter.client_version_above?([1, 5, 0])
85 if Redmine::Scm::Adapters::SubversionAdapter.client_version_above?([1, 5, 0])
86 assert_not_nil assigns(:properties)
86 assert_not_nil assigns(:properties)
87 assert_equal 'native', assigns(:properties)['svn:eol-style']
87 assert_equal 'native', assigns(:properties)['svn:eol-style']
88 assert_tag :ul,
88 assert_tag :ul,
89 :child => { :tag => 'li',
89 :child => { :tag => 'li',
90 :child => { :tag => 'b', :content => 'svn:eol-style' },
90 :child => { :tag => 'b', :content => 'svn:eol-style' },
91 :child => { :tag => 'span', :content => 'native' } }
91 :child => { :tag => 'span', :content => 'native' } }
92 end
92 end
93 end
93 end
94
94
95 def test_directory_changes
95 def test_directory_changes
96 get :changes, :id => 1, :path => ['subversion_test', 'folder' ]
96 get :changes, :id => 1, :path => ['subversion_test', 'folder' ]
97 assert_response :success
97 assert_response :success
98 assert_template 'changes'
98 assert_template 'changes'
99
99
100 changesets = assigns(:changesets)
100 changesets = assigns(:changesets)
101 assert_not_nil changesets
101 assert_not_nil changesets
102 assert_equal %w(10 9 7 6 5 2), changesets.collect(&:revision)
102 assert_equal %w(10 9 7 6 5 2), changesets.collect(&:revision)
103 end
103 end
104
104
105 def test_entry
105 def test_entry
106 get :entry, :id => 1, :path => ['subversion_test', 'helloworld.c']
106 get :entry, :id => 1, :path => ['subversion_test', 'helloworld.c']
107 assert_response :success
107 assert_response :success
108 assert_template 'entry'
108 assert_template 'entry'
109 end
109 end
110
110
111 def test_entry_should_send_if_too_big
111 def test_entry_should_send_if_too_big
112 # no files in the test repo is larger than 1KB...
112 # no files in the test repo is larger than 1KB...
113 with_settings :file_max_size_displayed => 0 do
113 with_settings :file_max_size_displayed => 0 do
114 get :entry, :id => 1, :path => ['subversion_test', 'helloworld.c']
114 get :entry, :id => 1, :path => ['subversion_test', 'helloworld.c']
115 assert_response :success
115 assert_response :success
116 assert_template ''
116 assert_template ''
117 assert_equal 'attachment; filename="helloworld.c"', @response.headers['Content-Disposition']
117 assert_equal 'attachment; filename="helloworld.c"', @response.headers['Content-Disposition']
118 end
118 end
119 end
119 end
120
120
121 def test_entry_at_given_revision
121 def test_entry_at_given_revision
122 get :entry, :id => 1, :path => ['subversion_test', 'helloworld.rb'], :rev => 2
122 get :entry, :id => 1, :path => ['subversion_test', 'helloworld.rb'], :rev => 2
123 assert_response :success
123 assert_response :success
124 assert_template 'entry'
124 assert_template 'entry'
125 # this line was removed in r3 and file was moved in r6
125 # this line was removed in r3 and file was moved in r6
126 assert_tag :tag => 'td', :attributes => { :class => /line-code/},
126 assert_tag :tag => 'td', :attributes => { :class => /line-code/},
127 :content => /Here's the code/
127 :content => /Here's the code/
128 end
128 end
129
129
130 def test_entry_not_found
130 def test_entry_not_found
131 get :entry, :id => 1, :path => ['subversion_test', 'zzz.c']
131 get :entry, :id => 1, :path => ['subversion_test', 'zzz.c']
132 assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ },
132 assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ },
133 :content => /The entry or revision was not found in the repository/
133 :content => /The entry or revision was not found in the repository/
134 end
134 end
135
135
136 def test_entry_download
136 def test_entry_download
137 get :entry, :id => 1, :path => ['subversion_test', 'helloworld.c'], :format => 'raw'
137 get :entry, :id => 1, :path => ['subversion_test', 'helloworld.c'], :format => 'raw'
138 assert_response :success
138 assert_response :success
139 assert_template ''
139 assert_template ''
140 assert_equal 'attachment; filename="helloworld.c"', @response.headers['Content-Disposition']
140 assert_equal 'attachment; filename="helloworld.c"', @response.headers['Content-Disposition']
141 end
141 end
142
142
143 def test_directory_entry
143 def test_directory_entry
144 get :entry, :id => 1, :path => ['subversion_test', 'folder']
144 get :entry, :id => 1, :path => ['subversion_test', 'folder']
145 assert_response :success
145 assert_response :success
146 assert_template 'show'
146 assert_template 'show'
147 assert_not_nil assigns(:entry)
147 assert_not_nil assigns(:entry)
148 assert_equal 'folder', assigns(:entry).name
148 assert_equal 'folder', assigns(:entry).name
149 end
149 end
150
150
151 def test_revision
151 def test_revision
152 get :revision, :id => 1, :rev => 2
152 get :revision, :id => 1, :rev => 2
153 assert_response :success
153 assert_response :success
154 assert_template 'revision'
154 assert_template 'revision'
155 assert_tag :tag => 'ul',
155 assert_tag :tag => 'ul',
156 :child => { :tag => 'li',
156 :child => { :tag => 'li',
157 # link to the entry at rev 2
157 # link to the entry at rev 2
158 :child => { :tag => 'a',
158 :child => { :tag => 'a',
159 :attributes => {:href => '/projects/ecookbook/repository/revisions/2/entry/test/some/path/in/the/repo'},
159 :attributes => {:href => '/projects/ecookbook/repository/revisions/2/entry/test/some/path/in/the/repo'},
160 :content => 'repo',
160 :content => 'repo',
161 # link to partial diff
161 # link to partial diff
162 :sibling => { :tag => 'a',
162 :sibling => { :tag => 'a',
163 :attributes => { :href => '/projects/ecookbook/repository/revisions/2/diff/test/some/path/in/the/repo' }
163 :attributes => { :href => '/projects/ecookbook/repository/revisions/2/diff/test/some/path/in/the/repo' }
164 }
164 }
165 }
165 }
166 }
166 }
167 end
167 end
168
168
169 def test_invalid_revision
169 def test_invalid_revision
170 get :revision, :id => 1, :rev => 'something_weird'
170 get :revision, :id => 1, :rev => 'something_weird'
171 assert_response 500
171 assert_response 404
172 assert_error_tag :content => /was not found/
172 assert_error_tag :content => /was not found/
173 end
173 end
174
174
175 def test_empty_revision
175 def test_empty_revision
176 ['', ' ', nil].each do |r|
176 ['', ' ', nil].each do |r|
177 get :revision, :id => 1, :rev => r
177 get :revision, :id => 1, :rev => r
178 assert_response 500
178 assert_response 404
179 assert_error_tag :content => /was not found/
179 assert_error_tag :content => /was not found/
180 end
180 end
181 end
181 end
182
182
183 def test_revision_with_repository_pointing_to_a_subdirectory
183 def test_revision_with_repository_pointing_to_a_subdirectory
184 r = Project.find(1).repository
184 r = Project.find(1).repository
185 # Changes repository url to a subdirectory
185 # Changes repository url to a subdirectory
186 r.update_attribute :url, (r.url + '/test/some')
186 r.update_attribute :url, (r.url + '/test/some')
187
187
188 get :revision, :id => 1, :rev => 2
188 get :revision, :id => 1, :rev => 2
189 assert_response :success
189 assert_response :success
190 assert_template 'revision'
190 assert_template 'revision'
191 assert_tag :tag => 'ul',
191 assert_tag :tag => 'ul',
192 :child => { :tag => 'li',
192 :child => { :tag => 'li',
193 # link to the entry at rev 2
193 # link to the entry at rev 2
194 :child => { :tag => 'a',
194 :child => { :tag => 'a',
195 :attributes => {:href => '/projects/ecookbook/repository/revisions/2/entry/path/in/the/repo'},
195 :attributes => {:href => '/projects/ecookbook/repository/revisions/2/entry/path/in/the/repo'},
196 :content => 'repo',
196 :content => 'repo',
197 # link to partial diff
197 # link to partial diff
198 :sibling => { :tag => 'a',
198 :sibling => { :tag => 'a',
199 :attributes => { :href => '/projects/ecookbook/repository/revisions/2/diff/path/in/the/repo' }
199 :attributes => { :href => '/projects/ecookbook/repository/revisions/2/diff/path/in/the/repo' }
200 }
200 }
201 }
201 }
202 }
202 }
203 end
203 end
204
204
205 def test_revision_diff
205 def test_revision_diff
206 get :diff, :id => 1, :rev => 3
206 get :diff, :id => 1, :rev => 3
207 assert_response :success
207 assert_response :success
208 assert_template 'diff'
208 assert_template 'diff'
209
209
210 assert_tag :tag => 'h2', :content => /3/
210 assert_tag :tag => 'h2', :content => /3/
211 end
211 end
212
212
213 def test_directory_diff
213 def test_directory_diff
214 get :diff, :id => 1, :rev => 6, :rev_to => 2, :path => ['subversion_test', 'folder']
214 get :diff, :id => 1, :rev => 6, :rev_to => 2, :path => ['subversion_test', 'folder']
215 assert_response :success
215 assert_response :success
216 assert_template 'diff'
216 assert_template 'diff'
217
217
218 diff = assigns(:diff)
218 diff = assigns(:diff)
219 assert_not_nil diff
219 assert_not_nil diff
220 # 2 files modified
220 # 2 files modified
221 assert_equal 2, Redmine::UnifiedDiff.new(diff).size
221 assert_equal 2, Redmine::UnifiedDiff.new(diff).size
222
222
223 assert_tag :tag => 'h2', :content => /2:6/
223 assert_tag :tag => 'h2', :content => /2:6/
224 end
224 end
225
225
226 def test_annotate
226 def test_annotate
227 get :annotate, :id => 1, :path => ['subversion_test', 'helloworld.c']
227 get :annotate, :id => 1, :path => ['subversion_test', 'helloworld.c']
228 assert_response :success
228 assert_response :success
229 assert_template 'annotate'
229 assert_template 'annotate'
230 end
230 end
231 else
231 else
232 puts "Subversion test repository NOT FOUND. Skipping functional tests !!!"
232 puts "Subversion test repository NOT FOUND. Skipping functional tests !!!"
233 def test_fake; assert true end
233 def test_fake; assert true end
234 end
234 end
235 end
235 end
General Comments 0
You need to be logged in to leave comments. Login now