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