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