##// END OF EJS Templates
Show repository images inline when clicking 'View' (#10362)....
Jean-Philippe Lang -
r9593:234e5d59acf4
parent child
Show More
@@ -1,457 +1,458
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 require 'redmine/scm/adapters/abstract_adapter'
21 require 'redmine/scm/adapters/abstract_adapter'
22
22
23 class ChangesetNotFound < Exception; end
23 class ChangesetNotFound < Exception; end
24 class InvalidRevisionParam < Exception; end
24 class InvalidRevisionParam < Exception; end
25
25
26 class RepositoriesController < ApplicationController
26 class RepositoriesController < ApplicationController
27 menu_item :repository
27 menu_item :repository
28 menu_item :settings, :only => [:new, :create, :edit, :update, :destroy, :committers]
28 menu_item :settings, :only => [:new, :create, :edit, :update, :destroy, :committers]
29 default_search_scope :changesets
29 default_search_scope :changesets
30
30
31 before_filter :find_project_by_project_id, :only => [:new, :create]
31 before_filter :find_project_by_project_id, :only => [:new, :create]
32 before_filter :find_repository, :only => [:edit, :update, :destroy, :committers]
32 before_filter :find_repository, :only => [:edit, :update, :destroy, :committers]
33 before_filter :find_project_repository, :except => [:new, :create, :edit, :update, :destroy, :committers]
33 before_filter :find_project_repository, :except => [:new, :create, :edit, :update, :destroy, :committers]
34 before_filter :find_changeset, :only => [:revision, :add_related_issue, :remove_related_issue]
34 before_filter :find_changeset, :only => [:revision, :add_related_issue, :remove_related_issue]
35 before_filter :authorize
35 before_filter :authorize
36 accept_rss_auth :revisions
36 accept_rss_auth :revisions
37
37
38 rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed
38 rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed
39
39
40 def new
40 def new
41 scm = params[:repository_scm] || (Redmine::Scm::Base.all & Setting.enabled_scm).first
41 scm = params[:repository_scm] || (Redmine::Scm::Base.all & Setting.enabled_scm).first
42 @repository = Repository.factory(scm)
42 @repository = Repository.factory(scm)
43 @repository.is_default = @project.repository.nil?
43 @repository.is_default = @project.repository.nil?
44 @repository.project = @project
44 @repository.project = @project
45 render :layout => !request.xhr?
45 render :layout => !request.xhr?
46 end
46 end
47
47
48 def create
48 def create
49 attrs = pickup_extra_info
49 attrs = pickup_extra_info
50 @repository = Repository.factory(params[:repository_scm], attrs[:attrs])
50 @repository = Repository.factory(params[:repository_scm], attrs[:attrs])
51 if attrs[:attrs_extra].keys.any?
51 if attrs[:attrs_extra].keys.any?
52 @repository.merge_extra_info(attrs[:attrs_extra])
52 @repository.merge_extra_info(attrs[:attrs_extra])
53 end
53 end
54 @repository.project = @project
54 @repository.project = @project
55 if request.post? && @repository.save
55 if request.post? && @repository.save
56 redirect_to settings_project_path(@project, :tab => 'repositories')
56 redirect_to settings_project_path(@project, :tab => 'repositories')
57 else
57 else
58 render :action => 'new'
58 render :action => 'new'
59 end
59 end
60 end
60 end
61
61
62 def edit
62 def edit
63 end
63 end
64
64
65 def update
65 def update
66 attrs = pickup_extra_info
66 attrs = pickup_extra_info
67 @repository.attributes = attrs[:attrs]
67 @repository.attributes = attrs[:attrs]
68 if attrs[:attrs_extra].keys.any?
68 if attrs[:attrs_extra].keys.any?
69 @repository.merge_extra_info(attrs[:attrs_extra])
69 @repository.merge_extra_info(attrs[:attrs_extra])
70 end
70 end
71 @repository.project = @project
71 @repository.project = @project
72 if request.put? && @repository.save
72 if request.put? && @repository.save
73 redirect_to settings_project_path(@project, :tab => 'repositories')
73 redirect_to settings_project_path(@project, :tab => 'repositories')
74 else
74 else
75 render :action => 'edit'
75 render :action => 'edit'
76 end
76 end
77 end
77 end
78
78
79 def pickup_extra_info
79 def pickup_extra_info
80 p = {}
80 p = {}
81 p_extra = {}
81 p_extra = {}
82 params[:repository].each do |k, v|
82 params[:repository].each do |k, v|
83 if k =~ /^extra_/
83 if k =~ /^extra_/
84 p_extra[k] = v
84 p_extra[k] = v
85 else
85 else
86 p[k] = v
86 p[k] = v
87 end
87 end
88 end
88 end
89 {:attrs => p, :attrs_extra => p_extra}
89 {:attrs => p, :attrs_extra => p_extra}
90 end
90 end
91 private :pickup_extra_info
91 private :pickup_extra_info
92
92
93 def committers
93 def committers
94 @committers = @repository.committers
94 @committers = @repository.committers
95 @users = @project.users
95 @users = @project.users
96 additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id)
96 additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id)
97 @users += User.find_all_by_id(additional_user_ids) unless additional_user_ids.empty?
97 @users += User.find_all_by_id(additional_user_ids) unless additional_user_ids.empty?
98 @users.compact!
98 @users.compact!
99 @users.sort!
99 @users.sort!
100 if request.post? && params[:committers].is_a?(Hash)
100 if request.post? && params[:committers].is_a?(Hash)
101 # Build a hash with repository usernames as keys and corresponding user ids as values
101 # Build a hash with repository usernames as keys and corresponding user ids as values
102 @repository.committer_ids = params[:committers].values.inject({}) {|h, c| h[c.first] = c.last; h}
102 @repository.committer_ids = params[:committers].values.inject({}) {|h, c| h[c.first] = c.last; h}
103 flash[:notice] = l(:notice_successful_update)
103 flash[:notice] = l(:notice_successful_update)
104 redirect_to settings_project_path(@project, :tab => 'repositories')
104 redirect_to settings_project_path(@project, :tab => 'repositories')
105 end
105 end
106 end
106 end
107
107
108 def destroy
108 def destroy
109 @repository.destroy if request.delete?
109 @repository.destroy if request.delete?
110 redirect_to settings_project_path(@project, :tab => 'repositories')
110 redirect_to settings_project_path(@project, :tab => 'repositories')
111 end
111 end
112
112
113 def show
113 def show
114 @repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty?
114 @repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty?
115
115
116 @entries = @repository.entries(@path, @rev)
116 @entries = @repository.entries(@path, @rev)
117 @changeset = @repository.find_changeset_by_name(@rev)
117 @changeset = @repository.find_changeset_by_name(@rev)
118 if request.xhr?
118 if request.xhr?
119 @entries ? render(:partial => 'dir_list_content') : render(:nothing => true)
119 @entries ? render(:partial => 'dir_list_content') : render(:nothing => true)
120 else
120 else
121 (show_error_not_found; return) unless @entries
121 (show_error_not_found; return) unless @entries
122 @changesets = @repository.latest_changesets(@path, @rev)
122 @changesets = @repository.latest_changesets(@path, @rev)
123 @properties = @repository.properties(@path, @rev)
123 @properties = @repository.properties(@path, @rev)
124 @repositories = @project.repositories
124 @repositories = @project.repositories
125 render :action => 'show'
125 render :action => 'show'
126 end
126 end
127 end
127 end
128
128
129 alias_method :browse, :show
129 alias_method :browse, :show
130
130
131 def changes
131 def changes
132 @entry = @repository.entry(@path, @rev)
132 @entry = @repository.entry(@path, @rev)
133 (show_error_not_found; return) unless @entry
133 (show_error_not_found; return) unless @entry
134 @changesets = @repository.latest_changesets(@path, @rev, Setting.repository_log_display_limit.to_i)
134 @changesets = @repository.latest_changesets(@path, @rev, Setting.repository_log_display_limit.to_i)
135 @properties = @repository.properties(@path, @rev)
135 @properties = @repository.properties(@path, @rev)
136 @changeset = @repository.find_changeset_by_name(@rev)
136 @changeset = @repository.find_changeset_by_name(@rev)
137 end
137 end
138
138
139 def revisions
139 def revisions
140 @changeset_count = @repository.changesets.count
140 @changeset_count = @repository.changesets.count
141 @changeset_pages = Paginator.new self, @changeset_count,
141 @changeset_pages = Paginator.new self, @changeset_count,
142 per_page_option,
142 per_page_option,
143 params['page']
143 params['page']
144 @changesets = @repository.changesets.find(:all,
144 @changesets = @repository.changesets.find(:all,
145 :limit => @changeset_pages.items_per_page,
145 :limit => @changeset_pages.items_per_page,
146 :offset => @changeset_pages.current.offset,
146 :offset => @changeset_pages.current.offset,
147 :include => [:user, :repository, :parents])
147 :include => [:user, :repository, :parents])
148
148
149 respond_to do |format|
149 respond_to do |format|
150 format.html { render :layout => false if request.xhr? }
150 format.html { render :layout => false if request.xhr? }
151 format.atom { render_feed(@changesets, :title => "#{@project.name}: #{l(:label_revision_plural)}") }
151 format.atom { render_feed(@changesets, :title => "#{@project.name}: #{l(:label_revision_plural)}") }
152 end
152 end
153 end
153 end
154
154
155 def raw
155 def raw
156 entry_and_raw(true)
156 entry_and_raw(true)
157 end
157 end
158
158
159 def entry
159 def entry
160 entry_and_raw(false)
160 entry_and_raw(false)
161 end
161 end
162
162
163 def entry_and_raw(is_raw)
163 def entry_and_raw(is_raw)
164 @entry = @repository.entry(@path, @rev)
164 @entry = @repository.entry(@path, @rev)
165 (show_error_not_found; return) unless @entry
165 (show_error_not_found; return) unless @entry
166
166
167 # If the entry is a dir, show the browser
167 # If the entry is a dir, show the browser
168 (show; return) if @entry.is_dir?
168 (show; return) if @entry.is_dir?
169
169
170 @content = @repository.cat(@path, @rev)
170 @content = @repository.cat(@path, @rev)
171 (show_error_not_found; return) unless @content
171 (show_error_not_found; return) unless @content
172 if is_raw ||
172 if is_raw ||
173 (@content.size && @content.size > Setting.file_max_size_displayed.to_i.kilobyte) ||
173 (@content.size && @content.size > Setting.file_max_size_displayed.to_i.kilobyte) ||
174 ! is_entry_text_data?(@content, @path)
174 ! is_entry_text_data?(@content, @path)
175 # Force the download
175 # Force the download
176 send_opt = { :filename => filename_for_content_disposition(@path.split('/').last) }
176 send_opt = { :filename => filename_for_content_disposition(@path.split('/').last) }
177 send_type = Redmine::MimeType.of(@path)
177 send_type = Redmine::MimeType.of(@path)
178 send_opt[:type] = send_type.to_s if send_type
178 send_opt[:type] = send_type.to_s if send_type
179 send_opt[:disposition] = (Redmine::MimeType.is_type?('image', @path) && !is_raw ? 'inline' : 'attachment')
179 send_data @content, send_opt
180 send_data @content, send_opt
180 else
181 else
181 # Prevent empty lines when displaying a file with Windows style eol
182 # Prevent empty lines when displaying a file with Windows style eol
182 # TODO: UTF-16
183 # TODO: UTF-16
183 # Is this needs? AttachmentsController reads file simply.
184 # Is this needs? AttachmentsController reads file simply.
184 @content.gsub!("\r\n", "\n")
185 @content.gsub!("\r\n", "\n")
185 @changeset = @repository.find_changeset_by_name(@rev)
186 @changeset = @repository.find_changeset_by_name(@rev)
186 end
187 end
187 end
188 end
188 private :entry_and_raw
189 private :entry_and_raw
189
190
190 def is_entry_text_data?(ent, path)
191 def is_entry_text_data?(ent, path)
191 # UTF-16 contains "\x00".
192 # UTF-16 contains "\x00".
192 # It is very strict that file contains less than 30% of ascii symbols
193 # It is very strict that file contains less than 30% of ascii symbols
193 # in non Western Europe.
194 # in non Western Europe.
194 return true if Redmine::MimeType.is_type?('text', path)
195 return true if Redmine::MimeType.is_type?('text', path)
195 # Ruby 1.8.6 has a bug of integer divisions.
196 # Ruby 1.8.6 has a bug of integer divisions.
196 # http://apidock.com/ruby/v1_8_6_287/String/is_binary_data%3F
197 # http://apidock.com/ruby/v1_8_6_287/String/is_binary_data%3F
197 return false if ent.is_binary_data?
198 return false if ent.is_binary_data?
198 true
199 true
199 end
200 end
200 private :is_entry_text_data?
201 private :is_entry_text_data?
201
202
202 def annotate
203 def annotate
203 @entry = @repository.entry(@path, @rev)
204 @entry = @repository.entry(@path, @rev)
204 (show_error_not_found; return) unless @entry
205 (show_error_not_found; return) unless @entry
205
206
206 @annotate = @repository.scm.annotate(@path, @rev)
207 @annotate = @repository.scm.annotate(@path, @rev)
207 if @annotate.nil? || @annotate.empty?
208 if @annotate.nil? || @annotate.empty?
208 (render_error l(:error_scm_annotate); return)
209 (render_error l(:error_scm_annotate); return)
209 end
210 end
210 ann_buf_size = 0
211 ann_buf_size = 0
211 @annotate.lines.each do |buf|
212 @annotate.lines.each do |buf|
212 ann_buf_size += buf.size
213 ann_buf_size += buf.size
213 end
214 end
214 if ann_buf_size > Setting.file_max_size_displayed.to_i.kilobyte
215 if ann_buf_size > Setting.file_max_size_displayed.to_i.kilobyte
215 (render_error l(:error_scm_annotate_big_text_file); return)
216 (render_error l(:error_scm_annotate_big_text_file); return)
216 end
217 end
217 @changeset = @repository.find_changeset_by_name(@rev)
218 @changeset = @repository.find_changeset_by_name(@rev)
218 end
219 end
219
220
220 def revision
221 def revision
221 respond_to do |format|
222 respond_to do |format|
222 format.html
223 format.html
223 format.js {render :layout => false}
224 format.js {render :layout => false}
224 end
225 end
225 end
226 end
226
227
227 # Adds a related issue to a changeset
228 # Adds a related issue to a changeset
228 # POST /projects/:project_id/repository/(:repository_id/)revisions/:rev/issues
229 # POST /projects/:project_id/repository/(:repository_id/)revisions/:rev/issues
229 def add_related_issue
230 def add_related_issue
230 @issue = @changeset.find_referenced_issue_by_id(params[:issue_id])
231 @issue = @changeset.find_referenced_issue_by_id(params[:issue_id])
231 if @issue && (!@issue.visible? || @changeset.issues.include?(@issue))
232 if @issue && (!@issue.visible? || @changeset.issues.include?(@issue))
232 @issue = nil
233 @issue = nil
233 end
234 end
234
235
235 if @issue
236 if @issue
236 @changeset.issues << @issue
237 @changeset.issues << @issue
237 respond_to do |format|
238 respond_to do |format|
238 format.js {
239 format.js {
239 render :update do |page|
240 render :update do |page|
240 page.replace_html "related-issues", :partial => "related_issues"
241 page.replace_html "related-issues", :partial => "related_issues"
241 page.visual_effect :highlight, "related-issue-#{@issue.id}"
242 page.visual_effect :highlight, "related-issue-#{@issue.id}"
242 end
243 end
243 }
244 }
244 end
245 end
245 else
246 else
246 respond_to do |format|
247 respond_to do |format|
247 format.js {
248 format.js {
248 render :update do |page|
249 render :update do |page|
249 page.alert(l(:label_issue) + ' ' + l('activerecord.errors.messages.invalid'))
250 page.alert(l(:label_issue) + ' ' + l('activerecord.errors.messages.invalid'))
250 end
251 end
251 }
252 }
252 end
253 end
253 end
254 end
254 end
255 end
255
256
256 # Removes a related issue from a changeset
257 # Removes a related issue from a changeset
257 # DELETE /projects/:project_id/repository/(:repository_id/)revisions/:rev/issues/:issue_id
258 # DELETE /projects/:project_id/repository/(:repository_id/)revisions/:rev/issues/:issue_id
258 def remove_related_issue
259 def remove_related_issue
259 @issue = Issue.visible.find_by_id(params[:issue_id])
260 @issue = Issue.visible.find_by_id(params[:issue_id])
260 if @issue
261 if @issue
261 @changeset.issues.delete(@issue)
262 @changeset.issues.delete(@issue)
262 end
263 end
263
264
264 respond_to do |format|
265 respond_to do |format|
265 format.js {
266 format.js {
266 render :update do |page|
267 render :update do |page|
267 page.remove "related-issue-#{@issue.id}"
268 page.remove "related-issue-#{@issue.id}"
268 end if @issue
269 end if @issue
269 }
270 }
270 end
271 end
271 end
272 end
272
273
273 def diff
274 def diff
274 if params[:format] == 'diff'
275 if params[:format] == 'diff'
275 @diff = @repository.diff(@path, @rev, @rev_to)
276 @diff = @repository.diff(@path, @rev, @rev_to)
276 (show_error_not_found; return) unless @diff
277 (show_error_not_found; return) unless @diff
277 filename = "changeset_r#{@rev}"
278 filename = "changeset_r#{@rev}"
278 filename << "_r#{@rev_to}" if @rev_to
279 filename << "_r#{@rev_to}" if @rev_to
279 send_data @diff.join, :filename => "#{filename}.diff",
280 send_data @diff.join, :filename => "#{filename}.diff",
280 :type => 'text/x-patch',
281 :type => 'text/x-patch',
281 :disposition => 'attachment'
282 :disposition => 'attachment'
282 else
283 else
283 @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline'
284 @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline'
284 @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type)
285 @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type)
285
286
286 # Save diff type as user preference
287 # Save diff type as user preference
287 if User.current.logged? && @diff_type != User.current.pref[:diff_type]
288 if User.current.logged? && @diff_type != User.current.pref[:diff_type]
288 User.current.pref[:diff_type] = @diff_type
289 User.current.pref[:diff_type] = @diff_type
289 User.current.preference.save
290 User.current.preference.save
290 end
291 end
291 @cache_key = "repositories/diff/#{@repository.id}/" +
292 @cache_key = "repositories/diff/#{@repository.id}/" +
292 Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}-#{current_language}")
293 Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}-#{current_language}")
293 unless read_fragment(@cache_key)
294 unless read_fragment(@cache_key)
294 @diff = @repository.diff(@path, @rev, @rev_to)
295 @diff = @repository.diff(@path, @rev, @rev_to)
295 show_error_not_found unless @diff
296 show_error_not_found unless @diff
296 end
297 end
297
298
298 @changeset = @repository.find_changeset_by_name(@rev)
299 @changeset = @repository.find_changeset_by_name(@rev)
299 @changeset_to = @rev_to ? @repository.find_changeset_by_name(@rev_to) : nil
300 @changeset_to = @rev_to ? @repository.find_changeset_by_name(@rev_to) : nil
300 @diff_format_revisions = @repository.diff_format_revisions(@changeset, @changeset_to)
301 @diff_format_revisions = @repository.diff_format_revisions(@changeset, @changeset_to)
301 end
302 end
302 end
303 end
303
304
304 def stats
305 def stats
305 end
306 end
306
307
307 def graph
308 def graph
308 data = nil
309 data = nil
309 case params[:graph]
310 case params[:graph]
310 when "commits_per_month"
311 when "commits_per_month"
311 data = graph_commits_per_month(@repository)
312 data = graph_commits_per_month(@repository)
312 when "commits_per_author"
313 when "commits_per_author"
313 data = graph_commits_per_author(@repository)
314 data = graph_commits_per_author(@repository)
314 end
315 end
315 if data
316 if data
316 headers["Content-Type"] = "image/svg+xml"
317 headers["Content-Type"] = "image/svg+xml"
317 send_data(data, :type => "image/svg+xml", :disposition => "inline")
318 send_data(data, :type => "image/svg+xml", :disposition => "inline")
318 else
319 else
319 render_404
320 render_404
320 end
321 end
321 end
322 end
322
323
323 private
324 private
324
325
325 def find_repository
326 def find_repository
326 @repository = Repository.find(params[:id])
327 @repository = Repository.find(params[:id])
327 @project = @repository.project
328 @project = @repository.project
328 rescue ActiveRecord::RecordNotFound
329 rescue ActiveRecord::RecordNotFound
329 render_404
330 render_404
330 end
331 end
331
332
332 REV_PARAM_RE = %r{\A[a-f0-9]*\Z}i
333 REV_PARAM_RE = %r{\A[a-f0-9]*\Z}i
333
334
334 def find_project_repository
335 def find_project_repository
335 @project = Project.find(params[:id])
336 @project = Project.find(params[:id])
336 if params[:repository_id].present?
337 if params[:repository_id].present?
337 @repository = @project.repositories.find_by_identifier_param(params[:repository_id])
338 @repository = @project.repositories.find_by_identifier_param(params[:repository_id])
338 else
339 else
339 @repository = @project.repository
340 @repository = @project.repository
340 end
341 end
341 (render_404; return false) unless @repository
342 (render_404; return false) unless @repository
342 @path = params[:path].is_a?(Array) ? params[:path].join('/') : params[:path].to_s
343 @path = params[:path].is_a?(Array) ? params[:path].join('/') : params[:path].to_s
343 @rev = params[:rev].blank? ? @repository.default_branch : params[:rev].to_s.strip
344 @rev = params[:rev].blank? ? @repository.default_branch : params[:rev].to_s.strip
344 @rev_to = params[:rev_to]
345 @rev_to = params[:rev_to]
345
346
346 unless @rev.to_s.match(REV_PARAM_RE) && @rev_to.to_s.match(REV_PARAM_RE)
347 unless @rev.to_s.match(REV_PARAM_RE) && @rev_to.to_s.match(REV_PARAM_RE)
347 if @repository.branches.blank?
348 if @repository.branches.blank?
348 raise InvalidRevisionParam
349 raise InvalidRevisionParam
349 end
350 end
350 end
351 end
351 rescue ActiveRecord::RecordNotFound
352 rescue ActiveRecord::RecordNotFound
352 render_404
353 render_404
353 rescue InvalidRevisionParam
354 rescue InvalidRevisionParam
354 show_error_not_found
355 show_error_not_found
355 end
356 end
356
357
357 def find_changeset
358 def find_changeset
358 if @rev.present?
359 if @rev.present?
359 @changeset = @repository.find_changeset_by_name(@rev)
360 @changeset = @repository.find_changeset_by_name(@rev)
360 end
361 end
361 show_error_not_found unless @changeset
362 show_error_not_found unless @changeset
362 end
363 end
363
364
364 def show_error_not_found
365 def show_error_not_found
365 render_error :message => l(:error_scm_not_found), :status => 404
366 render_error :message => l(:error_scm_not_found), :status => 404
366 end
367 end
367
368
368 # Handler for Redmine::Scm::Adapters::CommandFailed exception
369 # Handler for Redmine::Scm::Adapters::CommandFailed exception
369 def show_error_command_failed(exception)
370 def show_error_command_failed(exception)
370 render_error l(:error_scm_command_failed, exception.message)
371 render_error l(:error_scm_command_failed, exception.message)
371 end
372 end
372
373
373 def graph_commits_per_month(repository)
374 def graph_commits_per_month(repository)
374 @date_to = Date.today
375 @date_to = Date.today
375 @date_from = @date_to << 11
376 @date_from = @date_to << 11
376 @date_from = Date.civil(@date_from.year, @date_from.month, 1)
377 @date_from = Date.civil(@date_from.year, @date_from.month, 1)
377 commits_by_day = Changeset.count(
378 commits_by_day = Changeset.count(
378 :all, :group => :commit_date,
379 :all, :group => :commit_date,
379 :conditions => ["repository_id = ? AND commit_date BETWEEN ? AND ?", repository.id, @date_from, @date_to])
380 :conditions => ["repository_id = ? AND commit_date BETWEEN ? AND ?", repository.id, @date_from, @date_to])
380 commits_by_month = [0] * 12
381 commits_by_month = [0] * 12
381 commits_by_day.each {|c| commits_by_month[(@date_to.month - c.first.to_date.month) % 12] += c.last }
382 commits_by_day.each {|c| commits_by_month[(@date_to.month - c.first.to_date.month) % 12] += c.last }
382
383
383 changes_by_day = Change.count(
384 changes_by_day = Change.count(
384 :all, :group => :commit_date, :include => :changeset,
385 :all, :group => :commit_date, :include => :changeset,
385 :conditions => ["#{Changeset.table_name}.repository_id = ? AND #{Changeset.table_name}.commit_date BETWEEN ? AND ?", repository.id, @date_from, @date_to])
386 :conditions => ["#{Changeset.table_name}.repository_id = ? AND #{Changeset.table_name}.commit_date BETWEEN ? AND ?", repository.id, @date_from, @date_to])
386 changes_by_month = [0] * 12
387 changes_by_month = [0] * 12
387 changes_by_day.each {|c| changes_by_month[(@date_to.month - c.first.to_date.month) % 12] += c.last }
388 changes_by_day.each {|c| changes_by_month[(@date_to.month - c.first.to_date.month) % 12] += c.last }
388
389
389 fields = []
390 fields = []
390 12.times {|m| fields << month_name(((Date.today.month - 1 - m) % 12) + 1)}
391 12.times {|m| fields << month_name(((Date.today.month - 1 - m) % 12) + 1)}
391
392
392 graph = SVG::Graph::Bar.new(
393 graph = SVG::Graph::Bar.new(
393 :height => 300,
394 :height => 300,
394 :width => 800,
395 :width => 800,
395 :fields => fields.reverse,
396 :fields => fields.reverse,
396 :stack => :side,
397 :stack => :side,
397 :scale_integers => true,
398 :scale_integers => true,
398 :step_x_labels => 2,
399 :step_x_labels => 2,
399 :show_data_values => false,
400 :show_data_values => false,
400 :graph_title => l(:label_commits_per_month),
401 :graph_title => l(:label_commits_per_month),
401 :show_graph_title => true
402 :show_graph_title => true
402 )
403 )
403
404
404 graph.add_data(
405 graph.add_data(
405 :data => commits_by_month[0..11].reverse,
406 :data => commits_by_month[0..11].reverse,
406 :title => l(:label_revision_plural)
407 :title => l(:label_revision_plural)
407 )
408 )
408
409
409 graph.add_data(
410 graph.add_data(
410 :data => changes_by_month[0..11].reverse,
411 :data => changes_by_month[0..11].reverse,
411 :title => l(:label_change_plural)
412 :title => l(:label_change_plural)
412 )
413 )
413
414
414 graph.burn
415 graph.burn
415 end
416 end
416
417
417 def graph_commits_per_author(repository)
418 def graph_commits_per_author(repository)
418 commits_by_author = Changeset.count(:all, :group => :committer, :conditions => ["repository_id = ?", repository.id])
419 commits_by_author = Changeset.count(:all, :group => :committer, :conditions => ["repository_id = ?", repository.id])
419 commits_by_author.to_a.sort! {|x, y| x.last <=> y.last}
420 commits_by_author.to_a.sort! {|x, y| x.last <=> y.last}
420
421
421 changes_by_author = Change.count(:all, :group => :committer, :include => :changeset, :conditions => ["#{Changeset.table_name}.repository_id = ?", repository.id])
422 changes_by_author = Change.count(:all, :group => :committer, :include => :changeset, :conditions => ["#{Changeset.table_name}.repository_id = ?", repository.id])
422 h = changes_by_author.inject({}) {|o, i| o[i.first] = i.last; o}
423 h = changes_by_author.inject({}) {|o, i| o[i.first] = i.last; o}
423
424
424 fields = commits_by_author.collect {|r| r.first}
425 fields = commits_by_author.collect {|r| r.first}
425 commits_data = commits_by_author.collect {|r| r.last}
426 commits_data = commits_by_author.collect {|r| r.last}
426 changes_data = commits_by_author.collect {|r| h[r.first] || 0}
427 changes_data = commits_by_author.collect {|r| h[r.first] || 0}
427
428
428 fields = fields + [""]*(10 - fields.length) if fields.length<10
429 fields = fields + [""]*(10 - fields.length) if fields.length<10
429 commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10
430 commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10
430 changes_data = changes_data + [0]*(10 - changes_data.length) if changes_data.length<10
431 changes_data = changes_data + [0]*(10 - changes_data.length) if changes_data.length<10
431
432
432 # Remove email adress in usernames
433 # Remove email adress in usernames
433 fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') }
434 fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') }
434
435
435 graph = SVG::Graph::BarHorizontal.new(
436 graph = SVG::Graph::BarHorizontal.new(
436 :height => 400,
437 :height => 400,
437 :width => 800,
438 :width => 800,
438 :fields => fields,
439 :fields => fields,
439 :stack => :side,
440 :stack => :side,
440 :scale_integers => true,
441 :scale_integers => true,
441 :show_data_values => false,
442 :show_data_values => false,
442 :rotate_y_labels => false,
443 :rotate_y_labels => false,
443 :graph_title => l(:label_commits_per_author),
444 :graph_title => l(:label_commits_per_author),
444 :show_graph_title => true
445 :show_graph_title => true
445 )
446 )
446 graph.add_data(
447 graph.add_data(
447 :data => commits_data,
448 :data => commits_data,
448 :title => l(:label_revision_plural)
449 :title => l(:label_revision_plural)
449 )
450 )
450 graph.add_data(
451 graph.add_data(
451 :data => changes_data,
452 :data => changes_data,
452 :title => l(:label_change_plural)
453 :title => l(:label_change_plural)
453 )
454 )
454 graph.burn
455 graph.burn
455 end
456 end
456 end
457 end
457
458
@@ -1,411 +1,418
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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
19
20 class RepositoriesSubversionControllerTest < ActionController::TestCase
20 class RepositoriesSubversionControllerTest < ActionController::TestCase
21 tests RepositoriesController
21 tests RepositoriesController
22
22
23 fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules,
23 fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules,
24 :repositories, :issues, :issue_statuses, :changesets, :changes,
24 :repositories, :issues, :issue_statuses, :changesets, :changes,
25 :issue_categories, :enumerations, :custom_fields, :custom_values, :trackers
25 :issue_categories, :enumerations, :custom_fields, :custom_values, :trackers
26
26
27 PRJ_ID = 3
27 PRJ_ID = 3
28 NUM_REV = 11
28 NUM_REV = 11
29
29
30 def setup
30 def setup
31 Setting.default_language = 'en'
31 Setting.default_language = 'en'
32 User.current = nil
32 User.current = nil
33
33
34 @project = Project.find(PRJ_ID)
34 @project = Project.find(PRJ_ID)
35 @repository = Repository::Subversion.create(:project => @project,
35 @repository = Repository::Subversion.create(:project => @project,
36 :url => self.class.subversion_repository_url)
36 :url => self.class.subversion_repository_url)
37 assert @repository
37 assert @repository
38 end
38 end
39
39
40 if repository_configured?('subversion')
40 if repository_configured?('subversion')
41 def test_new
41 def test_new
42 @request.session[:user_id] = 1
42 @request.session[:user_id] = 1
43 @project.repository.destroy
43 @project.repository.destroy
44 get :new, :project_id => 'subproject1', :repository_scm => 'Subversion'
44 get :new, :project_id => 'subproject1', :repository_scm => 'Subversion'
45 assert_response :success
45 assert_response :success
46 assert_template 'new'
46 assert_template 'new'
47 assert_kind_of Repository::Subversion, assigns(:repository)
47 assert_kind_of Repository::Subversion, assigns(:repository)
48 assert assigns(:repository).new_record?
48 assert assigns(:repository).new_record?
49 end
49 end
50
50
51 def test_show
51 def test_show
52 assert_equal 0, @repository.changesets.count
52 assert_equal 0, @repository.changesets.count
53 @repository.fetch_changesets
53 @repository.fetch_changesets
54 @project.reload
54 @project.reload
55 assert_equal NUM_REV, @repository.changesets.count
55 assert_equal NUM_REV, @repository.changesets.count
56 get :show, :id => PRJ_ID
56 get :show, :id => PRJ_ID
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_not_nil assigns(:changesets)
60 assert_not_nil assigns(:changesets)
61
61
62 entry = assigns(:entries).detect {|e| e.name == 'subversion_test'}
62 entry = assigns(:entries).detect {|e| e.name == 'subversion_test'}
63 assert_not_nil entry
63 assert_not_nil entry
64 assert_equal 'dir', entry.kind
64 assert_equal 'dir', entry.kind
65 assert_select 'tr.dir a[href=/projects/subproject1/repository/show/subversion_test]'
65 assert_select 'tr.dir a[href=/projects/subproject1/repository/show/subversion_test]'
66
66
67 assert_tag 'input', :attributes => {:name => 'rev'}
67 assert_tag 'input', :attributes => {:name => 'rev'}
68 assert_tag 'a', :content => 'Statistics'
68 assert_tag 'a', :content => 'Statistics'
69 assert_tag 'a', :content => 'Atom'
69 assert_tag 'a', :content => 'Atom'
70 assert_tag :tag => 'a',
70 assert_tag :tag => 'a',
71 :attributes => {:href => '/projects/subproject1/repository'},
71 :attributes => {:href => '/projects/subproject1/repository'},
72 :content => 'root'
72 :content => 'root'
73 end
73 end
74
74
75 def test_show_non_default
75 def test_show_non_default
76 Repository::Subversion.create(:project => @project,
76 Repository::Subversion.create(:project => @project,
77 :url => self.class.subversion_repository_url,
77 :url => self.class.subversion_repository_url,
78 :is_default => false, :identifier => 'svn')
78 :is_default => false, :identifier => 'svn')
79
79
80 get :show, :id => PRJ_ID, :repository_id => 'svn'
80 get :show, :id => PRJ_ID, :repository_id => 'svn'
81 assert_response :success
81 assert_response :success
82 assert_template 'show'
82 assert_template 'show'
83 assert_select 'tr.dir a[href=/projects/subproject1/repository/svn/show/subversion_test]'
83 assert_select 'tr.dir a[href=/projects/subproject1/repository/svn/show/subversion_test]'
84 # Repository menu should link to the main repo
84 # Repository menu should link to the main repo
85 assert_select '#main-menu a[href=/projects/subproject1/repository]'
85 assert_select '#main-menu a[href=/projects/subproject1/repository]'
86 end
86 end
87
87
88 def test_browse_directory
88 def test_browse_directory
89 assert_equal 0, @repository.changesets.count
89 assert_equal 0, @repository.changesets.count
90 @repository.fetch_changesets
90 @repository.fetch_changesets
91 @project.reload
91 @project.reload
92 assert_equal NUM_REV, @repository.changesets.count
92 assert_equal NUM_REV, @repository.changesets.count
93 get :show, :id => PRJ_ID, :path => repository_path_hash(['subversion_test'])[:param]
93 get :show, :id => PRJ_ID, :path => repository_path_hash(['subversion_test'])[:param]
94 assert_response :success
94 assert_response :success
95 assert_template 'show'
95 assert_template 'show'
96 assert_not_nil assigns(:entries)
96 assert_not_nil assigns(:entries)
97 assert_equal [
97 assert_equal [
98 '[folder_with_brackets]', 'folder', '.project',
98 '[folder_with_brackets]', 'folder', '.project',
99 'helloworld.c', 'textfile.txt'
99 'helloworld.c', 'textfile.txt'
100 ],
100 ],
101 assigns(:entries).collect(&:name)
101 assigns(:entries).collect(&:name)
102 entry = assigns(:entries).detect {|e| e.name == 'helloworld.c'}
102 entry = assigns(:entries).detect {|e| e.name == 'helloworld.c'}
103 assert_equal 'file', entry.kind
103 assert_equal 'file', entry.kind
104 assert_equal 'subversion_test/helloworld.c', entry.path
104 assert_equal 'subversion_test/helloworld.c', entry.path
105 assert_tag :a, :content => 'helloworld.c', :attributes => { :class => /text\-x\-c/ }
105 assert_tag :a, :content => 'helloworld.c', :attributes => { :class => /text\-x\-c/ }
106 end
106 end
107
107
108 def test_browse_at_given_revision
108 def test_browse_at_given_revision
109 assert_equal 0, @repository.changesets.count
109 assert_equal 0, @repository.changesets.count
110 @repository.fetch_changesets
110 @repository.fetch_changesets
111 @project.reload
111 @project.reload
112 assert_equal NUM_REV, @repository.changesets.count
112 assert_equal NUM_REV, @repository.changesets.count
113 get :show, :id => PRJ_ID, :path => repository_path_hash(['subversion_test'])[:param],
113 get :show, :id => PRJ_ID, :path => repository_path_hash(['subversion_test'])[:param],
114 :rev => 4
114 :rev => 4
115 assert_response :success
115 assert_response :success
116 assert_template 'show'
116 assert_template 'show'
117 assert_not_nil assigns(:entries)
117 assert_not_nil assigns(:entries)
118 assert_equal ['folder', '.project', 'helloworld.c', 'helloworld.rb', 'textfile.txt'],
118 assert_equal ['folder', '.project', 'helloworld.c', 'helloworld.rb', 'textfile.txt'],
119 assigns(:entries).collect(&:name)
119 assigns(:entries).collect(&:name)
120 end
120 end
121
121
122 def test_file_changes
122 def test_file_changes
123 assert_equal 0, @repository.changesets.count
123 assert_equal 0, @repository.changesets.count
124 @repository.fetch_changesets
124 @repository.fetch_changesets
125 @project.reload
125 @project.reload
126 assert_equal NUM_REV, @repository.changesets.count
126 assert_equal NUM_REV, @repository.changesets.count
127 get :changes, :id => PRJ_ID,
127 get :changes, :id => PRJ_ID,
128 :path => repository_path_hash(['subversion_test', 'folder', 'helloworld.rb'])[:param]
128 :path => repository_path_hash(['subversion_test', 'folder', 'helloworld.rb'])[:param]
129 assert_response :success
129 assert_response :success
130 assert_template 'changes'
130 assert_template 'changes'
131
131
132 changesets = assigns(:changesets)
132 changesets = assigns(:changesets)
133 assert_not_nil changesets
133 assert_not_nil changesets
134 assert_equal %w(6 3 2), changesets.collect(&:revision)
134 assert_equal %w(6 3 2), changesets.collect(&:revision)
135
135
136 # svn properties displayed with svn >= 1.5 only
136 # svn properties displayed with svn >= 1.5 only
137 if Redmine::Scm::Adapters::SubversionAdapter.client_version_above?([1, 5, 0])
137 if Redmine::Scm::Adapters::SubversionAdapter.client_version_above?([1, 5, 0])
138 assert_not_nil assigns(:properties)
138 assert_not_nil assigns(:properties)
139 assert_equal 'native', assigns(:properties)['svn:eol-style']
139 assert_equal 'native', assigns(:properties)['svn:eol-style']
140 assert_tag :ul,
140 assert_tag :ul,
141 :child => { :tag => 'li',
141 :child => { :tag => 'li',
142 :child => { :tag => 'b', :content => 'svn:eol-style' },
142 :child => { :tag => 'b', :content => 'svn:eol-style' },
143 :child => { :tag => 'span', :content => 'native' } }
143 :child => { :tag => 'span', :content => 'native' } }
144 end
144 end
145 end
145 end
146
146
147 def test_directory_changes
147 def test_directory_changes
148 assert_equal 0, @repository.changesets.count
148 assert_equal 0, @repository.changesets.count
149 @repository.fetch_changesets
149 @repository.fetch_changesets
150 @project.reload
150 @project.reload
151 assert_equal NUM_REV, @repository.changesets.count
151 assert_equal NUM_REV, @repository.changesets.count
152 get :changes, :id => PRJ_ID,
152 get :changes, :id => PRJ_ID,
153 :path => repository_path_hash(['subversion_test', 'folder'])[:param]
153 :path => repository_path_hash(['subversion_test', 'folder'])[:param]
154 assert_response :success
154 assert_response :success
155 assert_template 'changes'
155 assert_template 'changes'
156
156
157 changesets = assigns(:changesets)
157 changesets = assigns(:changesets)
158 assert_not_nil changesets
158 assert_not_nil changesets
159 assert_equal %w(10 9 7 6 5 2), changesets.collect(&:revision)
159 assert_equal %w(10 9 7 6 5 2), changesets.collect(&:revision)
160 end
160 end
161
161
162 def test_entry
162 def test_entry
163 assert_equal 0, @repository.changesets.count
163 assert_equal 0, @repository.changesets.count
164 @repository.fetch_changesets
164 @repository.fetch_changesets
165 @project.reload
165 @project.reload
166 assert_equal NUM_REV, @repository.changesets.count
166 assert_equal NUM_REV, @repository.changesets.count
167 get :entry, :id => PRJ_ID,
167 get :entry, :id => PRJ_ID,
168 :path => repository_path_hash(['subversion_test', 'helloworld.c'])[:param]
168 :path => repository_path_hash(['subversion_test', 'helloworld.c'])[:param]
169 assert_response :success
169 assert_response :success
170 assert_template 'entry'
170 assert_template 'entry'
171 end
171 end
172
172
173 def test_entry_should_send_if_too_big
173 def test_entry_should_send_if_too_big
174 assert_equal 0, @repository.changesets.count
174 assert_equal 0, @repository.changesets.count
175 @repository.fetch_changesets
175 @repository.fetch_changesets
176 @project.reload
176 @project.reload
177 assert_equal NUM_REV, @repository.changesets.count
177 assert_equal NUM_REV, @repository.changesets.count
178 # no files in the test repo is larger than 1KB...
178 # no files in the test repo is larger than 1KB...
179 with_settings :file_max_size_displayed => 0 do
179 with_settings :file_max_size_displayed => 0 do
180 get :entry, :id => PRJ_ID,
180 get :entry, :id => PRJ_ID,
181 :path => repository_path_hash(['subversion_test', 'helloworld.c'])[:param]
181 :path => repository_path_hash(['subversion_test', 'helloworld.c'])[:param]
182 assert_response :success
182 assert_response :success
183 assert_equal 'attachment; filename="helloworld.c"',
183 assert_equal 'attachment; filename="helloworld.c"',
184 @response.headers['Content-Disposition']
184 @response.headers['Content-Disposition']
185 end
185 end
186 end
186 end
187
187
188 def test_entry_should_send_images_inline
189 get :entry, :id => PRJ_ID,
190 :path => repository_path_hash(['subversion_test', 'folder', 'subfolder', 'rubylogo.gif'])[:param]
191 assert_response :success
192 assert_equal 'inline; filename="rubylogo.gif"', response.headers['Content-Disposition']
193 end
194
188 def test_entry_at_given_revision
195 def test_entry_at_given_revision
189 assert_equal 0, @repository.changesets.count
196 assert_equal 0, @repository.changesets.count
190 @repository.fetch_changesets
197 @repository.fetch_changesets
191 @project.reload
198 @project.reload
192 assert_equal NUM_REV, @repository.changesets.count
199 assert_equal NUM_REV, @repository.changesets.count
193 get :entry, :id => PRJ_ID,
200 get :entry, :id => PRJ_ID,
194 :path => repository_path_hash(['subversion_test', 'helloworld.rb'])[:param],
201 :path => repository_path_hash(['subversion_test', 'helloworld.rb'])[:param],
195 :rev => 2
202 :rev => 2
196 assert_response :success
203 assert_response :success
197 assert_template 'entry'
204 assert_template 'entry'
198 # this line was removed in r3 and file was moved in r6
205 # this line was removed in r3 and file was moved in r6
199 assert_tag :tag => 'td', :attributes => { :class => /line-code/},
206 assert_tag :tag => 'td', :attributes => { :class => /line-code/},
200 :content => /Here's the code/
207 :content => /Here's the code/
201 end
208 end
202
209
203 def test_entry_not_found
210 def test_entry_not_found
204 assert_equal 0, @repository.changesets.count
211 assert_equal 0, @repository.changesets.count
205 @repository.fetch_changesets
212 @repository.fetch_changesets
206 @project.reload
213 @project.reload
207 assert_equal NUM_REV, @repository.changesets.count
214 assert_equal NUM_REV, @repository.changesets.count
208 get :entry, :id => PRJ_ID,
215 get :entry, :id => PRJ_ID,
209 :path => repository_path_hash(['subversion_test', 'zzz.c'])[:param]
216 :path => repository_path_hash(['subversion_test', 'zzz.c'])[:param]
210 assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ },
217 assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ },
211 :content => /The entry or revision was not found in the repository/
218 :content => /The entry or revision was not found in the repository/
212 end
219 end
213
220
214 def test_entry_download
221 def test_entry_download
215 assert_equal 0, @repository.changesets.count
222 assert_equal 0, @repository.changesets.count
216 @repository.fetch_changesets
223 @repository.fetch_changesets
217 @project.reload
224 @project.reload
218 assert_equal NUM_REV, @repository.changesets.count
225 assert_equal NUM_REV, @repository.changesets.count
219 get :raw, :id => PRJ_ID,
226 get :raw, :id => PRJ_ID,
220 :path => repository_path_hash(['subversion_test', 'helloworld.c'])[:param]
227 :path => repository_path_hash(['subversion_test', 'helloworld.c'])[:param]
221 assert_response :success
228 assert_response :success
222 assert_equal 'attachment; filename="helloworld.c"', @response.headers['Content-Disposition']
229 assert_equal 'attachment; filename="helloworld.c"', @response.headers['Content-Disposition']
223 end
230 end
224
231
225 def test_directory_entry
232 def test_directory_entry
226 assert_equal 0, @repository.changesets.count
233 assert_equal 0, @repository.changesets.count
227 @repository.fetch_changesets
234 @repository.fetch_changesets
228 @project.reload
235 @project.reload
229 assert_equal NUM_REV, @repository.changesets.count
236 assert_equal NUM_REV, @repository.changesets.count
230 get :entry, :id => PRJ_ID,
237 get :entry, :id => PRJ_ID,
231 :path => repository_path_hash(['subversion_test', 'folder'])[:param]
238 :path => repository_path_hash(['subversion_test', 'folder'])[:param]
232 assert_response :success
239 assert_response :success
233 assert_template 'show'
240 assert_template 'show'
234 assert_not_nil assigns(:entry)
241 assert_not_nil assigns(:entry)
235 assert_equal 'folder', assigns(:entry).name
242 assert_equal 'folder', assigns(:entry).name
236 end
243 end
237
244
238 # TODO: this test needs fixtures.
245 # TODO: this test needs fixtures.
239 def test_revision
246 def test_revision
240 get :revision, :id => 1, :rev => 2
247 get :revision, :id => 1, :rev => 2
241 assert_response :success
248 assert_response :success
242 assert_template 'revision'
249 assert_template 'revision'
243 assert_tag :tag => 'ul',
250 assert_tag :tag => 'ul',
244 :child => { :tag => 'li',
251 :child => { :tag => 'li',
245 # link to the entry at rev 2
252 # link to the entry at rev 2
246 :child => { :tag => 'a',
253 :child => { :tag => 'a',
247 :attributes => {:href => '/projects/ecookbook/repository/revisions/2/entry/test/some/path/in/the/repo'},
254 :attributes => {:href => '/projects/ecookbook/repository/revisions/2/entry/test/some/path/in/the/repo'},
248 :content => 'repo',
255 :content => 'repo',
249 # link to partial diff
256 # link to partial diff
250 :sibling => { :tag => 'a',
257 :sibling => { :tag => 'a',
251 :attributes => { :href => '/projects/ecookbook/repository/revisions/2/diff/test/some/path/in/the/repo' }
258 :attributes => { :href => '/projects/ecookbook/repository/revisions/2/diff/test/some/path/in/the/repo' }
252 }
259 }
253 }
260 }
254 }
261 }
255 end
262 end
256
263
257 def test_invalid_revision
264 def test_invalid_revision
258 assert_equal 0, @repository.changesets.count
265 assert_equal 0, @repository.changesets.count
259 @repository.fetch_changesets
266 @repository.fetch_changesets
260 @project.reload
267 @project.reload
261 assert_equal NUM_REV, @repository.changesets.count
268 assert_equal NUM_REV, @repository.changesets.count
262 get :revision, :id => PRJ_ID, :rev => 'something_weird'
269 get :revision, :id => PRJ_ID, :rev => 'something_weird'
263 assert_response 404
270 assert_response 404
264 assert_error_tag :content => /was not found/
271 assert_error_tag :content => /was not found/
265 end
272 end
266
273
267 def test_invalid_revision_diff
274 def test_invalid_revision_diff
268 get :diff, :id => PRJ_ID, :rev => '1', :rev_to => 'something_weird'
275 get :diff, :id => PRJ_ID, :rev => '1', :rev_to => 'something_weird'
269 assert_response 404
276 assert_response 404
270 assert_error_tag :content => /was not found/
277 assert_error_tag :content => /was not found/
271 end
278 end
272
279
273 def test_empty_revision
280 def test_empty_revision
274 assert_equal 0, @repository.changesets.count
281 assert_equal 0, @repository.changesets.count
275 @repository.fetch_changesets
282 @repository.fetch_changesets
276 @project.reload
283 @project.reload
277 assert_equal NUM_REV, @repository.changesets.count
284 assert_equal NUM_REV, @repository.changesets.count
278 ['', ' ', nil].each do |r|
285 ['', ' ', nil].each do |r|
279 get :revision, :id => PRJ_ID, :rev => r
286 get :revision, :id => PRJ_ID, :rev => r
280 assert_response 404
287 assert_response 404
281 assert_error_tag :content => /was not found/
288 assert_error_tag :content => /was not found/
282 end
289 end
283 end
290 end
284
291
285 # TODO: this test needs fixtures.
292 # TODO: this test needs fixtures.
286 def test_revision_with_repository_pointing_to_a_subdirectory
293 def test_revision_with_repository_pointing_to_a_subdirectory
287 r = Project.find(1).repository
294 r = Project.find(1).repository
288 # Changes repository url to a subdirectory
295 # Changes repository url to a subdirectory
289 r.update_attribute :url, (r.url + '/test/some')
296 r.update_attribute :url, (r.url + '/test/some')
290
297
291 get :revision, :id => 1, :rev => 2
298 get :revision, :id => 1, :rev => 2
292 assert_response :success
299 assert_response :success
293 assert_template 'revision'
300 assert_template 'revision'
294 assert_tag :tag => 'ul',
301 assert_tag :tag => 'ul',
295 :child => { :tag => 'li',
302 :child => { :tag => 'li',
296 # link to the entry at rev 2
303 # link to the entry at rev 2
297 :child => { :tag => 'a',
304 :child => { :tag => 'a',
298 :attributes => {:href => '/projects/ecookbook/repository/revisions/2/entry/path/in/the/repo'},
305 :attributes => {:href => '/projects/ecookbook/repository/revisions/2/entry/path/in/the/repo'},
299 :content => 'repo',
306 :content => 'repo',
300 # link to partial diff
307 # link to partial diff
301 :sibling => { :tag => 'a',
308 :sibling => { :tag => 'a',
302 :attributes => { :href => '/projects/ecookbook/repository/revisions/2/diff/path/in/the/repo' }
309 :attributes => { :href => '/projects/ecookbook/repository/revisions/2/diff/path/in/the/repo' }
303 }
310 }
304 }
311 }
305 }
312 }
306 end
313 end
307
314
308 def test_revision_diff
315 def test_revision_diff
309 assert_equal 0, @repository.changesets.count
316 assert_equal 0, @repository.changesets.count
310 @repository.fetch_changesets
317 @repository.fetch_changesets
311 @project.reload
318 @project.reload
312 assert_equal NUM_REV, @repository.changesets.count
319 assert_equal NUM_REV, @repository.changesets.count
313 ['inline', 'sbs'].each do |dt|
320 ['inline', 'sbs'].each do |dt|
314 get :diff, :id => PRJ_ID, :rev => 3, :type => dt
321 get :diff, :id => PRJ_ID, :rev => 3, :type => dt
315 assert_response :success
322 assert_response :success
316 assert_template 'diff'
323 assert_template 'diff'
317 assert_tag :tag => 'h2',
324 assert_tag :tag => 'h2',
318 :content => / 3/
325 :content => / 3/
319 end
326 end
320 end
327 end
321
328
322 def test_revision_diff_raw_format
329 def test_revision_diff_raw_format
323 assert_equal 0, @repository.changesets.count
330 assert_equal 0, @repository.changesets.count
324 @repository.fetch_changesets
331 @repository.fetch_changesets
325 @project.reload
332 @project.reload
326 assert_equal NUM_REV, @repository.changesets.count
333 assert_equal NUM_REV, @repository.changesets.count
327
334
328 get :diff, :id => PRJ_ID, :rev => 3, :format => 'diff'
335 get :diff, :id => PRJ_ID, :rev => 3, :format => 'diff'
329 assert_response :success
336 assert_response :success
330 assert_equal 'text/x-patch', @response.content_type
337 assert_equal 'text/x-patch', @response.content_type
331 assert_equal 'Index: subversion_test/textfile.txt', @response.body.split(/\r?\n/).first
338 assert_equal 'Index: subversion_test/textfile.txt', @response.body.split(/\r?\n/).first
332 end
339 end
333
340
334 def test_directory_diff
341 def test_directory_diff
335 assert_equal 0, @repository.changesets.count
342 assert_equal 0, @repository.changesets.count
336 @repository.fetch_changesets
343 @repository.fetch_changesets
337 @project.reload
344 @project.reload
338 assert_equal NUM_REV, @repository.changesets.count
345 assert_equal NUM_REV, @repository.changesets.count
339 ['inline', 'sbs'].each do |dt|
346 ['inline', 'sbs'].each do |dt|
340 get :diff, :id => PRJ_ID, :rev => 6, :rev_to => 2,
347 get :diff, :id => PRJ_ID, :rev => 6, :rev_to => 2,
341 :path => repository_path_hash(['subversion_test', 'folder'])[:param],
348 :path => repository_path_hash(['subversion_test', 'folder'])[:param],
342 :type => dt
349 :type => dt
343 assert_response :success
350 assert_response :success
344 assert_template 'diff'
351 assert_template 'diff'
345
352
346 diff = assigns(:diff)
353 diff = assigns(:diff)
347 assert_not_nil diff
354 assert_not_nil diff
348 # 2 files modified
355 # 2 files modified
349 assert_equal 2, Redmine::UnifiedDiff.new(diff).size
356 assert_equal 2, Redmine::UnifiedDiff.new(diff).size
350 assert_tag :tag => 'h2', :content => /2:6/
357 assert_tag :tag => 'h2', :content => /2:6/
351 end
358 end
352 end
359 end
353
360
354 def test_annotate
361 def test_annotate
355 assert_equal 0, @repository.changesets.count
362 assert_equal 0, @repository.changesets.count
356 @repository.fetch_changesets
363 @repository.fetch_changesets
357 @project.reload
364 @project.reload
358 assert_equal NUM_REV, @repository.changesets.count
365 assert_equal NUM_REV, @repository.changesets.count
359 get :annotate, :id => PRJ_ID,
366 get :annotate, :id => PRJ_ID,
360 :path => repository_path_hash(['subversion_test', 'helloworld.c'])[:param]
367 :path => repository_path_hash(['subversion_test', 'helloworld.c'])[:param]
361 assert_response :success
368 assert_response :success
362 assert_template 'annotate'
369 assert_template 'annotate'
363 end
370 end
364
371
365 def test_annotate_at_given_revision
372 def test_annotate_at_given_revision
366 assert_equal 0, @repository.changesets.count
373 assert_equal 0, @repository.changesets.count
367 @repository.fetch_changesets
374 @repository.fetch_changesets
368 @project.reload
375 @project.reload
369 assert_equal NUM_REV, @repository.changesets.count
376 assert_equal NUM_REV, @repository.changesets.count
370 get :annotate, :id => PRJ_ID, :rev => 8,
377 get :annotate, :id => PRJ_ID, :rev => 8,
371 :path => repository_path_hash(['subversion_test', 'helloworld.c'])[:param]
378 :path => repository_path_hash(['subversion_test', 'helloworld.c'])[:param]
372 assert_response :success
379 assert_response :success
373 assert_template 'annotate'
380 assert_template 'annotate'
374 assert_tag :tag => 'h2', :content => /@ 8/
381 assert_tag :tag => 'h2', :content => /@ 8/
375 end
382 end
376
383
377 def test_destroy_valid_repository
384 def test_destroy_valid_repository
378 @request.session[:user_id] = 1 # admin
385 @request.session[:user_id] = 1 # admin
379 assert_equal 0, @repository.changesets.count
386 assert_equal 0, @repository.changesets.count
380 @repository.fetch_changesets
387 @repository.fetch_changesets
381 assert_equal NUM_REV, @repository.changesets.count
388 assert_equal NUM_REV, @repository.changesets.count
382
389
383 assert_difference 'Repository.count', -1 do
390 assert_difference 'Repository.count', -1 do
384 delete :destroy, :id => @repository.id
391 delete :destroy, :id => @repository.id
385 end
392 end
386 assert_response 302
393 assert_response 302
387 @project.reload
394 @project.reload
388 assert_nil @project.repository
395 assert_nil @project.repository
389 end
396 end
390
397
391 def test_destroy_invalid_repository
398 def test_destroy_invalid_repository
392 @request.session[:user_id] = 1 # admin
399 @request.session[:user_id] = 1 # admin
393 @project.repository.destroy
400 @project.repository.destroy
394 @repository = Repository::Subversion.create!(
401 @repository = Repository::Subversion.create!(
395 :project => @project,
402 :project => @project,
396 :url => "file:///invalid")
403 :url => "file:///invalid")
397 @repository.fetch_changesets
404 @repository.fetch_changesets
398 assert_equal 0, @repository.changesets.count
405 assert_equal 0, @repository.changesets.count
399
406
400 assert_difference 'Repository.count', -1 do
407 assert_difference 'Repository.count', -1 do
401 delete :destroy, :id => @repository.id
408 delete :destroy, :id => @repository.id
402 end
409 end
403 assert_response 302
410 assert_response 302
404 @project.reload
411 @project.reload
405 assert_nil @project.repository
412 assert_nil @project.repository
406 end
413 end
407 else
414 else
408 puts "Subversion test repository NOT FOUND. Skipping functional tests !!!"
415 puts "Subversion test repository NOT FOUND. Skipping functional tests !!!"
409 def test_fake; assert true end
416 def test_fake; assert true end
410 end
417 end
411 end
418 end
General Comments 0
You need to be logged in to leave comments. Login now