##// END OF EJS Templates
Merged r12848 (#16032)....
Jean-Philippe Lang -
r12578:287bcacd81d9
parent child
Show More
@@ -1,437 +1,443
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2013 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class ScmFetchError < Exception; end
19 19
20 20 class Repository < ActiveRecord::Base
21 21 include Redmine::Ciphering
22 22 include Redmine::SafeAttributes
23 23
24 24 # Maximum length for repository identifiers
25 25 IDENTIFIER_MAX_LENGTH = 255
26 26
27 27 belongs_to :project
28 28 has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC"
29 29 has_many :filechanges, :class_name => 'Change', :through => :changesets
30 30
31 31 serialize :extra_info
32 32
33 33 before_save :check_default
34 34
35 35 # Raw SQL to delete changesets and changes in the database
36 36 # has_many :changesets, :dependent => :destroy is too slow for big repositories
37 37 before_destroy :clear_changesets
38 38
39 39 validates_length_of :password, :maximum => 255, :allow_nil => true
40 40 validates_length_of :identifier, :maximum => IDENTIFIER_MAX_LENGTH, :allow_blank => true
41 41 validates_presence_of :identifier, :unless => Proc.new { |r| r.is_default? || r.set_as_default? }
42 42 validates_uniqueness_of :identifier, :scope => :project_id, :allow_blank => true
43 43 validates_exclusion_of :identifier, :in => %w(show entry raw changes annotate diff show stats graph)
44 44 # donwcase letters, digits, dashes, underscores but not digits only
45 45 validates_format_of :identifier, :with => /\A(?!\d+$)[a-z0-9\-_]*\z/, :allow_blank => true
46 46 # Checks if the SCM is enabled when creating a repository
47 47 validate :repo_create_validation, :on => :create
48 48
49 49 safe_attributes 'identifier',
50 50 'login',
51 51 'password',
52 52 'path_encoding',
53 53 'log_encoding',
54 54 'is_default'
55 55
56 56 safe_attributes 'url',
57 57 :if => lambda {|repository, user| repository.new_record?}
58 58
59 59 def repo_create_validation
60 60 unless Setting.enabled_scm.include?(self.class.name.demodulize)
61 61 errors.add(:type, :invalid)
62 62 end
63 63 end
64 64
65 65 def self.human_attribute_name(attribute_key_name, *args)
66 66 attr_name = attribute_key_name.to_s
67 67 if attr_name == "log_encoding"
68 68 attr_name = "commit_logs_encoding"
69 69 end
70 70 super(attr_name, *args)
71 71 end
72 72
73 73 # Removes leading and trailing whitespace
74 74 def url=(arg)
75 75 write_attribute(:url, arg ? arg.to_s.strip : nil)
76 76 end
77 77
78 78 # Removes leading and trailing whitespace
79 79 def root_url=(arg)
80 80 write_attribute(:root_url, arg ? arg.to_s.strip : nil)
81 81 end
82 82
83 83 def password
84 84 read_ciphered_attribute(:password)
85 85 end
86 86
87 87 def password=(arg)
88 88 write_ciphered_attribute(:password, arg)
89 89 end
90 90
91 91 def scm_adapter
92 92 self.class.scm_adapter_class
93 93 end
94 94
95 95 def scm
96 96 unless @scm
97 97 @scm = self.scm_adapter.new(url, root_url,
98 98 login, password, path_encoding)
99 99 if root_url.blank? && @scm.root_url.present?
100 100 update_attribute(:root_url, @scm.root_url)
101 101 end
102 102 end
103 103 @scm
104 104 end
105 105
106 106 def scm_name
107 107 self.class.scm_name
108 108 end
109 109
110 110 def name
111 111 if identifier.present?
112 112 identifier
113 113 elsif is_default?
114 114 l(:field_repository_is_default)
115 115 else
116 116 scm_name
117 117 end
118 118 end
119 119
120 120 def identifier=(identifier)
121 121 super unless identifier_frozen?
122 122 end
123 123
124 124 def identifier_frozen?
125 125 errors[:identifier].blank? && !(new_record? || identifier.blank?)
126 126 end
127 127
128 128 def identifier_param
129 129 if is_default?
130 130 nil
131 131 elsif identifier.present?
132 132 identifier
133 133 else
134 134 id.to_s
135 135 end
136 136 end
137 137
138 138 def <=>(repository)
139 139 if is_default?
140 140 -1
141 141 elsif repository.is_default?
142 142 1
143 143 else
144 144 identifier.to_s <=> repository.identifier.to_s
145 145 end
146 146 end
147 147
148 148 def self.find_by_identifier_param(param)
149 149 if param.to_s =~ /^\d+$/
150 150 find_by_id(param)
151 151 else
152 152 find_by_identifier(param)
153 153 end
154 154 end
155 155
156 # TODO: should return an empty hash instead of nil to avoid many ||{}
157 def extra_info
158 h = read_attribute(:extra_info)
159 h.is_a?(Hash) ? h : nil
160 end
161
156 162 def merge_extra_info(arg)
157 163 h = extra_info || {}
158 164 return h if arg.nil?
159 165 h.merge!(arg)
160 166 write_attribute(:extra_info, h)
161 167 end
162 168
163 169 def report_last_commit
164 170 true
165 171 end
166 172
167 173 def supports_cat?
168 174 scm.supports_cat?
169 175 end
170 176
171 177 def supports_annotate?
172 178 scm.supports_annotate?
173 179 end
174 180
175 181 def supports_all_revisions?
176 182 true
177 183 end
178 184
179 185 def supports_directory_revisions?
180 186 false
181 187 end
182 188
183 189 def supports_revision_graph?
184 190 false
185 191 end
186 192
187 193 def entry(path=nil, identifier=nil)
188 194 scm.entry(path, identifier)
189 195 end
190 196
191 197 def entries(path=nil, identifier=nil)
192 198 entries = scm.entries(path, identifier)
193 199 load_entries_changesets(entries)
194 200 entries
195 201 end
196 202
197 203 def branches
198 204 scm.branches
199 205 end
200 206
201 207 def tags
202 208 scm.tags
203 209 end
204 210
205 211 def default_branch
206 212 nil
207 213 end
208 214
209 215 def properties(path, identifier=nil)
210 216 scm.properties(path, identifier)
211 217 end
212 218
213 219 def cat(path, identifier=nil)
214 220 scm.cat(path, identifier)
215 221 end
216 222
217 223 def diff(path, rev, rev_to)
218 224 scm.diff(path, rev, rev_to)
219 225 end
220 226
221 227 def diff_format_revisions(cs, cs_to, sep=':')
222 228 text = ""
223 229 text << cs_to.format_identifier + sep if cs_to
224 230 text << cs.format_identifier if cs
225 231 text
226 232 end
227 233
228 234 # Returns a path relative to the url of the repository
229 235 def relative_path(path)
230 236 path
231 237 end
232 238
233 239 # Finds and returns a revision with a number or the beginning of a hash
234 240 def find_changeset_by_name(name)
235 241 return nil if name.blank?
236 242 s = name.to_s
237 243 if s.match(/^\d*$/)
238 244 changesets.where("revision = ?", s).first
239 245 else
240 246 changesets.where("revision LIKE ?", s + '%').first
241 247 end
242 248 end
243 249
244 250 def latest_changeset
245 251 @latest_changeset ||= changesets.first
246 252 end
247 253
248 254 # Returns the latest changesets for +path+
249 255 # Default behaviour is to search in cached changesets
250 256 def latest_changesets(path, rev, limit=10)
251 257 if path.blank?
252 258 changesets.
253 259 reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
254 260 limit(limit).
255 261 preload(:user).
256 262 all
257 263 else
258 264 filechanges.
259 265 where("path = ?", path.with_leading_slash).
260 266 reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
261 267 limit(limit).
262 268 preload(:changeset => :user).
263 269 collect(&:changeset)
264 270 end
265 271 end
266 272
267 273 def scan_changesets_for_issue_ids
268 274 self.changesets.each(&:scan_comment_for_issue_ids)
269 275 end
270 276
271 277 # Returns an array of committers usernames and associated user_id
272 278 def committers
273 279 @committers ||= Changeset.connection.select_rows(
274 280 "SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}")
275 281 end
276 282
277 283 # Maps committers username to a user ids
278 284 def committer_ids=(h)
279 285 if h.is_a?(Hash)
280 286 committers.each do |committer, user_id|
281 287 new_user_id = h[committer]
282 288 if new_user_id && (new_user_id.to_i != user_id.to_i)
283 289 new_user_id = (new_user_id.to_i > 0 ? new_user_id.to_i : nil)
284 290 Changeset.update_all(
285 291 "user_id = #{ new_user_id.nil? ? 'NULL' : new_user_id }",
286 292 ["repository_id = ? AND committer = ?", id, committer])
287 293 end
288 294 end
289 295 @committers = nil
290 296 @found_committer_users = nil
291 297 true
292 298 else
293 299 false
294 300 end
295 301 end
296 302
297 303 # Returns the Redmine User corresponding to the given +committer+
298 304 # It will return nil if the committer is not yet mapped and if no User
299 305 # with the same username or email was found
300 306 def find_committer_user(committer)
301 307 unless committer.blank?
302 308 @found_committer_users ||= {}
303 309 return @found_committer_users[committer] if @found_committer_users.has_key?(committer)
304 310
305 311 user = nil
306 312 c = changesets.where(:committer => committer).includes(:user).first
307 313 if c && c.user
308 314 user = c.user
309 315 elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
310 316 username, email = $1.strip, $3
311 317 u = User.find_by_login(username)
312 318 u ||= User.find_by_mail(email) unless email.blank?
313 319 user = u
314 320 end
315 321 @found_committer_users[committer] = user
316 322 user
317 323 end
318 324 end
319 325
320 326 def repo_log_encoding
321 327 encoding = log_encoding.to_s.strip
322 328 encoding.blank? ? 'UTF-8' : encoding
323 329 end
324 330
325 331 # Fetches new changesets for all repositories of active projects
326 332 # Can be called periodically by an external script
327 333 # eg. ruby script/runner "Repository.fetch_changesets"
328 334 def self.fetch_changesets
329 335 Project.active.has_module(:repository).all.each do |project|
330 336 project.repositories.each do |repository|
331 337 begin
332 338 repository.fetch_changesets
333 339 rescue Redmine::Scm::Adapters::CommandFailed => e
334 340 logger.error "scm: error during fetching changesets: #{e.message}"
335 341 end
336 342 end
337 343 end
338 344 end
339 345
340 346 # scan changeset comments to find related and fixed issues for all repositories
341 347 def self.scan_changesets_for_issue_ids
342 348 all.each(&:scan_changesets_for_issue_ids)
343 349 end
344 350
345 351 def self.scm_name
346 352 'Abstract'
347 353 end
348 354
349 355 def self.available_scm
350 356 subclasses.collect {|klass| [klass.scm_name, klass.name]}
351 357 end
352 358
353 359 def self.factory(klass_name, *args)
354 360 klass = "Repository::#{klass_name}".constantize
355 361 klass.new(*args)
356 362 rescue
357 363 nil
358 364 end
359 365
360 366 def self.scm_adapter_class
361 367 nil
362 368 end
363 369
364 370 def self.scm_command
365 371 ret = ""
366 372 begin
367 373 ret = self.scm_adapter_class.client_command if self.scm_adapter_class
368 374 rescue Exception => e
369 375 logger.error "scm: error during get command: #{e.message}"
370 376 end
371 377 ret
372 378 end
373 379
374 380 def self.scm_version_string
375 381 ret = ""
376 382 begin
377 383 ret = self.scm_adapter_class.client_version_string if self.scm_adapter_class
378 384 rescue Exception => e
379 385 logger.error "scm: error during get version string: #{e.message}"
380 386 end
381 387 ret
382 388 end
383 389
384 390 def self.scm_available
385 391 ret = false
386 392 begin
387 393 ret = self.scm_adapter_class.client_available if self.scm_adapter_class
388 394 rescue Exception => e
389 395 logger.error "scm: error during get scm available: #{e.message}"
390 396 end
391 397 ret
392 398 end
393 399
394 400 def set_as_default?
395 401 new_record? && project && Repository.where(:project_id => project.id).empty?
396 402 end
397 403
398 404 protected
399 405
400 406 def check_default
401 407 if !is_default? && set_as_default?
402 408 self.is_default = true
403 409 end
404 410 if is_default? && is_default_changed?
405 411 Repository.update_all(["is_default = ?", false], ["project_id = ?", project_id])
406 412 end
407 413 end
408 414
409 415 def load_entries_changesets(entries)
410 416 if entries
411 417 entries.each do |entry|
412 418 if entry.lastrev && entry.lastrev.identifier
413 419 entry.changeset = find_changeset_by_name(entry.lastrev.identifier)
414 420 end
415 421 end
416 422 end
417 423 end
418 424
419 425 private
420 426
421 427 # Deletes repository data
422 428 def clear_changesets
423 429 cs = Changeset.table_name
424 430 ch = Change.table_name
425 431 ci = "#{table_name_prefix}changesets_issues#{table_name_suffix}"
426 432 cp = "#{table_name_prefix}changeset_parents#{table_name_suffix}"
427 433
428 434 connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
429 435 connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
430 436 connection.delete("DELETE FROM #{cp} WHERE #{cp}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
431 437 connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
432 438 clear_extra_info_of_changesets
433 439 end
434 440
435 441 def clear_extra_info_of_changesets
436 442 end
437 443 end
@@ -1,370 +1,376
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2013 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../test_helper', __FILE__)
19 19
20 20 class RepositoryTest < ActiveSupport::TestCase
21 21 fixtures :projects,
22 22 :trackers,
23 23 :projects_trackers,
24 24 :enabled_modules,
25 25 :repositories,
26 26 :issues,
27 27 :issue_statuses,
28 28 :issue_categories,
29 29 :changesets,
30 30 :changes,
31 31 :users,
32 32 :members,
33 33 :member_roles,
34 34 :roles,
35 35 :enumerations
36 36
37 37 include Redmine::I18n
38 38
39 39 def setup
40 40 @repository = Project.find(1).repository
41 41 end
42 42
43 43 def test_blank_log_encoding_error_message
44 44 set_language_if_valid 'en'
45 45 repo = Repository::Bazaar.new(
46 46 :project => Project.find(3),
47 47 :url => "/test",
48 48 :log_encoding => ''
49 49 )
50 50 assert !repo.save
51 51 assert_include "Commit messages encoding can't be blank",
52 52 repo.errors.full_messages
53 53 end
54 54
55 55 def test_blank_log_encoding_error_message_fr
56 56 set_language_if_valid 'fr'
57 57 str = "Encodage des messages de commit doit \xc3\xaatre renseign\xc3\xa9(e)"
58 58 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
59 59 repo = Repository::Bazaar.new(
60 60 :project => Project.find(3),
61 61 :url => "/test"
62 62 )
63 63 assert !repo.save
64 64 assert_include str, repo.errors.full_messages
65 65 end
66 66
67 67 def test_create
68 68 repository = Repository::Subversion.new(:project => Project.find(3))
69 69 assert !repository.save
70 70
71 71 repository.url = "svn://localhost"
72 72 assert repository.save
73 73 repository.reload
74 74
75 75 project = Project.find(3)
76 76 assert_equal repository, project.repository
77 77 end
78 78
79 79 def test_first_repository_should_be_set_as_default
80 80 repository1 = Repository::Subversion.new(
81 81 :project => Project.find(3),
82 82 :identifier => 'svn1',
83 83 :url => 'file:///svn1'
84 84 )
85 85 assert repository1.save
86 86 assert repository1.is_default?
87 87
88 88 repository2 = Repository::Subversion.new(
89 89 :project => Project.find(3),
90 90 :identifier => 'svn2',
91 91 :url => 'file:///svn2'
92 92 )
93 93 assert repository2.save
94 94 assert !repository2.is_default?
95 95
96 96 assert_equal repository1, Project.find(3).repository
97 97 assert_equal [repository1, repository2], Project.find(3).repositories.sort
98 98 end
99 99
100 100 def test_identifier_should_accept_letters_digits_dashes_and_underscores
101 101 r = Repository::Subversion.new(
102 102 :project_id => 3,
103 103 :identifier => 'svn-123_45',
104 104 :url => 'file:///svn'
105 105 )
106 106 assert r.save
107 107 end
108 108
109 109 def test_identifier_should_not_be_frozen_for_a_new_repository
110 110 assert_equal false, Repository.new.identifier_frozen?
111 111 end
112 112
113 113 def test_identifier_should_not_be_frozen_for_a_saved_repository_with_blank_identifier
114 114 Repository.update_all(["identifier = ''"], "id = 10")
115 115
116 116 assert_equal false, Repository.find(10).identifier_frozen?
117 117 end
118 118
119 119 def test_identifier_should_be_frozen_for_a_saved_repository_with_valid_identifier
120 120 Repository.update_all(["identifier = 'abc123'"], "id = 10")
121 121
122 122 assert_equal true, Repository.find(10).identifier_frozen?
123 123 end
124 124
125 125 def test_identifier_should_not_accept_change_if_frozen
126 126 r = Repository.new(:identifier => 'foo')
127 127 r.stubs(:identifier_frozen?).returns(true)
128 128
129 129 r.identifier = 'bar'
130 130 assert_equal 'foo', r.identifier
131 131 end
132 132
133 133 def test_identifier_should_accept_change_if_not_frozen
134 134 r = Repository.new(:identifier => 'foo')
135 135 r.stubs(:identifier_frozen?).returns(false)
136 136
137 137 r.identifier = 'bar'
138 138 assert_equal 'bar', r.identifier
139 139 end
140 140
141 141 def test_destroy
142 142 repository = Repository.find(10)
143 143 changesets = repository.changesets.count
144 144 changes = repository.filechanges.count
145 145
146 146 assert_difference 'Changeset.count', -changesets do
147 147 assert_difference 'Change.count', -changes do
148 148 Repository.find(10).destroy
149 149 end
150 150 end
151 151 end
152 152
153 153 def test_destroy_should_delete_parents_associations
154 154 changeset = Changeset.find(102)
155 155 changeset.parents = Changeset.find_all_by_id([100, 101])
156 156
157 157 assert_difference 'Changeset.connection.select_all("select * from changeset_parents").size', -2 do
158 158 Repository.find(10).destroy
159 159 end
160 160 end
161 161
162 162 def test_destroy_should_delete_issues_associations
163 163 changeset = Changeset.find(102)
164 164 changeset.issues = Issue.find_all_by_id([1, 2])
165 165
166 166 assert_difference 'Changeset.connection.select_all("select * from changesets_issues").size', -2 do
167 167 Repository.find(10).destroy
168 168 end
169 169 end
170 170
171 171 def test_should_not_create_with_disabled_scm
172 172 # disable Subversion
173 173 with_settings :enabled_scm => ['Darcs', 'Git'] do
174 174 repository = Repository::Subversion.new(
175 175 :project => Project.find(3), :url => "svn://localhost")
176 176 assert !repository.save
177 177 assert_include I18n.translate('activerecord.errors.messages.invalid'),
178 178 repository.errors[:type]
179 179 end
180 180 end
181 181
182 182 def test_scan_changesets_for_issue_ids
183 183 Setting.default_language = 'en'
184 184
185 185 Setting.commit_ref_keywords = 'refs , references, IssueID'
186 186 Setting.commit_update_keywords = [
187 187 {'keywords' => 'fixes , closes', 'status_id' => IssueStatus.where(:is_closed => true).first.id, 'done_ratio' => '90'}
188 188 ]
189 189 Setting.default_language = 'en'
190 190 ActionMailer::Base.deliveries.clear
191 191
192 192 # make sure issue 1 is not already closed
193 193 fixed_issue = Issue.find(1)
194 194 assert !fixed_issue.status.is_closed?
195 195 old_status = fixed_issue.status
196 196
197 197 with_settings :notified_events => %w(issue_added issue_updated) do
198 198 Repository.scan_changesets_for_issue_ids
199 199 end
200 200 assert_equal [101, 102], Issue.find(3).changeset_ids
201 201
202 202 # fixed issues
203 203 fixed_issue.reload
204 204 assert fixed_issue.status.is_closed?
205 205 assert_equal 90, fixed_issue.done_ratio
206 206 assert_equal [101], fixed_issue.changeset_ids
207 207
208 208 # issue change
209 209 journal = fixed_issue.journals.reorder('created_on desc').first
210 210 assert_equal User.find_by_login('dlopper'), journal.user
211 211 assert_equal 'Applied in changeset r2.', journal.notes
212 212
213 213 # 2 email notifications
214 214 assert_equal 2, ActionMailer::Base.deliveries.size
215 215 mail = ActionMailer::Base.deliveries.first
216 216 assert_not_nil mail
217 217 assert mail.subject.starts_with?(
218 218 "[#{fixed_issue.project.name} - #{fixed_issue.tracker.name} ##{fixed_issue.id}]")
219 219 assert_mail_body_match(
220 220 "Status changed from #{old_status} to #{fixed_issue.status}", mail)
221 221
222 222 # ignoring commits referencing an issue of another project
223 223 assert_equal [], Issue.find(4).changesets
224 224 end
225 225
226 226 def test_for_changeset_comments_strip
227 227 repository = Repository::Mercurial.create(
228 228 :project => Project.find( 4 ),
229 229 :url => '/foo/bar/baz' )
230 230 comment = <<-COMMENT
231 231 This is a loooooooooooooooooooooooooooong comment
232 232
233 233
234 234 COMMENT
235 235 changeset = Changeset.new(
236 236 :comments => comment, :commit_date => Time.now,
237 237 :revision => 0, :scmid => 'f39b7922fb3c',
238 238 :committer => 'foo <foo@example.com>',
239 239 :committed_on => Time.now, :repository => repository )
240 240 assert( changeset.save )
241 241 assert_not_equal( comment, changeset.comments )
242 242 assert_equal( 'This is a loooooooooooooooooooooooooooong comment',
243 243 changeset.comments )
244 244 end
245 245
246 246 def test_for_urls_strip_cvs
247 247 repository = Repository::Cvs.create(
248 248 :project => Project.find(4),
249 249 :url => ' :pserver:login:password@host:/path/to/the/repository',
250 250 :root_url => 'foo ',
251 251 :log_encoding => 'UTF-8')
252 252 assert repository.save
253 253 repository.reload
254 254 assert_equal ':pserver:login:password@host:/path/to/the/repository',
255 255 repository.url
256 256 assert_equal 'foo', repository.root_url
257 257 end
258 258
259 259 def test_for_urls_strip_subversion
260 260 repository = Repository::Subversion.create(
261 261 :project => Project.find(4),
262 262 :url => ' file:///dummy ')
263 263 assert repository.save
264 264 repository.reload
265 265 assert_equal 'file:///dummy', repository.url
266 266 end
267 267
268 268 def test_for_urls_strip_git
269 269 repository = Repository::Git.create(
270 270 :project => Project.find(4),
271 271 :url => ' c:\dummy ')
272 272 assert repository.save
273 273 repository.reload
274 274 assert_equal 'c:\dummy', repository.url
275 275 end
276 276
277 277 def test_manual_user_mapping
278 278 assert_no_difference "Changeset.where('user_id <> 2').count" do
279 279 c = Changeset.create!(
280 280 :repository => @repository,
281 281 :committer => 'foo',
282 282 :committed_on => Time.now,
283 283 :revision => 100,
284 284 :comments => 'Committed by foo.'
285 285 )
286 286 assert_nil c.user
287 287 @repository.committer_ids = {'foo' => '2'}
288 288 assert_equal User.find(2), c.reload.user
289 289 # committer is now mapped
290 290 c = Changeset.create!(
291 291 :repository => @repository,
292 292 :committer => 'foo',
293 293 :committed_on => Time.now,
294 294 :revision => 101,
295 295 :comments => 'Another commit by foo.'
296 296 )
297 297 assert_equal User.find(2), c.user
298 298 end
299 299 end
300 300
301 301 def test_auto_user_mapping_by_username
302 302 c = Changeset.create!(
303 303 :repository => @repository,
304 304 :committer => 'jsmith',
305 305 :committed_on => Time.now,
306 306 :revision => 100,
307 307 :comments => 'Committed by john.'
308 308 )
309 309 assert_equal User.find(2), c.user
310 310 end
311 311
312 312 def test_auto_user_mapping_by_email
313 313 c = Changeset.create!(
314 314 :repository => @repository,
315 315 :committer => 'john <jsmith@somenet.foo>',
316 316 :committed_on => Time.now,
317 317 :revision => 100,
318 318 :comments => 'Committed by john.'
319 319 )
320 320 assert_equal User.find(2), c.user
321 321 end
322 322
323 323 def test_filesystem_avaialbe
324 324 klass = Repository::Filesystem
325 325 assert klass.scm_adapter_class
326 326 assert_equal true, klass.scm_available
327 327 end
328 328
329 def test_extra_info_should_not_return_non_hash_value
330 repo = Repository.new
331 repo.extra_info = "foo"
332 assert_nil repo.extra_info
333 end
334
329 335 def test_merge_extra_info
330 336 repo = Repository::Subversion.new(:project => Project.find(3))
331 337 assert !repo.save
332 338 repo.url = "svn://localhost"
333 339 assert repo.save
334 340 repo.reload
335 341 project = Project.find(3)
336 342 assert_equal repo, project.repository
337 343 assert_nil repo.extra_info
338 344 h1 = {"test_1" => {"test_11" => "test_value_11"}}
339 345 repo.merge_extra_info(h1)
340 346 assert_equal h1, repo.extra_info
341 347 h2 = {"test_2" => {
342 348 "test_21" => "test_value_21",
343 349 "test_22" => "test_value_22",
344 350 }}
345 351 repo.merge_extra_info(h2)
346 352 assert_equal (h = {"test_11" => "test_value_11"}),
347 353 repo.extra_info["test_1"]
348 354 assert_equal "test_value_21",
349 355 repo.extra_info["test_2"]["test_21"]
350 356 h3 = {"test_2" => {
351 357 "test_23" => "test_value_23",
352 358 "test_24" => "test_value_24",
353 359 }}
354 360 repo.merge_extra_info(h3)
355 361 assert_equal (h = {"test_11" => "test_value_11"}),
356 362 repo.extra_info["test_1"]
357 363 assert_nil repo.extra_info["test_2"]["test_21"]
358 364 assert_equal "test_value_23",
359 365 repo.extra_info["test_2"]["test_23"]
360 366 end
361 367
362 368 def test_sort_should_not_raise_an_error_with_nil_identifiers
363 369 r1 = Repository.new
364 370 r2 = Repository.new
365 371
366 372 assert_nothing_raised do
367 373 [r1, r2].sort
368 374 end
369 375 end
370 376 end
General Comments 0
You need to be logged in to leave comments. Login now