##// END OF EJS Templates
Merged r14050 (#19260)....
Jean-Philippe Lang -
r13676:36b70437e0fc
parent child
Show More
@@ -1,510 +1,509
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, lambda{order("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC")}
28 has_many :changesets, lambda{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_save :check_default
33 before_save :check_default
34
34
35 # Raw SQL to delete changesets and changes in the database
35 # Raw SQL to delete changesets and changes in the database
36 # has_many :changesets, :dependent => :destroy is too slow for big repositories
36 # has_many :changesets, :dependent => :destroy is too slow for big repositories
37 before_destroy :clear_changesets
37 before_destroy :clear_changesets
38
38
39 validates_length_of :password, :maximum => 255, :allow_nil => true
39 validates_length_of :password, :maximum => 255, :allow_nil => true
40 validates_length_of :identifier, :maximum => IDENTIFIER_MAX_LENGTH, :allow_blank => true
40 validates_length_of :identifier, :maximum => IDENTIFIER_MAX_LENGTH, :allow_blank => true
41 validates_presence_of :identifier, :unless => Proc.new { |r| r.is_default? || r.set_as_default? }
42 validates_uniqueness_of :identifier, :scope => :project_id, :allow_blank => true
41 validates_uniqueness_of :identifier, :scope => :project_id, :allow_blank => true
43 validates_exclusion_of :identifier, :in => %w(browse show entry raw changes annotate diff statistics graph revisions revision)
42 validates_exclusion_of :identifier, :in => %w(browse show entry raw changes annotate diff statistics graph revisions revision)
44 # donwcase letters, digits, dashes, underscores but not digits only
43 # donwcase letters, digits, dashes, underscores but not digits only
45 validates_format_of :identifier, :with => /\A(?!\d+$)[a-z0-9\-_]*\z/, :allow_blank => true
44 validates_format_of :identifier, :with => /\A(?!\d+$)[a-z0-9\-_]*\z/, :allow_blank => true
46 # Checks if the SCM is enabled when creating a repository
45 # Checks if the SCM is enabled when creating a repository
47 validate :repo_create_validation, :on => :create
46 validate :repo_create_validation, :on => :create
48 validate :validate_repository_path
47 validate :validate_repository_path
49 attr_protected :id
48 attr_protected :id
50
49
51 safe_attributes 'identifier',
50 safe_attributes 'identifier',
52 'login',
51 'login',
53 'password',
52 'password',
54 'path_encoding',
53 'path_encoding',
55 'log_encoding',
54 'log_encoding',
56 'is_default'
55 'is_default'
57
56
58 safe_attributes 'url',
57 safe_attributes 'url',
59 :if => lambda {|repository, user| repository.new_record?}
58 :if => lambda {|repository, user| repository.new_record?}
60
59
61 def repo_create_validation
60 def repo_create_validation
62 unless Setting.enabled_scm.include?(self.class.name.demodulize)
61 unless Setting.enabled_scm.include?(self.class.name.demodulize)
63 errors.add(:type, :invalid)
62 errors.add(:type, :invalid)
64 end
63 end
65 end
64 end
66
65
67 def self.human_attribute_name(attribute_key_name, *args)
66 def self.human_attribute_name(attribute_key_name, *args)
68 attr_name = attribute_key_name.to_s
67 attr_name = attribute_key_name.to_s
69 if attr_name == "log_encoding"
68 if attr_name == "log_encoding"
70 attr_name = "commit_logs_encoding"
69 attr_name = "commit_logs_encoding"
71 end
70 end
72 super(attr_name, *args)
71 super(attr_name, *args)
73 end
72 end
74
73
75 # Removes leading and trailing whitespace
74 # Removes leading and trailing whitespace
76 def url=(arg)
75 def url=(arg)
77 write_attribute(:url, arg ? arg.to_s.strip : nil)
76 write_attribute(:url, arg ? arg.to_s.strip : nil)
78 end
77 end
79
78
80 # Removes leading and trailing whitespace
79 # Removes leading and trailing whitespace
81 def root_url=(arg)
80 def root_url=(arg)
82 write_attribute(:root_url, arg ? arg.to_s.strip : nil)
81 write_attribute(:root_url, arg ? arg.to_s.strip : nil)
83 end
82 end
84
83
85 def password
84 def password
86 read_ciphered_attribute(:password)
85 read_ciphered_attribute(:password)
87 end
86 end
88
87
89 def password=(arg)
88 def password=(arg)
90 write_ciphered_attribute(:password, arg)
89 write_ciphered_attribute(:password, arg)
91 end
90 end
92
91
93 def scm_adapter
92 def scm_adapter
94 self.class.scm_adapter_class
93 self.class.scm_adapter_class
95 end
94 end
96
95
97 def scm
96 def scm
98 unless @scm
97 unless @scm
99 @scm = self.scm_adapter.new(url, root_url,
98 @scm = self.scm_adapter.new(url, root_url,
100 login, password, path_encoding)
99 login, password, path_encoding)
101 if root_url.blank? && @scm.root_url.present?
100 if root_url.blank? && @scm.root_url.present?
102 update_attribute(:root_url, @scm.root_url)
101 update_attribute(:root_url, @scm.root_url)
103 end
102 end
104 end
103 end
105 @scm
104 @scm
106 end
105 end
107
106
108 def scm_name
107 def scm_name
109 self.class.scm_name
108 self.class.scm_name
110 end
109 end
111
110
112 def name
111 def name
113 if identifier.present?
112 if identifier.present?
114 identifier
113 identifier
115 elsif is_default?
114 elsif is_default?
116 l(:field_repository_is_default)
115 l(:field_repository_is_default)
117 else
116 else
118 scm_name
117 scm_name
119 end
118 end
120 end
119 end
121
120
122 def identifier=(identifier)
121 def identifier=(identifier)
123 super unless identifier_frozen?
122 super unless identifier_frozen?
124 end
123 end
125
124
126 def identifier_frozen?
125 def identifier_frozen?
127 errors[:identifier].blank? && !(new_record? || identifier.blank?)
126 errors[:identifier].blank? && !(new_record? || identifier.blank?)
128 end
127 end
129
128
130 def identifier_param
129 def identifier_param
131 if is_default?
130 if is_default?
132 nil
131 nil
133 elsif identifier.present?
132 elsif identifier.present?
134 identifier
133 identifier
135 else
134 else
136 id.to_s
135 id.to_s
137 end
136 end
138 end
137 end
139
138
140 def <=>(repository)
139 def <=>(repository)
141 if is_default?
140 if is_default?
142 -1
141 -1
143 elsif repository.is_default?
142 elsif repository.is_default?
144 1
143 1
145 else
144 else
146 identifier.to_s <=> repository.identifier.to_s
145 identifier.to_s <=> repository.identifier.to_s
147 end
146 end
148 end
147 end
149
148
150 def self.find_by_identifier_param(param)
149 def self.find_by_identifier_param(param)
151 if param.to_s =~ /^\d+$/
150 if param.to_s =~ /^\d+$/
152 find_by_id(param)
151 find_by_id(param)
153 else
152 else
154 find_by_identifier(param)
153 find_by_identifier(param)
155 end
154 end
156 end
155 end
157
156
158 # TODO: should return an empty hash instead of nil to avoid many ||{}
157 # TODO: should return an empty hash instead of nil to avoid many ||{}
159 def extra_info
158 def extra_info
160 h = read_attribute(:extra_info)
159 h = read_attribute(:extra_info)
161 h.is_a?(Hash) ? h : nil
160 h.is_a?(Hash) ? h : nil
162 end
161 end
163
162
164 def merge_extra_info(arg)
163 def merge_extra_info(arg)
165 h = extra_info || {}
164 h = extra_info || {}
166 return h if arg.nil?
165 return h if arg.nil?
167 h.merge!(arg)
166 h.merge!(arg)
168 write_attribute(:extra_info, h)
167 write_attribute(:extra_info, h)
169 end
168 end
170
169
171 def report_last_commit
170 def report_last_commit
172 true
171 true
173 end
172 end
174
173
175 def supports_cat?
174 def supports_cat?
176 scm.supports_cat?
175 scm.supports_cat?
177 end
176 end
178
177
179 def supports_annotate?
178 def supports_annotate?
180 scm.supports_annotate?
179 scm.supports_annotate?
181 end
180 end
182
181
183 def supports_all_revisions?
182 def supports_all_revisions?
184 true
183 true
185 end
184 end
186
185
187 def supports_directory_revisions?
186 def supports_directory_revisions?
188 false
187 false
189 end
188 end
190
189
191 def supports_revision_graph?
190 def supports_revision_graph?
192 false
191 false
193 end
192 end
194
193
195 def entry(path=nil, identifier=nil)
194 def entry(path=nil, identifier=nil)
196 scm.entry(path, identifier)
195 scm.entry(path, identifier)
197 end
196 end
198
197
199 def scm_entries(path=nil, identifier=nil)
198 def scm_entries(path=nil, identifier=nil)
200 scm.entries(path, identifier)
199 scm.entries(path, identifier)
201 end
200 end
202 protected :scm_entries
201 protected :scm_entries
203
202
204 def entries(path=nil, identifier=nil)
203 def entries(path=nil, identifier=nil)
205 entries = scm_entries(path, identifier)
204 entries = scm_entries(path, identifier)
206 load_entries_changesets(entries)
205 load_entries_changesets(entries)
207 entries
206 entries
208 end
207 end
209
208
210 def branches
209 def branches
211 scm.branches
210 scm.branches
212 end
211 end
213
212
214 def tags
213 def tags
215 scm.tags
214 scm.tags
216 end
215 end
217
216
218 def default_branch
217 def default_branch
219 nil
218 nil
220 end
219 end
221
220
222 def properties(path, identifier=nil)
221 def properties(path, identifier=nil)
223 scm.properties(path, identifier)
222 scm.properties(path, identifier)
224 end
223 end
225
224
226 def cat(path, identifier=nil)
225 def cat(path, identifier=nil)
227 scm.cat(path, identifier)
226 scm.cat(path, identifier)
228 end
227 end
229
228
230 def diff(path, rev, rev_to)
229 def diff(path, rev, rev_to)
231 scm.diff(path, rev, rev_to)
230 scm.diff(path, rev, rev_to)
232 end
231 end
233
232
234 def diff_format_revisions(cs, cs_to, sep=':')
233 def diff_format_revisions(cs, cs_to, sep=':')
235 text = ""
234 text = ""
236 text << cs_to.format_identifier + sep if cs_to
235 text << cs_to.format_identifier + sep if cs_to
237 text << cs.format_identifier if cs
236 text << cs.format_identifier if cs
238 text
237 text
239 end
238 end
240
239
241 # Returns a path relative to the url of the repository
240 # Returns a path relative to the url of the repository
242 def relative_path(path)
241 def relative_path(path)
243 path
242 path
244 end
243 end
245
244
246 # Finds and returns a revision with a number or the beginning of a hash
245 # Finds and returns a revision with a number or the beginning of a hash
247 def find_changeset_by_name(name)
246 def find_changeset_by_name(name)
248 return nil if name.blank?
247 return nil if name.blank?
249 s = name.to_s
248 s = name.to_s
250 if s.match(/^\d*$/)
249 if s.match(/^\d*$/)
251 changesets.where("revision = ?", s).first
250 changesets.where("revision = ?", s).first
252 else
251 else
253 changesets.where("revision LIKE ?", s + '%').first
252 changesets.where("revision LIKE ?", s + '%').first
254 end
253 end
255 end
254 end
256
255
257 def latest_changeset
256 def latest_changeset
258 @latest_changeset ||= changesets.first
257 @latest_changeset ||= changesets.first
259 end
258 end
260
259
261 # Returns the latest changesets for +path+
260 # Returns the latest changesets for +path+
262 # Default behaviour is to search in cached changesets
261 # Default behaviour is to search in cached changesets
263 def latest_changesets(path, rev, limit=10)
262 def latest_changesets(path, rev, limit=10)
264 if path.blank?
263 if path.blank?
265 changesets.
264 changesets.
266 reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
265 reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
267 limit(limit).
266 limit(limit).
268 preload(:user).
267 preload(:user).
269 to_a
268 to_a
270 else
269 else
271 filechanges.
270 filechanges.
272 where("path = ?", path.with_leading_slash).
271 where("path = ?", path.with_leading_slash).
273 reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
272 reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
274 limit(limit).
273 limit(limit).
275 preload(:changeset => :user).
274 preload(:changeset => :user).
276 collect(&:changeset)
275 collect(&:changeset)
277 end
276 end
278 end
277 end
279
278
280 def scan_changesets_for_issue_ids
279 def scan_changesets_for_issue_ids
281 self.changesets.each(&:scan_comment_for_issue_ids)
280 self.changesets.each(&:scan_comment_for_issue_ids)
282 end
281 end
283
282
284 # Returns an array of committers usernames and associated user_id
283 # Returns an array of committers usernames and associated user_id
285 def committers
284 def committers
286 @committers ||= Changeset.where(:repository_id => id).uniq.pluck(:committer, :user_id)
285 @committers ||= Changeset.where(:repository_id => id).uniq.pluck(:committer, :user_id)
287 end
286 end
288
287
289 # Maps committers username to a user ids
288 # Maps committers username to a user ids
290 def committer_ids=(h)
289 def committer_ids=(h)
291 if h.is_a?(Hash)
290 if h.is_a?(Hash)
292 committers.each do |committer, user_id|
291 committers.each do |committer, user_id|
293 new_user_id = h[committer]
292 new_user_id = h[committer]
294 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)
295 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)
296 Changeset.where(["repository_id = ? AND committer = ?", id, committer]).
295 Changeset.where(["repository_id = ? AND committer = ?", id, committer]).
297 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}")
298 end
297 end
299 end
298 end
300 @committers = nil
299 @committers = nil
301 @found_committer_users = nil
300 @found_committer_users = nil
302 true
301 true
303 else
302 else
304 false
303 false
305 end
304 end
306 end
305 end
307
306
308 # Returns the Redmine User corresponding to the given +committer+
307 # Returns the Redmine User corresponding to the given +committer+
309 # 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
310 # with the same username or email was found
309 # with the same username or email was found
311 def find_committer_user(committer)
310 def find_committer_user(committer)
312 unless committer.blank?
311 unless committer.blank?
313 @found_committer_users ||= {}
312 @found_committer_users ||= {}
314 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)
315
314
316 user = nil
315 user = nil
317 c = changesets.where(:committer => committer).
316 c = changesets.where(:committer => committer).
318 includes(:user).references(:user).first
317 includes(:user).references(:user).first
319 if c && c.user
318 if c && c.user
320 user = c.user
319 user = c.user
321 elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
320 elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
322 username, email = $1.strip, $3
321 username, email = $1.strip, $3
323 u = User.find_by_login(username)
322 u = User.find_by_login(username)
324 u ||= User.find_by_mail(email) unless email.blank?
323 u ||= User.find_by_mail(email) unless email.blank?
325 user = u
324 user = u
326 end
325 end
327 @found_committer_users[committer] = user
326 @found_committer_users[committer] = user
328 user
327 user
329 end
328 end
330 end
329 end
331
330
332 def repo_log_encoding
331 def repo_log_encoding
333 encoding = log_encoding.to_s.strip
332 encoding = log_encoding.to_s.strip
334 encoding.blank? ? 'UTF-8' : encoding
333 encoding.blank? ? 'UTF-8' : encoding
335 end
334 end
336
335
337 # Fetches new changesets for all repositories of active projects
336 # Fetches new changesets for all repositories of active projects
338 # Can be called periodically by an external script
337 # Can be called periodically by an external script
339 # eg. ruby script/runner "Repository.fetch_changesets"
338 # eg. ruby script/runner "Repository.fetch_changesets"
340 def self.fetch_changesets
339 def self.fetch_changesets
341 Project.active.has_module(:repository).all.each do |project|
340 Project.active.has_module(:repository).all.each do |project|
342 project.repositories.each do |repository|
341 project.repositories.each do |repository|
343 begin
342 begin
344 repository.fetch_changesets
343 repository.fetch_changesets
345 rescue Redmine::Scm::Adapters::CommandFailed => e
344 rescue Redmine::Scm::Adapters::CommandFailed => e
346 logger.error "scm: error during fetching changesets: #{e.message}"
345 logger.error "scm: error during fetching changesets: #{e.message}"
347 end
346 end
348 end
347 end
349 end
348 end
350 end
349 end
351
350
352 # scan changeset comments to find related and fixed issues for all repositories
351 # scan changeset comments to find related and fixed issues for all repositories
353 def self.scan_changesets_for_issue_ids
352 def self.scan_changesets_for_issue_ids
354 all.each(&:scan_changesets_for_issue_ids)
353 all.each(&:scan_changesets_for_issue_ids)
355 end
354 end
356
355
357 def self.scm_name
356 def self.scm_name
358 'Abstract'
357 'Abstract'
359 end
358 end
360
359
361 def self.available_scm
360 def self.available_scm
362 subclasses.collect {|klass| [klass.scm_name, klass.name]}
361 subclasses.collect {|klass| [klass.scm_name, klass.name]}
363 end
362 end
364
363
365 def self.factory(klass_name, *args)
364 def self.factory(klass_name, *args)
366 klass = "Repository::#{klass_name}".constantize
365 klass = "Repository::#{klass_name}".constantize
367 klass.new(*args)
366 klass.new(*args)
368 rescue
367 rescue
369 nil
368 nil
370 end
369 end
371
370
372 def self.scm_adapter_class
371 def self.scm_adapter_class
373 nil
372 nil
374 end
373 end
375
374
376 def self.scm_command
375 def self.scm_command
377 ret = ""
376 ret = ""
378 begin
377 begin
379 ret = self.scm_adapter_class.client_command if self.scm_adapter_class
378 ret = self.scm_adapter_class.client_command if self.scm_adapter_class
380 rescue Exception => e
379 rescue Exception => e
381 logger.error "scm: error during get command: #{e.message}"
380 logger.error "scm: error during get command: #{e.message}"
382 end
381 end
383 ret
382 ret
384 end
383 end
385
384
386 def self.scm_version_string
385 def self.scm_version_string
387 ret = ""
386 ret = ""
388 begin
387 begin
389 ret = self.scm_adapter_class.client_version_string if self.scm_adapter_class
388 ret = self.scm_adapter_class.client_version_string if self.scm_adapter_class
390 rescue Exception => e
389 rescue Exception => e
391 logger.error "scm: error during get version string: #{e.message}"
390 logger.error "scm: error during get version string: #{e.message}"
392 end
391 end
393 ret
392 ret
394 end
393 end
395
394
396 def self.scm_available
395 def self.scm_available
397 ret = false
396 ret = false
398 begin
397 begin
399 ret = self.scm_adapter_class.client_available if self.scm_adapter_class
398 ret = self.scm_adapter_class.client_available if self.scm_adapter_class
400 rescue Exception => e
399 rescue Exception => e
401 logger.error "scm: error during get scm available: #{e.message}"
400 logger.error "scm: error during get scm available: #{e.message}"
402 end
401 end
403 ret
402 ret
404 end
403 end
405
404
406 def set_as_default?
405 def set_as_default?
407 new_record? && project && Repository.where(:project_id => project.id).empty?
406 new_record? && project && Repository.where(:project_id => project.id).empty?
408 end
407 end
409
408
410 # Returns a hash with statistics by author in the following form:
409 # Returns a hash with statistics by author in the following form:
411 # {
410 # {
412 # "John Smith" => { :commits => 45, :changes => 324 },
411 # "John Smith" => { :commits => 45, :changes => 324 },
413 # "Bob" => { ... }
412 # "Bob" => { ... }
414 # }
413 # }
415 #
414 #
416 # Notes:
415 # Notes:
417 # - this hash honnors the users mapping defined for the repository
416 # - this hash honnors the users mapping defined for the repository
418 def stats_by_author
417 def stats_by_author
419 commits = Changeset.where("repository_id = ?", id).select("committer, user_id, count(*) as count").group("committer, user_id")
418 commits = Changeset.where("repository_id = ?", id).select("committer, user_id, count(*) as count").group("committer, user_id")
420
419
421 #TODO: restore ordering ; this line probably never worked
420 #TODO: restore ordering ; this line probably never worked
422 #commits.to_a.sort! {|x, y| x.last <=> y.last}
421 #commits.to_a.sort! {|x, y| x.last <=> y.last}
423
422
424 changes = Change.joins(:changeset).where("#{Changeset.table_name}.repository_id = ?", id).select("committer, user_id, count(*) as count").group("committer, user_id")
423 changes = Change.joins(:changeset).where("#{Changeset.table_name}.repository_id = ?", id).select("committer, user_id, count(*) as count").group("committer, user_id")
425
424
426 user_ids = changesets.map(&:user_id).compact.uniq
425 user_ids = changesets.map(&:user_id).compact.uniq
427 authors_names = User.where(:id => user_ids).inject({}) do |memo, user|
426 authors_names = User.where(:id => user_ids).inject({}) do |memo, user|
428 memo[user.id] = user.to_s
427 memo[user.id] = user.to_s
429 memo
428 memo
430 end
429 end
431
430
432 (commits + changes).inject({}) do |hash, element|
431 (commits + changes).inject({}) do |hash, element|
433 mapped_name = element.committer
432 mapped_name = element.committer
434 if username = authors_names[element.user_id.to_i]
433 if username = authors_names[element.user_id.to_i]
435 mapped_name = username
434 mapped_name = username
436 end
435 end
437 hash[mapped_name] ||= { :commits_count => 0, :changes_count => 0 }
436 hash[mapped_name] ||= { :commits_count => 0, :changes_count => 0 }
438 if element.is_a?(Changeset)
437 if element.is_a?(Changeset)
439 hash[mapped_name][:commits_count] += element.count.to_i
438 hash[mapped_name][:commits_count] += element.count.to_i
440 else
439 else
441 hash[mapped_name][:changes_count] += element.count.to_i
440 hash[mapped_name][:changes_count] += element.count.to_i
442 end
441 end
443 hash
442 hash
444 end
443 end
445 end
444 end
446
445
447 # Returns a scope of changesets that come from the same commit as the given changeset
446 # Returns a scope of changesets that come from the same commit as the given changeset
448 # in different repositories that point to the same backend
447 # in different repositories that point to the same backend
449 def same_commits_in_scope(scope, changeset)
448 def same_commits_in_scope(scope, changeset)
450 scope = scope.joins(:repository).where(:repositories => {:url => url, :root_url => root_url, :type => type})
449 scope = scope.joins(:repository).where(:repositories => {:url => url, :root_url => root_url, :type => type})
451 if changeset.scmid.present?
450 if changeset.scmid.present?
452 scope = scope.where(:scmid => changeset.scmid)
451 scope = scope.where(:scmid => changeset.scmid)
453 else
452 else
454 scope = scope.where(:revision => changeset.revision)
453 scope = scope.where(:revision => changeset.revision)
455 end
454 end
456 scope
455 scope
457 end
456 end
458
457
459 protected
458 protected
460
459
461 # Validates repository url based against an optional regular expression
460 # Validates repository url based against an optional regular expression
462 # that can be set in the Redmine configuration file.
461 # that can be set in the Redmine configuration file.
463 def validate_repository_path(attribute=:url)
462 def validate_repository_path(attribute=:url)
464 regexp = Redmine::Configuration["scm_#{scm_name.to_s.downcase}_path_regexp"]
463 regexp = Redmine::Configuration["scm_#{scm_name.to_s.downcase}_path_regexp"]
465 if changes[attribute] && regexp.present?
464 if changes[attribute] && regexp.present?
466 regexp = regexp.to_s.strip.gsub('%project%') {Regexp.escape(project.try(:identifier).to_s)}
465 regexp = regexp.to_s.strip.gsub('%project%') {Regexp.escape(project.try(:identifier).to_s)}
467 unless send(attribute).to_s.match(Regexp.new("\\A#{regexp}\\z"))
466 unless send(attribute).to_s.match(Regexp.new("\\A#{regexp}\\z"))
468 errors.add(attribute, :invalid)
467 errors.add(attribute, :invalid)
469 end
468 end
470 end
469 end
471 end
470 end
472
471
473 def check_default
472 def check_default
474 if !is_default? && set_as_default?
473 if !is_default? && set_as_default?
475 self.is_default = true
474 self.is_default = true
476 end
475 end
477 if is_default? && is_default_changed?
476 if is_default? && is_default_changed?
478 Repository.where(["project_id = ?", project_id]).update_all(["is_default = ?", false])
477 Repository.where(["project_id = ?", project_id]).update_all(["is_default = ?", false])
479 end
478 end
480 end
479 end
481
480
482 def load_entries_changesets(entries)
481 def load_entries_changesets(entries)
483 if entries
482 if entries
484 entries.each do |entry|
483 entries.each do |entry|
485 if entry.lastrev && entry.lastrev.identifier
484 if entry.lastrev && entry.lastrev.identifier
486 entry.changeset = find_changeset_by_name(entry.lastrev.identifier)
485 entry.changeset = find_changeset_by_name(entry.lastrev.identifier)
487 end
486 end
488 end
487 end
489 end
488 end
490 end
489 end
491
490
492 private
491 private
493
492
494 # Deletes repository data
493 # Deletes repository data
495 def clear_changesets
494 def clear_changesets
496 cs = Changeset.table_name
495 cs = Changeset.table_name
497 ch = Change.table_name
496 ch = Change.table_name
498 ci = "#{table_name_prefix}changesets_issues#{table_name_suffix}"
497 ci = "#{table_name_prefix}changesets_issues#{table_name_suffix}"
499 cp = "#{table_name_prefix}changeset_parents#{table_name_suffix}"
498 cp = "#{table_name_prefix}changeset_parents#{table_name_suffix}"
500
499
501 self.class.connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
500 self.class.connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
502 self.class.connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
501 self.class.connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
503 self.class.connection.delete("DELETE FROM #{cp} WHERE #{cp}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
502 self.class.connection.delete("DELETE FROM #{cp} WHERE #{cp}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
504 self.class.connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
503 self.class.connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
505 clear_extra_info_of_changesets
504 clear_extra_info_of_changesets
506 end
505 end
507
506
508 def clear_extra_info_of_changesets
507 def clear_extra_info_of_changesets
509 end
508 end
510 end
509 end
@@ -1,592 +1,621
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".force_encoding('UTF-8')
31 FELIX_HEX = "Felix Sch\xC3\xA4fer".force_encoding('UTF-8')
32 CHAR_1_HEX = "\xc3\x9c".force_encoding('UTF-8')
32 CHAR_1_HEX = "\xc3\x9c".force_encoding('UTF-8')
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 end
50 end
51
51
52 def test_nondefault_repo_with_blank_identifier_destruction
53 repo1 = Repository::Git.new(
54 :project => @project,
55 :url => REPOSITORY_PATH,
56 :identifier => '',
57 :is_default => true
58 )
59 assert repo1.save
60 repo1.fetch_changesets
61
62 repo2 = Repository::Git.new(
63 :project => @project,
64 :url => REPOSITORY_PATH,
65 :identifier => 'repo2',
66 :is_default => true
67 )
68 assert repo2.save
69 repo2.fetch_changesets
70
71 repo1.reload
72 repo2.reload
73 assert !repo1.is_default?
74 assert repo2.is_default?
75
76 assert_difference 'Repository.count', -1 do
77 repo1.destroy
78 end
79 end
80
52 def test_blank_path_to_repository_error_message
81 def test_blank_path_to_repository_error_message
53 set_language_if_valid 'en'
82 set_language_if_valid 'en'
54 repo = Repository::Git.new(
83 repo = Repository::Git.new(
55 :project => @project,
84 :project => @project,
56 :identifier => 'test'
85 :identifier => 'test'
57 )
86 )
58 assert !repo.save
87 assert !repo.save
59 assert_include "Path to repository cannot be blank",
88 assert_include "Path to repository cannot be blank",
60 repo.errors.full_messages
89 repo.errors.full_messages
61 end
90 end
62
91
63 def test_blank_path_to_repository_error_message_fr
92 def test_blank_path_to_repository_error_message_fr
64 set_language_if_valid 'fr'
93 set_language_if_valid 'fr'
65 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)".force_encoding('UTF-8')
94 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)".force_encoding('UTF-8')
66 repo = Repository::Git.new(
95 repo = Repository::Git.new(
67 :project => @project,
96 :project => @project,
68 :url => "",
97 :url => "",
69 :identifier => 'test',
98 :identifier => 'test',
70 :path_encoding => ''
99 :path_encoding => ''
71 )
100 )
72 assert !repo.save
101 assert !repo.save
73 assert_include str, repo.errors.full_messages
102 assert_include str, repo.errors.full_messages
74 end
103 end
75
104
76 if File.directory?(REPOSITORY_PATH)
105 if File.directory?(REPOSITORY_PATH)
77 ## Ruby uses ANSI api to fork a process on Windows.
106 ## Ruby uses ANSI api to fork a process on Windows.
78 ## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
107 ## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
79 ## and these are incompatible with ASCII.
108 ## and these are incompatible with ASCII.
80 ## Git for Windows (msysGit) changed internal API from ANSI to Unicode in 1.7.10
109 ## Git for Windows (msysGit) changed internal API from ANSI to Unicode in 1.7.10
81 ## http://code.google.com/p/msysgit/issues/detail?id=80
110 ## http://code.google.com/p/msysgit/issues/detail?id=80
82 ## So, Latin-1 path tests fail on Japanese Windows
111 ## So, Latin-1 path tests fail on Japanese Windows
83 WINDOWS_PASS = (Redmine::Platform.mswin? &&
112 WINDOWS_PASS = (Redmine::Platform.mswin? &&
84 Redmine::Scm::Adapters::GitAdapter.client_version_above?([1, 7, 10]))
113 Redmine::Scm::Adapters::GitAdapter.client_version_above?([1, 7, 10]))
85 WINDOWS_SKIP_STR = "TODO: This test fails in Git for Windows above 1.7.10"
114 WINDOWS_SKIP_STR = "TODO: This test fails in Git for Windows above 1.7.10"
86
115
87 def test_scm_available
116 def test_scm_available
88 klass = Repository::Git
117 klass = Repository::Git
89 assert_equal "Git", klass.scm_name
118 assert_equal "Git", klass.scm_name
90 assert klass.scm_adapter_class
119 assert klass.scm_adapter_class
91 assert_not_equal "", klass.scm_command
120 assert_not_equal "", klass.scm_command
92 assert_equal true, klass.scm_available
121 assert_equal true, klass.scm_available
93 end
122 end
94
123
95 def test_entries
124 def test_entries
96 entries = @repository.entries
125 entries = @repository.entries
97 assert_kind_of Redmine::Scm::Adapters::Entries, entries
126 assert_kind_of Redmine::Scm::Adapters::Entries, entries
98 end
127 end
99
128
100 def test_fetch_changesets_from_scratch
129 def test_fetch_changesets_from_scratch
101 assert_nil @repository.extra_info
130 assert_nil @repository.extra_info
102
131
103 assert_equal 0, @repository.changesets.count
132 assert_equal 0, @repository.changesets.count
104 @repository.fetch_changesets
133 @repository.fetch_changesets
105 @project.reload
134 @project.reload
106
135
107 assert_equal NUM_REV, @repository.changesets.count
136 assert_equal NUM_REV, @repository.changesets.count
108 assert_equal 39, @repository.filechanges.count
137 assert_equal 39, @repository.filechanges.count
109
138
110 commit = @repository.changesets.find_by_revision("7234cb2750b63f47bff735edc50a1c0a433c2518")
139 commit = @repository.changesets.find_by_revision("7234cb2750b63f47bff735edc50a1c0a433c2518")
111 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", commit.scmid
140 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", commit.scmid
112 assert_equal "Initial import.\nThe repository contains 3 files.", commit.comments
141 assert_equal "Initial import.\nThe repository contains 3 files.", commit.comments
113 assert_equal "jsmith <jsmith@foo.bar>", commit.committer
142 assert_equal "jsmith <jsmith@foo.bar>", commit.committer
114 assert_equal User.find_by_login('jsmith'), commit.user
143 assert_equal User.find_by_login('jsmith'), commit.user
115 # TODO: add a commit with commit time <> author time to the test repository
144 # TODO: add a commit with commit time <> author time to the test repository
116 assert_equal Time.gm(2007, 12, 14, 9, 22, 52), commit.committed_on
145 assert_equal Time.gm(2007, 12, 14, 9, 22, 52), commit.committed_on
117 assert_equal "2007-12-14".to_date, commit.commit_date
146 assert_equal "2007-12-14".to_date, commit.commit_date
118 assert_equal 3, commit.filechanges.count
147 assert_equal 3, commit.filechanges.count
119 change = commit.filechanges.sort_by(&:path).first
148 change = commit.filechanges.sort_by(&:path).first
120 assert_equal "README", change.path
149 assert_equal "README", change.path
121 assert_equal nil, change.from_path
150 assert_equal nil, change.from_path
122 assert_equal "A", change.action
151 assert_equal "A", change.action
123
152
124 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
153 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
125 end
154 end
126
155
127 def test_fetch_changesets_incremental
156 def test_fetch_changesets_incremental
128 assert_equal 0, @repository.changesets.count
157 assert_equal 0, @repository.changesets.count
129 @repository.fetch_changesets
158 @repository.fetch_changesets
130 @project.reload
159 @project.reload
131 assert_equal NUM_REV, @repository.changesets.count
160 assert_equal NUM_REV, @repository.changesets.count
132 extra_info_heads = @repository.extra_info["heads"].dup
161 extra_info_heads = @repository.extra_info["heads"].dup
133 assert_equal NUM_HEAD, extra_info_heads.size
162 assert_equal NUM_HEAD, extra_info_heads.size
134 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
163 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
135 assert_equal 4, extra_info_heads.size
164 assert_equal 4, extra_info_heads.size
136
165
137 del_revs = [
166 del_revs = [
138 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
167 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
139 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
168 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
140 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
169 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
141 "deff712f05a90d96edbd70facc47d944be5897e3",
170 "deff712f05a90d96edbd70facc47d944be5897e3",
142 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
171 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
143 "7e61ac704deecde634b51e59daa8110435dcb3da",
172 "7e61ac704deecde634b51e59daa8110435dcb3da",
144 ]
173 ]
145 @repository.changesets.each do |rev|
174 @repository.changesets.each do |rev|
146 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
175 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
147 end
176 end
148 @project.reload
177 @project.reload
149 cs1 = @repository.changesets
178 cs1 = @repository.changesets
150 assert_equal NUM_REV - 6, cs1.count
179 assert_equal NUM_REV - 6, cs1.count
151 extra_info_heads << "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8"
180 extra_info_heads << "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8"
152 h = {}
181 h = {}
153 h["heads"] = extra_info_heads
182 h["heads"] = extra_info_heads
154 @repository.merge_extra_info(h)
183 @repository.merge_extra_info(h)
155 @repository.save
184 @repository.save
156 @project.reload
185 @project.reload
157 assert @repository.extra_info["heads"].index("4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8")
186 assert @repository.extra_info["heads"].index("4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8")
158 @repository.fetch_changesets
187 @repository.fetch_changesets
159 @project.reload
188 @project.reload
160 assert_equal NUM_REV, @repository.changesets.count
189 assert_equal NUM_REV, @repository.changesets.count
161 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
190 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
162 assert @repository.extra_info["heads"].index("83ca5fd546063a3c7dc2e568ba3355661a9e2b2c")
191 assert @repository.extra_info["heads"].index("83ca5fd546063a3c7dc2e568ba3355661a9e2b2c")
163 end
192 end
164
193
165 def test_fetch_changesets_history_editing
194 def test_fetch_changesets_history_editing
166 assert_equal 0, @repository.changesets.count
195 assert_equal 0, @repository.changesets.count
167 @repository.fetch_changesets
196 @repository.fetch_changesets
168 @project.reload
197 @project.reload
169 assert_equal NUM_REV, @repository.changesets.count
198 assert_equal NUM_REV, @repository.changesets.count
170 extra_info_heads = @repository.extra_info["heads"].dup
199 extra_info_heads = @repository.extra_info["heads"].dup
171 assert_equal NUM_HEAD, extra_info_heads.size
200 assert_equal NUM_HEAD, extra_info_heads.size
172 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
201 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
173 assert_equal 4, extra_info_heads.size
202 assert_equal 4, extra_info_heads.size
174
203
175 del_revs = [
204 del_revs = [
176 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
205 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
177 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
206 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
178 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
207 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
179 "deff712f05a90d96edbd70facc47d944be5897e3",
208 "deff712f05a90d96edbd70facc47d944be5897e3",
180 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
209 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
181 "7e61ac704deecde634b51e59daa8110435dcb3da",
210 "7e61ac704deecde634b51e59daa8110435dcb3da",
182 ]
211 ]
183 @repository.changesets.each do |rev|
212 @repository.changesets.each do |rev|
184 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
213 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
185 end
214 end
186 @project.reload
215 @project.reload
187 assert_equal NUM_REV - 6, @repository.changesets.count
216 assert_equal NUM_REV - 6, @repository.changesets.count
188
217
189 c = Changeset.new(:repository => @repository,
218 c = Changeset.new(:repository => @repository,
190 :committed_on => Time.now,
219 :committed_on => Time.now,
191 :revision => "abcd1234efgh",
220 :revision => "abcd1234efgh",
192 :scmid => "abcd1234efgh",
221 :scmid => "abcd1234efgh",
193 :comments => 'test')
222 :comments => 'test')
194 assert c.save
223 assert c.save
195 @project.reload
224 @project.reload
196 assert_equal NUM_REV - 5, @repository.changesets.count
225 assert_equal NUM_REV - 5, @repository.changesets.count
197
226
198 extra_info_heads << "1234abcd5678"
227 extra_info_heads << "1234abcd5678"
199 h = {}
228 h = {}
200 h["heads"] = extra_info_heads
229 h["heads"] = extra_info_heads
201 @repository.merge_extra_info(h)
230 @repository.merge_extra_info(h)
202 @repository.save
231 @repository.save
203 @project.reload
232 @project.reload
204 h1 = @repository.extra_info["heads"].dup
233 h1 = @repository.extra_info["heads"].dup
205 assert h1.index("1234abcd5678")
234 assert h1.index("1234abcd5678")
206 assert_equal 5, h1.size
235 assert_equal 5, h1.size
207
236
208 @repository.fetch_changesets
237 @repository.fetch_changesets
209 @project.reload
238 @project.reload
210 assert_equal NUM_REV - 5, @repository.changesets.count
239 assert_equal NUM_REV - 5, @repository.changesets.count
211 h2 = @repository.extra_info["heads"].dup
240 h2 = @repository.extra_info["heads"].dup
212 assert_equal h1, h2
241 assert_equal h1, h2
213 end
242 end
214
243
215 def test_keep_extra_report_last_commit_in_clear_changesets
244 def test_keep_extra_report_last_commit_in_clear_changesets
216 assert_nil @repository.extra_info
245 assert_nil @repository.extra_info
217 h = {}
246 h = {}
218 h["extra_report_last_commit"] = "1"
247 h["extra_report_last_commit"] = "1"
219 @repository.merge_extra_info(h)
248 @repository.merge_extra_info(h)
220 @repository.save
249 @repository.save
221 @project.reload
250 @project.reload
222
251
223 assert_equal 0, @repository.changesets.count
252 assert_equal 0, @repository.changesets.count
224 @repository.fetch_changesets
253 @repository.fetch_changesets
225 @project.reload
254 @project.reload
226
255
227 assert_equal NUM_REV, @repository.changesets.count
256 assert_equal NUM_REV, @repository.changesets.count
228 @repository.send(:clear_changesets)
257 @repository.send(:clear_changesets)
229 assert_equal 1, @repository.extra_info.size
258 assert_equal 1, @repository.extra_info.size
230 assert_equal "1", @repository.extra_info["extra_report_last_commit"]
259 assert_equal "1", @repository.extra_info["extra_report_last_commit"]
231 end
260 end
232
261
233 def test_refetch_after_clear_changesets
262 def test_refetch_after_clear_changesets
234 assert_nil @repository.extra_info
263 assert_nil @repository.extra_info
235 assert_equal 0, @repository.changesets.count
264 assert_equal 0, @repository.changesets.count
236 @repository.fetch_changesets
265 @repository.fetch_changesets
237 @project.reload
266 @project.reload
238 assert_equal NUM_REV, @repository.changesets.count
267 assert_equal NUM_REV, @repository.changesets.count
239
268
240 @repository.send(:clear_changesets)
269 @repository.send(:clear_changesets)
241 @project.reload
270 @project.reload
242 assert_equal 0, @repository.changesets.count
271 assert_equal 0, @repository.changesets.count
243
272
244 @repository.fetch_changesets
273 @repository.fetch_changesets
245 @project.reload
274 @project.reload
246 assert_equal NUM_REV, @repository.changesets.count
275 assert_equal NUM_REV, @repository.changesets.count
247 end
276 end
248
277
249 def test_parents
278 def test_parents
250 assert_equal 0, @repository.changesets.count
279 assert_equal 0, @repository.changesets.count
251 @repository.fetch_changesets
280 @repository.fetch_changesets
252 @project.reload
281 @project.reload
253 assert_equal NUM_REV, @repository.changesets.count
282 assert_equal NUM_REV, @repository.changesets.count
254 r1 = @repository.find_changeset_by_name("7234cb2750b63")
283 r1 = @repository.find_changeset_by_name("7234cb2750b63")
255 assert_equal [], r1.parents
284 assert_equal [], r1.parents
256 r2 = @repository.find_changeset_by_name("899a15dba03a3")
285 r2 = @repository.find_changeset_by_name("899a15dba03a3")
257 assert_equal 1, r2.parents.length
286 assert_equal 1, r2.parents.length
258 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518",
287 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518",
259 r2.parents[0].identifier
288 r2.parents[0].identifier
260 r3 = @repository.find_changeset_by_name("32ae898b720c2")
289 r3 = @repository.find_changeset_by_name("32ae898b720c2")
261 assert_equal 2, r3.parents.length
290 assert_equal 2, r3.parents.length
262 r4 = [r3.parents[0].identifier, r3.parents[1].identifier].sort
291 r4 = [r3.parents[0].identifier, r3.parents[1].identifier].sort
263 assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", r4[0]
292 assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", r4[0]
264 assert_equal "7e61ac704deecde634b51e59daa8110435dcb3da", r4[1]
293 assert_equal "7e61ac704deecde634b51e59daa8110435dcb3da", r4[1]
265 end
294 end
266
295
267 def test_db_consistent_ordering_init
296 def test_db_consistent_ordering_init
268 assert_nil @repository.extra_info
297 assert_nil @repository.extra_info
269 assert_equal 0, @repository.changesets.count
298 assert_equal 0, @repository.changesets.count
270 @repository.fetch_changesets
299 @repository.fetch_changesets
271 @project.reload
300 @project.reload
272 assert_equal 1, @repository.extra_info["db_consistent"]["ordering"]
301 assert_equal 1, @repository.extra_info["db_consistent"]["ordering"]
273 end
302 end
274
303
275 def test_db_consistent_ordering_before_1_2
304 def test_db_consistent_ordering_before_1_2
276 assert_nil @repository.extra_info
305 assert_nil @repository.extra_info
277 assert_equal 0, @repository.changesets.count
306 assert_equal 0, @repository.changesets.count
278 @repository.fetch_changesets
307 @repository.fetch_changesets
279 @project.reload
308 @project.reload
280 assert_equal NUM_REV, @repository.changesets.count
309 assert_equal NUM_REV, @repository.changesets.count
281 assert_not_nil @repository.extra_info
310 assert_not_nil @repository.extra_info
282 h = {}
311 h = {}
283 h["heads"] = []
312 h["heads"] = []
284 h["branches"] = {}
313 h["branches"] = {}
285 h["db_consistent"] = {}
314 h["db_consistent"] = {}
286 @repository.merge_extra_info(h)
315 @repository.merge_extra_info(h)
287 @repository.save
316 @repository.save
288 assert_equal NUM_REV, @repository.changesets.count
317 assert_equal NUM_REV, @repository.changesets.count
289 @repository.fetch_changesets
318 @repository.fetch_changesets
290 @project.reload
319 @project.reload
291 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
320 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
292
321
293 extra_info_heads = @repository.extra_info["heads"].dup
322 extra_info_heads = @repository.extra_info["heads"].dup
294 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
323 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
295 del_revs = [
324 del_revs = [
296 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
325 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
297 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
326 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
298 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
327 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
299 "deff712f05a90d96edbd70facc47d944be5897e3",
328 "deff712f05a90d96edbd70facc47d944be5897e3",
300 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
329 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
301 "7e61ac704deecde634b51e59daa8110435dcb3da",
330 "7e61ac704deecde634b51e59daa8110435dcb3da",
302 ]
331 ]
303 @repository.changesets.each do |rev|
332 @repository.changesets.each do |rev|
304 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
333 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
305 end
334 end
306 @project.reload
335 @project.reload
307 cs1 = @repository.changesets
336 cs1 = @repository.changesets
308 assert_equal NUM_REV - 6, cs1.count
337 assert_equal NUM_REV - 6, cs1.count
309 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
338 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
310
339
311 extra_info_heads << "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8"
340 extra_info_heads << "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8"
312 h = {}
341 h = {}
313 h["heads"] = extra_info_heads
342 h["heads"] = extra_info_heads
314 @repository.merge_extra_info(h)
343 @repository.merge_extra_info(h)
315 @repository.save
344 @repository.save
316 @project.reload
345 @project.reload
317 assert @repository.extra_info["heads"].index("4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8")
346 assert @repository.extra_info["heads"].index("4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8")
318 @repository.fetch_changesets
347 @repository.fetch_changesets
319 @project.reload
348 @project.reload
320 assert_equal NUM_REV, @repository.changesets.count
349 assert_equal NUM_REV, @repository.changesets.count
321 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
350 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
322
351
323 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
352 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
324 end
353 end
325
354
326 def test_heads_from_branches_hash
355 def test_heads_from_branches_hash
327 assert_nil @repository.extra_info
356 assert_nil @repository.extra_info
328 assert_equal 0, @repository.changesets.count
357 assert_equal 0, @repository.changesets.count
329 assert_equal [], @repository.heads_from_branches_hash
358 assert_equal [], @repository.heads_from_branches_hash
330 h = {}
359 h = {}
331 h["branches"] = {}
360 h["branches"] = {}
332 h["branches"]["test1"] = {}
361 h["branches"]["test1"] = {}
333 h["branches"]["test1"]["last_scmid"] = "1234abcd"
362 h["branches"]["test1"]["last_scmid"] = "1234abcd"
334 h["branches"]["test2"] = {}
363 h["branches"]["test2"] = {}
335 h["branches"]["test2"]["last_scmid"] = "abcd1234"
364 h["branches"]["test2"]["last_scmid"] = "abcd1234"
336 @repository.merge_extra_info(h)
365 @repository.merge_extra_info(h)
337 @repository.save
366 @repository.save
338 @project.reload
367 @project.reload
339 assert_equal ["1234abcd", "abcd1234"], @repository.heads_from_branches_hash.sort
368 assert_equal ["1234abcd", "abcd1234"], @repository.heads_from_branches_hash.sort
340 end
369 end
341
370
342 def test_latest_changesets
371 def test_latest_changesets
343 assert_equal 0, @repository.changesets.count
372 assert_equal 0, @repository.changesets.count
344 @repository.fetch_changesets
373 @repository.fetch_changesets
345 @project.reload
374 @project.reload
346 assert_equal NUM_REV, @repository.changesets.count
375 assert_equal NUM_REV, @repository.changesets.count
347 # with limit
376 # with limit
348 changesets = @repository.latest_changesets('', 'master', 2)
377 changesets = @repository.latest_changesets('', 'master', 2)
349 assert_equal 2, changesets.size
378 assert_equal 2, changesets.size
350
379
351 # with path
380 # with path
352 changesets = @repository.latest_changesets('images', 'master')
381 changesets = @repository.latest_changesets('images', 'master')
353 assert_equal [
382 assert_equal [
354 'deff712f05a90d96edbd70facc47d944be5897e3',
383 'deff712f05a90d96edbd70facc47d944be5897e3',
355 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
384 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
356 '7234cb2750b63f47bff735edc50a1c0a433c2518',
385 '7234cb2750b63f47bff735edc50a1c0a433c2518',
357 ], changesets.collect(&:revision)
386 ], changesets.collect(&:revision)
358
387
359 changesets = @repository.latest_changesets('README', nil)
388 changesets = @repository.latest_changesets('README', nil)
360 assert_equal [
389 assert_equal [
361 '32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf',
390 '32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf',
362 '4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8',
391 '4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8',
363 '713f4944648826f558cf548222f813dabe7cbb04',
392 '713f4944648826f558cf548222f813dabe7cbb04',
364 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
393 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
365 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
394 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
366 '7234cb2750b63f47bff735edc50a1c0a433c2518',
395 '7234cb2750b63f47bff735edc50a1c0a433c2518',
367 ], changesets.collect(&:revision)
396 ], changesets.collect(&:revision)
368
397
369 # with path, revision and limit
398 # with path, revision and limit
370 changesets = @repository.latest_changesets('images', '899a15dba')
399 changesets = @repository.latest_changesets('images', '899a15dba')
371 assert_equal [
400 assert_equal [
372 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
401 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
373 '7234cb2750b63f47bff735edc50a1c0a433c2518',
402 '7234cb2750b63f47bff735edc50a1c0a433c2518',
374 ], changesets.collect(&:revision)
403 ], changesets.collect(&:revision)
375
404
376 changesets = @repository.latest_changesets('images', '899a15dba', 1)
405 changesets = @repository.latest_changesets('images', '899a15dba', 1)
377 assert_equal [
406 assert_equal [
378 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
407 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
379 ], changesets.collect(&:revision)
408 ], changesets.collect(&:revision)
380
409
381 changesets = @repository.latest_changesets('README', '899a15dba')
410 changesets = @repository.latest_changesets('README', '899a15dba')
382 assert_equal [
411 assert_equal [
383 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
412 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
384 '7234cb2750b63f47bff735edc50a1c0a433c2518',
413 '7234cb2750b63f47bff735edc50a1c0a433c2518',
385 ], changesets.collect(&:revision)
414 ], changesets.collect(&:revision)
386
415
387 changesets = @repository.latest_changesets('README', '899a15dba', 1)
416 changesets = @repository.latest_changesets('README', '899a15dba', 1)
388 assert_equal [
417 assert_equal [
389 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
418 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
390 ], changesets.collect(&:revision)
419 ], changesets.collect(&:revision)
391
420
392 # with path, tag and limit
421 # with path, tag and limit
393 changesets = @repository.latest_changesets('images', 'tag01.annotated')
422 changesets = @repository.latest_changesets('images', 'tag01.annotated')
394 assert_equal [
423 assert_equal [
395 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
424 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
396 '7234cb2750b63f47bff735edc50a1c0a433c2518',
425 '7234cb2750b63f47bff735edc50a1c0a433c2518',
397 ], changesets.collect(&:revision)
426 ], changesets.collect(&:revision)
398
427
399 changesets = @repository.latest_changesets('images', 'tag01.annotated', 1)
428 changesets = @repository.latest_changesets('images', 'tag01.annotated', 1)
400 assert_equal [
429 assert_equal [
401 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
430 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
402 ], changesets.collect(&:revision)
431 ], changesets.collect(&:revision)
403
432
404 changesets = @repository.latest_changesets('README', 'tag01.annotated')
433 changesets = @repository.latest_changesets('README', 'tag01.annotated')
405 assert_equal [
434 assert_equal [
406 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
435 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
407 '7234cb2750b63f47bff735edc50a1c0a433c2518',
436 '7234cb2750b63f47bff735edc50a1c0a433c2518',
408 ], changesets.collect(&:revision)
437 ], changesets.collect(&:revision)
409
438
410 changesets = @repository.latest_changesets('README', 'tag01.annotated', 1)
439 changesets = @repository.latest_changesets('README', 'tag01.annotated', 1)
411 assert_equal [
440 assert_equal [
412 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
441 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
413 ], changesets.collect(&:revision)
442 ], changesets.collect(&:revision)
414
443
415 # with path, branch and limit
444 # with path, branch and limit
416 changesets = @repository.latest_changesets('images', 'test_branch')
445 changesets = @repository.latest_changesets('images', 'test_branch')
417 assert_equal [
446 assert_equal [
418 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
447 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
419 '7234cb2750b63f47bff735edc50a1c0a433c2518',
448 '7234cb2750b63f47bff735edc50a1c0a433c2518',
420 ], changesets.collect(&:revision)
449 ], changesets.collect(&:revision)
421
450
422 changesets = @repository.latest_changesets('images', 'test_branch', 1)
451 changesets = @repository.latest_changesets('images', 'test_branch', 1)
423 assert_equal [
452 assert_equal [
424 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
453 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
425 ], changesets.collect(&:revision)
454 ], changesets.collect(&:revision)
426
455
427 changesets = @repository.latest_changesets('README', 'test_branch')
456 changesets = @repository.latest_changesets('README', 'test_branch')
428 assert_equal [
457 assert_equal [
429 '713f4944648826f558cf548222f813dabe7cbb04',
458 '713f4944648826f558cf548222f813dabe7cbb04',
430 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
459 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
431 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
460 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
432 '7234cb2750b63f47bff735edc50a1c0a433c2518',
461 '7234cb2750b63f47bff735edc50a1c0a433c2518',
433 ], changesets.collect(&:revision)
462 ], changesets.collect(&:revision)
434
463
435 changesets = @repository.latest_changesets('README', 'test_branch', 2)
464 changesets = @repository.latest_changesets('README', 'test_branch', 2)
436 assert_equal [
465 assert_equal [
437 '713f4944648826f558cf548222f813dabe7cbb04',
466 '713f4944648826f558cf548222f813dabe7cbb04',
438 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
467 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
439 ], changesets.collect(&:revision)
468 ], changesets.collect(&:revision)
440
469
441 if WINDOWS_PASS
470 if WINDOWS_PASS
442 puts WINDOWS_SKIP_STR
471 puts WINDOWS_SKIP_STR
443 elsif JRUBY_SKIP
472 elsif JRUBY_SKIP
444 puts JRUBY_SKIP_STR
473 puts JRUBY_SKIP_STR
445 else
474 else
446 # latin-1 encoding path
475 # latin-1 encoding path
447 changesets = @repository.latest_changesets(
476 changesets = @repository.latest_changesets(
448 "latin-1-dir/test-#{CHAR_1_HEX}-2.txt", '64f1f3e89')
477 "latin-1-dir/test-#{CHAR_1_HEX}-2.txt", '64f1f3e89')
449 assert_equal [
478 assert_equal [
450 '64f1f3e89ad1cb57976ff0ad99a107012ba3481d',
479 '64f1f3e89ad1cb57976ff0ad99a107012ba3481d',
451 '4fc55c43bf3d3dc2efb66145365ddc17639ce81e',
480 '4fc55c43bf3d3dc2efb66145365ddc17639ce81e',
452 ], changesets.collect(&:revision)
481 ], changesets.collect(&:revision)
453
482
454 changesets = @repository.latest_changesets(
483 changesets = @repository.latest_changesets(
455 "latin-1-dir/test-#{CHAR_1_HEX}-2.txt", '64f1f3e89', 1)
484 "latin-1-dir/test-#{CHAR_1_HEX}-2.txt", '64f1f3e89', 1)
456 assert_equal [
485 assert_equal [
457 '64f1f3e89ad1cb57976ff0ad99a107012ba3481d',
486 '64f1f3e89ad1cb57976ff0ad99a107012ba3481d',
458 ], changesets.collect(&:revision)
487 ], changesets.collect(&:revision)
459 end
488 end
460 end
489 end
461
490
462 def test_latest_changesets_latin_1_dir
491 def test_latest_changesets_latin_1_dir
463 if WINDOWS_PASS
492 if WINDOWS_PASS
464 puts WINDOWS_SKIP_STR
493 puts WINDOWS_SKIP_STR
465 elsif JRUBY_SKIP
494 elsif JRUBY_SKIP
466 puts JRUBY_SKIP_STR
495 puts JRUBY_SKIP_STR
467 else
496 else
468 assert_equal 0, @repository.changesets.count
497 assert_equal 0, @repository.changesets.count
469 @repository.fetch_changesets
498 @repository.fetch_changesets
470 @project.reload
499 @project.reload
471 assert_equal NUM_REV, @repository.changesets.count
500 assert_equal NUM_REV, @repository.changesets.count
472 changesets = @repository.latest_changesets(
501 changesets = @repository.latest_changesets(
473 "latin-1-dir/test-#{CHAR_1_HEX}-subdir", '1ca7f5ed')
502 "latin-1-dir/test-#{CHAR_1_HEX}-subdir", '1ca7f5ed')
474 assert_equal [
503 assert_equal [
475 '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127',
504 '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127',
476 ], changesets.collect(&:revision)
505 ], changesets.collect(&:revision)
477 end
506 end
478 end
507 end
479
508
480 def test_find_changeset_by_name
509 def test_find_changeset_by_name
481 assert_equal 0, @repository.changesets.count
510 assert_equal 0, @repository.changesets.count
482 @repository.fetch_changesets
511 @repository.fetch_changesets
483 @project.reload
512 @project.reload
484 assert_equal NUM_REV, @repository.changesets.count
513 assert_equal NUM_REV, @repository.changesets.count
485 ['7234cb2750b63f47bff735edc50a1c0a433c2518', '7234cb2750b'].each do |r|
514 ['7234cb2750b63f47bff735edc50a1c0a433c2518', '7234cb2750b'].each do |r|
486 assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518',
515 assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518',
487 @repository.find_changeset_by_name(r).revision
516 @repository.find_changeset_by_name(r).revision
488 end
517 end
489 end
518 end
490
519
491 def test_find_changeset_by_empty_name
520 def test_find_changeset_by_empty_name
492 assert_equal 0, @repository.changesets.count
521 assert_equal 0, @repository.changesets.count
493 @repository.fetch_changesets
522 @repository.fetch_changesets
494 @project.reload
523 @project.reload
495 assert_equal NUM_REV, @repository.changesets.count
524 assert_equal NUM_REV, @repository.changesets.count
496 ['', ' ', nil].each do |r|
525 ['', ' ', nil].each do |r|
497 assert_nil @repository.find_changeset_by_name(r)
526 assert_nil @repository.find_changeset_by_name(r)
498 end
527 end
499 end
528 end
500
529
501 def test_identifier
530 def test_identifier
502 assert_equal 0, @repository.changesets.count
531 assert_equal 0, @repository.changesets.count
503 @repository.fetch_changesets
532 @repository.fetch_changesets
504 @project.reload
533 @project.reload
505 assert_equal NUM_REV, @repository.changesets.count
534 assert_equal NUM_REV, @repository.changesets.count
506 c = @repository.changesets.find_by_revision(
535 c = @repository.changesets.find_by_revision(
507 '7234cb2750b63f47bff735edc50a1c0a433c2518')
536 '7234cb2750b63f47bff735edc50a1c0a433c2518')
508 assert_equal c.scmid, c.identifier
537 assert_equal c.scmid, c.identifier
509 end
538 end
510
539
511 def test_format_identifier
540 def test_format_identifier
512 assert_equal 0, @repository.changesets.count
541 assert_equal 0, @repository.changesets.count
513 @repository.fetch_changesets
542 @repository.fetch_changesets
514 @project.reload
543 @project.reload
515 assert_equal NUM_REV, @repository.changesets.count
544 assert_equal NUM_REV, @repository.changesets.count
516 c = @repository.changesets.find_by_revision(
545 c = @repository.changesets.find_by_revision(
517 '7234cb2750b63f47bff735edc50a1c0a433c2518')
546 '7234cb2750b63f47bff735edc50a1c0a433c2518')
518 assert_equal '7234cb27', c.format_identifier
547 assert_equal '7234cb27', c.format_identifier
519 end
548 end
520
549
521 def test_activities
550 def test_activities
522 c = Changeset.new(:repository => @repository,
551 c = Changeset.new(:repository => @repository,
523 :committed_on => Time.now,
552 :committed_on => Time.now,
524 :revision => 'abc7234cb2750b63f47bff735edc50a1c0a433c2',
553 :revision => 'abc7234cb2750b63f47bff735edc50a1c0a433c2',
525 :scmid => 'abc7234cb2750b63f47bff735edc50a1c0a433c2',
554 :scmid => 'abc7234cb2750b63f47bff735edc50a1c0a433c2',
526 :comments => 'test')
555 :comments => 'test')
527 assert c.event_title.include?('abc7234c:')
556 assert c.event_title.include?('abc7234c:')
528 assert_equal 'abc7234cb2750b63f47bff735edc50a1c0a433c2', c.event_url[:rev]
557 assert_equal 'abc7234cb2750b63f47bff735edc50a1c0a433c2', c.event_url[:rev]
529 end
558 end
530
559
531 def test_log_utf8
560 def test_log_utf8
532 assert_equal 0, @repository.changesets.count
561 assert_equal 0, @repository.changesets.count
533 @repository.fetch_changesets
562 @repository.fetch_changesets
534 @project.reload
563 @project.reload
535 assert_equal NUM_REV, @repository.changesets.count
564 assert_equal NUM_REV, @repository.changesets.count
536 c = @repository.changesets.find_by_revision(
565 c = @repository.changesets.find_by_revision(
537 'ed5bb786bbda2dee66a2d50faf51429dbc043a7b')
566 'ed5bb786bbda2dee66a2d50faf51429dbc043a7b')
538 assert_equal "#{FELIX_HEX} <felix@fachschaften.org>", c.committer
567 assert_equal "#{FELIX_HEX} <felix@fachschaften.org>", c.committer
539 end
568 end
540
569
541 def test_previous
570 def test_previous
542 assert_equal 0, @repository.changesets.count
571 assert_equal 0, @repository.changesets.count
543 @repository.fetch_changesets
572 @repository.fetch_changesets
544 @project.reload
573 @project.reload
545 assert_equal NUM_REV, @repository.changesets.count
574 assert_equal NUM_REV, @repository.changesets.count
546 %w|1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127 1ca7f5ed|.each do |r1|
575 %w|1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127 1ca7f5ed|.each do |r1|
547 changeset = @repository.find_changeset_by_name(r1)
576 changeset = @repository.find_changeset_by_name(r1)
548 %w|64f1f3e89ad1cb57976ff0ad99a107012ba3481d 64f1f3e89ad1|.each do |r2|
577 %w|64f1f3e89ad1cb57976ff0ad99a107012ba3481d 64f1f3e89ad1|.each do |r2|
549 assert_equal @repository.find_changeset_by_name(r2), changeset.previous
578 assert_equal @repository.find_changeset_by_name(r2), changeset.previous
550 end
579 end
551 end
580 end
552 end
581 end
553
582
554 def test_previous_nil
583 def test_previous_nil
555 assert_equal 0, @repository.changesets.count
584 assert_equal 0, @repository.changesets.count
556 @repository.fetch_changesets
585 @repository.fetch_changesets
557 @project.reload
586 @project.reload
558 assert_equal NUM_REV, @repository.changesets.count
587 assert_equal NUM_REV, @repository.changesets.count
559 %w|7234cb2750b63f47bff735edc50a1c0a433c2518 7234cb275|.each do |r1|
588 %w|7234cb2750b63f47bff735edc50a1c0a433c2518 7234cb275|.each do |r1|
560 changeset = @repository.find_changeset_by_name(r1)
589 changeset = @repository.find_changeset_by_name(r1)
561 assert_nil changeset.previous
590 assert_nil changeset.previous
562 end
591 end
563 end
592 end
564
593
565 def test_next
594 def test_next
566 assert_equal 0, @repository.changesets.count
595 assert_equal 0, @repository.changesets.count
567 @repository.fetch_changesets
596 @repository.fetch_changesets
568 @project.reload
597 @project.reload
569 assert_equal NUM_REV, @repository.changesets.count
598 assert_equal NUM_REV, @repository.changesets.count
570 %w|64f1f3e89ad1cb57976ff0ad99a107012ba3481d 64f1f3e89ad1|.each do |r2|
599 %w|64f1f3e89ad1cb57976ff0ad99a107012ba3481d 64f1f3e89ad1|.each do |r2|
571 changeset = @repository.find_changeset_by_name(r2)
600 changeset = @repository.find_changeset_by_name(r2)
572 %w|1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127 1ca7f5ed|.each do |r1|
601 %w|1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127 1ca7f5ed|.each do |r1|
573 assert_equal @repository.find_changeset_by_name(r1), changeset.next
602 assert_equal @repository.find_changeset_by_name(r1), changeset.next
574 end
603 end
575 end
604 end
576 end
605 end
577
606
578 def test_next_nil
607 def test_next_nil
579 assert_equal 0, @repository.changesets.count
608 assert_equal 0, @repository.changesets.count
580 @repository.fetch_changesets
609 @repository.fetch_changesets
581 @project.reload
610 @project.reload
582 assert_equal NUM_REV, @repository.changesets.count
611 assert_equal NUM_REV, @repository.changesets.count
583 %w|2a682156a3b6e77a8bf9cd4590e8db757f3c6c78 2a682156a3b6e77a|.each do |r1|
612 %w|2a682156a3b6e77a8bf9cd4590e8db757f3c6c78 2a682156a3b6e77a|.each do |r1|
584 changeset = @repository.find_changeset_by_name(r1)
613 changeset = @repository.find_changeset_by_name(r1)
585 assert_nil changeset.next
614 assert_nil changeset.next
586 end
615 end
587 end
616 end
588 else
617 else
589 puts "Git test repository NOT FOUND. Skipping unit tests !!!"
618 puts "Git test repository NOT FOUND. Skipping unit tests !!!"
590 def test_fake; assert true end
619 def test_fake; assert true end
591 end
620 end
592 end
621 end
General Comments 0
You need to be logged in to leave comments. Login now