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