##// END OF EJS Templates
Merged r6073 from trunk....
Jean-Philippe Lang -
r6042:30255b8054d5
parent child
Show More
@@ -1,374 +1,374
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require 'SVG/Graph/Bar'
18 require 'SVG/Graph/Bar'
19 require 'SVG/Graph/BarHorizontal'
19 require 'SVG/Graph/BarHorizontal'
20 require 'digest/sha1'
20 require 'digest/sha1'
21
21
22 class ChangesetNotFound < Exception; end
22 class ChangesetNotFound < Exception; end
23 class InvalidRevisionParam < Exception; end
23 class InvalidRevisionParam < Exception; end
24
24
25 class RepositoriesController < ApplicationController
25 class RepositoriesController < ApplicationController
26 menu_item :repository
26 menu_item :repository
27 menu_item :settings, :only => :edit
27 menu_item :settings, :only => :edit
28 default_search_scope :changesets
28 default_search_scope :changesets
29
29
30 before_filter :find_repository, :except => :edit
30 before_filter :find_repository, :except => :edit
31 before_filter :find_project, :only => :edit
31 before_filter :find_project, :only => :edit
32 before_filter :authorize
32 before_filter :authorize
33 accept_key_auth :revisions
33 accept_key_auth :revisions
34
34
35 rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed
35 rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed
36
36
37 def edit
37 def edit
38 @repository = @project.repository
38 @repository = @project.repository
39 if !@repository && !params[:repository_scm].blank?
39 if !@repository && !params[:repository_scm].blank?
40 @repository = Repository.factory(params[:repository_scm])
40 @repository = Repository.factory(params[:repository_scm])
41 @repository.project = @project if @repository
41 @repository.project = @project if @repository
42 end
42 end
43 if request.post? && @repository
43 if request.post? && @repository
44 p1 = params[:repository]
44 p1 = params[:repository]
45 p = {}
45 p = {}
46 p_extra = {}
46 p_extra = {}
47 p1.each do |k, v|
47 p1.each do |k, v|
48 if k =~ /^extra_/
48 if k =~ /^extra_/
49 p_extra[k] = v
49 p_extra[k] = v
50 else
50 else
51 p[k] = v
51 p[k] = v
52 end
52 end
53 end
53 end
54 @repository.attributes = p
54 @repository.attributes = p
55 @repository.merge_extra_info(p_extra)
55 @repository.merge_extra_info(p_extra)
56 @repository.save
56 @repository.save
57 end
57 end
58 render(:update) do |page|
58 render(:update) do |page|
59 page.replace_html "tab-content-repository",
59 page.replace_html "tab-content-repository",
60 :partial => 'projects/settings/repository'
60 :partial => 'projects/settings/repository'
61 if @repository && !@project.repository
61 if @repository && !@project.repository
62 @project.reload # needed to reload association
62 @project.reload # needed to reload association
63 page.replace_html "main-menu", render_main_menu(@project)
63 page.replace_html "main-menu", render_main_menu(@project)
64 end
64 end
65 end
65 end
66 end
66 end
67
67
68 def committers
68 def committers
69 @committers = @repository.committers
69 @committers = @repository.committers
70 @users = @project.users
70 @users = @project.users
71 additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id)
71 additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id)
72 @users += User.find_all_by_id(additional_user_ids) unless additional_user_ids.empty?
72 @users += User.find_all_by_id(additional_user_ids) unless additional_user_ids.empty?
73 @users.compact!
73 @users.compact!
74 @users.sort!
74 @users.sort!
75 if request.post? && params[:committers].is_a?(Hash)
75 if request.post? && params[:committers].is_a?(Hash)
76 # Build a hash with repository usernames as keys and corresponding user ids as values
76 # Build a hash with repository usernames as keys and corresponding user ids as values
77 @repository.committer_ids = params[:committers].values.inject({}) {|h, c| h[c.first] = c.last; h}
77 @repository.committer_ids = params[:committers].values.inject({}) {|h, c| h[c.first] = c.last; h}
78 flash[:notice] = l(:notice_successful_update)
78 flash[:notice] = l(:notice_successful_update)
79 redirect_to :action => 'committers', :id => @project
79 redirect_to :action => 'committers', :id => @project
80 end
80 end
81 end
81 end
82
82
83 def destroy
83 def destroy
84 @repository.destroy
84 @repository.destroy
85 redirect_to :controller => 'projects',
85 redirect_to :controller => 'projects',
86 :action => 'settings',
86 :action => 'settings',
87 :id => @project,
87 :id => @project,
88 :tab => 'repository'
88 :tab => 'repository'
89 end
89 end
90
90
91 def show
91 def show
92 @repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty?
92 @repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty?
93
93
94 @entries = @repository.entries(@path, @rev)
94 @entries = @repository.entries(@path, @rev)
95 @changeset = @repository.find_changeset_by_name(@rev)
95 @changeset = @repository.find_changeset_by_name(@rev)
96 if request.xhr?
96 if request.xhr?
97 @entries ? render(:partial => 'dir_list_content') : render(:nothing => true)
97 @entries ? render(:partial => 'dir_list_content') : render(:nothing => true)
98 else
98 else
99 (show_error_not_found; return) unless @entries
99 (show_error_not_found; return) unless @entries
100 @changesets = @repository.latest_changesets(@path, @rev)
100 @changesets = @repository.latest_changesets(@path, @rev)
101 @properties = @repository.properties(@path, @rev)
101 @properties = @repository.properties(@path, @rev)
102 render :action => 'show'
102 render :action => 'show'
103 end
103 end
104 end
104 end
105
105
106 alias_method :browse, :show
106 alias_method :browse, :show
107
107
108 def changes
108 def changes
109 @entry = @repository.entry(@path, @rev)
109 @entry = @repository.entry(@path, @rev)
110 (show_error_not_found; return) unless @entry
110 (show_error_not_found; return) unless @entry
111 @changesets = @repository.latest_changesets(@path, @rev, Setting.repository_log_display_limit.to_i)
111 @changesets = @repository.latest_changesets(@path, @rev, Setting.repository_log_display_limit.to_i)
112 @properties = @repository.properties(@path, @rev)
112 @properties = @repository.properties(@path, @rev)
113 @changeset = @repository.find_changeset_by_name(@rev)
113 @changeset = @repository.find_changeset_by_name(@rev)
114 end
114 end
115
115
116 def revisions
116 def revisions
117 @changeset_count = @repository.changesets.count
117 @changeset_count = @repository.changesets.count
118 @changeset_pages = Paginator.new self, @changeset_count,
118 @changeset_pages = Paginator.new self, @changeset_count,
119 per_page_option,
119 per_page_option,
120 params['page']
120 params['page']
121 @changesets = @repository.changesets.find(:all,
121 @changesets = @repository.changesets.find(:all,
122 :limit => @changeset_pages.items_per_page,
122 :limit => @changeset_pages.items_per_page,
123 :offset => @changeset_pages.current.offset,
123 :offset => @changeset_pages.current.offset,
124 :include => [:user, :repository])
124 :include => [:user, :repository])
125
125
126 respond_to do |format|
126 respond_to do |format|
127 format.html { render :layout => false if request.xhr? }
127 format.html { render :layout => false if request.xhr? }
128 format.atom { render_feed(@changesets, :title => "#{@project.name}: #{l(:label_revision_plural)}") }
128 format.atom { render_feed(@changesets, :title => "#{@project.name}: #{l(:label_revision_plural)}") }
129 end
129 end
130 end
130 end
131
131
132 def entry
132 def entry
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
135
136 # If the entry is a dir, show the browser
136 # If the entry is a dir, show the browser
137 (show; return) if @entry.is_dir?
137 (show; return) if @entry.is_dir?
138
138
139 @content = @repository.cat(@path, @rev)
139 @content = @repository.cat(@path, @rev)
140 (show_error_not_found; return) unless @content
140 (show_error_not_found; return) unless @content
141 if 'raw' == params[:format] ||
141 if 'raw' == params[:format] ||
142 (@content.size && @content.size > Setting.file_max_size_displayed.to_i.kilobyte) ||
142 (@content.size && @content.size > Setting.file_max_size_displayed.to_i.kilobyte) ||
143 ! is_entry_text_data?(@content, @path)
143 ! is_entry_text_data?(@content, @path)
144 # Force the download
144 # Force the download
145 send_opt = { :filename => filename_for_content_disposition(@path.split('/').last) }
145 send_opt = { :filename => filename_for_content_disposition(@path.split('/').last) }
146 send_type = Redmine::MimeType.of(@path)
146 send_type = Redmine::MimeType.of(@path)
147 send_opt[:type] = send_type.to_s if send_type
147 send_opt[:type] = send_type.to_s if send_type
148 send_data @content, send_opt
148 send_data @content, send_opt
149 else
149 else
150 # Prevent empty lines when displaying a file with Windows style eol
150 # Prevent empty lines when displaying a file with Windows style eol
151 # TODO: UTF-16
151 # TODO: UTF-16
152 # Is this needs? AttachmentsController reads file simply.
152 # Is this needs? AttachmentsController reads file simply.
153 @content.gsub!("\r\n", "\n")
153 @content.gsub!("\r\n", "\n")
154 @changeset = @repository.find_changeset_by_name(@rev)
154 @changeset = @repository.find_changeset_by_name(@rev)
155 end
155 end
156 end
156 end
157
157
158 def is_entry_text_data?(ent, path)
158 def is_entry_text_data?(ent, path)
159 # UTF-16 contains "\x00".
159 # UTF-16 contains "\x00".
160 # It is very strict that file contains less than 30% of ascii symbols
160 # It is very strict that file contains less than 30% of ascii symbols
161 # in non Western Europe.
161 # in non Western Europe.
162 return true if Redmine::MimeType.is_type?('text', path)
162 return true if Redmine::MimeType.is_type?('text', path)
163 # Ruby 1.8.6 has a bug of integer divisions.
163 # Ruby 1.8.6 has a bug of integer divisions.
164 # http://apidock.com/ruby/v1_8_6_287/String/is_binary_data%3F
164 # http://apidock.com/ruby/v1_8_6_287/String/is_binary_data%3F
165 return false if ent.is_binary_data?
165 return false if ent.is_binary_data?
166 true
166 true
167 end
167 end
168 private :is_entry_text_data?
168 private :is_entry_text_data?
169
169
170 def annotate
170 def annotate
171 @entry = @repository.entry(@path, @rev)
171 @entry = @repository.entry(@path, @rev)
172 (show_error_not_found; return) unless @entry
172 (show_error_not_found; return) unless @entry
173
173
174 @annotate = @repository.scm.annotate(@path, @rev)
174 @annotate = @repository.scm.annotate(@path, @rev)
175 (render_error l(:error_scm_annotate); return) if @annotate.nil? || @annotate.empty?
175 (render_error l(:error_scm_annotate); return) if @annotate.nil? || @annotate.empty?
176 @changeset = @repository.find_changeset_by_name(@rev)
176 @changeset = @repository.find_changeset_by_name(@rev)
177 end
177 end
178
178
179 def revision
179 def revision
180 raise ChangesetNotFound if @rev.blank?
180 raise ChangesetNotFound if @rev.blank?
181 @changeset = @repository.find_changeset_by_name(@rev)
181 @changeset = @repository.find_changeset_by_name(@rev)
182 raise ChangesetNotFound unless @changeset
182 raise ChangesetNotFound unless @changeset
183
183
184 respond_to do |format|
184 respond_to do |format|
185 format.html
185 format.html
186 format.js {render :layout => false}
186 format.js {render :layout => false}
187 end
187 end
188 rescue ChangesetNotFound
188 rescue ChangesetNotFound
189 show_error_not_found
189 show_error_not_found
190 end
190 end
191
191
192 def diff
192 def diff
193 if params[:format] == 'diff'
193 if params[:format] == 'diff'
194 @diff = @repository.diff(@path, @rev, @rev_to)
194 @diff = @repository.diff(@path, @rev, @rev_to)
195 (show_error_not_found; return) unless @diff
195 (show_error_not_found; return) unless @diff
196 filename = "changeset_r#{@rev}"
196 filename = "changeset_r#{@rev}"
197 filename << "_r#{@rev_to}" if @rev_to
197 filename << "_r#{@rev_to}" if @rev_to
198 send_data @diff.join, :filename => "#{filename}.diff",
198 send_data @diff.join, :filename => "#{filename}.diff",
199 :type => 'text/x-patch',
199 :type => 'text/x-patch',
200 :disposition => 'attachment'
200 :disposition => 'attachment'
201 else
201 else
202 @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline'
202 @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline'
203 @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type)
203 @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type)
204
204
205 # Save diff type as user preference
205 # Save diff type as user preference
206 if User.current.logged? && @diff_type != User.current.pref[:diff_type]
206 if User.current.logged? && @diff_type != User.current.pref[:diff_type]
207 User.current.pref[:diff_type] = @diff_type
207 User.current.pref[:diff_type] = @diff_type
208 User.current.preference.save
208 User.current.preference.save
209 end
209 end
210 @cache_key = "repositories/diff/#{@repository.id}/" +
210 @cache_key = "repositories/diff/#{@repository.id}/" +
211 Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}")
211 Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}-#{current_language}")
212 unless read_fragment(@cache_key)
212 unless read_fragment(@cache_key)
213 @diff = @repository.diff(@path, @rev, @rev_to)
213 @diff = @repository.diff(@path, @rev, @rev_to)
214 show_error_not_found unless @diff
214 show_error_not_found unless @diff
215 end
215 end
216
216
217 @changeset = @repository.find_changeset_by_name(@rev)
217 @changeset = @repository.find_changeset_by_name(@rev)
218 @changeset_to = @rev_to ? @repository.find_changeset_by_name(@rev_to) : nil
218 @changeset_to = @rev_to ? @repository.find_changeset_by_name(@rev_to) : nil
219 @diff_format_revisions = @repository.diff_format_revisions(@changeset, @changeset_to)
219 @diff_format_revisions = @repository.diff_format_revisions(@changeset, @changeset_to)
220 end
220 end
221 end
221 end
222
222
223 def stats
223 def stats
224 end
224 end
225
225
226 def graph
226 def graph
227 data = nil
227 data = nil
228 case params[:graph]
228 case params[:graph]
229 when "commits_per_month"
229 when "commits_per_month"
230 data = graph_commits_per_month(@repository)
230 data = graph_commits_per_month(@repository)
231 when "commits_per_author"
231 when "commits_per_author"
232 data = graph_commits_per_author(@repository)
232 data = graph_commits_per_author(@repository)
233 end
233 end
234 if data
234 if data
235 headers["Content-Type"] = "image/svg+xml"
235 headers["Content-Type"] = "image/svg+xml"
236 send_data(data, :type => "image/svg+xml", :disposition => "inline")
236 send_data(data, :type => "image/svg+xml", :disposition => "inline")
237 else
237 else
238 render_404
238 render_404
239 end
239 end
240 end
240 end
241
241
242 private
242 private
243
243
244 REV_PARAM_RE = %r{\A[a-f0-9]*\Z}i
244 REV_PARAM_RE = %r{\A[a-f0-9]*\Z}i
245
245
246 def find_repository
246 def find_repository
247 @project = Project.find(params[:id])
247 @project = Project.find(params[:id])
248 @repository = @project.repository
248 @repository = @project.repository
249 (render_404; return false) unless @repository
249 (render_404; return false) unless @repository
250 @path = params[:path].join('/') unless params[:path].nil?
250 @path = params[:path].join('/') unless params[:path].nil?
251 @path ||= ''
251 @path ||= ''
252 @rev = params[:rev].blank? ? @repository.default_branch : params[:rev].strip
252 @rev = params[:rev].blank? ? @repository.default_branch : params[:rev].strip
253 @rev_to = params[:rev_to]
253 @rev_to = params[:rev_to]
254
254
255 unless @rev.to_s.match(REV_PARAM_RE) && @rev_to.to_s.match(REV_PARAM_RE)
255 unless @rev.to_s.match(REV_PARAM_RE) && @rev_to.to_s.match(REV_PARAM_RE)
256 if @repository.branches.blank?
256 if @repository.branches.blank?
257 raise InvalidRevisionParam
257 raise InvalidRevisionParam
258 end
258 end
259 end
259 end
260 rescue ActiveRecord::RecordNotFound
260 rescue ActiveRecord::RecordNotFound
261 render_404
261 render_404
262 rescue InvalidRevisionParam
262 rescue InvalidRevisionParam
263 show_error_not_found
263 show_error_not_found
264 end
264 end
265
265
266 def show_error_not_found
266 def show_error_not_found
267 render_error :message => l(:error_scm_not_found), :status => 404
267 render_error :message => l(:error_scm_not_found), :status => 404
268 end
268 end
269
269
270 # Handler for Redmine::Scm::Adapters::CommandFailed exception
270 # Handler for Redmine::Scm::Adapters::CommandFailed exception
271 def show_error_command_failed(exception)
271 def show_error_command_failed(exception)
272 render_error l(:error_scm_command_failed, exception.message)
272 render_error l(:error_scm_command_failed, exception.message)
273 end
273 end
274
274
275 def graph_commits_per_month(repository)
275 def graph_commits_per_month(repository)
276 @date_to = Date.today
276 @date_to = Date.today
277 @date_from = @date_to << 11
277 @date_from = @date_to << 11
278 @date_from = Date.civil(@date_from.year, @date_from.month, 1)
278 @date_from = Date.civil(@date_from.year, @date_from.month, 1)
279 commits_by_day = repository.changesets.count(
279 commits_by_day = repository.changesets.count(
280 :all, :group => :commit_date,
280 :all, :group => :commit_date,
281 :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
281 :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
282 commits_by_month = [0] * 12
282 commits_by_month = [0] * 12
283 commits_by_day.each {|c| commits_by_month[c.first.to_date.months_ago] += c.last }
283 commits_by_day.each {|c| commits_by_month[c.first.to_date.months_ago] += c.last }
284
284
285 changes_by_day = repository.changes.count(
285 changes_by_day = repository.changes.count(
286 :all, :group => :commit_date,
286 :all, :group => :commit_date,
287 :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
287 :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
288 changes_by_month = [0] * 12
288 changes_by_month = [0] * 12
289 changes_by_day.each {|c| changes_by_month[c.first.to_date.months_ago] += c.last }
289 changes_by_day.each {|c| changes_by_month[c.first.to_date.months_ago] += c.last }
290
290
291 fields = []
291 fields = []
292 12.times {|m| fields << month_name(((Date.today.month - 1 - m) % 12) + 1)}
292 12.times {|m| fields << month_name(((Date.today.month - 1 - m) % 12) + 1)}
293
293
294 graph = SVG::Graph::Bar.new(
294 graph = SVG::Graph::Bar.new(
295 :height => 300,
295 :height => 300,
296 :width => 800,
296 :width => 800,
297 :fields => fields.reverse,
297 :fields => fields.reverse,
298 :stack => :side,
298 :stack => :side,
299 :scale_integers => true,
299 :scale_integers => true,
300 :step_x_labels => 2,
300 :step_x_labels => 2,
301 :show_data_values => false,
301 :show_data_values => false,
302 :graph_title => l(:label_commits_per_month),
302 :graph_title => l(:label_commits_per_month),
303 :show_graph_title => true
303 :show_graph_title => true
304 )
304 )
305
305
306 graph.add_data(
306 graph.add_data(
307 :data => commits_by_month[0..11].reverse,
307 :data => commits_by_month[0..11].reverse,
308 :title => l(:label_revision_plural)
308 :title => l(:label_revision_plural)
309 )
309 )
310
310
311 graph.add_data(
311 graph.add_data(
312 :data => changes_by_month[0..11].reverse,
312 :data => changes_by_month[0..11].reverse,
313 :title => l(:label_change_plural)
313 :title => l(:label_change_plural)
314 )
314 )
315
315
316 graph.burn
316 graph.burn
317 end
317 end
318
318
319 def graph_commits_per_author(repository)
319 def graph_commits_per_author(repository)
320 commits_by_author = repository.changesets.count(:all, :group => :committer)
320 commits_by_author = repository.changesets.count(:all, :group => :committer)
321 commits_by_author.to_a.sort! {|x, y| x.last <=> y.last}
321 commits_by_author.to_a.sort! {|x, y| x.last <=> y.last}
322
322
323 changes_by_author = repository.changes.count(:all, :group => :committer)
323 changes_by_author = repository.changes.count(:all, :group => :committer)
324 h = changes_by_author.inject({}) {|o, i| o[i.first] = i.last; o}
324 h = changes_by_author.inject({}) {|o, i| o[i.first] = i.last; o}
325
325
326 fields = commits_by_author.collect {|r| r.first}
326 fields = commits_by_author.collect {|r| r.first}
327 commits_data = commits_by_author.collect {|r| r.last}
327 commits_data = commits_by_author.collect {|r| r.last}
328 changes_data = commits_by_author.collect {|r| h[r.first] || 0}
328 changes_data = commits_by_author.collect {|r| h[r.first] || 0}
329
329
330 fields = fields + [""]*(10 - fields.length) if fields.length<10
330 fields = fields + [""]*(10 - fields.length) if fields.length<10
331 commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10
331 commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10
332 changes_data = changes_data + [0]*(10 - changes_data.length) if changes_data.length<10
332 changes_data = changes_data + [0]*(10 - changes_data.length) if changes_data.length<10
333
333
334 # Remove email adress in usernames
334 # Remove email adress in usernames
335 fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') }
335 fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') }
336
336
337 graph = SVG::Graph::BarHorizontal.new(
337 graph = SVG::Graph::BarHorizontal.new(
338 :height => 400,
338 :height => 400,
339 :width => 800,
339 :width => 800,
340 :fields => fields,
340 :fields => fields,
341 :stack => :side,
341 :stack => :side,
342 :scale_integers => true,
342 :scale_integers => true,
343 :show_data_values => false,
343 :show_data_values => false,
344 :rotate_y_labels => false,
344 :rotate_y_labels => false,
345 :graph_title => l(:label_commits_per_author),
345 :graph_title => l(:label_commits_per_author),
346 :show_graph_title => true
346 :show_graph_title => true
347 )
347 )
348 graph.add_data(
348 graph.add_data(
349 :data => commits_data,
349 :data => commits_data,
350 :title => l(:label_revision_plural)
350 :title => l(:label_revision_plural)
351 )
351 )
352 graph.add_data(
352 graph.add_data(
353 :data => changes_data,
353 :data => changes_data,
354 :title => l(:label_change_plural)
354 :title => l(:label_change_plural)
355 )
355 )
356 graph.burn
356 graph.burn
357 end
357 end
358 end
358 end
359
359
360 class Date
360 class Date
361 def months_ago(date = Date.today)
361 def months_ago(date = Date.today)
362 (date.year - self.year)*12 + (date.month - self.month)
362 (date.year - self.year)*12 + (date.month - self.month)
363 end
363 end
364
364
365 def weeks_ago(date = Date.today)
365 def weeks_ago(date = Date.today)
366 (date.year - self.year)*52 + (date.cweek - self.cweek)
366 (date.year - self.year)*52 + (date.cweek - self.cweek)
367 end
367 end
368 end
368 end
369
369
370 class String
370 class String
371 def with_leading_slash
371 def with_leading_slash
372 starts_with?('/') ? self : "/#{self}"
372 starts_with?('/') ? self : "/#{self}"
373 end
373 end
374 end
374 end
@@ -1,339 +1,370
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19 require 'repositories_controller'
19 require 'repositories_controller'
20
20
21 # Re-raise errors caught by the controller.
21 # Re-raise errors caught by the controller.
22 class RepositoriesController; def rescue_action(e) raise e end; end
22 class RepositoriesController; def rescue_action(e) raise e end; end
23
23
24 class RepositoriesGitControllerTest < ActionController::TestCase
24 class RepositoriesGitControllerTest < ActionController::TestCase
25 fixtures :projects, :users, :roles, :members, :member_roles, :repositories, :enabled_modules
25 fixtures :projects, :users, :roles, :members, :member_roles, :repositories, :enabled_modules
26
26
27 # No '..' in the repository path
27 # No '..' in the repository path
28 REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/git_repository'
28 REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/git_repository'
29 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
29 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
30 PRJ_ID = 3
30 PRJ_ID = 3
31 CHAR_1_HEX = "\xc3\x9c"
31 CHAR_1_HEX = "\xc3\x9c"
32
32
33 def setup
33 def setup
34 @ruby19_non_utf8_pass =
34 @ruby19_non_utf8_pass =
35 (RUBY_VERSION >= '1.9' && Encoding.default_external.to_s != 'UTF-8')
35 (RUBY_VERSION >= '1.9' && Encoding.default_external.to_s != 'UTF-8')
36
36
37 @controller = RepositoriesController.new
37 @controller = RepositoriesController.new
38 @request = ActionController::TestRequest.new
38 @request = ActionController::TestRequest.new
39 @response = ActionController::TestResponse.new
39 @response = ActionController::TestResponse.new
40 User.current = nil
40 User.current = nil
41 @repository = Repository::Git.create(
41 @repository = Repository::Git.create(
42 :project => Project.find(3),
42 :project => Project.find(3),
43 :url => REPOSITORY_PATH,
43 :url => REPOSITORY_PATH,
44 :path_encoding => 'ISO-8859-1'
44 :path_encoding => 'ISO-8859-1'
45 )
45 )
46 assert @repository
46 assert @repository
47 @char_1 = CHAR_1_HEX.dup
47 @char_1 = CHAR_1_HEX.dup
48 if @char_1.respond_to?(:force_encoding)
48 if @char_1.respond_to?(:force_encoding)
49 @char_1.force_encoding('UTF-8')
49 @char_1.force_encoding('UTF-8')
50 end
50 end
51
52 Setting.default_language = 'en'
51 end
53 end
52
54
53 if File.directory?(REPOSITORY_PATH)
55 if File.directory?(REPOSITORY_PATH)
54 def test_browse_root
56 def test_browse_root
55 @repository.fetch_changesets
57 @repository.fetch_changesets
56 @repository.reload
58 @repository.reload
57 get :show, :id => PRJ_ID
59 get :show, :id => PRJ_ID
58 assert_response :success
60 assert_response :success
59 assert_template 'show'
61 assert_template 'show'
60 assert_not_nil assigns(:entries)
62 assert_not_nil assigns(:entries)
61 assert_equal 9, assigns(:entries).size
63 assert_equal 9, assigns(:entries).size
62 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
64 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
63 assert assigns(:entries).detect {|e| e.name == 'this_is_a_really_long_and_verbose_directory_name' && e.kind == 'dir'}
65 assert assigns(:entries).detect {|e| e.name == 'this_is_a_really_long_and_verbose_directory_name' && e.kind == 'dir'}
64 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
66 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
65 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
67 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
66 assert assigns(:entries).detect {|e| e.name == 'copied_README' && e.kind == 'file'}
68 assert assigns(:entries).detect {|e| e.name == 'copied_README' && e.kind == 'file'}
67 assert assigns(:entries).detect {|e| e.name == 'new_file.txt' && e.kind == 'file'}
69 assert assigns(:entries).detect {|e| e.name == 'new_file.txt' && e.kind == 'file'}
68 assert assigns(:entries).detect {|e| e.name == 'renamed_test.txt' && e.kind == 'file'}
70 assert assigns(:entries).detect {|e| e.name == 'renamed_test.txt' && e.kind == 'file'}
69 assert assigns(:entries).detect {|e| e.name == 'filemane with spaces.txt' && e.kind == 'file'}
71 assert assigns(:entries).detect {|e| e.name == 'filemane with spaces.txt' && e.kind == 'file'}
70 assert assigns(:entries).detect {|e| e.name == ' filename with a leading space.txt ' && e.kind == 'file'}
72 assert assigns(:entries).detect {|e| e.name == ' filename with a leading space.txt ' && e.kind == 'file'}
71 assert_not_nil assigns(:changesets)
73 assert_not_nil assigns(:changesets)
72 assigns(:changesets).size > 0
74 assigns(:changesets).size > 0
73 end
75 end
74
76
75 def test_browse_branch
77 def test_browse_branch
76 @repository.fetch_changesets
78 @repository.fetch_changesets
77 @repository.reload
79 @repository.reload
78 get :show, :id => PRJ_ID, :rev => 'test_branch'
80 get :show, :id => PRJ_ID, :rev => 'test_branch'
79 assert_response :success
81 assert_response :success
80 assert_template 'show'
82 assert_template 'show'
81 assert_not_nil assigns(:entries)
83 assert_not_nil assigns(:entries)
82 assert_equal 4, assigns(:entries).size
84 assert_equal 4, assigns(:entries).size
83 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
85 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
84 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
86 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
85 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
87 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
86 assert assigns(:entries).detect {|e| e.name == 'test.txt' && e.kind == 'file'}
88 assert assigns(:entries).detect {|e| e.name == 'test.txt' && e.kind == 'file'}
87 assert_not_nil assigns(:changesets)
89 assert_not_nil assigns(:changesets)
88 assigns(:changesets).size > 0
90 assigns(:changesets).size > 0
89 end
91 end
90
92
91 def test_browse_tag
93 def test_browse_tag
92 @repository.fetch_changesets
94 @repository.fetch_changesets
93 @repository.reload
95 @repository.reload
94 [
96 [
95 "tag00.lightweight",
97 "tag00.lightweight",
96 "tag01.annotated",
98 "tag01.annotated",
97 ].each do |t1|
99 ].each do |t1|
98 get :show, :id => PRJ_ID, :rev => t1
100 get :show, :id => PRJ_ID, :rev => t1
99 assert_response :success
101 assert_response :success
100 assert_template 'show'
102 assert_template 'show'
101 assert_not_nil assigns(:entries)
103 assert_not_nil assigns(:entries)
102 assigns(:entries).size > 0
104 assigns(:entries).size > 0
103 assert_not_nil assigns(:changesets)
105 assert_not_nil assigns(:changesets)
104 assigns(:changesets).size > 0
106 assigns(:changesets).size > 0
105 end
107 end
106 end
108 end
107
109
108 def test_browse_directory
110 def test_browse_directory
109 @repository.fetch_changesets
111 @repository.fetch_changesets
110 @repository.reload
112 @repository.reload
111 get :show, :id => PRJ_ID, :path => ['images']
113 get :show, :id => PRJ_ID, :path => ['images']
112 assert_response :success
114 assert_response :success
113 assert_template 'show'
115 assert_template 'show'
114 assert_not_nil assigns(:entries)
116 assert_not_nil assigns(:entries)
115 assert_equal ['edit.png'], assigns(:entries).collect(&:name)
117 assert_equal ['edit.png'], assigns(:entries).collect(&:name)
116 entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
118 entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
117 assert_not_nil entry
119 assert_not_nil entry
118 assert_equal 'file', entry.kind
120 assert_equal 'file', entry.kind
119 assert_equal 'images/edit.png', entry.path
121 assert_equal 'images/edit.png', entry.path
120 assert_not_nil assigns(:changesets)
122 assert_not_nil assigns(:changesets)
121 assigns(:changesets).size > 0
123 assigns(:changesets).size > 0
122 end
124 end
123
125
124 def test_browse_at_given_revision
126 def test_browse_at_given_revision
125 @repository.fetch_changesets
127 @repository.fetch_changesets
126 @repository.reload
128 @repository.reload
127 get :show, :id => PRJ_ID, :path => ['images'],
129 get :show, :id => PRJ_ID, :path => ['images'],
128 :rev => '7234cb2750b63f47bff735edc50a1c0a433c2518'
130 :rev => '7234cb2750b63f47bff735edc50a1c0a433c2518'
129 assert_response :success
131 assert_response :success
130 assert_template 'show'
132 assert_template 'show'
131 assert_not_nil assigns(:entries)
133 assert_not_nil assigns(:entries)
132 assert_equal ['delete.png'], assigns(:entries).collect(&:name)
134 assert_equal ['delete.png'], assigns(:entries).collect(&:name)
133 assert_not_nil assigns(:changesets)
135 assert_not_nil assigns(:changesets)
134 assigns(:changesets).size > 0
136 assigns(:changesets).size > 0
135 end
137 end
136
138
137 def test_changes
139 def test_changes
138 get :changes, :id => PRJ_ID, :path => ['images', 'edit.png']
140 get :changes, :id => PRJ_ID, :path => ['images', 'edit.png']
139 assert_response :success
141 assert_response :success
140 assert_template 'changes'
142 assert_template 'changes'
141 assert_tag :tag => 'h2', :content => 'edit.png'
143 assert_tag :tag => 'h2', :content => 'edit.png'
142 end
144 end
143
145
144 def test_entry_show
146 def test_entry_show
145 get :entry, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb']
147 get :entry, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb']
146 assert_response :success
148 assert_response :success
147 assert_template 'entry'
149 assert_template 'entry'
148 # Line 19
150 # Line 19
149 assert_tag :tag => 'th',
151 assert_tag :tag => 'th',
150 :content => '11',
152 :content => '11',
151 :attributes => { :class => 'line-num' },
153 :attributes => { :class => 'line-num' },
152 :sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ }
154 :sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ }
153 end
155 end
154
156
155 def test_entry_show_latin_1
157 def test_entry_show_latin_1
156 if @ruby19_non_utf8_pass
158 if @ruby19_non_utf8_pass
157 puts_ruby19_non_utf8_pass()
159 puts_ruby19_non_utf8_pass()
158 else
160 else
159 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
161 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
160 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
162 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
161 get :entry, :id => PRJ_ID,
163 get :entry, :id => PRJ_ID,
162 :path => ['latin-1-dir', "test-#{@char_1}.txt"], :rev => r1
164 :path => ['latin-1-dir', "test-#{@char_1}.txt"], :rev => r1
163 assert_response :success
165 assert_response :success
164 assert_template 'entry'
166 assert_template 'entry'
165 assert_tag :tag => 'th',
167 assert_tag :tag => 'th',
166 :content => '1',
168 :content => '1',
167 :attributes => { :class => 'line-num' },
169 :attributes => { :class => 'line-num' },
168 :sibling => { :tag => 'td',
170 :sibling => { :tag => 'td',
169 :content => /test-#{@char_1}.txt/ }
171 :content => /test-#{@char_1}.txt/ }
170 end
172 end
171 end
173 end
172 end
174 end
173 end
175 end
174
176
175 def test_entry_download
177 def test_entry_download
176 get :entry, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'],
178 get :entry, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'],
177 :format => 'raw'
179 :format => 'raw'
178 assert_response :success
180 assert_response :success
179 # File content
181 # File content
180 assert @response.body.include?('WITHOUT ANY WARRANTY')
182 assert @response.body.include?('WITHOUT ANY WARRANTY')
181 end
183 end
182
184
183 def test_directory_entry
185 def test_directory_entry
184 get :entry, :id => PRJ_ID, :path => ['sources']
186 get :entry, :id => PRJ_ID, :path => ['sources']
185 assert_response :success
187 assert_response :success
186 assert_template 'show'
188 assert_template 'show'
187 assert_not_nil assigns(:entry)
189 assert_not_nil assigns(:entry)
188 assert_equal 'sources', assigns(:entry).name
190 assert_equal 'sources', assigns(:entry).name
189 end
191 end
190
192
191 def test_diff
193 def test_diff
192 @repository.fetch_changesets
194 @repository.fetch_changesets
193 @repository.reload
195 @repository.reload
194 # Full diff of changeset 2f9c0091
196 # Full diff of changeset 2f9c0091
195 get :diff, :id => PRJ_ID, :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
197 get :diff, :id => PRJ_ID, :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
196 assert_response :success
198 assert_response :success
197 assert_template 'diff'
199 assert_template 'diff'
198 # Line 22 removed
200 # Line 22 removed
199 assert_tag :tag => 'th',
201 assert_tag :tag => 'th',
200 :content => /22/,
202 :content => /22/,
201 :sibling => { :tag => 'td',
203 :sibling => { :tag => 'td',
202 :attributes => { :class => /diff_out/ },
204 :attributes => { :class => /diff_out/ },
203 :content => /def remove/ }
205 :content => /def remove/ }
204 assert_tag :tag => 'h2', :content => /2f9c0091/
206 assert_tag :tag => 'h2', :content => /2f9c0091/
205 end
207 end
206
208
209 def test_diff_truncated
210 @repository.fetch_changesets
211 @repository.reload
212 Setting.diff_max_lines_displayed = 5
213
214 # Truncated diff of changeset 2f9c0091
215 with_cache do
216 get :diff, :id => PRJ_ID, :type => 'inline',
217 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
218 assert_response :success
219 assert @response.body.include?("... This diff was truncated")
220
221 Setting.default_language = 'fr'
222 get :diff, :id => PRJ_ID, :type => 'inline',
223 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
224 assert_response :success
225 assert ! @response.body.include?("... This diff was truncated")
226 assert @response.body.include?("... Ce diff")
227 end
228 end
229
207 def test_diff_two_revs
230 def test_diff_two_revs
208 @repository.fetch_changesets
231 @repository.fetch_changesets
209 @repository.reload
232 @repository.reload
210 get :diff, :id => PRJ_ID,
233 get :diff, :id => PRJ_ID,
211 :rev => '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
234 :rev => '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
212 :rev_to => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
235 :rev_to => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
213 assert_response :success
236 assert_response :success
214 assert_template 'diff'
237 assert_template 'diff'
215 diff = assigns(:diff)
238 diff = assigns(:diff)
216 assert_not_nil diff
239 assert_not_nil diff
217 assert_tag :tag => 'h2', :content => /2f9c0091:61b685fb/
240 assert_tag :tag => 'h2', :content => /2f9c0091:61b685fb/
218 end
241 end
219
242
220 def test_diff_latin_1
243 def test_diff_latin_1
221 if @ruby19_non_utf8_pass
244 if @ruby19_non_utf8_pass
222 puts_ruby19_non_utf8_pass()
245 puts_ruby19_non_utf8_pass()
223 else
246 else
224 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
247 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
225 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
248 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
226 get :diff, :id => PRJ_ID, :rev => r1
249 get :diff, :id => PRJ_ID, :rev => r1
227 assert_response :success
250 assert_response :success
228 assert_template 'diff'
251 assert_template 'diff'
229 assert_tag :tag => 'thead',
252 assert_tag :tag => 'thead',
230 :descendant => {
253 :descendant => {
231 :tag => 'th',
254 :tag => 'th',
232 :attributes => { :class => 'filename' } ,
255 :attributes => { :class => 'filename' } ,
233 :content => /latin-1-dir\/test-#{@char_1}.txt/ ,
256 :content => /latin-1-dir\/test-#{@char_1}.txt/ ,
234 },
257 },
235 :sibling => {
258 :sibling => {
236 :tag => 'tbody',
259 :tag => 'tbody',
237 :descendant => {
260 :descendant => {
238 :tag => 'td',
261 :tag => 'td',
239 :attributes => { :class => /diff_in/ },
262 :attributes => { :class => /diff_in/ },
240 :content => /test-#{@char_1}.txt/
263 :content => /test-#{@char_1}.txt/
241 }
264 }
242 }
265 }
243 end
266 end
244 end
267 end
245 end
268 end
246 end
269 end
247
270
248 def test_annotate
271 def test_annotate
249 get :annotate, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb']
272 get :annotate, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb']
250 assert_response :success
273 assert_response :success
251 assert_template 'annotate'
274 assert_template 'annotate'
252 # Line 23, changeset 2f9c0091
275 # Line 23, changeset 2f9c0091
253 assert_tag :tag => 'th', :content => '24',
276 assert_tag :tag => 'th', :content => '24',
254 :sibling => {
277 :sibling => {
255 :tag => 'td',
278 :tag => 'td',
256 :child => {
279 :child => {
257 :tag => 'a',
280 :tag => 'a',
258 :content => /2f9c0091c754a91af7a9c478e36556b4bde8dcf7/
281 :content => /2f9c0091c754a91af7a9c478e36556b4bde8dcf7/
259 }
282 }
260 },
283 },
261 :sibling => { :tag => 'td', :content => /jsmith/ }
284 :sibling => { :tag => 'td', :content => /jsmith/ }
262 assert_tag :tag => 'th', :content => '24',
285 assert_tag :tag => 'th', :content => '24',
263 :sibling => {
286 :sibling => {
264 :tag => 'td',
287 :tag => 'td',
265 :child => {
288 :child => {
266 :tag => 'a',
289 :tag => 'a',
267 :content => /2f9c0091c754a91af7a9c478e36556b4bde8dcf7/
290 :content => /2f9c0091c754a91af7a9c478e36556b4bde8dcf7/
268 }
291 }
269 },
292 },
270 :sibling => { :tag => 'td', :content => /watcher =/ }
293 :sibling => { :tag => 'td', :content => /watcher =/ }
271 end
294 end
272
295
273 def test_annotate_at_given_revision
296 def test_annotate_at_given_revision
274 @repository.fetch_changesets
297 @repository.fetch_changesets
275 @repository.reload
298 @repository.reload
276 get :annotate, :id => PRJ_ID, :rev => 'deff7',
299 get :annotate, :id => PRJ_ID, :rev => 'deff7',
277 :path => ['sources', 'watchers_controller.rb']
300 :path => ['sources', 'watchers_controller.rb']
278 assert_response :success
301 assert_response :success
279 assert_template 'annotate'
302 assert_template 'annotate'
280 assert_tag :tag => 'h2', :content => /@ deff712f/
303 assert_tag :tag => 'h2', :content => /@ deff712f/
281 end
304 end
282
305
283 def test_annotate_binary_file
306 def test_annotate_binary_file
284 get :annotate, :id => PRJ_ID, :path => ['images', 'edit.png']
307 get :annotate, :id => PRJ_ID, :path => ['images', 'edit.png']
285 assert_response 500
308 assert_response 500
286 assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ },
309 assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ },
287 :content => /cannot be annotated/
310 :content => /cannot be annotated/
288 end
311 end
289
312
290 def test_annotate_latin_1
313 def test_annotate_latin_1
291 if @ruby19_non_utf8_pass
314 if @ruby19_non_utf8_pass
292 puts_ruby19_non_utf8_pass()
315 puts_ruby19_non_utf8_pass()
293 else
316 else
294 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
317 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
295 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
318 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
296 get :annotate, :id => PRJ_ID,
319 get :annotate, :id => PRJ_ID,
297 :path => ['latin-1-dir', "test-#{@char_1}.txt"], :rev => r1
320 :path => ['latin-1-dir', "test-#{@char_1}.txt"], :rev => r1
298 assert_tag :tag => 'th',
321 assert_tag :tag => 'th',
299 :content => '1',
322 :content => '1',
300 :attributes => { :class => 'line-num' },
323 :attributes => { :class => 'line-num' },
301 :sibling => { :tag => 'td',
324 :sibling => { :tag => 'td',
302 :content => /test-#{@char_1}.txt/ }
325 :content => /test-#{@char_1}.txt/ }
303 end
326 end
304 end
327 end
305 end
328 end
306 end
329 end
307
330
308 def test_revision
331 def test_revision
309 @repository.fetch_changesets
332 @repository.fetch_changesets
310 @repository.reload
333 @repository.reload
311 ['61b685fbe55ab05b5ac68402d5720c1a6ac973d1', '61b685f'].each do |r|
334 ['61b685fbe55ab05b5ac68402d5720c1a6ac973d1', '61b685f'].each do |r|
312 get :revision, :id => PRJ_ID, :rev => r
335 get :revision, :id => PRJ_ID, :rev => r
313 assert_response :success
336 assert_response :success
314 assert_template 'revision'
337 assert_template 'revision'
315 end
338 end
316 end
339 end
317
340
318 def test_empty_revision
341 def test_empty_revision
319 @repository.fetch_changesets
342 @repository.fetch_changesets
320 @repository.reload
343 @repository.reload
321 ['', ' ', nil].each do |r|
344 ['', ' ', nil].each do |r|
322 get :revision, :id => PRJ_ID, :rev => r
345 get :revision, :id => PRJ_ID, :rev => r
323 assert_response 404
346 assert_response 404
324 assert_error_tag :content => /was not found/
347 assert_error_tag :content => /was not found/
325 end
348 end
326 end
349 end
327
350
328 private
351 private
329
352
330 def puts_ruby19_non_utf8_pass
353 def puts_ruby19_non_utf8_pass
331 puts "TODO: This test fails in Ruby 1.9 " +
354 puts "TODO: This test fails in Ruby 1.9 " +
332 "and Encoding.default_external is not UTF-8. " +
355 "and Encoding.default_external is not UTF-8. " +
333 "Current value is '#{Encoding.default_external.to_s}'"
356 "Current value is '#{Encoding.default_external.to_s}'"
334 end
357 end
335 else
358 else
336 puts "Git test repository NOT FOUND. Skipping functional tests !!!"
359 puts "Git test repository NOT FOUND. Skipping functional tests !!!"
337 def test_fake; assert true end
360 def test_fake; assert true end
338 end
361 end
362
363 private
364 def with_cache(&block)
365 before = ActionController::Base.perform_caching
366 ActionController::Base.perform_caching = true
367 block.call
368 ActionController::Base.perform_caching = before
369 end
339 end
370 end
General Comments 0
You need to be logged in to leave comments. Login now