##// END OF EJS Templates
Merged r14156 and r14161 (#19400)....
Jean-Philippe Lang -
r13816:94d91e75f539
parent child
Show More
@@ -1,495 +1,500
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 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 class ScmFetchError < Exception; end
18 class ScmFetchError < Exception; end
19
19
20 class Repository < ActiveRecord::Base
20 class Repository < ActiveRecord::Base
21 include Redmine::Ciphering
21 include Redmine::Ciphering
22 include Redmine::SafeAttributes
22 include Redmine::SafeAttributes
23
23
24 # Maximum length for repository identifiers
24 # Maximum length for repository identifiers
25 IDENTIFIER_MAX_LENGTH = 255
25 IDENTIFIER_MAX_LENGTH = 255
26
26
27 belongs_to :project
27 belongs_to :project
28 has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC"
28 has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC"
29 has_many :filechanges, :class_name => 'Change', :through => :changesets
29 has_many :filechanges, :class_name => 'Change', :through => :changesets
30
30
31 serialize :extra_info
31 serialize :extra_info
32
32
33 before_validation :normalize_identifier
33 before_save :check_default
34 before_save :check_default
34
35
35 # Raw SQL to delete changesets and changes in the database
36 # Raw SQL to delete changesets and changes in the database
36 # has_many :changesets, :dependent => :destroy is too slow for big repositories
37 # has_many :changesets, :dependent => :destroy is too slow for big repositories
37 before_destroy :clear_changesets
38 before_destroy :clear_changesets
38
39
39 validates_length_of :password, :maximum => 255, :allow_nil => true
40 validates_length_of :password, :maximum => 255, :allow_nil => true
40 validates_length_of :identifier, :maximum => IDENTIFIER_MAX_LENGTH, :allow_blank => true
41 validates_length_of :identifier, :maximum => IDENTIFIER_MAX_LENGTH, :allow_blank => true
41 validates_uniqueness_of :identifier, :scope => :project_id
42 validates_uniqueness_of :identifier, :scope => :project_id
42 validates_exclusion_of :identifier, :in => %w(browse show entry raw changes annotate diff statistics graph revisions revision)
43 validates_exclusion_of :identifier, :in => %w(browse show entry raw changes annotate diff statistics graph revisions revision)
43 # donwcase letters, digits, dashes, underscores but not digits only
44 # donwcase letters, digits, dashes, underscores but not digits only
44 validates_format_of :identifier, :with => /\A(?!\d+$)[a-z0-9\-_]*\z/, :allow_blank => true
45 validates_format_of :identifier, :with => /\A(?!\d+$)[a-z0-9\-_]*\z/, :allow_blank => true
45 # Checks if the SCM is enabled when creating a repository
46 # Checks if the SCM is enabled when creating a repository
46 validate :repo_create_validation, :on => :create
47 validate :repo_create_validation, :on => :create
47
48
48 safe_attributes 'identifier',
49 safe_attributes 'identifier',
49 'login',
50 'login',
50 'password',
51 'password',
51 'path_encoding',
52 'path_encoding',
52 'log_encoding',
53 'log_encoding',
53 'is_default'
54 'is_default'
54
55
55 safe_attributes 'url',
56 safe_attributes 'url',
56 :if => lambda {|repository, user| repository.new_record?}
57 :if => lambda {|repository, user| repository.new_record?}
57
58
58 def repo_create_validation
59 def repo_create_validation
59 unless Setting.enabled_scm.include?(self.class.name.demodulize)
60 unless Setting.enabled_scm.include?(self.class.name.demodulize)
60 errors.add(:type, :invalid)
61 errors.add(:type, :invalid)
61 end
62 end
62 end
63 end
63
64
64 def self.human_attribute_name(attribute_key_name, *args)
65 def self.human_attribute_name(attribute_key_name, *args)
65 attr_name = attribute_key_name.to_s
66 attr_name = attribute_key_name.to_s
66 if attr_name == "log_encoding"
67 if attr_name == "log_encoding"
67 attr_name = "commit_logs_encoding"
68 attr_name = "commit_logs_encoding"
68 end
69 end
69 super(attr_name, *args)
70 super(attr_name, *args)
70 end
71 end
71
72
72 # Removes leading and trailing whitespace
73 # Removes leading and trailing whitespace
73 def url=(arg)
74 def url=(arg)
74 write_attribute(:url, arg ? arg.to_s.strip : nil)
75 write_attribute(:url, arg ? arg.to_s.strip : nil)
75 end
76 end
76
77
77 # Removes leading and trailing whitespace
78 # Removes leading and trailing whitespace
78 def root_url=(arg)
79 def root_url=(arg)
79 write_attribute(:root_url, arg ? arg.to_s.strip : nil)
80 write_attribute(:root_url, arg ? arg.to_s.strip : nil)
80 end
81 end
81
82
82 def password
83 def password
83 read_ciphered_attribute(:password)
84 read_ciphered_attribute(:password)
84 end
85 end
85
86
86 def password=(arg)
87 def password=(arg)
87 write_ciphered_attribute(:password, arg)
88 write_ciphered_attribute(:password, arg)
88 end
89 end
89
90
90 def scm_adapter
91 def scm_adapter
91 self.class.scm_adapter_class
92 self.class.scm_adapter_class
92 end
93 end
93
94
94 def scm
95 def scm
95 unless @scm
96 unless @scm
96 @scm = self.scm_adapter.new(url, root_url,
97 @scm = self.scm_adapter.new(url, root_url,
97 login, password, path_encoding)
98 login, password, path_encoding)
98 if root_url.blank? && @scm.root_url.present?
99 if root_url.blank? && @scm.root_url.present?
99 update_attribute(:root_url, @scm.root_url)
100 update_attribute(:root_url, @scm.root_url)
100 end
101 end
101 end
102 end
102 @scm
103 @scm
103 end
104 end
104
105
105 def scm_name
106 def scm_name
106 self.class.scm_name
107 self.class.scm_name
107 end
108 end
108
109
109 def name
110 def name
110 if identifier.present?
111 if identifier.present?
111 identifier
112 identifier
112 elsif is_default?
113 elsif is_default?
113 l(:field_repository_is_default)
114 l(:field_repository_is_default)
114 else
115 else
115 scm_name
116 scm_name
116 end
117 end
117 end
118 end
118
119
119 def identifier=(identifier)
120 def identifier=(identifier)
120 super unless identifier_frozen?
121 super unless identifier_frozen?
121 end
122 end
122
123
123 def identifier_frozen?
124 def identifier_frozen?
124 errors[:identifier].blank? && !(new_record? || identifier.blank?)
125 errors[:identifier].blank? && !(new_record? || identifier.blank?)
125 end
126 end
126
127
127 def identifier_param
128 def identifier_param
128 if is_default?
129 if is_default?
129 nil
130 nil
130 elsif identifier.present?
131 elsif identifier.present?
131 identifier
132 identifier
132 else
133 else
133 id.to_s
134 id.to_s
134 end
135 end
135 end
136 end
136
137
137 def <=>(repository)
138 def <=>(repository)
138 if is_default?
139 if is_default?
139 -1
140 -1
140 elsif repository.is_default?
141 elsif repository.is_default?
141 1
142 1
142 else
143 else
143 identifier.to_s <=> repository.identifier.to_s
144 identifier.to_s <=> repository.identifier.to_s
144 end
145 end
145 end
146 end
146
147
147 def self.find_by_identifier_param(param)
148 def self.find_by_identifier_param(param)
148 if param.to_s =~ /^\d+$/
149 if param.to_s =~ /^\d+$/
149 find_by_id(param)
150 find_by_id(param)
150 else
151 else
151 find_by_identifier(param)
152 find_by_identifier(param)
152 end
153 end
153 end
154 end
154
155
155 # TODO: should return an empty hash instead of nil to avoid many ||{}
156 # TODO: should return an empty hash instead of nil to avoid many ||{}
156 def extra_info
157 def extra_info
157 h = read_attribute(:extra_info)
158 h = read_attribute(:extra_info)
158 h.is_a?(Hash) ? h : nil
159 h.is_a?(Hash) ? h : nil
159 end
160 end
160
161
161 def merge_extra_info(arg)
162 def merge_extra_info(arg)
162 h = extra_info || {}
163 h = extra_info || {}
163 return h if arg.nil?
164 return h if arg.nil?
164 h.merge!(arg)
165 h.merge!(arg)
165 write_attribute(:extra_info, h)
166 write_attribute(:extra_info, h)
166 end
167 end
167
168
168 def report_last_commit
169 def report_last_commit
169 true
170 true
170 end
171 end
171
172
172 def supports_cat?
173 def supports_cat?
173 scm.supports_cat?
174 scm.supports_cat?
174 end
175 end
175
176
176 def supports_annotate?
177 def supports_annotate?
177 scm.supports_annotate?
178 scm.supports_annotate?
178 end
179 end
179
180
180 def supports_all_revisions?
181 def supports_all_revisions?
181 true
182 true
182 end
183 end
183
184
184 def supports_directory_revisions?
185 def supports_directory_revisions?
185 false
186 false
186 end
187 end
187
188
188 def supports_revision_graph?
189 def supports_revision_graph?
189 false
190 false
190 end
191 end
191
192
192 def entry(path=nil, identifier=nil)
193 def entry(path=nil, identifier=nil)
193 scm.entry(path, identifier)
194 scm.entry(path, identifier)
194 end
195 end
195
196
196 def scm_entries(path=nil, identifier=nil)
197 def scm_entries(path=nil, identifier=nil)
197 scm.entries(path, identifier)
198 scm.entries(path, identifier)
198 end
199 end
199 protected :scm_entries
200 protected :scm_entries
200
201
201 def entries(path=nil, identifier=nil)
202 def entries(path=nil, identifier=nil)
202 entries = scm_entries(path, identifier)
203 entries = scm_entries(path, identifier)
203 load_entries_changesets(entries)
204 load_entries_changesets(entries)
204 entries
205 entries
205 end
206 end
206
207
207 def branches
208 def branches
208 scm.branches
209 scm.branches
209 end
210 end
210
211
211 def tags
212 def tags
212 scm.tags
213 scm.tags
213 end
214 end
214
215
215 def default_branch
216 def default_branch
216 nil
217 nil
217 end
218 end
218
219
219 def properties(path, identifier=nil)
220 def properties(path, identifier=nil)
220 scm.properties(path, identifier)
221 scm.properties(path, identifier)
221 end
222 end
222
223
223 def cat(path, identifier=nil)
224 def cat(path, identifier=nil)
224 scm.cat(path, identifier)
225 scm.cat(path, identifier)
225 end
226 end
226
227
227 def diff(path, rev, rev_to)
228 def diff(path, rev, rev_to)
228 scm.diff(path, rev, rev_to)
229 scm.diff(path, rev, rev_to)
229 end
230 end
230
231
231 def diff_format_revisions(cs, cs_to, sep=':')
232 def diff_format_revisions(cs, cs_to, sep=':')
232 text = ""
233 text = ""
233 text << cs_to.format_identifier + sep if cs_to
234 text << cs_to.format_identifier + sep if cs_to
234 text << cs.format_identifier if cs
235 text << cs.format_identifier if cs
235 text
236 text
236 end
237 end
237
238
238 # Returns a path relative to the url of the repository
239 # Returns a path relative to the url of the repository
239 def relative_path(path)
240 def relative_path(path)
240 path
241 path
241 end
242 end
242
243
243 # Finds and returns a revision with a number or the beginning of a hash
244 # Finds and returns a revision with a number or the beginning of a hash
244 def find_changeset_by_name(name)
245 def find_changeset_by_name(name)
245 return nil if name.blank?
246 return nil if name.blank?
246 s = name.to_s
247 s = name.to_s
247 if s.match(/^\d*$/)
248 if s.match(/^\d*$/)
248 changesets.where("revision = ?", s).first
249 changesets.where("revision = ?", s).first
249 else
250 else
250 changesets.where("revision LIKE ?", s + '%').first
251 changesets.where("revision LIKE ?", s + '%').first
251 end
252 end
252 end
253 end
253
254
254 def latest_changeset
255 def latest_changeset
255 @latest_changeset ||= changesets.first
256 @latest_changeset ||= changesets.first
256 end
257 end
257
258
258 # Returns the latest changesets for +path+
259 # Returns the latest changesets for +path+
259 # Default behaviour is to search in cached changesets
260 # Default behaviour is to search in cached changesets
260 def latest_changesets(path, rev, limit=10)
261 def latest_changesets(path, rev, limit=10)
261 if path.blank?
262 if path.blank?
262 changesets.
263 changesets.
263 reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
264 reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
264 limit(limit).
265 limit(limit).
265 preload(:user).
266 preload(:user).
266 all
267 all
267 else
268 else
268 filechanges.
269 filechanges.
269 where("path = ?", path.with_leading_slash).
270 where("path = ?", path.with_leading_slash).
270 reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
271 reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
271 limit(limit).
272 limit(limit).
272 preload(:changeset => :user).
273 preload(:changeset => :user).
273 collect(&:changeset)
274 collect(&:changeset)
274 end
275 end
275 end
276 end
276
277
277 def scan_changesets_for_issue_ids
278 def scan_changesets_for_issue_ids
278 self.changesets.each(&:scan_comment_for_issue_ids)
279 self.changesets.each(&:scan_comment_for_issue_ids)
279 end
280 end
280
281
281 # Returns an array of committers usernames and associated user_id
282 # Returns an array of committers usernames and associated user_id
282 def committers
283 def committers
283 @committers ||= Changeset.connection.select_rows(
284 @committers ||= Changeset.connection.select_rows(
284 "SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}")
285 "SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}")
285 end
286 end
286
287
287 # Maps committers username to a user ids
288 # Maps committers username to a user ids
288 def committer_ids=(h)
289 def committer_ids=(h)
289 if h.is_a?(Hash)
290 if h.is_a?(Hash)
290 committers.each do |committer, user_id|
291 committers.each do |committer, user_id|
291 new_user_id = h[committer]
292 new_user_id = h[committer]
292 if new_user_id && (new_user_id.to_i != user_id.to_i)
293 if new_user_id && (new_user_id.to_i != user_id.to_i)
293 new_user_id = (new_user_id.to_i > 0 ? new_user_id.to_i : nil)
294 new_user_id = (new_user_id.to_i > 0 ? new_user_id.to_i : nil)
294 Changeset.where(["repository_id = ? AND committer = ?", id, committer]).
295 Changeset.where(["repository_id = ? AND committer = ?", id, committer]).
295 update_all("user_id = #{new_user_id.nil? ? 'NULL' : new_user_id}")
296 update_all("user_id = #{new_user_id.nil? ? 'NULL' : new_user_id}")
296 end
297 end
297 end
298 end
298 @committers = nil
299 @committers = nil
299 @found_committer_users = nil
300 @found_committer_users = nil
300 true
301 true
301 else
302 else
302 false
303 false
303 end
304 end
304 end
305 end
305
306
306 # Returns the Redmine User corresponding to the given +committer+
307 # Returns the Redmine User corresponding to the given +committer+
307 # It will return nil if the committer is not yet mapped and if no User
308 # It will return nil if the committer is not yet mapped and if no User
308 # with the same username or email was found
309 # with the same username or email was found
309 def find_committer_user(committer)
310 def find_committer_user(committer)
310 unless committer.blank?
311 unless committer.blank?
311 @found_committer_users ||= {}
312 @found_committer_users ||= {}
312 return @found_committer_users[committer] if @found_committer_users.has_key?(committer)
313 return @found_committer_users[committer] if @found_committer_users.has_key?(committer)
313
314
314 user = nil
315 user = nil
315 c = changesets.where(:committer => committer).includes(:user).first
316 c = changesets.where(:committer => committer).includes(:user).first
316 if c && c.user
317 if c && c.user
317 user = c.user
318 user = c.user
318 elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
319 elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
319 username, email = $1.strip, $3
320 username, email = $1.strip, $3
320 u = User.find_by_login(username)
321 u = User.find_by_login(username)
321 u ||= User.find_by_mail(email) unless email.blank?
322 u ||= User.find_by_mail(email) unless email.blank?
322 user = u
323 user = u
323 end
324 end
324 @found_committer_users[committer] = user
325 @found_committer_users[committer] = user
325 user
326 user
326 end
327 end
327 end
328 end
328
329
329 def repo_log_encoding
330 def repo_log_encoding
330 encoding = log_encoding.to_s.strip
331 encoding = log_encoding.to_s.strip
331 encoding.blank? ? 'UTF-8' : encoding
332 encoding.blank? ? 'UTF-8' : encoding
332 end
333 end
333
334
334 # Fetches new changesets for all repositories of active projects
335 # Fetches new changesets for all repositories of active projects
335 # Can be called periodically by an external script
336 # Can be called periodically by an external script
336 # eg. ruby script/runner "Repository.fetch_changesets"
337 # eg. ruby script/runner "Repository.fetch_changesets"
337 def self.fetch_changesets
338 def self.fetch_changesets
338 Project.active.has_module(:repository).all.each do |project|
339 Project.active.has_module(:repository).all.each do |project|
339 project.repositories.each do |repository|
340 project.repositories.each do |repository|
340 begin
341 begin
341 repository.fetch_changesets
342 repository.fetch_changesets
342 rescue Redmine::Scm::Adapters::CommandFailed => e
343 rescue Redmine::Scm::Adapters::CommandFailed => e
343 logger.error "scm: error during fetching changesets: #{e.message}"
344 logger.error "scm: error during fetching changesets: #{e.message}"
344 end
345 end
345 end
346 end
346 end
347 end
347 end
348 end
348
349
349 # scan changeset comments to find related and fixed issues for all repositories
350 # scan changeset comments to find related and fixed issues for all repositories
350 def self.scan_changesets_for_issue_ids
351 def self.scan_changesets_for_issue_ids
351 all.each(&:scan_changesets_for_issue_ids)
352 all.each(&:scan_changesets_for_issue_ids)
352 end
353 end
353
354
354 def self.scm_name
355 def self.scm_name
355 'Abstract'
356 'Abstract'
356 end
357 end
357
358
358 def self.available_scm
359 def self.available_scm
359 subclasses.collect {|klass| [klass.scm_name, klass.name]}
360 subclasses.collect {|klass| [klass.scm_name, klass.name]}
360 end
361 end
361
362
362 def self.factory(klass_name, *args)
363 def self.factory(klass_name, *args)
363 klass = "Repository::#{klass_name}".constantize
364 klass = "Repository::#{klass_name}".constantize
364 klass.new(*args)
365 klass.new(*args)
365 rescue
366 rescue
366 nil
367 nil
367 end
368 end
368
369
369 def self.scm_adapter_class
370 def self.scm_adapter_class
370 nil
371 nil
371 end
372 end
372
373
373 def self.scm_command
374 def self.scm_command
374 ret = ""
375 ret = ""
375 begin
376 begin
376 ret = self.scm_adapter_class.client_command if self.scm_adapter_class
377 ret = self.scm_adapter_class.client_command if self.scm_adapter_class
377 rescue Exception => e
378 rescue Exception => e
378 logger.error "scm: error during get command: #{e.message}"
379 logger.error "scm: error during get command: #{e.message}"
379 end
380 end
380 ret
381 ret
381 end
382 end
382
383
383 def self.scm_version_string
384 def self.scm_version_string
384 ret = ""
385 ret = ""
385 begin
386 begin
386 ret = self.scm_adapter_class.client_version_string if self.scm_adapter_class
387 ret = self.scm_adapter_class.client_version_string if self.scm_adapter_class
387 rescue Exception => e
388 rescue Exception => e
388 logger.error "scm: error during get version string: #{e.message}"
389 logger.error "scm: error during get version string: #{e.message}"
389 end
390 end
390 ret
391 ret
391 end
392 end
392
393
393 def self.scm_available
394 def self.scm_available
394 ret = false
395 ret = false
395 begin
396 begin
396 ret = self.scm_adapter_class.client_available if self.scm_adapter_class
397 ret = self.scm_adapter_class.client_available if self.scm_adapter_class
397 rescue Exception => e
398 rescue Exception => e
398 logger.error "scm: error during get scm available: #{e.message}"
399 logger.error "scm: error during get scm available: #{e.message}"
399 end
400 end
400 ret
401 ret
401 end
402 end
402
403
403 def set_as_default?
404 def set_as_default?
404 new_record? && project && Repository.where(:project_id => project.id).empty?
405 new_record? && project && Repository.where(:project_id => project.id).empty?
405 end
406 end
406
407
407 # Returns a hash with statistics by author in the following form:
408 # Returns a hash with statistics by author in the following form:
408 # {
409 # {
409 # "John Smith" => { :commits => 45, :changes => 324 },
410 # "John Smith" => { :commits => 45, :changes => 324 },
410 # "Bob" => { ... }
411 # "Bob" => { ... }
411 # }
412 # }
412 #
413 #
413 # Notes:
414 # Notes:
414 # - this hash honnors the users mapping defined for the repository
415 # - this hash honnors the users mapping defined for the repository
415 def stats_by_author
416 def stats_by_author
416 commits = Changeset.where("repository_id = ?", id).select("committer, user_id, count(*) as count").group("committer, user_id")
417 commits = Changeset.where("repository_id = ?", id).select("committer, user_id, count(*) as count").group("committer, user_id")
417
418
418 #TODO: restore ordering ; this line probably never worked
419 #TODO: restore ordering ; this line probably never worked
419 #commits.to_a.sort! {|x, y| x.last <=> y.last}
420 #commits.to_a.sort! {|x, y| x.last <=> y.last}
420
421
421 changes = Change.joins(:changeset).where("#{Changeset.table_name}.repository_id = ?", id).select("committer, user_id, count(*) as count").group("committer, user_id")
422 changes = Change.joins(:changeset).where("#{Changeset.table_name}.repository_id = ?", id).select("committer, user_id, count(*) as count").group("committer, user_id")
422
423
423 user_ids = changesets.map(&:user_id).compact.uniq
424 user_ids = changesets.map(&:user_id).compact.uniq
424 authors_names = User.where(:id => user_ids).inject({}) do |memo, user|
425 authors_names = User.where(:id => user_ids).inject({}) do |memo, user|
425 memo[user.id] = user.to_s
426 memo[user.id] = user.to_s
426 memo
427 memo
427 end
428 end
428
429
429 (commits + changes).inject({}) do |hash, element|
430 (commits + changes).inject({}) do |hash, element|
430 mapped_name = element.committer
431 mapped_name = element.committer
431 if username = authors_names[element.user_id.to_i]
432 if username = authors_names[element.user_id.to_i]
432 mapped_name = username
433 mapped_name = username
433 end
434 end
434 hash[mapped_name] ||= { :commits_count => 0, :changes_count => 0 }
435 hash[mapped_name] ||= { :commits_count => 0, :changes_count => 0 }
435 if element.is_a?(Changeset)
436 if element.is_a?(Changeset)
436 hash[mapped_name][:commits_count] += element.count.to_i
437 hash[mapped_name][:commits_count] += element.count.to_i
437 else
438 else
438 hash[mapped_name][:changes_count] += element.count.to_i
439 hash[mapped_name][:changes_count] += element.count.to_i
439 end
440 end
440 hash
441 hash
441 end
442 end
442 end
443 end
443
444
444 # Returns a scope of changesets that come from the same commit as the given changeset
445 # Returns a scope of changesets that come from the same commit as the given changeset
445 # in different repositories that point to the same backend
446 # in different repositories that point to the same backend
446 def same_commits_in_scope(scope, changeset)
447 def same_commits_in_scope(scope, changeset)
447 scope = scope.joins(:repository).where(:repositories => {:url => url, :root_url => root_url, :type => type})
448 scope = scope.joins(:repository).where(:repositories => {:url => url, :root_url => root_url, :type => type})
448 if changeset.scmid.present?
449 if changeset.scmid.present?
449 scope = scope.where(:scmid => changeset.scmid)
450 scope = scope.where(:scmid => changeset.scmid)
450 else
451 else
451 scope = scope.where(:revision => changeset.revision)
452 scope = scope.where(:revision => changeset.revision)
452 end
453 end
453 scope
454 scope
454 end
455 end
455
456
456 protected
457 protected
457
458
459 def normalize_identifier
460 self.identifier = identifier.to_s.strip
461 end
462
458 def check_default
463 def check_default
459 if !is_default? && set_as_default?
464 if !is_default? && set_as_default?
460 self.is_default = true
465 self.is_default = true
461 end
466 end
462 if is_default? && is_default_changed?
467 if is_default? && is_default_changed?
463 Repository.where(["project_id = ?", project_id]).update_all(["is_default = ?", false])
468 Repository.where(["project_id = ?", project_id]).update_all(["is_default = ?", false])
464 end
469 end
465 end
470 end
466
471
467 def load_entries_changesets(entries)
472 def load_entries_changesets(entries)
468 if entries
473 if entries
469 entries.each do |entry|
474 entries.each do |entry|
470 if entry.lastrev && entry.lastrev.identifier
475 if entry.lastrev && entry.lastrev.identifier
471 entry.changeset = find_changeset_by_name(entry.lastrev.identifier)
476 entry.changeset = find_changeset_by_name(entry.lastrev.identifier)
472 end
477 end
473 end
478 end
474 end
479 end
475 end
480 end
476
481
477 private
482 private
478
483
479 # Deletes repository data
484 # Deletes repository data
480 def clear_changesets
485 def clear_changesets
481 cs = Changeset.table_name
486 cs = Changeset.table_name
482 ch = Change.table_name
487 ch = Change.table_name
483 ci = "#{table_name_prefix}changesets_issues#{table_name_suffix}"
488 ci = "#{table_name_prefix}changesets_issues#{table_name_suffix}"
484 cp = "#{table_name_prefix}changeset_parents#{table_name_suffix}"
489 cp = "#{table_name_prefix}changeset_parents#{table_name_suffix}"
485
490
486 connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
491 connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
487 connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
492 connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
488 connection.delete("DELETE FROM #{cp} WHERE #{cp}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
493 connection.delete("DELETE FROM #{cp} WHERE #{cp}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
489 connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
494 connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
490 clear_extra_info_of_changesets
495 clear_extra_info_of_changesets
491 end
496 end
492
497
493 def clear_extra_info_of_changesets
498 def clear_extra_info_of_changesets
494 end
499 end
495 end
500 end
@@ -1,662 +1,662
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class RepositoriesGitControllerTest < ActionController::TestCase
20 class RepositoriesGitControllerTest < ActionController::TestCase
21 tests RepositoriesController
21 tests RepositoriesController
22
22
23 fixtures :projects, :users, :roles, :members, :member_roles,
23 fixtures :projects, :users, :roles, :members, :member_roles,
24 :repositories, :enabled_modules
24 :repositories, :enabled_modules
25
25
26 REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
26 REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
27 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
27 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
28 PRJ_ID = 3
28 PRJ_ID = 3
29 CHAR_1_HEX = "\xc3\x9c"
29 CHAR_1_HEX = "\xc3\x9c"
30 FELIX_HEX = "Felix Sch\xC3\xA4fer"
30 FELIX_HEX = "Felix Sch\xC3\xA4fer"
31 NUM_REV = 28
31 NUM_REV = 28
32
32
33 ## Git, Mercurial and CVS path encodings are binary.
33 ## Git, Mercurial and CVS path encodings are binary.
34 ## Subversion supports URL encoding for path.
34 ## Subversion supports URL encoding for path.
35 ## Redmine Mercurial adapter and extension use URL encoding.
35 ## Redmine Mercurial adapter and extension use URL encoding.
36 ## Git accepts only binary path in command line parameter.
36 ## Git accepts only binary path in command line parameter.
37 ## So, there is no way to use binary command line parameter in JRuby.
37 ## So, there is no way to use binary command line parameter in JRuby.
38 JRUBY_SKIP = (RUBY_PLATFORM == 'java')
38 JRUBY_SKIP = (RUBY_PLATFORM == 'java')
39 JRUBY_SKIP_STR = "TODO: This test fails in JRuby"
39 JRUBY_SKIP_STR = "TODO: This test fails in JRuby"
40
40
41 def setup
41 def setup
42 @ruby19_non_utf8_pass =
42 @ruby19_non_utf8_pass =
43 (RUBY_VERSION >= '1.9' && Encoding.default_external.to_s != 'UTF-8')
43 (RUBY_VERSION >= '1.9' && Encoding.default_external.to_s != 'UTF-8')
44
44
45 User.current = nil
45 User.current = nil
46 @project = Project.find(PRJ_ID)
46 @project = Project.find(PRJ_ID)
47 @repository = Repository::Git.create(
47 @repository = Repository::Git.create(
48 :project => @project,
48 :project => @project,
49 :url => REPOSITORY_PATH,
49 :url => REPOSITORY_PATH,
50 :path_encoding => 'ISO-8859-1'
50 :path_encoding => 'ISO-8859-1'
51 )
51 )
52 assert @repository
52 assert @repository
53 @char_1 = CHAR_1_HEX.dup
53 @char_1 = CHAR_1_HEX.dup
54 @felix_utf8 = FELIX_HEX.dup
54 @felix_utf8 = FELIX_HEX.dup
55 if @char_1.respond_to?(:force_encoding)
55 if @char_1.respond_to?(:force_encoding)
56 @char_1.force_encoding('UTF-8')
56 @char_1.force_encoding('UTF-8')
57 @felix_utf8.force_encoding('UTF-8')
57 @felix_utf8.force_encoding('UTF-8')
58 end
58 end
59 end
59 end
60
60
61 def test_create_and_update
61 def test_create_and_update
62 @request.session[:user_id] = 1
62 @request.session[:user_id] = 1
63 assert_difference 'Repository.count' do
63 assert_difference 'Repository.count' do
64 post :create, :project_id => 'subproject1',
64 post :create, :project_id => 'subproject1',
65 :repository_scm => 'Git',
65 :repository_scm => 'Git',
66 :repository => {
66 :repository => {
67 :url => '/test',
67 :url => '/test',
68 :is_default => '0',
68 :is_default => '0',
69 :identifier => 'test-create',
69 :identifier => 'test-create',
70 :extra_report_last_commit => '1',
70 :extra_report_last_commit => '1',
71 }
71 }
72 end
72 end
73 assert_response 302
73 assert_response 302
74 repository = Repository.order('id DESC').first
74 repository = Repository.order('id DESC').first
75 assert_kind_of Repository::Git, repository
75 assert_kind_of Repository::Git, repository
76 assert_equal '/test', repository.url
76 assert_equal '/test', repository.url
77 assert_equal true, repository.extra_report_last_commit
77 assert_equal true, repository.extra_report_last_commit
78
78
79 put :update, :id => repository.id,
79 put :update, :id => repository.id,
80 :repository => {
80 :repository => {
81 :extra_report_last_commit => '0'
81 :extra_report_last_commit => '0'
82 }
82 }
83 assert_response 302
83 assert_response 302
84 repo2 = Repository.find(repository.id)
84 repo2 = Repository.find(repository.id)
85 assert_equal false, repo2.extra_report_last_commit
85 assert_equal false, repo2.extra_report_last_commit
86 end
86 end
87
87
88 if File.directory?(REPOSITORY_PATH)
88 if File.directory?(REPOSITORY_PATH)
89 ## Ruby uses ANSI api to fork a process on Windows.
89 ## Ruby uses ANSI api to fork a process on Windows.
90 ## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
90 ## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
91 ## and these are incompatible with ASCII.
91 ## and these are incompatible with ASCII.
92 ## Git for Windows (msysGit) changed internal API from ANSI to Unicode in 1.7.10
92 ## Git for Windows (msysGit) changed internal API from ANSI to Unicode in 1.7.10
93 ## http://code.google.com/p/msysgit/issues/detail?id=80
93 ## http://code.google.com/p/msysgit/issues/detail?id=80
94 ## So, Latin-1 path tests fail on Japanese Windows
94 ## So, Latin-1 path tests fail on Japanese Windows
95 WINDOWS_PASS = (Redmine::Platform.mswin? &&
95 WINDOWS_PASS = (Redmine::Platform.mswin? &&
96 Redmine::Scm::Adapters::GitAdapter.client_version_above?([1, 7, 10]))
96 Redmine::Scm::Adapters::GitAdapter.client_version_above?([1, 7, 10]))
97 WINDOWS_SKIP_STR = "TODO: This test fails in Git for Windows above 1.7.10"
97 WINDOWS_SKIP_STR = "TODO: This test fails in Git for Windows above 1.7.10"
98
98
99 def test_get_new
99 def test_get_new
100 @request.session[:user_id] = 1
100 @request.session[:user_id] = 1
101 @project.repository.destroy
101 @project.repository.destroy
102 get :new, :project_id => 'subproject1', :repository_scm => 'Git'
102 get :new, :project_id => 'subproject1', :repository_scm => 'Git'
103 assert_response :success
103 assert_response :success
104 assert_template 'new'
104 assert_template 'new'
105 assert_kind_of Repository::Git, assigns(:repository)
105 assert_kind_of Repository::Git, assigns(:repository)
106 assert assigns(:repository).new_record?
106 assert assigns(:repository).new_record?
107 end
107 end
108
108
109 def test_browse_root
109 def test_browse_root
110 assert_equal 0, @repository.changesets.count
110 assert_equal 0, @repository.changesets.count
111 @repository.fetch_changesets
111 @repository.fetch_changesets
112 @project.reload
112 @project.reload
113 assert_equal NUM_REV, @repository.changesets.count
113 assert_equal NUM_REV, @repository.changesets.count
114
114
115 get :show, :id => PRJ_ID
115 get :show, :id => PRJ_ID
116 assert_response :success
116 assert_response :success
117 assert_template 'show'
117 assert_template 'show'
118 assert_not_nil assigns(:entries)
118 assert_not_nil assigns(:entries)
119 assert_equal 9, assigns(:entries).size
119 assert_equal 9, assigns(:entries).size
120 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
120 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
121 assert assigns(:entries).detect {|e| e.name == 'this_is_a_really_long_and_verbose_directory_name' && e.kind == 'dir'}
121 assert assigns(:entries).detect {|e| e.name == 'this_is_a_really_long_and_verbose_directory_name' && e.kind == 'dir'}
122 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
122 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
123 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
123 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
124 assert assigns(:entries).detect {|e| e.name == 'copied_README' && e.kind == 'file'}
124 assert assigns(:entries).detect {|e| e.name == 'copied_README' && e.kind == 'file'}
125 assert assigns(:entries).detect {|e| e.name == 'new_file.txt' && e.kind == 'file'}
125 assert assigns(:entries).detect {|e| e.name == 'new_file.txt' && e.kind == 'file'}
126 assert assigns(:entries).detect {|e| e.name == 'renamed_test.txt' && e.kind == 'file'}
126 assert assigns(:entries).detect {|e| e.name == 'renamed_test.txt' && e.kind == 'file'}
127 assert assigns(:entries).detect {|e| e.name == 'filemane with spaces.txt' && e.kind == 'file'}
127 assert assigns(:entries).detect {|e| e.name == 'filemane with spaces.txt' && e.kind == 'file'}
128 assert assigns(:entries).detect {|e| e.name == ' filename with a leading space.txt ' && e.kind == 'file'}
128 assert assigns(:entries).detect {|e| e.name == ' filename with a leading space.txt ' && e.kind == 'file'}
129 assert_not_nil assigns(:changesets)
129 assert_not_nil assigns(:changesets)
130 assert assigns(:changesets).size > 0
130 assert assigns(:changesets).size > 0
131 end
131 end
132
132
133 def test_browse_branch
133 def test_browse_branch
134 assert_equal 0, @repository.changesets.count
134 assert_equal 0, @repository.changesets.count
135 @repository.fetch_changesets
135 @repository.fetch_changesets
136 @project.reload
136 @project.reload
137 assert_equal NUM_REV, @repository.changesets.count
137 assert_equal NUM_REV, @repository.changesets.count
138 get :show, :id => PRJ_ID, :rev => 'test_branch'
138 get :show, :id => PRJ_ID, :rev => 'test_branch'
139 assert_response :success
139 assert_response :success
140 assert_template 'show'
140 assert_template 'show'
141 assert_not_nil assigns(:entries)
141 assert_not_nil assigns(:entries)
142 assert_equal 4, assigns(:entries).size
142 assert_equal 4, assigns(:entries).size
143 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
143 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
144 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
144 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
145 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
145 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
146 assert assigns(:entries).detect {|e| e.name == 'test.txt' && e.kind == 'file'}
146 assert assigns(:entries).detect {|e| e.name == 'test.txt' && e.kind == 'file'}
147 assert_not_nil assigns(:changesets)
147 assert_not_nil assigns(:changesets)
148 assert assigns(:changesets).size > 0
148 assert assigns(:changesets).size > 0
149 end
149 end
150
150
151 def test_browse_tag
151 def test_browse_tag
152 assert_equal 0, @repository.changesets.count
152 assert_equal 0, @repository.changesets.count
153 @repository.fetch_changesets
153 @repository.fetch_changesets
154 @project.reload
154 @project.reload
155 assert_equal NUM_REV, @repository.changesets.count
155 assert_equal NUM_REV, @repository.changesets.count
156 [
156 [
157 "tag00.lightweight",
157 "tag00.lightweight",
158 "tag01.annotated",
158 "tag01.annotated",
159 ].each do |t1|
159 ].each do |t1|
160 get :show, :id => PRJ_ID, :rev => t1
160 get :show, :id => PRJ_ID, :rev => t1
161 assert_response :success
161 assert_response :success
162 assert_template 'show'
162 assert_template 'show'
163 assert_not_nil assigns(:entries)
163 assert_not_nil assigns(:entries)
164 assert assigns(:entries).size > 0
164 assert assigns(:entries).size > 0
165 assert_not_nil assigns(:changesets)
165 assert_not_nil assigns(:changesets)
166 assert assigns(:changesets).size > 0
166 assert assigns(:changesets).size > 0
167 end
167 end
168 end
168 end
169
169
170 def test_browse_directory
170 def test_browse_directory
171 assert_equal 0, @repository.changesets.count
171 assert_equal 0, @repository.changesets.count
172 @repository.fetch_changesets
172 @repository.fetch_changesets
173 @project.reload
173 @project.reload
174 assert_equal NUM_REV, @repository.changesets.count
174 assert_equal NUM_REV, @repository.changesets.count
175 get :show, :id => PRJ_ID, :path => repository_path_hash(['images'])[:param]
175 get :show, :id => PRJ_ID, :path => repository_path_hash(['images'])[:param]
176 assert_response :success
176 assert_response :success
177 assert_template 'show'
177 assert_template 'show'
178 assert_not_nil assigns(:entries)
178 assert_not_nil assigns(:entries)
179 assert_equal ['edit.png'], assigns(:entries).collect(&:name)
179 assert_equal ['edit.png'], assigns(:entries).collect(&:name)
180 entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
180 entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
181 assert_not_nil entry
181 assert_not_nil entry
182 assert_equal 'file', entry.kind
182 assert_equal 'file', entry.kind
183 assert_equal 'images/edit.png', entry.path
183 assert_equal 'images/edit.png', entry.path
184 assert_not_nil assigns(:changesets)
184 assert_not_nil assigns(:changesets)
185 assert assigns(:changesets).size > 0
185 assert assigns(:changesets).size > 0
186 end
186 end
187
187
188 def test_browse_at_given_revision
188 def test_browse_at_given_revision
189 assert_equal 0, @repository.changesets.count
189 assert_equal 0, @repository.changesets.count
190 @repository.fetch_changesets
190 @repository.fetch_changesets
191 @project.reload
191 @project.reload
192 assert_equal NUM_REV, @repository.changesets.count
192 assert_equal NUM_REV, @repository.changesets.count
193 get :show, :id => PRJ_ID, :path => repository_path_hash(['images'])[:param],
193 get :show, :id => PRJ_ID, :path => repository_path_hash(['images'])[:param],
194 :rev => '7234cb2750b63f47bff735edc50a1c0a433c2518'
194 :rev => '7234cb2750b63f47bff735edc50a1c0a433c2518'
195 assert_response :success
195 assert_response :success
196 assert_template 'show'
196 assert_template 'show'
197 assert_not_nil assigns(:entries)
197 assert_not_nil assigns(:entries)
198 assert_equal ['delete.png'], assigns(:entries).collect(&:name)
198 assert_equal ['delete.png'], assigns(:entries).collect(&:name)
199 assert_not_nil assigns(:changesets)
199 assert_not_nil assigns(:changesets)
200 assert assigns(:changesets).size > 0
200 assert assigns(:changesets).size > 0
201 end
201 end
202
202
203 def test_changes
203 def test_changes
204 get :changes, :id => PRJ_ID,
204 get :changes, :id => PRJ_ID,
205 :path => repository_path_hash(['images', 'edit.png'])[:param]
205 :path => repository_path_hash(['images', 'edit.png'])[:param]
206 assert_response :success
206 assert_response :success
207 assert_template 'changes'
207 assert_template 'changes'
208 assert_tag :tag => 'h2', :content => 'edit.png'
208 assert_tag :tag => 'h2', :content => 'edit.png'
209 end
209 end
210
210
211 def test_entry_show
211 def test_entry_show
212 get :entry, :id => PRJ_ID,
212 get :entry, :id => PRJ_ID,
213 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
213 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
214 assert_response :success
214 assert_response :success
215 assert_template 'entry'
215 assert_template 'entry'
216 # Line 19
216 # Line 19
217 assert_tag :tag => 'th',
217 assert_tag :tag => 'th',
218 :content => '11',
218 :content => '11',
219 :attributes => { :class => 'line-num' },
219 :attributes => { :class => 'line-num' },
220 :sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ }
220 :sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ }
221 end
221 end
222
222
223 def test_entry_show_latin_1
223 def test_entry_show_latin_1
224 if @ruby19_non_utf8_pass
224 if @ruby19_non_utf8_pass
225 puts_ruby19_non_utf8_pass()
225 puts_ruby19_non_utf8_pass()
226 elsif WINDOWS_PASS
226 elsif WINDOWS_PASS
227 puts WINDOWS_SKIP_STR
227 puts WINDOWS_SKIP_STR
228 elsif JRUBY_SKIP
228 elsif JRUBY_SKIP
229 puts JRUBY_SKIP_STR
229 puts JRUBY_SKIP_STR
230 else
230 else
231 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
231 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
232 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
232 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
233 get :entry, :id => PRJ_ID,
233 get :entry, :id => PRJ_ID,
234 :path => repository_path_hash(['latin-1-dir', "test-#{@char_1}.txt"])[:param],
234 :path => repository_path_hash(['latin-1-dir', "test-#{@char_1}.txt"])[:param],
235 :rev => r1
235 :rev => r1
236 assert_response :success
236 assert_response :success
237 assert_template 'entry'
237 assert_template 'entry'
238 assert_tag :tag => 'th',
238 assert_tag :tag => 'th',
239 :content => '1',
239 :content => '1',
240 :attributes => { :class => 'line-num' },
240 :attributes => { :class => 'line-num' },
241 :sibling => { :tag => 'td',
241 :sibling => { :tag => 'td',
242 :content => /test-#{@char_1}.txt/ }
242 :content => /test-#{@char_1}.txt/ }
243 end
243 end
244 end
244 end
245 end
245 end
246 end
246 end
247
247
248 def test_entry_download
248 def test_entry_download
249 get :entry, :id => PRJ_ID,
249 get :entry, :id => PRJ_ID,
250 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
250 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
251 :format => 'raw'
251 :format => 'raw'
252 assert_response :success
252 assert_response :success
253 # File content
253 # File content
254 assert @response.body.include?('WITHOUT ANY WARRANTY')
254 assert @response.body.include?('WITHOUT ANY WARRANTY')
255 end
255 end
256
256
257 def test_directory_entry
257 def test_directory_entry
258 get :entry, :id => PRJ_ID,
258 get :entry, :id => PRJ_ID,
259 :path => repository_path_hash(['sources'])[:param]
259 :path => repository_path_hash(['sources'])[:param]
260 assert_response :success
260 assert_response :success
261 assert_template 'show'
261 assert_template 'show'
262 assert_not_nil assigns(:entry)
262 assert_not_nil assigns(:entry)
263 assert_equal 'sources', assigns(:entry).name
263 assert_equal 'sources', assigns(:entry).name
264 end
264 end
265
265
266 def test_diff
266 def test_diff
267 assert_equal true, @repository.is_default
267 assert_equal true, @repository.is_default
268 assert_nil @repository.identifier
268 assert @repository.identifier.blank?
269 assert_equal 0, @repository.changesets.count
269 assert_equal 0, @repository.changesets.count
270 @repository.fetch_changesets
270 @repository.fetch_changesets
271 @project.reload
271 @project.reload
272 assert_equal NUM_REV, @repository.changesets.count
272 assert_equal NUM_REV, @repository.changesets.count
273 # Full diff of changeset 2f9c0091
273 # Full diff of changeset 2f9c0091
274 ['inline', 'sbs'].each do |dt|
274 ['inline', 'sbs'].each do |dt|
275 get :diff,
275 get :diff,
276 :id => PRJ_ID,
276 :id => PRJ_ID,
277 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
277 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
278 :type => dt
278 :type => dt
279 assert_response :success
279 assert_response :success
280 assert_template 'diff'
280 assert_template 'diff'
281 # Line 22 removed
281 # Line 22 removed
282 assert_tag :tag => 'th',
282 assert_tag :tag => 'th',
283 :content => /22/,
283 :content => /22/,
284 :sibling => { :tag => 'td',
284 :sibling => { :tag => 'td',
285 :attributes => { :class => /diff_out/ },
285 :attributes => { :class => /diff_out/ },
286 :content => /def remove/ }
286 :content => /def remove/ }
287 assert_tag :tag => 'h2', :content => /2f9c0091/
287 assert_tag :tag => 'h2', :content => /2f9c0091/
288 end
288 end
289 end
289 end
290
290
291 def test_diff_with_rev_and_path
291 def test_diff_with_rev_and_path
292 assert_equal 0, @repository.changesets.count
292 assert_equal 0, @repository.changesets.count
293 @repository.fetch_changesets
293 @repository.fetch_changesets
294 @project.reload
294 @project.reload
295 assert_equal NUM_REV, @repository.changesets.count
295 assert_equal NUM_REV, @repository.changesets.count
296 with_settings :diff_max_lines_displayed => 1000 do
296 with_settings :diff_max_lines_displayed => 1000 do
297 # Full diff of changeset 2f9c0091
297 # Full diff of changeset 2f9c0091
298 ['inline', 'sbs'].each do |dt|
298 ['inline', 'sbs'].each do |dt|
299 get :diff,
299 get :diff,
300 :id => PRJ_ID,
300 :id => PRJ_ID,
301 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
301 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
302 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
302 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
303 :type => dt
303 :type => dt
304 assert_response :success
304 assert_response :success
305 assert_template 'diff'
305 assert_template 'diff'
306 # Line 22 removed
306 # Line 22 removed
307 assert_tag :tag => 'th',
307 assert_tag :tag => 'th',
308 :content => '22',
308 :content => '22',
309 :sibling => { :tag => 'td',
309 :sibling => { :tag => 'td',
310 :attributes => { :class => /diff_out/ },
310 :attributes => { :class => /diff_out/ },
311 :content => /def remove/ }
311 :content => /def remove/ }
312 assert_tag :tag => 'h2', :content => /2f9c0091/
312 assert_tag :tag => 'h2', :content => /2f9c0091/
313 end
313 end
314 end
314 end
315 end
315 end
316
316
317 def test_diff_truncated
317 def test_diff_truncated
318 assert_equal 0, @repository.changesets.count
318 assert_equal 0, @repository.changesets.count
319 @repository.fetch_changesets
319 @repository.fetch_changesets
320 @project.reload
320 @project.reload
321 assert_equal NUM_REV, @repository.changesets.count
321 assert_equal NUM_REV, @repository.changesets.count
322
322
323 with_settings :diff_max_lines_displayed => 5 do
323 with_settings :diff_max_lines_displayed => 5 do
324 # Truncated diff of changeset 2f9c0091
324 # Truncated diff of changeset 2f9c0091
325 with_cache do
325 with_cache do
326 with_settings :default_language => 'en' do
326 with_settings :default_language => 'en' do
327 get :diff, :id => PRJ_ID, :type => 'inline',
327 get :diff, :id => PRJ_ID, :type => 'inline',
328 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
328 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
329 assert_response :success
329 assert_response :success
330 assert @response.body.include?("... This diff was truncated")
330 assert @response.body.include?("... This diff was truncated")
331 end
331 end
332 with_settings :default_language => 'fr' do
332 with_settings :default_language => 'fr' do
333 get :diff, :id => PRJ_ID, :type => 'inline',
333 get :diff, :id => PRJ_ID, :type => 'inline',
334 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
334 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
335 assert_response :success
335 assert_response :success
336 assert ! @response.body.include?("... This diff was truncated")
336 assert ! @response.body.include?("... This diff was truncated")
337 assert @response.body.include?("... Ce diff")
337 assert @response.body.include?("... Ce diff")
338 end
338 end
339 end
339 end
340 end
340 end
341 end
341 end
342
342
343 def test_diff_two_revs
343 def test_diff_two_revs
344 assert_equal 0, @repository.changesets.count
344 assert_equal 0, @repository.changesets.count
345 @repository.fetch_changesets
345 @repository.fetch_changesets
346 @project.reload
346 @project.reload
347 assert_equal NUM_REV, @repository.changesets.count
347 assert_equal NUM_REV, @repository.changesets.count
348 ['inline', 'sbs'].each do |dt|
348 ['inline', 'sbs'].each do |dt|
349 get :diff,
349 get :diff,
350 :id => PRJ_ID,
350 :id => PRJ_ID,
351 :rev => '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
351 :rev => '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
352 :rev_to => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
352 :rev_to => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
353 :type => dt
353 :type => dt
354 assert_response :success
354 assert_response :success
355 assert_template 'diff'
355 assert_template 'diff'
356 diff = assigns(:diff)
356 diff = assigns(:diff)
357 assert_not_nil diff
357 assert_not_nil diff
358 assert_tag :tag => 'h2', :content => /2f9c0091:61b685fb/
358 assert_tag :tag => 'h2', :content => /2f9c0091:61b685fb/
359 assert_tag :tag => "form",
359 assert_tag :tag => "form",
360 :attributes => {
360 :attributes => {
361 :action => "/projects/subproject1/repository/revisions/" +
361 :action => "/projects/subproject1/repository/revisions/" +
362 "61b685fbe55ab05b5ac68402d5720c1a6ac973d1/diff"
362 "61b685fbe55ab05b5ac68402d5720c1a6ac973d1/diff"
363 }
363 }
364 assert_tag :tag => 'input',
364 assert_tag :tag => 'input',
365 :attributes => {
365 :attributes => {
366 :id => "rev_to",
366 :id => "rev_to",
367 :name => "rev_to",
367 :name => "rev_to",
368 :type => "hidden",
368 :type => "hidden",
369 :value => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
369 :value => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
370 }
370 }
371 end
371 end
372 end
372 end
373
373
374 def test_diff_path_in_subrepo
374 def test_diff_path_in_subrepo
375 repo = Repository::Git.create(
375 repo = Repository::Git.create(
376 :project => @project,
376 :project => @project,
377 :url => REPOSITORY_PATH,
377 :url => REPOSITORY_PATH,
378 :identifier => 'test-diff-path',
378 :identifier => 'test-diff-path',
379 :path_encoding => 'ISO-8859-1'
379 :path_encoding => 'ISO-8859-1'
380 )
380 )
381 assert repo
381 assert repo
382 assert_equal false, repo.is_default
382 assert_equal false, repo.is_default
383 assert_equal 'test-diff-path', repo.identifier
383 assert_equal 'test-diff-path', repo.identifier
384 get :diff,
384 get :diff,
385 :id => PRJ_ID,
385 :id => PRJ_ID,
386 :repository_id => 'test-diff-path',
386 :repository_id => 'test-diff-path',
387 :rev => '61b685fbe55ab05b',
387 :rev => '61b685fbe55ab05b',
388 :rev_to => '2f9c0091c754a91a',
388 :rev_to => '2f9c0091c754a91a',
389 :type => 'inline'
389 :type => 'inline'
390 assert_response :success
390 assert_response :success
391 assert_template 'diff'
391 assert_template 'diff'
392 diff = assigns(:diff)
392 diff = assigns(:diff)
393 assert_not_nil diff
393 assert_not_nil diff
394 assert_tag :tag => "form",
394 assert_tag :tag => "form",
395 :attributes => {
395 :attributes => {
396 :action => "/projects/subproject1/repository/test-diff-path/" +
396 :action => "/projects/subproject1/repository/test-diff-path/" +
397 "revisions/61b685fbe55ab05b/diff"
397 "revisions/61b685fbe55ab05b/diff"
398 }
398 }
399 assert_tag :tag => 'input',
399 assert_tag :tag => 'input',
400 :attributes => {
400 :attributes => {
401 :id => "rev_to",
401 :id => "rev_to",
402 :name => "rev_to",
402 :name => "rev_to",
403 :type => "hidden",
403 :type => "hidden",
404 :value => '2f9c0091c754a91a'
404 :value => '2f9c0091c754a91a'
405 }
405 }
406 end
406 end
407
407
408 def test_diff_latin_1
408 def test_diff_latin_1
409 if @ruby19_non_utf8_pass
409 if @ruby19_non_utf8_pass
410 puts_ruby19_non_utf8_pass()
410 puts_ruby19_non_utf8_pass()
411 else
411 else
412 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
412 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
413 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
413 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
414 ['inline', 'sbs'].each do |dt|
414 ['inline', 'sbs'].each do |dt|
415 get :diff, :id => PRJ_ID, :rev => r1, :type => dt
415 get :diff, :id => PRJ_ID, :rev => r1, :type => dt
416 assert_response :success
416 assert_response :success
417 assert_template 'diff'
417 assert_template 'diff'
418 assert_tag :tag => 'thead',
418 assert_tag :tag => 'thead',
419 :descendant => {
419 :descendant => {
420 :tag => 'th',
420 :tag => 'th',
421 :attributes => { :class => 'filename' } ,
421 :attributes => { :class => 'filename' } ,
422 :content => /latin-1-dir\/test-#{@char_1}.txt/ ,
422 :content => /latin-1-dir\/test-#{@char_1}.txt/ ,
423 },
423 },
424 :sibling => {
424 :sibling => {
425 :tag => 'tbody',
425 :tag => 'tbody',
426 :descendant => {
426 :descendant => {
427 :tag => 'td',
427 :tag => 'td',
428 :attributes => { :class => /diff_in/ },
428 :attributes => { :class => /diff_in/ },
429 :content => /test-#{@char_1}.txt/
429 :content => /test-#{@char_1}.txt/
430 }
430 }
431 }
431 }
432 end
432 end
433 end
433 end
434 end
434 end
435 end
435 end
436 end
436 end
437
437
438 def test_diff_should_show_filenames
438 def test_diff_should_show_filenames
439 get :diff, :id => PRJ_ID, :rev => 'deff712f05a90d96edbd70facc47d944be5897e3', :type => 'inline'
439 get :diff, :id => PRJ_ID, :rev => 'deff712f05a90d96edbd70facc47d944be5897e3', :type => 'inline'
440 assert_response :success
440 assert_response :success
441 assert_template 'diff'
441 assert_template 'diff'
442 # modified file
442 # modified file
443 assert_select 'th.filename', :text => 'sources/watchers_controller.rb'
443 assert_select 'th.filename', :text => 'sources/watchers_controller.rb'
444 # deleted file
444 # deleted file
445 assert_select 'th.filename', :text => 'test.txt'
445 assert_select 'th.filename', :text => 'test.txt'
446 end
446 end
447
447
448 def test_save_diff_type
448 def test_save_diff_type
449 user1 = User.find(1)
449 user1 = User.find(1)
450 user1.pref[:diff_type] = nil
450 user1.pref[:diff_type] = nil
451 user1.preference.save
451 user1.preference.save
452 user = User.find(1)
452 user = User.find(1)
453 assert_nil user.pref[:diff_type]
453 assert_nil user.pref[:diff_type]
454
454
455 @request.session[:user_id] = 1 # admin
455 @request.session[:user_id] = 1 # admin
456 get :diff,
456 get :diff,
457 :id => PRJ_ID,
457 :id => PRJ_ID,
458 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
458 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
459 assert_response :success
459 assert_response :success
460 assert_template 'diff'
460 assert_template 'diff'
461 user.reload
461 user.reload
462 assert_equal "inline", user.pref[:diff_type]
462 assert_equal "inline", user.pref[:diff_type]
463 get :diff,
463 get :diff,
464 :id => PRJ_ID,
464 :id => PRJ_ID,
465 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
465 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
466 :type => 'sbs'
466 :type => 'sbs'
467 assert_response :success
467 assert_response :success
468 assert_template 'diff'
468 assert_template 'diff'
469 user.reload
469 user.reload
470 assert_equal "sbs", user.pref[:diff_type]
470 assert_equal "sbs", user.pref[:diff_type]
471 end
471 end
472
472
473 def test_annotate
473 def test_annotate
474 get :annotate, :id => PRJ_ID,
474 get :annotate, :id => PRJ_ID,
475 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
475 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
476 assert_response :success
476 assert_response :success
477 assert_template 'annotate'
477 assert_template 'annotate'
478
478
479 # Line 23, changeset 2f9c0091
479 # Line 23, changeset 2f9c0091
480 assert_select 'tr' do
480 assert_select 'tr' do
481 assert_select 'th.line-num', :text => '23'
481 assert_select 'th.line-num', :text => '23'
482 assert_select 'td.revision', :text => /2f9c0091/
482 assert_select 'td.revision', :text => /2f9c0091/
483 assert_select 'td.author', :text => 'jsmith'
483 assert_select 'td.author', :text => 'jsmith'
484 assert_select 'td', :text => /remove_watcher/
484 assert_select 'td', :text => /remove_watcher/
485 end
485 end
486 end
486 end
487
487
488 def test_annotate_at_given_revision
488 def test_annotate_at_given_revision
489 assert_equal 0, @repository.changesets.count
489 assert_equal 0, @repository.changesets.count
490 @repository.fetch_changesets
490 @repository.fetch_changesets
491 @project.reload
491 @project.reload
492 assert_equal NUM_REV, @repository.changesets.count
492 assert_equal NUM_REV, @repository.changesets.count
493 get :annotate, :id => PRJ_ID, :rev => 'deff7',
493 get :annotate, :id => PRJ_ID, :rev => 'deff7',
494 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
494 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
495 assert_response :success
495 assert_response :success
496 assert_template 'annotate'
496 assert_template 'annotate'
497 assert_tag :tag => 'h2', :content => /@ deff712f/
497 assert_tag :tag => 'h2', :content => /@ deff712f/
498 end
498 end
499
499
500 def test_annotate_binary_file
500 def test_annotate_binary_file
501 get :annotate, :id => PRJ_ID,
501 get :annotate, :id => PRJ_ID,
502 :path => repository_path_hash(['images', 'edit.png'])[:param]
502 :path => repository_path_hash(['images', 'edit.png'])[:param]
503 assert_response 500
503 assert_response 500
504 assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ },
504 assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ },
505 :content => /cannot be annotated/
505 :content => /cannot be annotated/
506 end
506 end
507
507
508 def test_annotate_error_when_too_big
508 def test_annotate_error_when_too_big
509 with_settings :file_max_size_displayed => 1 do
509 with_settings :file_max_size_displayed => 1 do
510 get :annotate, :id => PRJ_ID,
510 get :annotate, :id => PRJ_ID,
511 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
511 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
512 :rev => 'deff712f'
512 :rev => 'deff712f'
513 assert_response 500
513 assert_response 500
514 assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ },
514 assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ },
515 :content => /exceeds the maximum text file size/
515 :content => /exceeds the maximum text file size/
516
516
517 get :annotate, :id => PRJ_ID,
517 get :annotate, :id => PRJ_ID,
518 :path => repository_path_hash(['README'])[:param],
518 :path => repository_path_hash(['README'])[:param],
519 :rev => '7234cb2'
519 :rev => '7234cb2'
520 assert_response :success
520 assert_response :success
521 assert_template 'annotate'
521 assert_template 'annotate'
522 end
522 end
523 end
523 end
524
524
525 def test_annotate_latin_1
525 def test_annotate_latin_1
526 if @ruby19_non_utf8_pass
526 if @ruby19_non_utf8_pass
527 puts_ruby19_non_utf8_pass()
527 puts_ruby19_non_utf8_pass()
528 elsif WINDOWS_PASS
528 elsif WINDOWS_PASS
529 puts WINDOWS_SKIP_STR
529 puts WINDOWS_SKIP_STR
530 elsif JRUBY_SKIP
530 elsif JRUBY_SKIP
531 puts JRUBY_SKIP_STR
531 puts JRUBY_SKIP_STR
532 else
532 else
533 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
533 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
534 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
534 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
535 get :annotate, :id => PRJ_ID,
535 get :annotate, :id => PRJ_ID,
536 :path => repository_path_hash(['latin-1-dir', "test-#{@char_1}.txt"])[:param],
536 :path => repository_path_hash(['latin-1-dir', "test-#{@char_1}.txt"])[:param],
537 :rev => r1
537 :rev => r1
538 assert_select "th.line-num", :text => '1' do
538 assert_select "th.line-num", :text => '1' do
539 assert_select "+ td.revision" do
539 assert_select "+ td.revision" do
540 assert_select "a", :text => '57ca437c'
540 assert_select "a", :text => '57ca437c'
541 assert_select "+ td.author", :text => "jsmith" do
541 assert_select "+ td.author", :text => "jsmith" do
542 assert_select "+ td",
542 assert_select "+ td",
543 :text => "test-#{@char_1}.txt"
543 :text => "test-#{@char_1}.txt"
544 end
544 end
545 end
545 end
546 end
546 end
547 end
547 end
548 end
548 end
549 end
549 end
550 end
550 end
551
551
552 def test_annotate_latin_1_author
552 def test_annotate_latin_1_author
553 ['83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', '83ca5fd546063a'].each do |r1|
553 ['83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', '83ca5fd546063a'].each do |r1|
554 get :annotate, :id => PRJ_ID,
554 get :annotate, :id => PRJ_ID,
555 :path => repository_path_hash([" filename with a leading space.txt "])[:param],
555 :path => repository_path_hash([" filename with a leading space.txt "])[:param],
556 :rev => r1
556 :rev => r1
557 assert_select "th.line-num", :text => '1' do
557 assert_select "th.line-num", :text => '1' do
558 assert_select "+ td.revision" do
558 assert_select "+ td.revision" do
559 assert_select "a", :text => '83ca5fd5'
559 assert_select "a", :text => '83ca5fd5'
560 assert_select "+ td.author", :text => @felix_utf8 do
560 assert_select "+ td.author", :text => @felix_utf8 do
561 assert_select "+ td",
561 assert_select "+ td",
562 :text => "And this is a file with a leading and trailing space..."
562 :text => "And this is a file with a leading and trailing space..."
563 end
563 end
564 end
564 end
565 end
565 end
566 end
566 end
567 end
567 end
568
568
569 def test_revisions
569 def test_revisions
570 assert_equal 0, @repository.changesets.count
570 assert_equal 0, @repository.changesets.count
571 @repository.fetch_changesets
571 @repository.fetch_changesets
572 @project.reload
572 @project.reload
573 assert_equal NUM_REV, @repository.changesets.count
573 assert_equal NUM_REV, @repository.changesets.count
574 get :revisions, :id => PRJ_ID
574 get :revisions, :id => PRJ_ID
575 assert_response :success
575 assert_response :success
576 assert_template 'revisions'
576 assert_template 'revisions'
577 assert_tag :tag => 'form',
577 assert_tag :tag => 'form',
578 :attributes => {
578 :attributes => {
579 :method => 'get',
579 :method => 'get',
580 :action => '/projects/subproject1/repository/revision'
580 :action => '/projects/subproject1/repository/revision'
581 }
581 }
582 end
582 end
583
583
584 def test_revision
584 def test_revision
585 assert_equal 0, @repository.changesets.count
585 assert_equal 0, @repository.changesets.count
586 @repository.fetch_changesets
586 @repository.fetch_changesets
587 @project.reload
587 @project.reload
588 assert_equal NUM_REV, @repository.changesets.count
588 assert_equal NUM_REV, @repository.changesets.count
589 ['61b685fbe55ab05b5ac68402d5720c1a6ac973d1', '61b685f'].each do |r|
589 ['61b685fbe55ab05b5ac68402d5720c1a6ac973d1', '61b685f'].each do |r|
590 get :revision, :id => PRJ_ID, :rev => r
590 get :revision, :id => PRJ_ID, :rev => r
591 assert_response :success
591 assert_response :success
592 assert_template 'revision'
592 assert_template 'revision'
593 end
593 end
594 end
594 end
595
595
596 def test_empty_revision
596 def test_empty_revision
597 assert_equal 0, @repository.changesets.count
597 assert_equal 0, @repository.changesets.count
598 @repository.fetch_changesets
598 @repository.fetch_changesets
599 @project.reload
599 @project.reload
600 assert_equal NUM_REV, @repository.changesets.count
600 assert_equal NUM_REV, @repository.changesets.count
601 ['', ' ', nil].each do |r|
601 ['', ' ', nil].each do |r|
602 get :revision, :id => PRJ_ID, :rev => r
602 get :revision, :id => PRJ_ID, :rev => r
603 assert_response 404
603 assert_response 404
604 assert_error_tag :content => /was not found/
604 assert_error_tag :content => /was not found/
605 end
605 end
606 end
606 end
607
607
608 def test_destroy_valid_repository
608 def test_destroy_valid_repository
609 @request.session[:user_id] = 1 # admin
609 @request.session[:user_id] = 1 # admin
610 assert_equal 0, @repository.changesets.count
610 assert_equal 0, @repository.changesets.count
611 @repository.fetch_changesets
611 @repository.fetch_changesets
612 @project.reload
612 @project.reload
613 assert_equal NUM_REV, @repository.changesets.count
613 assert_equal NUM_REV, @repository.changesets.count
614
614
615 assert_difference 'Repository.count', -1 do
615 assert_difference 'Repository.count', -1 do
616 delete :destroy, :id => @repository.id
616 delete :destroy, :id => @repository.id
617 end
617 end
618 assert_response 302
618 assert_response 302
619 @project.reload
619 @project.reload
620 assert_nil @project.repository
620 assert_nil @project.repository
621 end
621 end
622
622
623 def test_destroy_invalid_repository
623 def test_destroy_invalid_repository
624 @request.session[:user_id] = 1 # admin
624 @request.session[:user_id] = 1 # admin
625 @project.repository.destroy
625 @project.repository.destroy
626 @repository = Repository::Git.create!(
626 @repository = Repository::Git.create!(
627 :project => @project,
627 :project => @project,
628 :url => "/invalid",
628 :url => "/invalid",
629 :path_encoding => 'ISO-8859-1'
629 :path_encoding => 'ISO-8859-1'
630 )
630 )
631 @repository.fetch_changesets
631 @repository.fetch_changesets
632 @repository.reload
632 @repository.reload
633 assert_equal 0, @repository.changesets.count
633 assert_equal 0, @repository.changesets.count
634
634
635 assert_difference 'Repository.count', -1 do
635 assert_difference 'Repository.count', -1 do
636 delete :destroy, :id => @repository.id
636 delete :destroy, :id => @repository.id
637 end
637 end
638 assert_response 302
638 assert_response 302
639 @project.reload
639 @project.reload
640 assert_nil @project.repository
640 assert_nil @project.repository
641 end
641 end
642
642
643 private
643 private
644
644
645 def puts_ruby19_non_utf8_pass
645 def puts_ruby19_non_utf8_pass
646 puts "TODO: This test fails in Ruby 1.9 " +
646 puts "TODO: This test fails in Ruby 1.9 " +
647 "and Encoding.default_external is not UTF-8. " +
647 "and Encoding.default_external is not UTF-8. " +
648 "Current value is '#{Encoding.default_external.to_s}'"
648 "Current value is '#{Encoding.default_external.to_s}'"
649 end
649 end
650 else
650 else
651 puts "Git test repository NOT FOUND. Skipping functional tests !!!"
651 puts "Git test repository NOT FOUND. Skipping functional tests !!!"
652 def test_fake; assert true end
652 def test_fake; assert true end
653 end
653 end
654
654
655 private
655 private
656 def with_cache(&block)
656 def with_cache(&block)
657 before = ActionController::Base.perform_caching
657 before = ActionController::Base.perform_caching
658 ActionController::Base.perform_caching = true
658 ActionController::Base.perform_caching = true
659 block.call
659 block.call
660 ActionController::Base.perform_caching = before
660 ActionController::Base.perform_caching = before
661 end
661 end
662 end
662 end
@@ -1,630 +1,632
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class RepositoryGitTest < ActiveSupport::TestCase
20 class RepositoryGitTest < ActiveSupport::TestCase
21 fixtures :projects, :repositories, :enabled_modules, :users, :roles
21 fixtures :projects, :repositories, :enabled_modules, :users, :roles
22
22
23 include Redmine::I18n
23 include Redmine::I18n
24
24
25 REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
25 REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
26 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
26 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
27
27
28 NUM_REV = 28
28 NUM_REV = 28
29 NUM_HEAD = 6
29 NUM_HEAD = 6
30
30
31 FELIX_HEX = "Felix Sch\xC3\xA4fer"
31 FELIX_HEX = "Felix Sch\xC3\xA4fer"
32 CHAR_1_HEX = "\xc3\x9c"
32 CHAR_1_HEX = "\xc3\x9c"
33
33
34 ## Git, Mercurial and CVS path encodings are binary.
34 ## Git, Mercurial and CVS path encodings are binary.
35 ## Subversion supports URL encoding for path.
35 ## Subversion supports URL encoding for path.
36 ## Redmine Mercurial adapter and extension use URL encoding.
36 ## Redmine Mercurial adapter and extension use URL encoding.
37 ## Git accepts only binary path in command line parameter.
37 ## Git accepts only binary path in command line parameter.
38 ## So, there is no way to use binary command line parameter in JRuby.
38 ## So, there is no way to use binary command line parameter in JRuby.
39 JRUBY_SKIP = (RUBY_PLATFORM == 'java')
39 JRUBY_SKIP = (RUBY_PLATFORM == 'java')
40 JRUBY_SKIP_STR = "TODO: This test fails in JRuby"
40 JRUBY_SKIP_STR = "TODO: This test fails in JRuby"
41
41
42 def setup
42 def setup
43 @project = Project.find(3)
43 @project = Project.find(3)
44 @repository = Repository::Git.create(
44 @repository = Repository::Git.create(
45 :project => @project,
45 :project => @project,
46 :url => REPOSITORY_PATH,
46 :url => REPOSITORY_PATH,
47 :path_encoding => 'ISO-8859-1'
47 :path_encoding => 'ISO-8859-1'
48 )
48 )
49 assert @repository
49 assert @repository
50 @char_1 = CHAR_1_HEX.dup
50 @char_1 = CHAR_1_HEX.dup
51 if @char_1.respond_to?(:force_encoding)
51 if @char_1.respond_to?(:force_encoding)
52 @char_1.force_encoding('UTF-8')
52 @char_1.force_encoding('UTF-8')
53 end
53 end
54 end
54 end
55
55
56 def test_nondefault_repo_with_blank_identifier_destruction
56 def test_nondefault_repo_with_blank_identifier_destruction
57 Repository.delete_all
58
57 repo1 = Repository::Git.new(
59 repo1 = Repository::Git.new(
58 :project => @project,
60 :project => @project,
59 :url => REPOSITORY_PATH,
61 :url => REPOSITORY_PATH,
60 :identifier => '',
62 :identifier => '',
61 :is_default => true
63 :is_default => true
62 )
64 )
63 assert repo1.save
65 assert repo1.save
64 repo1.fetch_changesets
66 repo1.fetch_changesets
65
67
66 repo2 = Repository::Git.new(
68 repo2 = Repository::Git.new(
67 :project => @project,
69 :project => @project,
68 :url => REPOSITORY_PATH,
70 :url => REPOSITORY_PATH,
69 :identifier => 'repo2',
71 :identifier => 'repo2',
70 :is_default => true
72 :is_default => true
71 )
73 )
72 assert repo2.save
74 assert repo2.save
73 repo2.fetch_changesets
75 repo2.fetch_changesets
74
76
75 repo1.reload
77 repo1.reload
76 repo2.reload
78 repo2.reload
77 assert !repo1.is_default?
79 assert !repo1.is_default?
78 assert repo2.is_default?
80 assert repo2.is_default?
79
81
80 assert_difference 'Repository.count', -1 do
82 assert_difference 'Repository.count', -1 do
81 repo1.destroy
83 repo1.destroy
82 end
84 end
83 end
85 end
84
86
85 def test_blank_path_to_repository_error_message
87 def test_blank_path_to_repository_error_message
86 set_language_if_valid 'en'
88 set_language_if_valid 'en'
87 repo = Repository::Git.new(
89 repo = Repository::Git.new(
88 :project => @project,
90 :project => @project,
89 :identifier => 'test'
91 :identifier => 'test'
90 )
92 )
91 assert !repo.save
93 assert !repo.save
92 assert_include "Path to repository can't be blank",
94 assert_include "Path to repository can't be blank",
93 repo.errors.full_messages
95 repo.errors.full_messages
94 end
96 end
95
97
96 def test_blank_path_to_repository_error_message_fr
98 def test_blank_path_to_repository_error_message_fr
97 set_language_if_valid 'fr'
99 set_language_if_valid 'fr'
98 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)"
100 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)"
99 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
101 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
100 repo = Repository::Git.new(
102 repo = Repository::Git.new(
101 :project => @project,
103 :project => @project,
102 :url => "",
104 :url => "",
103 :identifier => 'test',
105 :identifier => 'test',
104 :path_encoding => ''
106 :path_encoding => ''
105 )
107 )
106 assert !repo.save
108 assert !repo.save
107 assert_include str, repo.errors.full_messages
109 assert_include str, repo.errors.full_messages
108 end
110 end
109
111
110 if File.directory?(REPOSITORY_PATH)
112 if File.directory?(REPOSITORY_PATH)
111 ## Ruby uses ANSI api to fork a process on Windows.
113 ## Ruby uses ANSI api to fork a process on Windows.
112 ## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
114 ## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
113 ## and these are incompatible with ASCII.
115 ## and these are incompatible with ASCII.
114 ## Git for Windows (msysGit) changed internal API from ANSI to Unicode in 1.7.10
116 ## Git for Windows (msysGit) changed internal API from ANSI to Unicode in 1.7.10
115 ## http://code.google.com/p/msysgit/issues/detail?id=80
117 ## http://code.google.com/p/msysgit/issues/detail?id=80
116 ## So, Latin-1 path tests fail on Japanese Windows
118 ## So, Latin-1 path tests fail on Japanese Windows
117 WINDOWS_PASS = (Redmine::Platform.mswin? &&
119 WINDOWS_PASS = (Redmine::Platform.mswin? &&
118 Redmine::Scm::Adapters::GitAdapter.client_version_above?([1, 7, 10]))
120 Redmine::Scm::Adapters::GitAdapter.client_version_above?([1, 7, 10]))
119 WINDOWS_SKIP_STR = "TODO: This test fails in Git for Windows above 1.7.10"
121 WINDOWS_SKIP_STR = "TODO: This test fails in Git for Windows above 1.7.10"
120
122
121 def test_scm_available
123 def test_scm_available
122 klass = Repository::Git
124 klass = Repository::Git
123 assert_equal "Git", klass.scm_name
125 assert_equal "Git", klass.scm_name
124 assert klass.scm_adapter_class
126 assert klass.scm_adapter_class
125 assert_not_equal "", klass.scm_command
127 assert_not_equal "", klass.scm_command
126 assert_equal true, klass.scm_available
128 assert_equal true, klass.scm_available
127 end
129 end
128
130
129 def test_entries
131 def test_entries
130 entries = @repository.entries
132 entries = @repository.entries
131 assert_kind_of Redmine::Scm::Adapters::Entries, entries
133 assert_kind_of Redmine::Scm::Adapters::Entries, entries
132 end
134 end
133
135
134 def test_fetch_changesets_from_scratch
136 def test_fetch_changesets_from_scratch
135 assert_nil @repository.extra_info
137 assert_nil @repository.extra_info
136
138
137 assert_equal 0, @repository.changesets.count
139 assert_equal 0, @repository.changesets.count
138 @repository.fetch_changesets
140 @repository.fetch_changesets
139 @project.reload
141 @project.reload
140
142
141 assert_equal NUM_REV, @repository.changesets.count
143 assert_equal NUM_REV, @repository.changesets.count
142 assert_equal 39, @repository.filechanges.count
144 assert_equal 39, @repository.filechanges.count
143
145
144 commit = @repository.changesets.find_by_revision("7234cb2750b63f47bff735edc50a1c0a433c2518")
146 commit = @repository.changesets.find_by_revision("7234cb2750b63f47bff735edc50a1c0a433c2518")
145 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", commit.scmid
147 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", commit.scmid
146 assert_equal "Initial import.\nThe repository contains 3 files.", commit.comments
148 assert_equal "Initial import.\nThe repository contains 3 files.", commit.comments
147 assert_equal "jsmith <jsmith@foo.bar>", commit.committer
149 assert_equal "jsmith <jsmith@foo.bar>", commit.committer
148 assert_equal User.find_by_login('jsmith'), commit.user
150 assert_equal User.find_by_login('jsmith'), commit.user
149 # TODO: add a commit with commit time <> author time to the test repository
151 # TODO: add a commit with commit time <> author time to the test repository
150 assert_equal Time.gm(2007, 12, 14, 9, 22, 52), commit.committed_on
152 assert_equal Time.gm(2007, 12, 14, 9, 22, 52), commit.committed_on
151 assert_equal "2007-12-14".to_date, commit.commit_date
153 assert_equal "2007-12-14".to_date, commit.commit_date
152 assert_equal 3, commit.filechanges.count
154 assert_equal 3, commit.filechanges.count
153 change = commit.filechanges.sort_by(&:path).first
155 change = commit.filechanges.sort_by(&:path).first
154 assert_equal "README", change.path
156 assert_equal "README", change.path
155 assert_equal nil, change.from_path
157 assert_equal nil, change.from_path
156 assert_equal "A", change.action
158 assert_equal "A", change.action
157
159
158 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
160 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
159 end
161 end
160
162
161 def test_fetch_changesets_incremental
163 def test_fetch_changesets_incremental
162 assert_equal 0, @repository.changesets.count
164 assert_equal 0, @repository.changesets.count
163 @repository.fetch_changesets
165 @repository.fetch_changesets
164 @project.reload
166 @project.reload
165 assert_equal NUM_REV, @repository.changesets.count
167 assert_equal NUM_REV, @repository.changesets.count
166 extra_info_heads = @repository.extra_info["heads"].dup
168 extra_info_heads = @repository.extra_info["heads"].dup
167 assert_equal NUM_HEAD, extra_info_heads.size
169 assert_equal NUM_HEAD, extra_info_heads.size
168 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
170 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
169 assert_equal 4, extra_info_heads.size
171 assert_equal 4, extra_info_heads.size
170
172
171 del_revs = [
173 del_revs = [
172 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
174 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
173 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
175 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
174 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
176 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
175 "deff712f05a90d96edbd70facc47d944be5897e3",
177 "deff712f05a90d96edbd70facc47d944be5897e3",
176 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
178 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
177 "7e61ac704deecde634b51e59daa8110435dcb3da",
179 "7e61ac704deecde634b51e59daa8110435dcb3da",
178 ]
180 ]
179 @repository.changesets.each do |rev|
181 @repository.changesets.each do |rev|
180 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
182 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
181 end
183 end
182 @project.reload
184 @project.reload
183 cs1 = @repository.changesets
185 cs1 = @repository.changesets
184 assert_equal NUM_REV - 6, cs1.count
186 assert_equal NUM_REV - 6, cs1.count
185 extra_info_heads << "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8"
187 extra_info_heads << "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8"
186 h = {}
188 h = {}
187 h["heads"] = extra_info_heads
189 h["heads"] = extra_info_heads
188 @repository.merge_extra_info(h)
190 @repository.merge_extra_info(h)
189 @repository.save
191 @repository.save
190 @project.reload
192 @project.reload
191 assert @repository.extra_info["heads"].index("4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8")
193 assert @repository.extra_info["heads"].index("4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8")
192 @repository.fetch_changesets
194 @repository.fetch_changesets
193 @project.reload
195 @project.reload
194 assert_equal NUM_REV, @repository.changesets.count
196 assert_equal NUM_REV, @repository.changesets.count
195 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
197 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
196 assert @repository.extra_info["heads"].index("83ca5fd546063a3c7dc2e568ba3355661a9e2b2c")
198 assert @repository.extra_info["heads"].index("83ca5fd546063a3c7dc2e568ba3355661a9e2b2c")
197 end
199 end
198
200
199 def test_fetch_changesets_history_editing
201 def test_fetch_changesets_history_editing
200 assert_equal 0, @repository.changesets.count
202 assert_equal 0, @repository.changesets.count
201 @repository.fetch_changesets
203 @repository.fetch_changesets
202 @project.reload
204 @project.reload
203 assert_equal NUM_REV, @repository.changesets.count
205 assert_equal NUM_REV, @repository.changesets.count
204 extra_info_heads = @repository.extra_info["heads"].dup
206 extra_info_heads = @repository.extra_info["heads"].dup
205 assert_equal NUM_HEAD, extra_info_heads.size
207 assert_equal NUM_HEAD, extra_info_heads.size
206 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
208 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
207 assert_equal 4, extra_info_heads.size
209 assert_equal 4, extra_info_heads.size
208
210
209 del_revs = [
211 del_revs = [
210 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
212 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
211 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
213 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
212 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
214 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
213 "deff712f05a90d96edbd70facc47d944be5897e3",
215 "deff712f05a90d96edbd70facc47d944be5897e3",
214 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
216 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
215 "7e61ac704deecde634b51e59daa8110435dcb3da",
217 "7e61ac704deecde634b51e59daa8110435dcb3da",
216 ]
218 ]
217 @repository.changesets.each do |rev|
219 @repository.changesets.each do |rev|
218 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
220 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
219 end
221 end
220 @project.reload
222 @project.reload
221 assert_equal NUM_REV - 6, @repository.changesets.count
223 assert_equal NUM_REV - 6, @repository.changesets.count
222
224
223 c = Changeset.new(:repository => @repository,
225 c = Changeset.new(:repository => @repository,
224 :committed_on => Time.now,
226 :committed_on => Time.now,
225 :revision => "abcd1234efgh",
227 :revision => "abcd1234efgh",
226 :scmid => "abcd1234efgh",
228 :scmid => "abcd1234efgh",
227 :comments => 'test')
229 :comments => 'test')
228 assert c.save
230 assert c.save
229 @project.reload
231 @project.reload
230 assert_equal NUM_REV - 5, @repository.changesets.count
232 assert_equal NUM_REV - 5, @repository.changesets.count
231
233
232 extra_info_heads << "1234abcd5678"
234 extra_info_heads << "1234abcd5678"
233 h = {}
235 h = {}
234 h["heads"] = extra_info_heads
236 h["heads"] = extra_info_heads
235 @repository.merge_extra_info(h)
237 @repository.merge_extra_info(h)
236 @repository.save
238 @repository.save
237 @project.reload
239 @project.reload
238 h1 = @repository.extra_info["heads"].dup
240 h1 = @repository.extra_info["heads"].dup
239 assert h1.index("1234abcd5678")
241 assert h1.index("1234abcd5678")
240 assert_equal 5, h1.size
242 assert_equal 5, h1.size
241
243
242 @repository.fetch_changesets
244 @repository.fetch_changesets
243 @project.reload
245 @project.reload
244 assert_equal NUM_REV - 5, @repository.changesets.count
246 assert_equal NUM_REV - 5, @repository.changesets.count
245 h2 = @repository.extra_info["heads"].dup
247 h2 = @repository.extra_info["heads"].dup
246 assert_equal h1, h2
248 assert_equal h1, h2
247 end
249 end
248
250
249 def test_keep_extra_report_last_commit_in_clear_changesets
251 def test_keep_extra_report_last_commit_in_clear_changesets
250 assert_nil @repository.extra_info
252 assert_nil @repository.extra_info
251 h = {}
253 h = {}
252 h["extra_report_last_commit"] = "1"
254 h["extra_report_last_commit"] = "1"
253 @repository.merge_extra_info(h)
255 @repository.merge_extra_info(h)
254 @repository.save
256 @repository.save
255 @project.reload
257 @project.reload
256
258
257 assert_equal 0, @repository.changesets.count
259 assert_equal 0, @repository.changesets.count
258 @repository.fetch_changesets
260 @repository.fetch_changesets
259 @project.reload
261 @project.reload
260
262
261 assert_equal NUM_REV, @repository.changesets.count
263 assert_equal NUM_REV, @repository.changesets.count
262 @repository.send(:clear_changesets)
264 @repository.send(:clear_changesets)
263 assert_equal 1, @repository.extra_info.size
265 assert_equal 1, @repository.extra_info.size
264 assert_equal "1", @repository.extra_info["extra_report_last_commit"]
266 assert_equal "1", @repository.extra_info["extra_report_last_commit"]
265 end
267 end
266
268
267 def test_refetch_after_clear_changesets
269 def test_refetch_after_clear_changesets
268 assert_nil @repository.extra_info
270 assert_nil @repository.extra_info
269 assert_equal 0, @repository.changesets.count
271 assert_equal 0, @repository.changesets.count
270 @repository.fetch_changesets
272 @repository.fetch_changesets
271 @project.reload
273 @project.reload
272 assert_equal NUM_REV, @repository.changesets.count
274 assert_equal NUM_REV, @repository.changesets.count
273
275
274 @repository.send(:clear_changesets)
276 @repository.send(:clear_changesets)
275 @project.reload
277 @project.reload
276 assert_equal 0, @repository.changesets.count
278 assert_equal 0, @repository.changesets.count
277
279
278 @repository.fetch_changesets
280 @repository.fetch_changesets
279 @project.reload
281 @project.reload
280 assert_equal NUM_REV, @repository.changesets.count
282 assert_equal NUM_REV, @repository.changesets.count
281 end
283 end
282
284
283 def test_parents
285 def test_parents
284 assert_equal 0, @repository.changesets.count
286 assert_equal 0, @repository.changesets.count
285 @repository.fetch_changesets
287 @repository.fetch_changesets
286 @project.reload
288 @project.reload
287 assert_equal NUM_REV, @repository.changesets.count
289 assert_equal NUM_REV, @repository.changesets.count
288 r1 = @repository.find_changeset_by_name("7234cb2750b63")
290 r1 = @repository.find_changeset_by_name("7234cb2750b63")
289 assert_equal [], r1.parents
291 assert_equal [], r1.parents
290 r2 = @repository.find_changeset_by_name("899a15dba03a3")
292 r2 = @repository.find_changeset_by_name("899a15dba03a3")
291 assert_equal 1, r2.parents.length
293 assert_equal 1, r2.parents.length
292 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518",
294 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518",
293 r2.parents[0].identifier
295 r2.parents[0].identifier
294 r3 = @repository.find_changeset_by_name("32ae898b720c2")
296 r3 = @repository.find_changeset_by_name("32ae898b720c2")
295 assert_equal 2, r3.parents.length
297 assert_equal 2, r3.parents.length
296 r4 = [r3.parents[0].identifier, r3.parents[1].identifier].sort
298 r4 = [r3.parents[0].identifier, r3.parents[1].identifier].sort
297 assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", r4[0]
299 assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", r4[0]
298 assert_equal "7e61ac704deecde634b51e59daa8110435dcb3da", r4[1]
300 assert_equal "7e61ac704deecde634b51e59daa8110435dcb3da", r4[1]
299 end
301 end
300
302
301 def test_db_consistent_ordering_init
303 def test_db_consistent_ordering_init
302 assert_nil @repository.extra_info
304 assert_nil @repository.extra_info
303 assert_equal 0, @repository.changesets.count
305 assert_equal 0, @repository.changesets.count
304 @repository.fetch_changesets
306 @repository.fetch_changesets
305 @project.reload
307 @project.reload
306 assert_equal 1, @repository.extra_info["db_consistent"]["ordering"]
308 assert_equal 1, @repository.extra_info["db_consistent"]["ordering"]
307 end
309 end
308
310
309 def test_db_consistent_ordering_before_1_2
311 def test_db_consistent_ordering_before_1_2
310 assert_nil @repository.extra_info
312 assert_nil @repository.extra_info
311 assert_equal 0, @repository.changesets.count
313 assert_equal 0, @repository.changesets.count
312 @repository.fetch_changesets
314 @repository.fetch_changesets
313 @project.reload
315 @project.reload
314 assert_equal NUM_REV, @repository.changesets.count
316 assert_equal NUM_REV, @repository.changesets.count
315 assert_not_nil @repository.extra_info
317 assert_not_nil @repository.extra_info
316 h = {}
318 h = {}
317 h["heads"] = []
319 h["heads"] = []
318 h["branches"] = {}
320 h["branches"] = {}
319 h["db_consistent"] = {}
321 h["db_consistent"] = {}
320 @repository.merge_extra_info(h)
322 @repository.merge_extra_info(h)
321 @repository.save
323 @repository.save
322 assert_equal NUM_REV, @repository.changesets.count
324 assert_equal NUM_REV, @repository.changesets.count
323 @repository.fetch_changesets
325 @repository.fetch_changesets
324 @project.reload
326 @project.reload
325 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
327 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
326
328
327 extra_info_heads = @repository.extra_info["heads"].dup
329 extra_info_heads = @repository.extra_info["heads"].dup
328 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
330 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
329 del_revs = [
331 del_revs = [
330 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
332 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
331 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
333 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
332 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
334 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
333 "deff712f05a90d96edbd70facc47d944be5897e3",
335 "deff712f05a90d96edbd70facc47d944be5897e3",
334 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
336 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
335 "7e61ac704deecde634b51e59daa8110435dcb3da",
337 "7e61ac704deecde634b51e59daa8110435dcb3da",
336 ]
338 ]
337 @repository.changesets.each do |rev|
339 @repository.changesets.each do |rev|
338 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
340 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
339 end
341 end
340 @project.reload
342 @project.reload
341 cs1 = @repository.changesets
343 cs1 = @repository.changesets
342 assert_equal NUM_REV - 6, cs1.count
344 assert_equal NUM_REV - 6, cs1.count
343 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
345 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
344
346
345 extra_info_heads << "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8"
347 extra_info_heads << "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8"
346 h = {}
348 h = {}
347 h["heads"] = extra_info_heads
349 h["heads"] = extra_info_heads
348 @repository.merge_extra_info(h)
350 @repository.merge_extra_info(h)
349 @repository.save
351 @repository.save
350 @project.reload
352 @project.reload
351 assert @repository.extra_info["heads"].index("4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8")
353 assert @repository.extra_info["heads"].index("4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8")
352 @repository.fetch_changesets
354 @repository.fetch_changesets
353 @project.reload
355 @project.reload
354 assert_equal NUM_REV, @repository.changesets.count
356 assert_equal NUM_REV, @repository.changesets.count
355 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
357 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
356
358
357 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
359 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
358 end
360 end
359
361
360 def test_heads_from_branches_hash
362 def test_heads_from_branches_hash
361 assert_nil @repository.extra_info
363 assert_nil @repository.extra_info
362 assert_equal 0, @repository.changesets.count
364 assert_equal 0, @repository.changesets.count
363 assert_equal [], @repository.heads_from_branches_hash
365 assert_equal [], @repository.heads_from_branches_hash
364 h = {}
366 h = {}
365 h["branches"] = {}
367 h["branches"] = {}
366 h["branches"]["test1"] = {}
368 h["branches"]["test1"] = {}
367 h["branches"]["test1"]["last_scmid"] = "1234abcd"
369 h["branches"]["test1"]["last_scmid"] = "1234abcd"
368 h["branches"]["test2"] = {}
370 h["branches"]["test2"] = {}
369 h["branches"]["test2"]["last_scmid"] = "abcd1234"
371 h["branches"]["test2"]["last_scmid"] = "abcd1234"
370 @repository.merge_extra_info(h)
372 @repository.merge_extra_info(h)
371 @repository.save
373 @repository.save
372 @project.reload
374 @project.reload
373 assert_equal ["1234abcd", "abcd1234"], @repository.heads_from_branches_hash.sort
375 assert_equal ["1234abcd", "abcd1234"], @repository.heads_from_branches_hash.sort
374 end
376 end
375
377
376 def test_latest_changesets
378 def test_latest_changesets
377 assert_equal 0, @repository.changesets.count
379 assert_equal 0, @repository.changesets.count
378 @repository.fetch_changesets
380 @repository.fetch_changesets
379 @project.reload
381 @project.reload
380 assert_equal NUM_REV, @repository.changesets.count
382 assert_equal NUM_REV, @repository.changesets.count
381 # with limit
383 # with limit
382 changesets = @repository.latest_changesets('', 'master', 2)
384 changesets = @repository.latest_changesets('', 'master', 2)
383 assert_equal 2, changesets.size
385 assert_equal 2, changesets.size
384
386
385 # with path
387 # with path
386 changesets = @repository.latest_changesets('images', 'master')
388 changesets = @repository.latest_changesets('images', 'master')
387 assert_equal [
389 assert_equal [
388 'deff712f05a90d96edbd70facc47d944be5897e3',
390 'deff712f05a90d96edbd70facc47d944be5897e3',
389 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
391 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
390 '7234cb2750b63f47bff735edc50a1c0a433c2518',
392 '7234cb2750b63f47bff735edc50a1c0a433c2518',
391 ], changesets.collect(&:revision)
393 ], changesets.collect(&:revision)
392
394
393 changesets = @repository.latest_changesets('README', nil)
395 changesets = @repository.latest_changesets('README', nil)
394 assert_equal [
396 assert_equal [
395 '32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf',
397 '32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf',
396 '4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8',
398 '4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8',
397 '713f4944648826f558cf548222f813dabe7cbb04',
399 '713f4944648826f558cf548222f813dabe7cbb04',
398 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
400 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
399 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
401 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
400 '7234cb2750b63f47bff735edc50a1c0a433c2518',
402 '7234cb2750b63f47bff735edc50a1c0a433c2518',
401 ], changesets.collect(&:revision)
403 ], changesets.collect(&:revision)
402
404
403 # with path, revision and limit
405 # with path, revision and limit
404 changesets = @repository.latest_changesets('images', '899a15dba')
406 changesets = @repository.latest_changesets('images', '899a15dba')
405 assert_equal [
407 assert_equal [
406 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
408 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
407 '7234cb2750b63f47bff735edc50a1c0a433c2518',
409 '7234cb2750b63f47bff735edc50a1c0a433c2518',
408 ], changesets.collect(&:revision)
410 ], changesets.collect(&:revision)
409
411
410 changesets = @repository.latest_changesets('images', '899a15dba', 1)
412 changesets = @repository.latest_changesets('images', '899a15dba', 1)
411 assert_equal [
413 assert_equal [
412 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
414 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
413 ], changesets.collect(&:revision)
415 ], changesets.collect(&:revision)
414
416
415 changesets = @repository.latest_changesets('README', '899a15dba')
417 changesets = @repository.latest_changesets('README', '899a15dba')
416 assert_equal [
418 assert_equal [
417 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
419 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
418 '7234cb2750b63f47bff735edc50a1c0a433c2518',
420 '7234cb2750b63f47bff735edc50a1c0a433c2518',
419 ], changesets.collect(&:revision)
421 ], changesets.collect(&:revision)
420
422
421 changesets = @repository.latest_changesets('README', '899a15dba', 1)
423 changesets = @repository.latest_changesets('README', '899a15dba', 1)
422 assert_equal [
424 assert_equal [
423 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
425 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
424 ], changesets.collect(&:revision)
426 ], changesets.collect(&:revision)
425
427
426 # with path, tag and limit
428 # with path, tag and limit
427 changesets = @repository.latest_changesets('images', 'tag01.annotated')
429 changesets = @repository.latest_changesets('images', 'tag01.annotated')
428 assert_equal [
430 assert_equal [
429 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
431 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
430 '7234cb2750b63f47bff735edc50a1c0a433c2518',
432 '7234cb2750b63f47bff735edc50a1c0a433c2518',
431 ], changesets.collect(&:revision)
433 ], changesets.collect(&:revision)
432
434
433 changesets = @repository.latest_changesets('images', 'tag01.annotated', 1)
435 changesets = @repository.latest_changesets('images', 'tag01.annotated', 1)
434 assert_equal [
436 assert_equal [
435 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
437 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
436 ], changesets.collect(&:revision)
438 ], changesets.collect(&:revision)
437
439
438 changesets = @repository.latest_changesets('README', 'tag01.annotated')
440 changesets = @repository.latest_changesets('README', 'tag01.annotated')
439 assert_equal [
441 assert_equal [
440 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
442 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
441 '7234cb2750b63f47bff735edc50a1c0a433c2518',
443 '7234cb2750b63f47bff735edc50a1c0a433c2518',
442 ], changesets.collect(&:revision)
444 ], changesets.collect(&:revision)
443
445
444 changesets = @repository.latest_changesets('README', 'tag01.annotated', 1)
446 changesets = @repository.latest_changesets('README', 'tag01.annotated', 1)
445 assert_equal [
447 assert_equal [
446 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
448 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
447 ], changesets.collect(&:revision)
449 ], changesets.collect(&:revision)
448
450
449 # with path, branch and limit
451 # with path, branch and limit
450 changesets = @repository.latest_changesets('images', 'test_branch')
452 changesets = @repository.latest_changesets('images', 'test_branch')
451 assert_equal [
453 assert_equal [
452 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
454 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
453 '7234cb2750b63f47bff735edc50a1c0a433c2518',
455 '7234cb2750b63f47bff735edc50a1c0a433c2518',
454 ], changesets.collect(&:revision)
456 ], changesets.collect(&:revision)
455
457
456 changesets = @repository.latest_changesets('images', 'test_branch', 1)
458 changesets = @repository.latest_changesets('images', 'test_branch', 1)
457 assert_equal [
459 assert_equal [
458 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
460 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
459 ], changesets.collect(&:revision)
461 ], changesets.collect(&:revision)
460
462
461 changesets = @repository.latest_changesets('README', 'test_branch')
463 changesets = @repository.latest_changesets('README', 'test_branch')
462 assert_equal [
464 assert_equal [
463 '713f4944648826f558cf548222f813dabe7cbb04',
465 '713f4944648826f558cf548222f813dabe7cbb04',
464 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
466 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
465 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
467 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
466 '7234cb2750b63f47bff735edc50a1c0a433c2518',
468 '7234cb2750b63f47bff735edc50a1c0a433c2518',
467 ], changesets.collect(&:revision)
469 ], changesets.collect(&:revision)
468
470
469 changesets = @repository.latest_changesets('README', 'test_branch', 2)
471 changesets = @repository.latest_changesets('README', 'test_branch', 2)
470 assert_equal [
472 assert_equal [
471 '713f4944648826f558cf548222f813dabe7cbb04',
473 '713f4944648826f558cf548222f813dabe7cbb04',
472 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
474 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
473 ], changesets.collect(&:revision)
475 ], changesets.collect(&:revision)
474
476
475 if WINDOWS_PASS
477 if WINDOWS_PASS
476 puts WINDOWS_SKIP_STR
478 puts WINDOWS_SKIP_STR
477 elsif JRUBY_SKIP
479 elsif JRUBY_SKIP
478 puts JRUBY_SKIP_STR
480 puts JRUBY_SKIP_STR
479 else
481 else
480 # latin-1 encoding path
482 # latin-1 encoding path
481 changesets = @repository.latest_changesets(
483 changesets = @repository.latest_changesets(
482 "latin-1-dir/test-#{@char_1}-2.txt", '64f1f3e89')
484 "latin-1-dir/test-#{@char_1}-2.txt", '64f1f3e89')
483 assert_equal [
485 assert_equal [
484 '64f1f3e89ad1cb57976ff0ad99a107012ba3481d',
486 '64f1f3e89ad1cb57976ff0ad99a107012ba3481d',
485 '4fc55c43bf3d3dc2efb66145365ddc17639ce81e',
487 '4fc55c43bf3d3dc2efb66145365ddc17639ce81e',
486 ], changesets.collect(&:revision)
488 ], changesets.collect(&:revision)
487
489
488 changesets = @repository.latest_changesets(
490 changesets = @repository.latest_changesets(
489 "latin-1-dir/test-#{@char_1}-2.txt", '64f1f3e89', 1)
491 "latin-1-dir/test-#{@char_1}-2.txt", '64f1f3e89', 1)
490 assert_equal [
492 assert_equal [
491 '64f1f3e89ad1cb57976ff0ad99a107012ba3481d',
493 '64f1f3e89ad1cb57976ff0ad99a107012ba3481d',
492 ], changesets.collect(&:revision)
494 ], changesets.collect(&:revision)
493 end
495 end
494 end
496 end
495
497
496 def test_latest_changesets_latin_1_dir
498 def test_latest_changesets_latin_1_dir
497 if WINDOWS_PASS
499 if WINDOWS_PASS
498 puts WINDOWS_SKIP_STR
500 puts WINDOWS_SKIP_STR
499 elsif JRUBY_SKIP
501 elsif JRUBY_SKIP
500 puts JRUBY_SKIP_STR
502 puts JRUBY_SKIP_STR
501 else
503 else
502 assert_equal 0, @repository.changesets.count
504 assert_equal 0, @repository.changesets.count
503 @repository.fetch_changesets
505 @repository.fetch_changesets
504 @project.reload
506 @project.reload
505 assert_equal NUM_REV, @repository.changesets.count
507 assert_equal NUM_REV, @repository.changesets.count
506 changesets = @repository.latest_changesets(
508 changesets = @repository.latest_changesets(
507 "latin-1-dir/test-#{@char_1}-subdir", '1ca7f5ed')
509 "latin-1-dir/test-#{@char_1}-subdir", '1ca7f5ed')
508 assert_equal [
510 assert_equal [
509 '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127',
511 '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127',
510 ], changesets.collect(&:revision)
512 ], changesets.collect(&:revision)
511 end
513 end
512 end
514 end
513
515
514 def test_find_changeset_by_name
516 def test_find_changeset_by_name
515 assert_equal 0, @repository.changesets.count
517 assert_equal 0, @repository.changesets.count
516 @repository.fetch_changesets
518 @repository.fetch_changesets
517 @project.reload
519 @project.reload
518 assert_equal NUM_REV, @repository.changesets.count
520 assert_equal NUM_REV, @repository.changesets.count
519 ['7234cb2750b63f47bff735edc50a1c0a433c2518', '7234cb2750b'].each do |r|
521 ['7234cb2750b63f47bff735edc50a1c0a433c2518', '7234cb2750b'].each do |r|
520 assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518',
522 assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518',
521 @repository.find_changeset_by_name(r).revision
523 @repository.find_changeset_by_name(r).revision
522 end
524 end
523 end
525 end
524
526
525 def test_find_changeset_by_empty_name
527 def test_find_changeset_by_empty_name
526 assert_equal 0, @repository.changesets.count
528 assert_equal 0, @repository.changesets.count
527 @repository.fetch_changesets
529 @repository.fetch_changesets
528 @project.reload
530 @project.reload
529 assert_equal NUM_REV, @repository.changesets.count
531 assert_equal NUM_REV, @repository.changesets.count
530 ['', ' ', nil].each do |r|
532 ['', ' ', nil].each do |r|
531 assert_nil @repository.find_changeset_by_name(r)
533 assert_nil @repository.find_changeset_by_name(r)
532 end
534 end
533 end
535 end
534
536
535 def test_identifier
537 def test_identifier
536 assert_equal 0, @repository.changesets.count
538 assert_equal 0, @repository.changesets.count
537 @repository.fetch_changesets
539 @repository.fetch_changesets
538 @project.reload
540 @project.reload
539 assert_equal NUM_REV, @repository.changesets.count
541 assert_equal NUM_REV, @repository.changesets.count
540 c = @repository.changesets.find_by_revision(
542 c = @repository.changesets.find_by_revision(
541 '7234cb2750b63f47bff735edc50a1c0a433c2518')
543 '7234cb2750b63f47bff735edc50a1c0a433c2518')
542 assert_equal c.scmid, c.identifier
544 assert_equal c.scmid, c.identifier
543 end
545 end
544
546
545 def test_format_identifier
547 def test_format_identifier
546 assert_equal 0, @repository.changesets.count
548 assert_equal 0, @repository.changesets.count
547 @repository.fetch_changesets
549 @repository.fetch_changesets
548 @project.reload
550 @project.reload
549 assert_equal NUM_REV, @repository.changesets.count
551 assert_equal NUM_REV, @repository.changesets.count
550 c = @repository.changesets.find_by_revision(
552 c = @repository.changesets.find_by_revision(
551 '7234cb2750b63f47bff735edc50a1c0a433c2518')
553 '7234cb2750b63f47bff735edc50a1c0a433c2518')
552 assert_equal '7234cb27', c.format_identifier
554 assert_equal '7234cb27', c.format_identifier
553 end
555 end
554
556
555 def test_activities
557 def test_activities
556 c = Changeset.new(:repository => @repository,
558 c = Changeset.new(:repository => @repository,
557 :committed_on => Time.now,
559 :committed_on => Time.now,
558 :revision => 'abc7234cb2750b63f47bff735edc50a1c0a433c2',
560 :revision => 'abc7234cb2750b63f47bff735edc50a1c0a433c2',
559 :scmid => 'abc7234cb2750b63f47bff735edc50a1c0a433c2',
561 :scmid => 'abc7234cb2750b63f47bff735edc50a1c0a433c2',
560 :comments => 'test')
562 :comments => 'test')
561 assert c.event_title.include?('abc7234c:')
563 assert c.event_title.include?('abc7234c:')
562 assert_equal 'abc7234cb2750b63f47bff735edc50a1c0a433c2', c.event_url[:rev]
564 assert_equal 'abc7234cb2750b63f47bff735edc50a1c0a433c2', c.event_url[:rev]
563 end
565 end
564
566
565 def test_log_utf8
567 def test_log_utf8
566 assert_equal 0, @repository.changesets.count
568 assert_equal 0, @repository.changesets.count
567 @repository.fetch_changesets
569 @repository.fetch_changesets
568 @project.reload
570 @project.reload
569 assert_equal NUM_REV, @repository.changesets.count
571 assert_equal NUM_REV, @repository.changesets.count
570 str_felix_hex = FELIX_HEX.dup
572 str_felix_hex = FELIX_HEX.dup
571 if str_felix_hex.respond_to?(:force_encoding)
573 if str_felix_hex.respond_to?(:force_encoding)
572 str_felix_hex.force_encoding('UTF-8')
574 str_felix_hex.force_encoding('UTF-8')
573 end
575 end
574 c = @repository.changesets.find_by_revision(
576 c = @repository.changesets.find_by_revision(
575 'ed5bb786bbda2dee66a2d50faf51429dbc043a7b')
577 'ed5bb786bbda2dee66a2d50faf51429dbc043a7b')
576 assert_equal "#{str_felix_hex} <felix@fachschaften.org>", c.committer
578 assert_equal "#{str_felix_hex} <felix@fachschaften.org>", c.committer
577 end
579 end
578
580
579 def test_previous
581 def test_previous
580 assert_equal 0, @repository.changesets.count
582 assert_equal 0, @repository.changesets.count
581 @repository.fetch_changesets
583 @repository.fetch_changesets
582 @project.reload
584 @project.reload
583 assert_equal NUM_REV, @repository.changesets.count
585 assert_equal NUM_REV, @repository.changesets.count
584 %w|1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127 1ca7f5ed|.each do |r1|
586 %w|1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127 1ca7f5ed|.each do |r1|
585 changeset = @repository.find_changeset_by_name(r1)
587 changeset = @repository.find_changeset_by_name(r1)
586 %w|64f1f3e89ad1cb57976ff0ad99a107012ba3481d 64f1f3e89ad1|.each do |r2|
588 %w|64f1f3e89ad1cb57976ff0ad99a107012ba3481d 64f1f3e89ad1|.each do |r2|
587 assert_equal @repository.find_changeset_by_name(r2), changeset.previous
589 assert_equal @repository.find_changeset_by_name(r2), changeset.previous
588 end
590 end
589 end
591 end
590 end
592 end
591
593
592 def test_previous_nil
594 def test_previous_nil
593 assert_equal 0, @repository.changesets.count
595 assert_equal 0, @repository.changesets.count
594 @repository.fetch_changesets
596 @repository.fetch_changesets
595 @project.reload
597 @project.reload
596 assert_equal NUM_REV, @repository.changesets.count
598 assert_equal NUM_REV, @repository.changesets.count
597 %w|7234cb2750b63f47bff735edc50a1c0a433c2518 7234cb275|.each do |r1|
599 %w|7234cb2750b63f47bff735edc50a1c0a433c2518 7234cb275|.each do |r1|
598 changeset = @repository.find_changeset_by_name(r1)
600 changeset = @repository.find_changeset_by_name(r1)
599 assert_nil changeset.previous
601 assert_nil changeset.previous
600 end
602 end
601 end
603 end
602
604
603 def test_next
605 def test_next
604 assert_equal 0, @repository.changesets.count
606 assert_equal 0, @repository.changesets.count
605 @repository.fetch_changesets
607 @repository.fetch_changesets
606 @project.reload
608 @project.reload
607 assert_equal NUM_REV, @repository.changesets.count
609 assert_equal NUM_REV, @repository.changesets.count
608 %w|64f1f3e89ad1cb57976ff0ad99a107012ba3481d 64f1f3e89ad1|.each do |r2|
610 %w|64f1f3e89ad1cb57976ff0ad99a107012ba3481d 64f1f3e89ad1|.each do |r2|
609 changeset = @repository.find_changeset_by_name(r2)
611 changeset = @repository.find_changeset_by_name(r2)
610 %w|1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127 1ca7f5ed|.each do |r1|
612 %w|1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127 1ca7f5ed|.each do |r1|
611 assert_equal @repository.find_changeset_by_name(r1), changeset.next
613 assert_equal @repository.find_changeset_by_name(r1), changeset.next
612 end
614 end
613 end
615 end
614 end
616 end
615
617
616 def test_next_nil
618 def test_next_nil
617 assert_equal 0, @repository.changesets.count
619 assert_equal 0, @repository.changesets.count
618 @repository.fetch_changesets
620 @repository.fetch_changesets
619 @project.reload
621 @project.reload
620 assert_equal NUM_REV, @repository.changesets.count
622 assert_equal NUM_REV, @repository.changesets.count
621 %w|2a682156a3b6e77a8bf9cd4590e8db757f3c6c78 2a682156a3b6e77a|.each do |r1|
623 %w|2a682156a3b6e77a8bf9cd4590e8db757f3c6c78 2a682156a3b6e77a|.each do |r1|
622 changeset = @repository.find_changeset_by_name(r1)
624 changeset = @repository.find_changeset_by_name(r1)
623 assert_nil changeset.next
625 assert_nil changeset.next
624 end
626 end
625 end
627 end
626 else
628 else
627 puts "Git test repository NOT FOUND. Skipping unit tests !!!"
629 puts "Git test repository NOT FOUND. Skipping unit tests !!!"
628 def test_fake; assert true end
630 def test_fake; assert true end
629 end
631 end
630 end
632 end
@@ -1,481 +1,493
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class RepositoryTest < ActiveSupport::TestCase
20 class RepositoryTest < ActiveSupport::TestCase
21 fixtures :projects,
21 fixtures :projects,
22 :trackers,
22 :trackers,
23 :projects_trackers,
23 :projects_trackers,
24 :enabled_modules,
24 :enabled_modules,
25 :repositories,
25 :repositories,
26 :issues,
26 :issues,
27 :issue_statuses,
27 :issue_statuses,
28 :issue_categories,
28 :issue_categories,
29 :changesets,
29 :changesets,
30 :changes,
30 :changes,
31 :users,
31 :users,
32 :members,
32 :members,
33 :member_roles,
33 :member_roles,
34 :roles,
34 :roles,
35 :enumerations
35 :enumerations
36
36
37 include Redmine::I18n
37 include Redmine::I18n
38
38
39 def setup
39 def setup
40 @repository = Project.find(1).repository
40 @repository = Project.find(1).repository
41 end
41 end
42
42
43 def test_blank_log_encoding_error_message
43 def test_blank_log_encoding_error_message
44 set_language_if_valid 'en'
44 set_language_if_valid 'en'
45 repo = Repository::Bazaar.new(
45 repo = Repository::Bazaar.new(
46 :project => Project.find(3),
46 :project => Project.find(3),
47 :url => "/test",
47 :url => "/test",
48 :log_encoding => ''
48 :log_encoding => ''
49 )
49 )
50 assert !repo.save
50 assert !repo.save
51 assert_include "Commit messages encoding can't be blank",
51 assert_include "Commit messages encoding can't be blank",
52 repo.errors.full_messages
52 repo.errors.full_messages
53 end
53 end
54
54
55 def test_blank_log_encoding_error_message_fr
55 def test_blank_log_encoding_error_message_fr
56 set_language_if_valid 'fr'
56 set_language_if_valid 'fr'
57 str = "Encodage des messages de commit doit \xc3\xaatre renseign\xc3\xa9(e)"
57 str = "Encodage des messages de commit doit \xc3\xaatre renseign\xc3\xa9(e)"
58 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
58 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
59 repo = Repository::Bazaar.new(
59 repo = Repository::Bazaar.new(
60 :project => Project.find(3),
60 :project => Project.find(3),
61 :url => "/test"
61 :url => "/test"
62 )
62 )
63 assert !repo.save
63 assert !repo.save
64 assert_include str, repo.errors.full_messages
64 assert_include str, repo.errors.full_messages
65 end
65 end
66
66
67 def test_create
67 def test_create
68 repository = Repository::Subversion.new(:project => Project.find(3))
68 repository = Repository::Subversion.new(:project => Project.find(3))
69 assert !repository.save
69 assert !repository.save
70
70
71 repository.url = "svn://localhost"
71 repository.url = "svn://localhost"
72 assert repository.save
72 assert repository.save
73 repository.reload
73 repository.reload
74
74
75 project = Project.find(3)
75 project = Project.find(3)
76 assert_equal repository, project.repository
76 assert_equal repository, project.repository
77 end
77 end
78
78
79 def test_2_repositories_with_same_identifier_in_different_projects_should_be_valid
79 def test_2_repositories_with_same_identifier_in_different_projects_should_be_valid
80 Repository::Subversion.create!(:project_id => 2, :identifier => 'foo', :url => 'file:///foo')
80 Repository::Subversion.create!(:project_id => 2, :identifier => 'foo', :url => 'file:///foo')
81 r = Repository::Subversion.new(:project_id => 3, :identifier => 'foo', :url => 'file:///bar')
81 r = Repository::Subversion.new(:project_id => 3, :identifier => 'foo', :url => 'file:///bar')
82 assert r.save
82 assert r.save
83 end
83 end
84
84
85 def test_2_repositories_with_same_identifier_should_not_be_valid
85 def test_2_repositories_with_same_identifier_should_not_be_valid
86 Repository::Subversion.create!(:project_id => 3, :identifier => 'foo', :url => 'file:///foo')
86 Repository::Subversion.create!(:project_id => 3, :identifier => 'foo', :url => 'file:///foo')
87 r = Repository::Subversion.new(:project_id => 3, :identifier => 'foo', :url => 'file:///bar')
87 r = Repository::Subversion.new(:project_id => 3, :identifier => 'foo', :url => 'file:///bar')
88 assert !r.save
88 assert !r.save
89 end
89 end
90
90
91 def test_2_repositories_with_blank_identifier_should_not_be_valid
91 def test_2_repositories_with_blank_identifier_should_not_be_valid
92 Repository::Subversion.create!(:project_id => 3, :identifier => '', :url => 'file:///foo')
92 Repository::Subversion.create!(:project_id => 3, :identifier => '', :url => 'file:///foo')
93 r = Repository::Subversion.new(:project_id => 3, :identifier => '', :url => 'file:///bar')
93 r = Repository::Subversion.new(:project_id => 3, :identifier => '', :url => 'file:///bar')
94 assert !r.save
94 assert !r.save
95 end
95 end
96
96
97 def test_2_repositories_with_blank_identifier_and_one_as_default_should_not_be_valid
98 Repository::Subversion.create!(:project_id => 3, :identifier => '', :url => 'file:///foo', :is_default => true)
99 r = Repository::Subversion.new(:project_id => 3, :identifier => '', :url => 'file:///bar')
100 assert !r.save
101 end
102
103 def test_2_repositories_with_blank_and_nil_identifier_should_not_be_valid
104 Repository::Subversion.create!(:project_id => 3, :identifier => nil, :url => 'file:///foo')
105 r = Repository::Subversion.new(:project_id => 3, :identifier => '', :url => 'file:///bar')
106 assert !r.save
107 end
108
97 def test_first_repository_should_be_set_as_default
109 def test_first_repository_should_be_set_as_default
98 repository1 = Repository::Subversion.new(
110 repository1 = Repository::Subversion.new(
99 :project => Project.find(3),
111 :project => Project.find(3),
100 :identifier => 'svn1',
112 :identifier => 'svn1',
101 :url => 'file:///svn1'
113 :url => 'file:///svn1'
102 )
114 )
103 assert repository1.save
115 assert repository1.save
104 assert repository1.is_default?
116 assert repository1.is_default?
105
117
106 repository2 = Repository::Subversion.new(
118 repository2 = Repository::Subversion.new(
107 :project => Project.find(3),
119 :project => Project.find(3),
108 :identifier => 'svn2',
120 :identifier => 'svn2',
109 :url => 'file:///svn2'
121 :url => 'file:///svn2'
110 )
122 )
111 assert repository2.save
123 assert repository2.save
112 assert !repository2.is_default?
124 assert !repository2.is_default?
113
125
114 assert_equal repository1, Project.find(3).repository
126 assert_equal repository1, Project.find(3).repository
115 assert_equal [repository1, repository2], Project.find(3).repositories.sort
127 assert_equal [repository1, repository2], Project.find(3).repositories.sort
116 end
128 end
117
129
118 def test_default_repository_should_be_one
130 def test_default_repository_should_be_one
119 assert_equal 0, Project.find(3).repositories.count
131 assert_equal 0, Project.find(3).repositories.count
120 repository1 = Repository::Subversion.new(
132 repository1 = Repository::Subversion.new(
121 :project => Project.find(3),
133 :project => Project.find(3),
122 :identifier => 'svn1',
134 :identifier => 'svn1',
123 :url => 'file:///svn1'
135 :url => 'file:///svn1'
124 )
136 )
125 assert repository1.save
137 assert repository1.save
126 assert repository1.is_default?
138 assert repository1.is_default?
127
139
128 repository2 = Repository::Subversion.new(
140 repository2 = Repository::Subversion.new(
129 :project => Project.find(3),
141 :project => Project.find(3),
130 :identifier => 'svn2',
142 :identifier => 'svn2',
131 :url => 'file:///svn2',
143 :url => 'file:///svn2',
132 :is_default => true
144 :is_default => true
133 )
145 )
134 assert repository2.save
146 assert repository2.save
135 assert repository2.is_default?
147 assert repository2.is_default?
136 repository1.reload
148 repository1.reload
137 assert !repository1.is_default?
149 assert !repository1.is_default?
138
150
139 assert_equal repository2, Project.find(3).repository
151 assert_equal repository2, Project.find(3).repository
140 assert_equal [repository2, repository1], Project.find(3).repositories.sort
152 assert_equal [repository2, repository1], Project.find(3).repositories.sort
141 end
153 end
142
154
143 def test_identifier_should_accept_letters_digits_dashes_and_underscores
155 def test_identifier_should_accept_letters_digits_dashes_and_underscores
144 r = Repository::Subversion.new(
156 r = Repository::Subversion.new(
145 :project_id => 3,
157 :project_id => 3,
146 :identifier => 'svn-123_45',
158 :identifier => 'svn-123_45',
147 :url => 'file:///svn'
159 :url => 'file:///svn'
148 )
160 )
149 assert r.save
161 assert r.save
150 end
162 end
151
163
152 def test_identifier_should_not_be_frozen_for_a_new_repository
164 def test_identifier_should_not_be_frozen_for_a_new_repository
153 assert_equal false, Repository.new.identifier_frozen?
165 assert_equal false, Repository.new.identifier_frozen?
154 end
166 end
155
167
156 def test_identifier_should_not_be_frozen_for_a_saved_repository_with_blank_identifier
168 def test_identifier_should_not_be_frozen_for_a_saved_repository_with_blank_identifier
157 Repository.where(:id => 10).update_all(["identifier = ''"])
169 Repository.where(:id => 10).update_all(["identifier = ''"])
158 assert_equal false, Repository.find(10).identifier_frozen?
170 assert_equal false, Repository.find(10).identifier_frozen?
159 end
171 end
160
172
161 def test_identifier_should_be_frozen_for_a_saved_repository_with_valid_identifier
173 def test_identifier_should_be_frozen_for_a_saved_repository_with_valid_identifier
162 Repository.where(:id => 10).update_all(["identifier = 'abc123'"])
174 Repository.where(:id => 10).update_all(["identifier = 'abc123'"])
163 assert_equal true, Repository.find(10).identifier_frozen?
175 assert_equal true, Repository.find(10).identifier_frozen?
164 end
176 end
165
177
166 def test_identifier_should_not_accept_change_if_frozen
178 def test_identifier_should_not_accept_change_if_frozen
167 r = Repository.new(:identifier => 'foo')
179 r = Repository.new(:identifier => 'foo')
168 r.stubs(:identifier_frozen?).returns(true)
180 r.stubs(:identifier_frozen?).returns(true)
169
181
170 r.identifier = 'bar'
182 r.identifier = 'bar'
171 assert_equal 'foo', r.identifier
183 assert_equal 'foo', r.identifier
172 end
184 end
173
185
174 def test_identifier_should_accept_change_if_not_frozen
186 def test_identifier_should_accept_change_if_not_frozen
175 r = Repository.new(:identifier => 'foo')
187 r = Repository.new(:identifier => 'foo')
176 r.stubs(:identifier_frozen?).returns(false)
188 r.stubs(:identifier_frozen?).returns(false)
177
189
178 r.identifier = 'bar'
190 r.identifier = 'bar'
179 assert_equal 'bar', r.identifier
191 assert_equal 'bar', r.identifier
180 end
192 end
181
193
182 def test_destroy
194 def test_destroy
183 repository = Repository.find(10)
195 repository = Repository.find(10)
184 changesets = repository.changesets.count
196 changesets = repository.changesets.count
185 changes = repository.filechanges.count
197 changes = repository.filechanges.count
186
198
187 assert_difference 'Changeset.count', -changesets do
199 assert_difference 'Changeset.count', -changesets do
188 assert_difference 'Change.count', -changes do
200 assert_difference 'Change.count', -changes do
189 Repository.find(10).destroy
201 Repository.find(10).destroy
190 end
202 end
191 end
203 end
192 end
204 end
193
205
194 def test_destroy_should_delete_parents_associations
206 def test_destroy_should_delete_parents_associations
195 changeset = Changeset.find(102)
207 changeset = Changeset.find(102)
196 changeset.parents = Changeset.where(:id => [100, 101]).all
208 changeset.parents = Changeset.where(:id => [100, 101]).all
197 assert_difference 'Changeset.connection.select_all("select * from changeset_parents").count', -2 do
209 assert_difference 'Changeset.connection.select_all("select * from changeset_parents").count', -2 do
198 Repository.find(10).destroy
210 Repository.find(10).destroy
199 end
211 end
200 end
212 end
201
213
202 def test_destroy_should_delete_issues_associations
214 def test_destroy_should_delete_issues_associations
203 changeset = Changeset.find(102)
215 changeset = Changeset.find(102)
204 changeset.issues = Issue.where(:id => [1, 2]).all
216 changeset.issues = Issue.where(:id => [1, 2]).all
205 assert_difference 'Changeset.connection.select_all("select * from changesets_issues").count', -2 do
217 assert_difference 'Changeset.connection.select_all("select * from changesets_issues").count', -2 do
206 Repository.find(10).destroy
218 Repository.find(10).destroy
207 end
219 end
208 end
220 end
209
221
210 def test_should_not_create_with_disabled_scm
222 def test_should_not_create_with_disabled_scm
211 # disable Subversion
223 # disable Subversion
212 with_settings :enabled_scm => ['Darcs', 'Git'] do
224 with_settings :enabled_scm => ['Darcs', 'Git'] do
213 repository = Repository::Subversion.new(
225 repository = Repository::Subversion.new(
214 :project => Project.find(3), :url => "svn://localhost")
226 :project => Project.find(3), :url => "svn://localhost")
215 assert !repository.save
227 assert !repository.save
216 assert_include I18n.translate('activerecord.errors.messages.invalid'),
228 assert_include I18n.translate('activerecord.errors.messages.invalid'),
217 repository.errors[:type]
229 repository.errors[:type]
218 end
230 end
219 end
231 end
220
232
221 def test_scan_changesets_for_issue_ids
233 def test_scan_changesets_for_issue_ids
222 Setting.default_language = 'en'
234 Setting.default_language = 'en'
223 Setting.commit_ref_keywords = 'refs , references, IssueID'
235 Setting.commit_ref_keywords = 'refs , references, IssueID'
224 Setting.commit_update_keywords = [
236 Setting.commit_update_keywords = [
225 {'keywords' => 'fixes , closes',
237 {'keywords' => 'fixes , closes',
226 'status_id' => IssueStatus.where(:is_closed => true).first.id,
238 'status_id' => IssueStatus.where(:is_closed => true).first.id,
227 'done_ratio' => '90'}
239 'done_ratio' => '90'}
228 ]
240 ]
229 Setting.default_language = 'en'
241 Setting.default_language = 'en'
230 ActionMailer::Base.deliveries.clear
242 ActionMailer::Base.deliveries.clear
231
243
232 # make sure issue 1 is not already closed
244 # make sure issue 1 is not already closed
233 fixed_issue = Issue.find(1)
245 fixed_issue = Issue.find(1)
234 assert !fixed_issue.status.is_closed?
246 assert !fixed_issue.status.is_closed?
235 old_status = fixed_issue.status
247 old_status = fixed_issue.status
236
248
237 with_settings :notified_events => %w(issue_added issue_updated) do
249 with_settings :notified_events => %w(issue_added issue_updated) do
238 Repository.scan_changesets_for_issue_ids
250 Repository.scan_changesets_for_issue_ids
239 end
251 end
240 assert_equal [101, 102], Issue.find(3).changeset_ids
252 assert_equal [101, 102], Issue.find(3).changeset_ids
241
253
242 # fixed issues
254 # fixed issues
243 fixed_issue.reload
255 fixed_issue.reload
244 assert fixed_issue.status.is_closed?
256 assert fixed_issue.status.is_closed?
245 assert_equal 90, fixed_issue.done_ratio
257 assert_equal 90, fixed_issue.done_ratio
246 assert_equal [101], fixed_issue.changeset_ids
258 assert_equal [101], fixed_issue.changeset_ids
247
259
248 # issue change
260 # issue change
249 journal = fixed_issue.journals.reorder('created_on desc').first
261 journal = fixed_issue.journals.reorder('created_on desc').first
250 assert_equal User.find_by_login('dlopper'), journal.user
262 assert_equal User.find_by_login('dlopper'), journal.user
251 assert_equal 'Applied in changeset r2.', journal.notes
263 assert_equal 'Applied in changeset r2.', journal.notes
252
264
253 # 2 email notifications
265 # 2 email notifications
254 assert_equal 2, ActionMailer::Base.deliveries.size
266 assert_equal 2, ActionMailer::Base.deliveries.size
255 mail = ActionMailer::Base.deliveries.first
267 mail = ActionMailer::Base.deliveries.first
256 assert_not_nil mail
268 assert_not_nil mail
257 assert mail.subject.starts_with?(
269 assert mail.subject.starts_with?(
258 "[#{fixed_issue.project.name} - #{fixed_issue.tracker.name} ##{fixed_issue.id}]")
270 "[#{fixed_issue.project.name} - #{fixed_issue.tracker.name} ##{fixed_issue.id}]")
259 assert_mail_body_match(
271 assert_mail_body_match(
260 "Status changed from #{old_status} to #{fixed_issue.status}", mail)
272 "Status changed from #{old_status} to #{fixed_issue.status}", mail)
261
273
262 # ignoring commits referencing an issue of another project
274 # ignoring commits referencing an issue of another project
263 assert_equal [], Issue.find(4).changesets
275 assert_equal [], Issue.find(4).changesets
264 end
276 end
265
277
266 def test_for_changeset_comments_strip
278 def test_for_changeset_comments_strip
267 repository = Repository::Mercurial.create(
279 repository = Repository::Mercurial.create(
268 :project => Project.find( 4 ),
280 :project => Project.find( 4 ),
269 :url => '/foo/bar/baz' )
281 :url => '/foo/bar/baz' )
270 comment = <<-COMMENT
282 comment = <<-COMMENT
271 This is a loooooooooooooooooooooooooooong comment
283 This is a loooooooooooooooooooooooooooong comment
272
284
273
285
274 COMMENT
286 COMMENT
275 changeset = Changeset.new(
287 changeset = Changeset.new(
276 :comments => comment, :commit_date => Time.now,
288 :comments => comment, :commit_date => Time.now,
277 :revision => 0, :scmid => 'f39b7922fb3c',
289 :revision => 0, :scmid => 'f39b7922fb3c',
278 :committer => 'foo <foo@example.com>',
290 :committer => 'foo <foo@example.com>',
279 :committed_on => Time.now, :repository => repository )
291 :committed_on => Time.now, :repository => repository )
280 assert( changeset.save )
292 assert( changeset.save )
281 assert_not_equal( comment, changeset.comments )
293 assert_not_equal( comment, changeset.comments )
282 assert_equal( 'This is a loooooooooooooooooooooooooooong comment',
294 assert_equal( 'This is a loooooooooooooooooooooooooooong comment',
283 changeset.comments )
295 changeset.comments )
284 end
296 end
285
297
286 def test_for_urls_strip_cvs
298 def test_for_urls_strip_cvs
287 repository = Repository::Cvs.create(
299 repository = Repository::Cvs.create(
288 :project => Project.find(4),
300 :project => Project.find(4),
289 :url => ' :pserver:login:password@host:/path/to/the/repository',
301 :url => ' :pserver:login:password@host:/path/to/the/repository',
290 :root_url => 'foo ',
302 :root_url => 'foo ',
291 :log_encoding => 'UTF-8')
303 :log_encoding => 'UTF-8')
292 assert repository.save
304 assert repository.save
293 repository.reload
305 repository.reload
294 assert_equal ':pserver:login:password@host:/path/to/the/repository',
306 assert_equal ':pserver:login:password@host:/path/to/the/repository',
295 repository.url
307 repository.url
296 assert_equal 'foo', repository.root_url
308 assert_equal 'foo', repository.root_url
297 end
309 end
298
310
299 def test_for_urls_strip_subversion
311 def test_for_urls_strip_subversion
300 repository = Repository::Subversion.create(
312 repository = Repository::Subversion.create(
301 :project => Project.find(4),
313 :project => Project.find(4),
302 :url => ' file:///dummy ')
314 :url => ' file:///dummy ')
303 assert repository.save
315 assert repository.save
304 repository.reload
316 repository.reload
305 assert_equal 'file:///dummy', repository.url
317 assert_equal 'file:///dummy', repository.url
306 end
318 end
307
319
308 def test_for_urls_strip_git
320 def test_for_urls_strip_git
309 repository = Repository::Git.create(
321 repository = Repository::Git.create(
310 :project => Project.find(4),
322 :project => Project.find(4),
311 :url => ' c:\dummy ')
323 :url => ' c:\dummy ')
312 assert repository.save
324 assert repository.save
313 repository.reload
325 repository.reload
314 assert_equal 'c:\dummy', repository.url
326 assert_equal 'c:\dummy', repository.url
315 end
327 end
316
328
317 def test_manual_user_mapping
329 def test_manual_user_mapping
318 assert_no_difference "Changeset.where('user_id <> 2').count" do
330 assert_no_difference "Changeset.where('user_id <> 2').count" do
319 c = Changeset.create!(
331 c = Changeset.create!(
320 :repository => @repository,
332 :repository => @repository,
321 :committer => 'foo',
333 :committer => 'foo',
322 :committed_on => Time.now,
334 :committed_on => Time.now,
323 :revision => 100,
335 :revision => 100,
324 :comments => 'Committed by foo.'
336 :comments => 'Committed by foo.'
325 )
337 )
326 assert_nil c.user
338 assert_nil c.user
327 @repository.committer_ids = {'foo' => '2'}
339 @repository.committer_ids = {'foo' => '2'}
328 assert_equal User.find(2), c.reload.user
340 assert_equal User.find(2), c.reload.user
329 # committer is now mapped
341 # committer is now mapped
330 c = Changeset.create!(
342 c = Changeset.create!(
331 :repository => @repository,
343 :repository => @repository,
332 :committer => 'foo',
344 :committer => 'foo',
333 :committed_on => Time.now,
345 :committed_on => Time.now,
334 :revision => 101,
346 :revision => 101,
335 :comments => 'Another commit by foo.'
347 :comments => 'Another commit by foo.'
336 )
348 )
337 assert_equal User.find(2), c.user
349 assert_equal User.find(2), c.user
338 end
350 end
339 end
351 end
340
352
341 def test_auto_user_mapping_by_username
353 def test_auto_user_mapping_by_username
342 c = Changeset.create!(
354 c = Changeset.create!(
343 :repository => @repository,
355 :repository => @repository,
344 :committer => 'jsmith',
356 :committer => 'jsmith',
345 :committed_on => Time.now,
357 :committed_on => Time.now,
346 :revision => 100,
358 :revision => 100,
347 :comments => 'Committed by john.'
359 :comments => 'Committed by john.'
348 )
360 )
349 assert_equal User.find(2), c.user
361 assert_equal User.find(2), c.user
350 end
362 end
351
363
352 def test_auto_user_mapping_by_email
364 def test_auto_user_mapping_by_email
353 c = Changeset.create!(
365 c = Changeset.create!(
354 :repository => @repository,
366 :repository => @repository,
355 :committer => 'john <jsmith@somenet.foo>',
367 :committer => 'john <jsmith@somenet.foo>',
356 :committed_on => Time.now,
368 :committed_on => Time.now,
357 :revision => 100,
369 :revision => 100,
358 :comments => 'Committed by john.'
370 :comments => 'Committed by john.'
359 )
371 )
360 assert_equal User.find(2), c.user
372 assert_equal User.find(2), c.user
361 end
373 end
362
374
363 def test_filesystem_avaialbe
375 def test_filesystem_avaialbe
364 klass = Repository::Filesystem
376 klass = Repository::Filesystem
365 assert klass.scm_adapter_class
377 assert klass.scm_adapter_class
366 assert_equal true, klass.scm_available
378 assert_equal true, klass.scm_available
367 end
379 end
368
380
369 def test_extra_info_should_not_return_non_hash_value
381 def test_extra_info_should_not_return_non_hash_value
370 repo = Repository.new
382 repo = Repository.new
371 repo.extra_info = "foo"
383 repo.extra_info = "foo"
372 assert_nil repo.extra_info
384 assert_nil repo.extra_info
373 end
385 end
374
386
375 def test_merge_extra_info
387 def test_merge_extra_info
376 repo = Repository::Subversion.new(:project => Project.find(3))
388 repo = Repository::Subversion.new(:project => Project.find(3))
377 assert !repo.save
389 assert !repo.save
378 repo.url = "svn://localhost"
390 repo.url = "svn://localhost"
379 assert repo.save
391 assert repo.save
380 repo.reload
392 repo.reload
381 project = Project.find(3)
393 project = Project.find(3)
382 assert_equal repo, project.repository
394 assert_equal repo, project.repository
383 assert_nil repo.extra_info
395 assert_nil repo.extra_info
384 h1 = {"test_1" => {"test_11" => "test_value_11"}}
396 h1 = {"test_1" => {"test_11" => "test_value_11"}}
385 repo.merge_extra_info(h1)
397 repo.merge_extra_info(h1)
386 assert_equal h1, repo.extra_info
398 assert_equal h1, repo.extra_info
387 h2 = {"test_2" => {
399 h2 = {"test_2" => {
388 "test_21" => "test_value_21",
400 "test_21" => "test_value_21",
389 "test_22" => "test_value_22",
401 "test_22" => "test_value_22",
390 }}
402 }}
391 repo.merge_extra_info(h2)
403 repo.merge_extra_info(h2)
392 assert_equal (h = {"test_11" => "test_value_11"}),
404 assert_equal (h = {"test_11" => "test_value_11"}),
393 repo.extra_info["test_1"]
405 repo.extra_info["test_1"]
394 assert_equal "test_value_21",
406 assert_equal "test_value_21",
395 repo.extra_info["test_2"]["test_21"]
407 repo.extra_info["test_2"]["test_21"]
396 h3 = {"test_2" => {
408 h3 = {"test_2" => {
397 "test_23" => "test_value_23",
409 "test_23" => "test_value_23",
398 "test_24" => "test_value_24",
410 "test_24" => "test_value_24",
399 }}
411 }}
400 repo.merge_extra_info(h3)
412 repo.merge_extra_info(h3)
401 assert_equal (h = {"test_11" => "test_value_11"}),
413 assert_equal (h = {"test_11" => "test_value_11"}),
402 repo.extra_info["test_1"]
414 repo.extra_info["test_1"]
403 assert_nil repo.extra_info["test_2"]["test_21"]
415 assert_nil repo.extra_info["test_2"]["test_21"]
404 assert_equal "test_value_23",
416 assert_equal "test_value_23",
405 repo.extra_info["test_2"]["test_23"]
417 repo.extra_info["test_2"]["test_23"]
406 end
418 end
407
419
408 def test_sort_should_not_raise_an_error_with_nil_identifiers
420 def test_sort_should_not_raise_an_error_with_nil_identifiers
409 r1 = Repository.new
421 r1 = Repository.new
410 r2 = Repository.new
422 r2 = Repository.new
411
423
412 assert_nothing_raised do
424 assert_nothing_raised do
413 [r1, r2].sort
425 [r1, r2].sort
414 end
426 end
415 end
427 end
416
428
417 def test_stats_by_author_reflect_changesets_and_changes
429 def test_stats_by_author_reflect_changesets_and_changes
418 repository = Repository.find(10)
430 repository = Repository.find(10)
419
431
420 expected = {"Dave Lopper"=>{:commits_count=>10, :changes_count=>3}}
432 expected = {"Dave Lopper"=>{:commits_count=>10, :changes_count=>3}}
421 assert_equal expected, repository.stats_by_author
433 assert_equal expected, repository.stats_by_author
422
434
423 set = Changeset.create!(
435 set = Changeset.create!(
424 :repository => repository,
436 :repository => repository,
425 :committer => 'dlopper',
437 :committer => 'dlopper',
426 :committed_on => Time.now,
438 :committed_on => Time.now,
427 :revision => 101,
439 :revision => 101,
428 :comments => 'Another commit by foo.'
440 :comments => 'Another commit by foo.'
429 )
441 )
430 Change.create!(:changeset => set, :action => 'A', :path => '/path/to/file1')
442 Change.create!(:changeset => set, :action => 'A', :path => '/path/to/file1')
431 Change.create!(:changeset => set, :action => 'A', :path => '/path/to/file2')
443 Change.create!(:changeset => set, :action => 'A', :path => '/path/to/file2')
432 expected = {"Dave Lopper"=>{:commits_count=>11, :changes_count=>5}}
444 expected = {"Dave Lopper"=>{:commits_count=>11, :changes_count=>5}}
433 assert_equal expected, repository.stats_by_author
445 assert_equal expected, repository.stats_by_author
434 end
446 end
435
447
436 def test_stats_by_author_honnor_committers
448 def test_stats_by_author_honnor_committers
437 # in fact it is really tested above, but let's have a dedicated test
449 # in fact it is really tested above, but let's have a dedicated test
438 # to ensure things are dynamically linked to Users
450 # to ensure things are dynamically linked to Users
439 User.find_by_login("dlopper").update_attribute(:firstname, "Dave's")
451 User.find_by_login("dlopper").update_attribute(:firstname, "Dave's")
440 repository = Repository.find(10)
452 repository = Repository.find(10)
441 expected = {"Dave's Lopper"=>{:commits_count=>10, :changes_count=>3}}
453 expected = {"Dave's Lopper"=>{:commits_count=>10, :changes_count=>3}}
442 assert_equal expected, repository.stats_by_author
454 assert_equal expected, repository.stats_by_author
443 end
455 end
444
456
445 def test_stats_by_author_doesnt_drop_unmapped_users
457 def test_stats_by_author_doesnt_drop_unmapped_users
446 repository = Repository.find(10)
458 repository = Repository.find(10)
447 Changeset.create!(
459 Changeset.create!(
448 :repository => repository,
460 :repository => repository,
449 :committer => 'unnamed <foo@bar.net>',
461 :committer => 'unnamed <foo@bar.net>',
450 :committed_on => Time.now,
462 :committed_on => Time.now,
451 :revision => 101,
463 :revision => 101,
452 :comments => 'Another commit by foo.'
464 :comments => 'Another commit by foo.'
453 )
465 )
454
466
455 assert repository.stats_by_author.has_key?("unnamed <foo@bar.net>")
467 assert repository.stats_by_author.has_key?("unnamed <foo@bar.net>")
456 end
468 end
457
469
458 def test_stats_by_author_merge_correctly
470 def test_stats_by_author_merge_correctly
459 # as we honnor users->committer map and it's not injective,
471 # as we honnor users->committer map and it's not injective,
460 # we must be sure merges happen correctly and stats are not
472 # we must be sure merges happen correctly and stats are not
461 # wiped out when two source counts map to the same user.
473 # wiped out when two source counts map to the same user.
462 #
474 #
463 # Here we have Changeset's with committer="dlopper" and others
475 # Here we have Changeset's with committer="dlopper" and others
464 # with committer="dlopper <dlopper@somefoo.net>"
476 # with committer="dlopper <dlopper@somefoo.net>"
465 repository = Repository.find(10)
477 repository = Repository.find(10)
466
478
467 expected = {"Dave Lopper"=>{:commits_count=>10, :changes_count=>3}}
479 expected = {"Dave Lopper"=>{:commits_count=>10, :changes_count=>3}}
468 assert_equal expected, repository.stats_by_author
480 assert_equal expected, repository.stats_by_author
469
481
470 set = Changeset.create!(
482 set = Changeset.create!(
471 :repository => repository,
483 :repository => repository,
472 :committer => 'dlopper <dlopper@somefoo.net>',
484 :committer => 'dlopper <dlopper@somefoo.net>',
473 :committed_on => Time.now,
485 :committed_on => Time.now,
474 :revision => 101,
486 :revision => 101,
475 :comments => 'Another commit by foo.'
487 :comments => 'Another commit by foo.'
476 )
488 )
477
489
478 expected = {"Dave Lopper"=>{:commits_count=>11, :changes_count=>3}}
490 expected = {"Dave Lopper"=>{:commits_count=>11, :changes_count=>3}}
479 assert_equal expected, repository.stats_by_author
491 assert_equal expected, repository.stats_by_author
480 end
492 end
481 end
493 end
General Comments 0
You need to be logged in to leave comments. Login now