##// END OF EJS Templates
Limit the size of repository files displayed inline too....
Jean-Philippe Lang -
r2442:1c5a2ddfb07c
parent child
Show More
@@ -1,327 +1,327
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 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 before_filter :find_repository, :except => :edit
27 before_filter :find_repository, :except => :edit
28 before_filter :find_project, :only => :edit
28 before_filter :find_project, :only => :edit
29 before_filter :authorize
29 before_filter :authorize
30 accept_key_auth :revisions
30 accept_key_auth :revisions
31
31
32 rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed
32 rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed
33
33
34 def edit
34 def edit
35 @repository = @project.repository
35 @repository = @project.repository
36 if !@repository
36 if !@repository
37 @repository = Repository.factory(params[:repository_scm])
37 @repository = Repository.factory(params[:repository_scm])
38 @repository.project = @project if @repository
38 @repository.project = @project if @repository
39 end
39 end
40 if request.post? && @repository
40 if request.post? && @repository
41 @repository.attributes = params[:repository]
41 @repository.attributes = params[:repository]
42 @repository.save
42 @repository.save
43 end
43 end
44 render(:update) {|page| page.replace_html "tab-content-repository", :partial => 'projects/settings/repository'}
44 render(:update) {|page| page.replace_html "tab-content-repository", :partial => 'projects/settings/repository'}
45 end
45 end
46
46
47 def committers
47 def committers
48 @committers = @repository.committers
48 @committers = @repository.committers
49 @users = @project.users
49 @users = @project.users
50 additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id)
50 additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id)
51 @users += User.find_all_by_id(additional_user_ids) unless additional_user_ids.empty?
51 @users += User.find_all_by_id(additional_user_ids) unless additional_user_ids.empty?
52 @users.compact!
52 @users.compact!
53 @users.sort!
53 @users.sort!
54 if request.post? && params[:committers].is_a?(Hash)
54 if request.post? && params[:committers].is_a?(Hash)
55 # Build a hash with repository usernames as keys and corresponding user ids as values
55 # Build a hash with repository usernames as keys and corresponding user ids as values
56 @repository.committer_ids = params[:committers].values.inject({}) {|h, c| h[c.first] = c.last; h}
56 @repository.committer_ids = params[:committers].values.inject({}) {|h, c| h[c.first] = c.last; h}
57 flash[:notice] = l(:notice_successful_update)
57 flash[:notice] = l(:notice_successful_update)
58 redirect_to :action => 'committers', :id => @project
58 redirect_to :action => 'committers', :id => @project
59 end
59 end
60 end
60 end
61
61
62 def destroy
62 def destroy
63 @repository.destroy
63 @repository.destroy
64 redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'repository'
64 redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'repository'
65 end
65 end
66
66
67 def show
67 def show
68 # check if new revisions have been committed in the repository
68 # check if new revisions have been committed in the repository
69 @repository.fetch_changesets if Setting.autofetch_changesets?
69 @repository.fetch_changesets if Setting.autofetch_changesets?
70 # root entries
70 # root entries
71 @entries = @repository.entries('', @rev)
71 @entries = @repository.entries('', @rev)
72 # latest changesets
72 # latest changesets
73 @changesets = @repository.changesets.find(:all, :limit => 10, :order => "committed_on DESC")
73 @changesets = @repository.changesets.find(:all, :limit => 10, :order => "committed_on DESC")
74 show_error_not_found unless @entries || @changesets.any?
74 show_error_not_found unless @entries || @changesets.any?
75 end
75 end
76
76
77 def browse
77 def browse
78 @entries = @repository.entries(@path, @rev)
78 @entries = @repository.entries(@path, @rev)
79 if request.xhr?
79 if request.xhr?
80 @entries ? render(:partial => 'dir_list_content') : render(:nothing => true)
80 @entries ? render(:partial => 'dir_list_content') : render(:nothing => true)
81 else
81 else
82 show_error_not_found and return unless @entries
82 show_error_not_found and return unless @entries
83 @properties = @repository.properties(@path, @rev)
83 @properties = @repository.properties(@path, @rev)
84 render :action => 'browse'
84 render :action => 'browse'
85 end
85 end
86 end
86 end
87
87
88 def changes
88 def changes
89 @entry = @repository.entry(@path, @rev)
89 @entry = @repository.entry(@path, @rev)
90 show_error_not_found and return unless @entry
90 show_error_not_found and return unless @entry
91 @changesets = @repository.changesets_for_path(@path, :limit => Setting.repository_log_display_limit.to_i)
91 @changesets = @repository.changesets_for_path(@path, :limit => Setting.repository_log_display_limit.to_i)
92 @properties = @repository.properties(@path, @rev)
92 @properties = @repository.properties(@path, @rev)
93 end
93 end
94
94
95 def revisions
95 def revisions
96 @changeset_count = @repository.changesets.count
96 @changeset_count = @repository.changesets.count
97 @changeset_pages = Paginator.new self, @changeset_count,
97 @changeset_pages = Paginator.new self, @changeset_count,
98 per_page_option,
98 per_page_option,
99 params['page']
99 params['page']
100 @changesets = @repository.changesets.find(:all,
100 @changesets = @repository.changesets.find(:all,
101 :limit => @changeset_pages.items_per_page,
101 :limit => @changeset_pages.items_per_page,
102 :offset => @changeset_pages.current.offset,
102 :offset => @changeset_pages.current.offset,
103 :include => :user)
103 :include => :user)
104
104
105 respond_to do |format|
105 respond_to do |format|
106 format.html { render :layout => false if request.xhr? }
106 format.html { render :layout => false if request.xhr? }
107 format.atom { render_feed(@changesets, :title => "#{@project.name}: #{l(:label_revision_plural)}") }
107 format.atom { render_feed(@changesets, :title => "#{@project.name}: #{l(:label_revision_plural)}") }
108 end
108 end
109 end
109 end
110
110
111 def entry
111 def entry
112 @entry = @repository.entry(@path, @rev)
112 @entry = @repository.entry(@path, @rev)
113 show_error_not_found and return unless @entry
113 show_error_not_found and return unless @entry
114
114
115 # If the entry is a dir, show the browser
115 # If the entry is a dir, show the browser
116 browse and return if @entry.is_dir?
116 browse and return if @entry.is_dir?
117
117
118 @content = @repository.cat(@path, @rev)
118 @content = @repository.cat(@path, @rev)
119 show_error_not_found and return unless @content
119 show_error_not_found and return unless @content
120 if 'raw' == params[:format] || @content.is_binary_data?
120 if 'raw' == params[:format] || @content.is_binary_data? || (@entry.size && @entry.size > Setting.file_max_size_displayed.to_i.kilobyte)
121 # Force the download if it's a binary file
121 # Force the download
122 send_data @content, :filename => @path.split('/').last
122 send_data @content, :filename => @path.split('/').last
123 else
123 else
124 # Prevent empty lines when displaying a file with Windows style eol
124 # Prevent empty lines when displaying a file with Windows style eol
125 @content.gsub!("\r\n", "\n")
125 @content.gsub!("\r\n", "\n")
126 end
126 end
127 end
127 end
128
128
129 def annotate
129 def annotate
130 @entry = @repository.entry(@path, @rev)
130 @entry = @repository.entry(@path, @rev)
131 show_error_not_found and return unless @entry
131 show_error_not_found and return unless @entry
132
132
133 @annotate = @repository.scm.annotate(@path, @rev)
133 @annotate = @repository.scm.annotate(@path, @rev)
134 render_error l(:error_scm_annotate) and return if @annotate.nil? || @annotate.empty?
134 render_error l(:error_scm_annotate) and return if @annotate.nil? || @annotate.empty?
135 end
135 end
136
136
137 def revision
137 def revision
138 @changeset = @repository.changesets.find_by_revision(@rev)
138 @changeset = @repository.changesets.find_by_revision(@rev)
139 raise ChangesetNotFound unless @changeset
139 raise ChangesetNotFound unless @changeset
140
140
141 respond_to do |format|
141 respond_to do |format|
142 format.html
142 format.html
143 format.js {render :layout => false}
143 format.js {render :layout => false}
144 end
144 end
145 rescue ChangesetNotFound
145 rescue ChangesetNotFound
146 show_error_not_found
146 show_error_not_found
147 end
147 end
148
148
149 def diff
149 def diff
150 if params[:format] == 'diff'
150 if params[:format] == 'diff'
151 @diff = @repository.diff(@path, @rev, @rev_to)
151 @diff = @repository.diff(@path, @rev, @rev_to)
152 show_error_not_found and return unless @diff
152 show_error_not_found and return unless @diff
153 filename = "changeset_r#{@rev}"
153 filename = "changeset_r#{@rev}"
154 filename << "_r#{@rev_to}" if @rev_to
154 filename << "_r#{@rev_to}" if @rev_to
155 send_data @diff.join, :filename => "#{filename}.diff",
155 send_data @diff.join, :filename => "#{filename}.diff",
156 :type => 'text/x-patch',
156 :type => 'text/x-patch',
157 :disposition => 'attachment'
157 :disposition => 'attachment'
158 else
158 else
159 @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline'
159 @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline'
160 @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type)
160 @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type)
161
161
162 # Save diff type as user preference
162 # Save diff type as user preference
163 if User.current.logged? && @diff_type != User.current.pref[:diff_type]
163 if User.current.logged? && @diff_type != User.current.pref[:diff_type]
164 User.current.pref[:diff_type] = @diff_type
164 User.current.pref[:diff_type] = @diff_type
165 User.current.preference.save
165 User.current.preference.save
166 end
166 end
167
167
168 @cache_key = "repositories/diff/#{@repository.id}/" + Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}")
168 @cache_key = "repositories/diff/#{@repository.id}/" + Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}")
169 unless read_fragment(@cache_key)
169 unless read_fragment(@cache_key)
170 @diff = @repository.diff(@path, @rev, @rev_to)
170 @diff = @repository.diff(@path, @rev, @rev_to)
171 show_error_not_found unless @diff
171 show_error_not_found unless @diff
172 end
172 end
173 end
173 end
174 end
174 end
175
175
176 def stats
176 def stats
177 end
177 end
178
178
179 def graph
179 def graph
180 data = nil
180 data = nil
181 case params[:graph]
181 case params[:graph]
182 when "commits_per_month"
182 when "commits_per_month"
183 data = graph_commits_per_month(@repository)
183 data = graph_commits_per_month(@repository)
184 when "commits_per_author"
184 when "commits_per_author"
185 data = graph_commits_per_author(@repository)
185 data = graph_commits_per_author(@repository)
186 end
186 end
187 if data
187 if data
188 headers["Content-Type"] = "image/svg+xml"
188 headers["Content-Type"] = "image/svg+xml"
189 send_data(data, :type => "image/svg+xml", :disposition => "inline")
189 send_data(data, :type => "image/svg+xml", :disposition => "inline")
190 else
190 else
191 render_404
191 render_404
192 end
192 end
193 end
193 end
194
194
195 private
195 private
196 def find_project
196 def find_project
197 @project = Project.find(params[:id])
197 @project = Project.find(params[:id])
198 rescue ActiveRecord::RecordNotFound
198 rescue ActiveRecord::RecordNotFound
199 render_404
199 render_404
200 end
200 end
201
201
202 REV_PARAM_RE = %r{^[a-f0-9]*$}
202 REV_PARAM_RE = %r{^[a-f0-9]*$}
203
203
204 def find_repository
204 def find_repository
205 @project = Project.find(params[:id])
205 @project = Project.find(params[:id])
206 @repository = @project.repository
206 @repository = @project.repository
207 render_404 and return false unless @repository
207 render_404 and return false unless @repository
208 @path = params[:path].join('/') unless params[:path].nil?
208 @path = params[:path].join('/') unless params[:path].nil?
209 @path ||= ''
209 @path ||= ''
210 @rev = params[:rev]
210 @rev = params[:rev]
211 @rev_to = params[:rev_to]
211 @rev_to = params[:rev_to]
212 raise InvalidRevisionParam unless @rev.to_s.match(REV_PARAM_RE) && @rev.to_s.match(REV_PARAM_RE)
212 raise InvalidRevisionParam unless @rev.to_s.match(REV_PARAM_RE) && @rev.to_s.match(REV_PARAM_RE)
213 rescue ActiveRecord::RecordNotFound
213 rescue ActiveRecord::RecordNotFound
214 render_404
214 render_404
215 rescue InvalidRevisionParam
215 rescue InvalidRevisionParam
216 show_error_not_found
216 show_error_not_found
217 end
217 end
218
218
219 def show_error_not_found
219 def show_error_not_found
220 render_error l(:error_scm_not_found)
220 render_error l(:error_scm_not_found)
221 end
221 end
222
222
223 # Handler for Redmine::Scm::Adapters::CommandFailed exception
223 # Handler for Redmine::Scm::Adapters::CommandFailed exception
224 def show_error_command_failed(exception)
224 def show_error_command_failed(exception)
225 render_error l(:error_scm_command_failed, exception.message)
225 render_error l(:error_scm_command_failed, exception.message)
226 end
226 end
227
227
228 def graph_commits_per_month(repository)
228 def graph_commits_per_month(repository)
229 @date_to = Date.today
229 @date_to = Date.today
230 @date_from = @date_to << 11
230 @date_from = @date_to << 11
231 @date_from = Date.civil(@date_from.year, @date_from.month, 1)
231 @date_from = Date.civil(@date_from.year, @date_from.month, 1)
232 commits_by_day = repository.changesets.count(:all, :group => :commit_date, :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
232 commits_by_day = repository.changesets.count(:all, :group => :commit_date, :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
233 commits_by_month = [0] * 12
233 commits_by_month = [0] * 12
234 commits_by_day.each {|c| commits_by_month[c.first.to_date.months_ago] += c.last }
234 commits_by_day.each {|c| commits_by_month[c.first.to_date.months_ago] += c.last }
235
235
236 changes_by_day = repository.changes.count(:all, :group => :commit_date, :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
236 changes_by_day = repository.changes.count(:all, :group => :commit_date, :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
237 changes_by_month = [0] * 12
237 changes_by_month = [0] * 12
238 changes_by_day.each {|c| changes_by_month[c.first.to_date.months_ago] += c.last }
238 changes_by_day.each {|c| changes_by_month[c.first.to_date.months_ago] += c.last }
239
239
240 fields = []
240 fields = []
241 12.times {|m| fields << month_name(((Date.today.month - 1 - m) % 12) + 1)}
241 12.times {|m| fields << month_name(((Date.today.month - 1 - m) % 12) + 1)}
242
242
243 graph = SVG::Graph::Bar.new(
243 graph = SVG::Graph::Bar.new(
244 :height => 300,
244 :height => 300,
245 :width => 800,
245 :width => 800,
246 :fields => fields.reverse,
246 :fields => fields.reverse,
247 :stack => :side,
247 :stack => :side,
248 :scale_integers => true,
248 :scale_integers => true,
249 :step_x_labels => 2,
249 :step_x_labels => 2,
250 :show_data_values => false,
250 :show_data_values => false,
251 :graph_title => l(:label_commits_per_month),
251 :graph_title => l(:label_commits_per_month),
252 :show_graph_title => true
252 :show_graph_title => true
253 )
253 )
254
254
255 graph.add_data(
255 graph.add_data(
256 :data => commits_by_month[0..11].reverse,
256 :data => commits_by_month[0..11].reverse,
257 :title => l(:label_revision_plural)
257 :title => l(:label_revision_plural)
258 )
258 )
259
259
260 graph.add_data(
260 graph.add_data(
261 :data => changes_by_month[0..11].reverse,
261 :data => changes_by_month[0..11].reverse,
262 :title => l(:label_change_plural)
262 :title => l(:label_change_plural)
263 )
263 )
264
264
265 graph.burn
265 graph.burn
266 end
266 end
267
267
268 def graph_commits_per_author(repository)
268 def graph_commits_per_author(repository)
269 commits_by_author = repository.changesets.count(:all, :group => :committer)
269 commits_by_author = repository.changesets.count(:all, :group => :committer)
270 commits_by_author.sort! {|x, y| x.last <=> y.last}
270 commits_by_author.sort! {|x, y| x.last <=> y.last}
271
271
272 changes_by_author = repository.changes.count(:all, :group => :committer)
272 changes_by_author = repository.changes.count(:all, :group => :committer)
273 h = changes_by_author.inject({}) {|o, i| o[i.first] = i.last; o}
273 h = changes_by_author.inject({}) {|o, i| o[i.first] = i.last; o}
274
274
275 fields = commits_by_author.collect {|r| r.first}
275 fields = commits_by_author.collect {|r| r.first}
276 commits_data = commits_by_author.collect {|r| r.last}
276 commits_data = commits_by_author.collect {|r| r.last}
277 changes_data = commits_by_author.collect {|r| h[r.first] || 0}
277 changes_data = commits_by_author.collect {|r| h[r.first] || 0}
278
278
279 fields = fields + [""]*(10 - fields.length) if fields.length<10
279 fields = fields + [""]*(10 - fields.length) if fields.length<10
280 commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10
280 commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10
281 changes_data = changes_data + [0]*(10 - changes_data.length) if changes_data.length<10
281 changes_data = changes_data + [0]*(10 - changes_data.length) if changes_data.length<10
282
282
283 # Remove email adress in usernames
283 # Remove email adress in usernames
284 fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') }
284 fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') }
285
285
286 graph = SVG::Graph::BarHorizontal.new(
286 graph = SVG::Graph::BarHorizontal.new(
287 :height => 400,
287 :height => 400,
288 :width => 800,
288 :width => 800,
289 :fields => fields,
289 :fields => fields,
290 :stack => :side,
290 :stack => :side,
291 :scale_integers => true,
291 :scale_integers => true,
292 :show_data_values => false,
292 :show_data_values => false,
293 :rotate_y_labels => false,
293 :rotate_y_labels => false,
294 :graph_title => l(:label_commits_per_author),
294 :graph_title => l(:label_commits_per_author),
295 :show_graph_title => true
295 :show_graph_title => true
296 )
296 )
297
297
298 graph.add_data(
298 graph.add_data(
299 :data => commits_data,
299 :data => commits_data,
300 :title => l(:label_revision_plural)
300 :title => l(:label_revision_plural)
301 )
301 )
302
302
303 graph.add_data(
303 graph.add_data(
304 :data => changes_data,
304 :data => changes_data,
305 :title => l(:label_change_plural)
305 :title => l(:label_change_plural)
306 )
306 )
307
307
308 graph.burn
308 graph.burn
309 end
309 end
310
310
311 end
311 end
312
312
313 class Date
313 class Date
314 def months_ago(date = Date.today)
314 def months_ago(date = Date.today)
315 (date.year - self.year)*12 + (date.month - self.month)
315 (date.year - self.year)*12 + (date.month - self.month)
316 end
316 end
317
317
318 def weeks_ago(date = Date.today)
318 def weeks_ago(date = Date.today)
319 (date.year - self.year)*52 + (date.cweek - self.cweek)
319 (date.year - self.year)*52 + (date.cweek - self.cweek)
320 end
320 end
321 end
321 end
322
322
323 class String
323 class String
324 def with_leading_slash
324 def with_leading_slash
325 starts_with?('/') ? self : "/#{self}"
325 starts_with?('/') ? self : "/#{self}"
326 end
326 end
327 end
327 end
@@ -1,181 +1,193
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.dirname(__FILE__) + '/../test_helper'
18 require File.dirname(__FILE__) + '/../test_helper'
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 < Test::Unit::TestCase
24 class RepositoriesSubversionControllerTest < Test::Unit::TestCase
25 fixtures :projects, :users, :roles, :members, :enabled_modules,
25 fixtures :projects, :users, :roles, :members, :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 # No '..' in the repository path for svn
29 # No '..' in the repository path for svn
30 REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/subversion_repository'
30 REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/subversion_repository'
31
31
32 def setup
32 def setup
33 @controller = RepositoriesController.new
33 @controller = RepositoriesController.new
34 @request = ActionController::TestRequest.new
34 @request = ActionController::TestRequest.new
35 @response = ActionController::TestResponse.new
35 @response = ActionController::TestResponse.new
36 Setting.default_language = 'en'
36 Setting.default_language = 'en'
37 User.current = nil
37 User.current = nil
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 => 1
42 get :show, :id => 1
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 :browse, :id => 1
50 get :browse, :id => 1
51 assert_response :success
51 assert_response :success
52 assert_template 'browse'
52 assert_template 'browse'
53 assert_not_nil assigns(:entries)
53 assert_not_nil assigns(:entries)
54 entry = assigns(:entries).detect {|e| e.name == 'subversion_test'}
54 entry = assigns(:entries).detect {|e| e.name == 'subversion_test'}
55 assert_equal 'dir', entry.kind
55 assert_equal 'dir', entry.kind
56 end
56 end
57
57
58 def test_browse_directory
58 def test_browse_directory
59 get :browse, :id => 1, :path => ['subversion_test']
59 get :browse, :id => 1, :path => ['subversion_test']
60 assert_response :success
60 assert_response :success
61 assert_template 'browse'
61 assert_template 'browse'
62 assert_not_nil assigns(:entries)
62 assert_not_nil assigns(:entries)
63 assert_equal ['folder', '.project', 'helloworld.c', 'textfile.txt'], assigns(:entries).collect(&:name)
63 assert_equal ['folder', '.project', 'helloworld.c', 'textfile.txt'], assigns(:entries).collect(&:name)
64 entry = assigns(:entries).detect {|e| e.name == 'helloworld.c'}
64 entry = assigns(:entries).detect {|e| e.name == 'helloworld.c'}
65 assert_equal 'file', entry.kind
65 assert_equal 'file', entry.kind
66 assert_equal 'subversion_test/helloworld.c', entry.path
66 assert_equal 'subversion_test/helloworld.c', entry.path
67 end
67 end
68
68
69 def test_browse_at_given_revision
69 def test_browse_at_given_revision
70 get :browse, :id => 1, :path => ['subversion_test'], :rev => 4
70 get :browse, :id => 1, :path => ['subversion_test'], :rev => 4
71 assert_response :success
71 assert_response :success
72 assert_template 'browse'
72 assert_template 'browse'
73 assert_not_nil assigns(:entries)
73 assert_not_nil assigns(:entries)
74 assert_equal ['folder', '.project', 'helloworld.c', 'helloworld.rb', 'textfile.txt'], assigns(:entries).collect(&:name)
74 assert_equal ['folder', '.project', 'helloworld.c', 'helloworld.rb', 'textfile.txt'], assigns(:entries).collect(&:name)
75 end
75 end
76
76
77 def test_changes
77 def test_changes
78 get :changes, :id => 1, :path => ['subversion_test', 'folder', 'helloworld.rb' ]
78 get :changes, :id => 1, :path => ['subversion_test', 'folder', 'helloworld.rb' ]
79 assert_response :success
79 assert_response :success
80 assert_template 'changes'
80 assert_template 'changes'
81 # svn properties displayed with svn >= 1.5 only
81 # svn properties displayed with svn >= 1.5 only
82 if Redmine::Scm::Adapters::SubversionAdapter.client_version_above?([1, 5, 0])
82 if Redmine::Scm::Adapters::SubversionAdapter.client_version_above?([1, 5, 0])
83 assert_not_nil assigns(:properties)
83 assert_not_nil assigns(:properties)
84 assert_equal 'native', assigns(:properties)['svn:eol-style']
84 assert_equal 'native', assigns(:properties)['svn:eol-style']
85 assert_tag :ul,
85 assert_tag :ul,
86 :child => { :tag => 'li',
86 :child => { :tag => 'li',
87 :child => { :tag => 'b', :content => 'svn:eol-style' },
87 :child => { :tag => 'b', :content => 'svn:eol-style' },
88 :child => { :tag => 'span', :content => 'native' } }
88 :child => { :tag => 'span', :content => 'native' } }
89 end
89 end
90 end
90 end
91
91
92 def test_entry
92 def test_entry
93 get :entry, :id => 1, :path => ['subversion_test', 'helloworld.c']
93 get :entry, :id => 1, :path => ['subversion_test', 'helloworld.c']
94 assert_response :success
94 assert_response :success
95 assert_template 'entry'
95 assert_template 'entry'
96 end
96 end
97
97
98 def test_entry_should_send_if_too_big
99 # no files in the test repo is larger than 1KB...
100 with_settings :file_max_size_displayed => 0 do
101 get :entry, :id => 1, :path => ['subversion_test', 'helloworld.c']
102 assert_response :success
103 assert_template ''
104 assert_equal 'attachment; filename="helloworld.c"', @response.headers['Content-Disposition']
105 end
106 end
107
98 def test_entry_at_given_revision
108 def test_entry_at_given_revision
99 get :entry, :id => 1, :path => ['subversion_test', 'helloworld.rb'], :rev => 2
109 get :entry, :id => 1, :path => ['subversion_test', 'helloworld.rb'], :rev => 2
100 assert_response :success
110 assert_response :success
101 assert_template 'entry'
111 assert_template 'entry'
102 # this line was removed in r3 and file was moved in r6
112 # this line was removed in r3 and file was moved in r6
103 assert_tag :tag => 'td', :attributes => { :class => /line-code/},
113 assert_tag :tag => 'td', :attributes => { :class => /line-code/},
104 :content => /Here's the code/
114 :content => /Here's the code/
105 end
115 end
106
116
107 def test_entry_not_found
117 def test_entry_not_found
108 get :entry, :id => 1, :path => ['subversion_test', 'zzz.c']
118 get :entry, :id => 1, :path => ['subversion_test', 'zzz.c']
109 assert_tag :tag => 'div', :attributes => { :class => /error/ },
119 assert_tag :tag => 'div', :attributes => { :class => /error/ },
110 :content => /The entry or revision was not found in the repository/
120 :content => /The entry or revision was not found in the repository/
111 end
121 end
112
122
113 def test_entry_download
123 def test_entry_download
114 get :entry, :id => 1, :path => ['subversion_test', 'helloworld.c'], :format => 'raw'
124 get :entry, :id => 1, :path => ['subversion_test', 'helloworld.c'], :format => 'raw'
115 assert_response :success
125 assert_response :success
126 assert_template ''
127 assert_equal 'attachment; filename="helloworld.c"', @response.headers['Content-Disposition']
116 end
128 end
117
129
118 def test_directory_entry
130 def test_directory_entry
119 get :entry, :id => 1, :path => ['subversion_test', 'folder']
131 get :entry, :id => 1, :path => ['subversion_test', 'folder']
120 assert_response :success
132 assert_response :success
121 assert_template 'browse'
133 assert_template 'browse'
122 assert_not_nil assigns(:entry)
134 assert_not_nil assigns(:entry)
123 assert_equal 'folder', assigns(:entry).name
135 assert_equal 'folder', assigns(:entry).name
124 end
136 end
125
137
126 def test_revision
138 def test_revision
127 get :revision, :id => 1, :rev => 2
139 get :revision, :id => 1, :rev => 2
128 assert_response :success
140 assert_response :success
129 assert_template 'revision'
141 assert_template 'revision'
130 assert_tag :tag => 'ul',
142 assert_tag :tag => 'ul',
131 :child => { :tag => 'li',
143 :child => { :tag => 'li',
132 # link to the entry at rev 2
144 # link to the entry at rev 2
133 :child => { :tag => 'a',
145 :child => { :tag => 'a',
134 :attributes => {:href => '/projects/ecookbook/repository/revisions/2/entry/test/some/path/in/the/repo'},
146 :attributes => {:href => '/projects/ecookbook/repository/revisions/2/entry/test/some/path/in/the/repo'},
135 :content => 'repo',
147 :content => 'repo',
136 # link to partial diff
148 # link to partial diff
137 :sibling => { :tag => 'a',
149 :sibling => { :tag => 'a',
138 :attributes => { :href => '/projects/ecookbook/repository/revisions/2/diff/test/some/path/in/the/repo' }
150 :attributes => { :href => '/projects/ecookbook/repository/revisions/2/diff/test/some/path/in/the/repo' }
139 }
151 }
140 }
152 }
141 }
153 }
142 end
154 end
143
155
144 def test_revision_with_repository_pointing_to_a_subdirectory
156 def test_revision_with_repository_pointing_to_a_subdirectory
145 r = Project.find(1).repository
157 r = Project.find(1).repository
146 # Changes repository url to a subdirectory
158 # Changes repository url to a subdirectory
147 r.update_attribute :url, (r.url + '/test/some')
159 r.update_attribute :url, (r.url + '/test/some')
148
160
149 get :revision, :id => 1, :rev => 2
161 get :revision, :id => 1, :rev => 2
150 assert_response :success
162 assert_response :success
151 assert_template 'revision'
163 assert_template 'revision'
152 assert_tag :tag => 'ul',
164 assert_tag :tag => 'ul',
153 :child => { :tag => 'li',
165 :child => { :tag => 'li',
154 # link to the entry at rev 2
166 # link to the entry at rev 2
155 :child => { :tag => 'a',
167 :child => { :tag => 'a',
156 :attributes => {:href => '/projects/ecookbook/repository/revisions/2/entry/path/in/the/repo'},
168 :attributes => {:href => '/projects/ecookbook/repository/revisions/2/entry/path/in/the/repo'},
157 :content => 'repo',
169 :content => 'repo',
158 # link to partial diff
170 # link to partial diff
159 :sibling => { :tag => 'a',
171 :sibling => { :tag => 'a',
160 :attributes => { :href => '/projects/ecookbook/repository/revisions/2/diff/path/in/the/repo' }
172 :attributes => { :href => '/projects/ecookbook/repository/revisions/2/diff/path/in/the/repo' }
161 }
173 }
162 }
174 }
163 }
175 }
164 end
176 end
165
177
166 def test_diff
178 def test_diff
167 get :diff, :id => 1, :rev => 3
179 get :diff, :id => 1, :rev => 3
168 assert_response :success
180 assert_response :success
169 assert_template 'diff'
181 assert_template 'diff'
170 end
182 end
171
183
172 def test_annotate
184 def test_annotate
173 get :annotate, :id => 1, :path => ['subversion_test', 'helloworld.c']
185 get :annotate, :id => 1, :path => ['subversion_test', 'helloworld.c']
174 assert_response :success
186 assert_response :success
175 assert_template 'annotate'
187 assert_template 'annotate'
176 end
188 end
177 else
189 else
178 puts "Subversion test repository NOT FOUND. Skipping functional tests !!!"
190 puts "Subversion test repository NOT FOUND. Skipping functional tests !!!"
179 def test_fake; assert true end
191 def test_fake; assert true end
180 end
192 end
181 end
193 end
@@ -1,67 +1,74
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 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 ENV["RAILS_ENV"] ||= "test"
18 ENV["RAILS_ENV"] ||= "test"
19 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
19 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
20 require 'test_help'
20 require 'test_help'
21 require File.expand_path(File.dirname(__FILE__) + '/helper_testcase')
21 require File.expand_path(File.dirname(__FILE__) + '/helper_testcase')
22 require File.join(RAILS_ROOT,'test', 'mocks', 'open_id_authentication_mock.rb')
22 require File.join(RAILS_ROOT,'test', 'mocks', 'open_id_authentication_mock.rb')
23
23
24 class Test::Unit::TestCase
24 class Test::Unit::TestCase
25 # Transactional fixtures accelerate your tests by wrapping each test method
25 # Transactional fixtures accelerate your tests by wrapping each test method
26 # in a transaction that's rolled back on completion. This ensures that the
26 # in a transaction that's rolled back on completion. This ensures that the
27 # test database remains unchanged so your fixtures don't have to be reloaded
27 # test database remains unchanged so your fixtures don't have to be reloaded
28 # between every test method. Fewer database queries means faster tests.
28 # between every test method. Fewer database queries means faster tests.
29 #
29 #
30 # Read Mike Clark's excellent walkthrough at
30 # Read Mike Clark's excellent walkthrough at
31 # http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
31 # http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
32 #
32 #
33 # Every Active Record database supports transactions except MyISAM tables
33 # Every Active Record database supports transactions except MyISAM tables
34 # in MySQL. Turn off transactional fixtures in this case; however, if you
34 # in MySQL. Turn off transactional fixtures in this case; however, if you
35 # don't care one way or the other, switching from MyISAM to InnoDB tables
35 # don't care one way or the other, switching from MyISAM to InnoDB tables
36 # is recommended.
36 # is recommended.
37 self.use_transactional_fixtures = true
37 self.use_transactional_fixtures = true
38
38
39 # Instantiated fixtures are slow, but give you @david where otherwise you
39 # Instantiated fixtures are slow, but give you @david where otherwise you
40 # would need people(:david). If you don't want to migrate your existing
40 # would need people(:david). If you don't want to migrate your existing
41 # test cases which use the @david style and don't mind the speed hit (each
41 # test cases which use the @david style and don't mind the speed hit (each
42 # instantiated fixtures translates to a database query per test method),
42 # instantiated fixtures translates to a database query per test method),
43 # then set this back to true.
43 # then set this back to true.
44 self.use_instantiated_fixtures = false
44 self.use_instantiated_fixtures = false
45
45
46 # Add more helper methods to be used by all tests here...
46 # Add more helper methods to be used by all tests here...
47
47
48 def log_user(login, password)
48 def log_user(login, password)
49 get "/login"
49 get "/login"
50 assert_equal nil, session[:user_id]
50 assert_equal nil, session[:user_id]
51 assert_response :success
51 assert_response :success
52 assert_template "account/login"
52 assert_template "account/login"
53 post "/login", :username => login, :password => password
53 post "/login", :username => login, :password => password
54 assert_equal login, User.find(session[:user_id]).login
54 assert_equal login, User.find(session[:user_id]).login
55 end
55 end
56
56
57 def test_uploaded_file(name, mime)
57 def test_uploaded_file(name, mime)
58 ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + "/files/#{name}", mime)
58 ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + "/files/#{name}", mime)
59 end
59 end
60
60
61 # Use a temporary directory for attachment related tests
61 # Use a temporary directory for attachment related tests
62 def set_tmp_attachments_directory
62 def set_tmp_attachments_directory
63 Dir.mkdir "#{RAILS_ROOT}/tmp/test" unless File.directory?("#{RAILS_ROOT}/tmp/test")
63 Dir.mkdir "#{RAILS_ROOT}/tmp/test" unless File.directory?("#{RAILS_ROOT}/tmp/test")
64 Dir.mkdir "#{RAILS_ROOT}/tmp/test/attachments" unless File.directory?("#{RAILS_ROOT}/tmp/test/attachments")
64 Dir.mkdir "#{RAILS_ROOT}/tmp/test/attachments" unless File.directory?("#{RAILS_ROOT}/tmp/test/attachments")
65 Attachment.storage_path = "#{RAILS_ROOT}/tmp/test/attachments"
65 Attachment.storage_path = "#{RAILS_ROOT}/tmp/test/attachments"
66 end
66 end
67
68 def with_settings(options, &block)
69 saved_settings = options.keys.inject({}) {|h, k| h[k] = Setting[k].dup; h}
70 options.each {|k, v| Setting[k] = v}
71 yield
72 saved_settings.each {|k, v| Setting[k] = v}
73 end
67 end
74 end
General Comments 0
You need to be logged in to leave comments. Login now