##// END OF EJS Templates
Make sure that Repository#extra_info returns a Hash or nil (#16032)....
Jean-Philippe Lang -
r12573:09b95905dc2d
parent child
Show More
@@ -1,441 +1,447
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2014 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 scm_entries(path=nil, identifier=nil)
192 198 scm.entries(path, identifier)
193 199 end
194 200 protected :scm_entries
195 201
196 202 def entries(path=nil, identifier=nil)
197 203 entries = scm_entries(path, identifier)
198 204 load_entries_changesets(entries)
199 205 entries
200 206 end
201 207
202 208 def branches
203 209 scm.branches
204 210 end
205 211
206 212 def tags
207 213 scm.tags
208 214 end
209 215
210 216 def default_branch
211 217 nil
212 218 end
213 219
214 220 def properties(path, identifier=nil)
215 221 scm.properties(path, identifier)
216 222 end
217 223
218 224 def cat(path, identifier=nil)
219 225 scm.cat(path, identifier)
220 226 end
221 227
222 228 def diff(path, rev, rev_to)
223 229 scm.diff(path, rev, rev_to)
224 230 end
225 231
226 232 def diff_format_revisions(cs, cs_to, sep=':')
227 233 text = ""
228 234 text << cs_to.format_identifier + sep if cs_to
229 235 text << cs.format_identifier if cs
230 236 text
231 237 end
232 238
233 239 # Returns a path relative to the url of the repository
234 240 def relative_path(path)
235 241 path
236 242 end
237 243
238 244 # Finds and returns a revision with a number or the beginning of a hash
239 245 def find_changeset_by_name(name)
240 246 return nil if name.blank?
241 247 s = name.to_s
242 248 if s.match(/^\d*$/)
243 249 changesets.where("revision = ?", s).first
244 250 else
245 251 changesets.where("revision LIKE ?", s + '%').first
246 252 end
247 253 end
248 254
249 255 def latest_changeset
250 256 @latest_changeset ||= changesets.first
251 257 end
252 258
253 259 # Returns the latest changesets for +path+
254 260 # Default behaviour is to search in cached changesets
255 261 def latest_changesets(path, rev, limit=10)
256 262 if path.blank?
257 263 changesets.
258 264 reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
259 265 limit(limit).
260 266 preload(:user).
261 267 all
262 268 else
263 269 filechanges.
264 270 where("path = ?", path.with_leading_slash).
265 271 reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
266 272 limit(limit).
267 273 preload(:changeset => :user).
268 274 collect(&:changeset)
269 275 end
270 276 end
271 277
272 278 def scan_changesets_for_issue_ids
273 279 self.changesets.each(&:scan_comment_for_issue_ids)
274 280 end
275 281
276 282 # Returns an array of committers usernames and associated user_id
277 283 def committers
278 284 @committers ||= Changeset.connection.select_rows(
279 285 "SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}")
280 286 end
281 287
282 288 # Maps committers username to a user ids
283 289 def committer_ids=(h)
284 290 if h.is_a?(Hash)
285 291 committers.each do |committer, user_id|
286 292 new_user_id = h[committer]
287 293 if new_user_id && (new_user_id.to_i != user_id.to_i)
288 294 new_user_id = (new_user_id.to_i > 0 ? new_user_id.to_i : nil)
289 295 Changeset.where(["repository_id = ? AND committer = ?", id, committer]).
290 296 update_all("user_id = #{new_user_id.nil? ? 'NULL' : new_user_id}")
291 297 end
292 298 end
293 299 @committers = nil
294 300 @found_committer_users = nil
295 301 true
296 302 else
297 303 false
298 304 end
299 305 end
300 306
301 307 # Returns the Redmine User corresponding to the given +committer+
302 308 # It will return nil if the committer is not yet mapped and if no User
303 309 # with the same username or email was found
304 310 def find_committer_user(committer)
305 311 unless committer.blank?
306 312 @found_committer_users ||= {}
307 313 return @found_committer_users[committer] if @found_committer_users.has_key?(committer)
308 314
309 315 user = nil
310 316 c = changesets.where(:committer => committer).includes(:user).first
311 317 if c && c.user
312 318 user = c.user
313 319 elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
314 320 username, email = $1.strip, $3
315 321 u = User.find_by_login(username)
316 322 u ||= User.find_by_mail(email) unless email.blank?
317 323 user = u
318 324 end
319 325 @found_committer_users[committer] = user
320 326 user
321 327 end
322 328 end
323 329
324 330 def repo_log_encoding
325 331 encoding = log_encoding.to_s.strip
326 332 encoding.blank? ? 'UTF-8' : encoding
327 333 end
328 334
329 335 # Fetches new changesets for all repositories of active projects
330 336 # Can be called periodically by an external script
331 337 # eg. ruby script/runner "Repository.fetch_changesets"
332 338 def self.fetch_changesets
333 339 Project.active.has_module(:repository).all.each do |project|
334 340 project.repositories.each do |repository|
335 341 begin
336 342 repository.fetch_changesets
337 343 rescue Redmine::Scm::Adapters::CommandFailed => e
338 344 logger.error "scm: error during fetching changesets: #{e.message}"
339 345 end
340 346 end
341 347 end
342 348 end
343 349
344 350 # scan changeset comments to find related and fixed issues for all repositories
345 351 def self.scan_changesets_for_issue_ids
346 352 all.each(&:scan_changesets_for_issue_ids)
347 353 end
348 354
349 355 def self.scm_name
350 356 'Abstract'
351 357 end
352 358
353 359 def self.available_scm
354 360 subclasses.collect {|klass| [klass.scm_name, klass.name]}
355 361 end
356 362
357 363 def self.factory(klass_name, *args)
358 364 klass = "Repository::#{klass_name}".constantize
359 365 klass.new(*args)
360 366 rescue
361 367 nil
362 368 end
363 369
364 370 def self.scm_adapter_class
365 371 nil
366 372 end
367 373
368 374 def self.scm_command
369 375 ret = ""
370 376 begin
371 377 ret = self.scm_adapter_class.client_command if self.scm_adapter_class
372 378 rescue Exception => e
373 379 logger.error "scm: error during get command: #{e.message}"
374 380 end
375 381 ret
376 382 end
377 383
378 384 def self.scm_version_string
379 385 ret = ""
380 386 begin
381 387 ret = self.scm_adapter_class.client_version_string if self.scm_adapter_class
382 388 rescue Exception => e
383 389 logger.error "scm: error during get version string: #{e.message}"
384 390 end
385 391 ret
386 392 end
387 393
388 394 def self.scm_available
389 395 ret = false
390 396 begin
391 397 ret = self.scm_adapter_class.client_available if self.scm_adapter_class
392 398 rescue Exception => e
393 399 logger.error "scm: error during get scm available: #{e.message}"
394 400 end
395 401 ret
396 402 end
397 403
398 404 def set_as_default?
399 405 new_record? && project && Repository.where(:project_id => project.id).empty?
400 406 end
401 407
402 408 protected
403 409
404 410 def check_default
405 411 if !is_default? && set_as_default?
406 412 self.is_default = true
407 413 end
408 414 if is_default? && is_default_changed?
409 415 Repository.where(["project_id = ?", project_id]).update_all(["is_default = ?", false])
410 416 end
411 417 end
412 418
413 419 def load_entries_changesets(entries)
414 420 if entries
415 421 entries.each do |entry|
416 422 if entry.lastrev && entry.lastrev.identifier
417 423 entry.changeset = find_changeset_by_name(entry.lastrev.identifier)
418 424 end
419 425 end
420 426 end
421 427 end
422 428
423 429 private
424 430
425 431 # Deletes repository data
426 432 def clear_changesets
427 433 cs = Changeset.table_name
428 434 ch = Change.table_name
429 435 ci = "#{table_name_prefix}changesets_issues#{table_name_suffix}"
430 436 cp = "#{table_name_prefix}changeset_parents#{table_name_suffix}"
431 437
432 438 connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
433 439 connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
434 440 connection.delete("DELETE FROM #{cp} WHERE #{cp}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
435 441 connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
436 442 clear_extra_info_of_changesets
437 443 end
438 444
439 445 def clear_extra_info_of_changesets
440 446 end
441 447 end
@@ -1,392 +1,398
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2014 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_default_repository_should_be_one
101 101 assert_equal 0, Project.find(3).repositories.count
102 102 repository1 = Repository::Subversion.new(
103 103 :project => Project.find(3),
104 104 :identifier => 'svn1',
105 105 :url => 'file:///svn1'
106 106 )
107 107 assert repository1.save
108 108 assert repository1.is_default?
109 109
110 110 repository2 = Repository::Subversion.new(
111 111 :project => Project.find(3),
112 112 :identifier => 'svn2',
113 113 :url => 'file:///svn2',
114 114 :is_default => true
115 115 )
116 116 assert repository2.save
117 117 assert repository2.is_default?
118 118 repository1.reload
119 119 assert !repository1.is_default?
120 120
121 121 assert_equal repository2, Project.find(3).repository
122 122 assert_equal [repository2, repository1], Project.find(3).repositories.sort
123 123 end
124 124
125 125 def test_identifier_should_accept_letters_digits_dashes_and_underscores
126 126 r = Repository::Subversion.new(
127 127 :project_id => 3,
128 128 :identifier => 'svn-123_45',
129 129 :url => 'file:///svn'
130 130 )
131 131 assert r.save
132 132 end
133 133
134 134 def test_identifier_should_not_be_frozen_for_a_new_repository
135 135 assert_equal false, Repository.new.identifier_frozen?
136 136 end
137 137
138 138 def test_identifier_should_not_be_frozen_for_a_saved_repository_with_blank_identifier
139 139 Repository.where(:id => 10).update_all(["identifier = ''"])
140 140 assert_equal false, Repository.find(10).identifier_frozen?
141 141 end
142 142
143 143 def test_identifier_should_be_frozen_for_a_saved_repository_with_valid_identifier
144 144 Repository.where(:id => 10).update_all(["identifier = 'abc123'"])
145 145 assert_equal true, Repository.find(10).identifier_frozen?
146 146 end
147 147
148 148 def test_identifier_should_not_accept_change_if_frozen
149 149 r = Repository.new(:identifier => 'foo')
150 150 r.stubs(:identifier_frozen?).returns(true)
151 151
152 152 r.identifier = 'bar'
153 153 assert_equal 'foo', r.identifier
154 154 end
155 155
156 156 def test_identifier_should_accept_change_if_not_frozen
157 157 r = Repository.new(:identifier => 'foo')
158 158 r.stubs(:identifier_frozen?).returns(false)
159 159
160 160 r.identifier = 'bar'
161 161 assert_equal 'bar', r.identifier
162 162 end
163 163
164 164 def test_destroy
165 165 repository = Repository.find(10)
166 166 changesets = repository.changesets.count
167 167 changes = repository.filechanges.count
168 168
169 169 assert_difference 'Changeset.count', -changesets do
170 170 assert_difference 'Change.count', -changes do
171 171 Repository.find(10).destroy
172 172 end
173 173 end
174 174 end
175 175
176 176 def test_destroy_should_delete_parents_associations
177 177 changeset = Changeset.find(102)
178 178 changeset.parents = Changeset.where(:id => [100, 101]).all
179 179 assert_difference 'Changeset.connection.select_all("select * from changeset_parents").count', -2 do
180 180 Repository.find(10).destroy
181 181 end
182 182 end
183 183
184 184 def test_destroy_should_delete_issues_associations
185 185 changeset = Changeset.find(102)
186 186 changeset.issues = Issue.where(:id => [1, 2]).all
187 187 assert_difference 'Changeset.connection.select_all("select * from changesets_issues").count', -2 do
188 188 Repository.find(10).destroy
189 189 end
190 190 end
191 191
192 192 def test_should_not_create_with_disabled_scm
193 193 # disable Subversion
194 194 with_settings :enabled_scm => ['Darcs', 'Git'] do
195 195 repository = Repository::Subversion.new(
196 196 :project => Project.find(3), :url => "svn://localhost")
197 197 assert !repository.save
198 198 assert_include I18n.translate('activerecord.errors.messages.invalid'),
199 199 repository.errors[:type]
200 200 end
201 201 end
202 202
203 203 def test_scan_changesets_for_issue_ids
204 204 Setting.default_language = 'en'
205 205 Setting.commit_ref_keywords = 'refs , references, IssueID'
206 206 Setting.commit_update_keywords = [
207 207 {'keywords' => 'fixes , closes',
208 208 'status_id' => IssueStatus.where(:is_closed => true).first.id,
209 209 'done_ratio' => '90'}
210 210 ]
211 211 Setting.default_language = 'en'
212 212 ActionMailer::Base.deliveries.clear
213 213
214 214 # make sure issue 1 is not already closed
215 215 fixed_issue = Issue.find(1)
216 216 assert !fixed_issue.status.is_closed?
217 217 old_status = fixed_issue.status
218 218
219 219 with_settings :notified_events => %w(issue_added issue_updated) do
220 220 Repository.scan_changesets_for_issue_ids
221 221 end
222 222 assert_equal [101, 102], Issue.find(3).changeset_ids
223 223
224 224 # fixed issues
225 225 fixed_issue.reload
226 226 assert fixed_issue.status.is_closed?
227 227 assert_equal 90, fixed_issue.done_ratio
228 228 assert_equal [101], fixed_issue.changeset_ids
229 229
230 230 # issue change
231 231 journal = fixed_issue.journals.reorder('created_on desc').first
232 232 assert_equal User.find_by_login('dlopper'), journal.user
233 233 assert_equal 'Applied in changeset r2.', journal.notes
234 234
235 235 # 2 email notifications
236 236 assert_equal 2, ActionMailer::Base.deliveries.size
237 237 mail = ActionMailer::Base.deliveries.first
238 238 assert_not_nil mail
239 239 assert mail.subject.starts_with?(
240 240 "[#{fixed_issue.project.name} - #{fixed_issue.tracker.name} ##{fixed_issue.id}]")
241 241 assert_mail_body_match(
242 242 "Status changed from #{old_status} to #{fixed_issue.status}", mail)
243 243
244 244 # ignoring commits referencing an issue of another project
245 245 assert_equal [], Issue.find(4).changesets
246 246 end
247 247
248 248 def test_for_changeset_comments_strip
249 249 repository = Repository::Mercurial.create(
250 250 :project => Project.find( 4 ),
251 251 :url => '/foo/bar/baz' )
252 252 comment = <<-COMMENT
253 253 This is a loooooooooooooooooooooooooooong comment
254 254
255 255
256 256 COMMENT
257 257 changeset = Changeset.new(
258 258 :comments => comment, :commit_date => Time.now,
259 259 :revision => 0, :scmid => 'f39b7922fb3c',
260 260 :committer => 'foo <foo@example.com>',
261 261 :committed_on => Time.now, :repository => repository )
262 262 assert( changeset.save )
263 263 assert_not_equal( comment, changeset.comments )
264 264 assert_equal( 'This is a loooooooooooooooooooooooooooong comment',
265 265 changeset.comments )
266 266 end
267 267
268 268 def test_for_urls_strip_cvs
269 269 repository = Repository::Cvs.create(
270 270 :project => Project.find(4),
271 271 :url => ' :pserver:login:password@host:/path/to/the/repository',
272 272 :root_url => 'foo ',
273 273 :log_encoding => 'UTF-8')
274 274 assert repository.save
275 275 repository.reload
276 276 assert_equal ':pserver:login:password@host:/path/to/the/repository',
277 277 repository.url
278 278 assert_equal 'foo', repository.root_url
279 279 end
280 280
281 281 def test_for_urls_strip_subversion
282 282 repository = Repository::Subversion.create(
283 283 :project => Project.find(4),
284 284 :url => ' file:///dummy ')
285 285 assert repository.save
286 286 repository.reload
287 287 assert_equal 'file:///dummy', repository.url
288 288 end
289 289
290 290 def test_for_urls_strip_git
291 291 repository = Repository::Git.create(
292 292 :project => Project.find(4),
293 293 :url => ' c:\dummy ')
294 294 assert repository.save
295 295 repository.reload
296 296 assert_equal 'c:\dummy', repository.url
297 297 end
298 298
299 299 def test_manual_user_mapping
300 300 assert_no_difference "Changeset.where('user_id <> 2').count" do
301 301 c = Changeset.create!(
302 302 :repository => @repository,
303 303 :committer => 'foo',
304 304 :committed_on => Time.now,
305 305 :revision => 100,
306 306 :comments => 'Committed by foo.'
307 307 )
308 308 assert_nil c.user
309 309 @repository.committer_ids = {'foo' => '2'}
310 310 assert_equal User.find(2), c.reload.user
311 311 # committer is now mapped
312 312 c = Changeset.create!(
313 313 :repository => @repository,
314 314 :committer => 'foo',
315 315 :committed_on => Time.now,
316 316 :revision => 101,
317 317 :comments => 'Another commit by foo.'
318 318 )
319 319 assert_equal User.find(2), c.user
320 320 end
321 321 end
322 322
323 323 def test_auto_user_mapping_by_username
324 324 c = Changeset.create!(
325 325 :repository => @repository,
326 326 :committer => 'jsmith',
327 327 :committed_on => Time.now,
328 328 :revision => 100,
329 329 :comments => 'Committed by john.'
330 330 )
331 331 assert_equal User.find(2), c.user
332 332 end
333 333
334 334 def test_auto_user_mapping_by_email
335 335 c = Changeset.create!(
336 336 :repository => @repository,
337 337 :committer => 'john <jsmith@somenet.foo>',
338 338 :committed_on => Time.now,
339 339 :revision => 100,
340 340 :comments => 'Committed by john.'
341 341 )
342 342 assert_equal User.find(2), c.user
343 343 end
344 344
345 345 def test_filesystem_avaialbe
346 346 klass = Repository::Filesystem
347 347 assert klass.scm_adapter_class
348 348 assert_equal true, klass.scm_available
349 349 end
350 350
351 def test_extra_info_should_not_return_non_hash_value
352 repo = Repository.new
353 repo.extra_info = "foo"
354 assert_nil repo.extra_info
355 end
356
351 357 def test_merge_extra_info
352 358 repo = Repository::Subversion.new(:project => Project.find(3))
353 359 assert !repo.save
354 360 repo.url = "svn://localhost"
355 361 assert repo.save
356 362 repo.reload
357 363 project = Project.find(3)
358 364 assert_equal repo, project.repository
359 365 assert_nil repo.extra_info
360 366 h1 = {"test_1" => {"test_11" => "test_value_11"}}
361 367 repo.merge_extra_info(h1)
362 368 assert_equal h1, repo.extra_info
363 369 h2 = {"test_2" => {
364 370 "test_21" => "test_value_21",
365 371 "test_22" => "test_value_22",
366 372 }}
367 373 repo.merge_extra_info(h2)
368 374 assert_equal (h = {"test_11" => "test_value_11"}),
369 375 repo.extra_info["test_1"]
370 376 assert_equal "test_value_21",
371 377 repo.extra_info["test_2"]["test_21"]
372 378 h3 = {"test_2" => {
373 379 "test_23" => "test_value_23",
374 380 "test_24" => "test_value_24",
375 381 }}
376 382 repo.merge_extra_info(h3)
377 383 assert_equal (h = {"test_11" => "test_value_11"}),
378 384 repo.extra_info["test_1"]
379 385 assert_nil repo.extra_info["test_2"]["test_21"]
380 386 assert_equal "test_value_23",
381 387 repo.extra_info["test_2"]["test_23"]
382 388 end
383 389
384 390 def test_sort_should_not_raise_an_error_with_nil_identifiers
385 391 r1 = Repository.new
386 392 r2 = Repository.new
387 393
388 394 assert_nothing_raised do
389 395 [r1, r2].sort
390 396 end
391 397 end
392 398 end
General Comments 0
You need to be logged in to leave comments. Login now