##// END OF EJS Templates
Adds the repository identifier to Changeset#text_tag (#779)....
Jean-Philippe Lang -
r9135:bb36fa5d1208
parent child
Show More
@@ -1,275 +1,278
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 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 'iconv'
18 require 'iconv'
19
19
20 class Changeset < ActiveRecord::Base
20 class Changeset < ActiveRecord::Base
21 belongs_to :repository
21 belongs_to :repository
22 belongs_to :user
22 belongs_to :user
23 has_many :changes, :dependent => :delete_all
23 has_many :changes, :dependent => :delete_all
24 has_and_belongs_to_many :issues
24 has_and_belongs_to_many :issues
25 has_and_belongs_to_many :parents,
25 has_and_belongs_to_many :parents,
26 :class_name => "Changeset",
26 :class_name => "Changeset",
27 :join_table => "#{table_name_prefix}changeset_parents#{table_name_suffix}",
27 :join_table => "#{table_name_prefix}changeset_parents#{table_name_suffix}",
28 :association_foreign_key => 'parent_id', :foreign_key => 'changeset_id'
28 :association_foreign_key => 'parent_id', :foreign_key => 'changeset_id'
29 has_and_belongs_to_many :children,
29 has_and_belongs_to_many :children,
30 :class_name => "Changeset",
30 :class_name => "Changeset",
31 :join_table => "#{table_name_prefix}changeset_parents#{table_name_suffix}",
31 :join_table => "#{table_name_prefix}changeset_parents#{table_name_suffix}",
32 :association_foreign_key => 'changeset_id', :foreign_key => 'parent_id'
32 :association_foreign_key => 'changeset_id', :foreign_key => 'parent_id'
33
33
34 acts_as_event :title => Proc.new {|o| "#{l(:label_revision)} #{o.format_identifier}" + (o.short_comments.blank? ? '' : (': ' + o.short_comments))},
34 acts_as_event :title => Proc.new {|o| "#{l(:label_revision)} #{o.format_identifier}" + (o.short_comments.blank? ? '' : (': ' + o.short_comments))},
35 :description => :long_comments,
35 :description => :long_comments,
36 :datetime => :committed_on,
36 :datetime => :committed_on,
37 :url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project, :repository_id => o.repository.identifier_param, :rev => o.identifier}}
37 :url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project, :repository_id => o.repository.identifier_param, :rev => o.identifier}}
38
38
39 acts_as_searchable :columns => 'comments',
39 acts_as_searchable :columns => 'comments',
40 :include => {:repository => :project},
40 :include => {:repository => :project},
41 :project_key => "#{Repository.table_name}.project_id",
41 :project_key => "#{Repository.table_name}.project_id",
42 :date_column => 'committed_on'
42 :date_column => 'committed_on'
43
43
44 acts_as_activity_provider :timestamp => "#{table_name}.committed_on",
44 acts_as_activity_provider :timestamp => "#{table_name}.committed_on",
45 :author_key => :user_id,
45 :author_key => :user_id,
46 :find_options => {:include => [:user, {:repository => :project}]}
46 :find_options => {:include => [:user, {:repository => :project}]}
47
47
48 validates_presence_of :repository_id, :revision, :committed_on, :commit_date
48 validates_presence_of :repository_id, :revision, :committed_on, :commit_date
49 validates_uniqueness_of :revision, :scope => :repository_id
49 validates_uniqueness_of :revision, :scope => :repository_id
50 validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true
50 validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true
51
51
52 named_scope :visible, lambda {|*args| { :include => {:repository => :project},
52 named_scope :visible, lambda {|*args| { :include => {:repository => :project},
53 :conditions => Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args) } }
53 :conditions => Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args) } }
54
54
55 after_create :scan_for_issues
55 after_create :scan_for_issues
56 before_create :before_create_cs
56 before_create :before_create_cs
57
57
58 def revision=(r)
58 def revision=(r)
59 write_attribute :revision, (r.nil? ? nil : r.to_s)
59 write_attribute :revision, (r.nil? ? nil : r.to_s)
60 end
60 end
61
61
62 # Returns the identifier of this changeset; depending on repository backends
62 # Returns the identifier of this changeset; depending on repository backends
63 def identifier
63 def identifier
64 if repository.class.respond_to? :changeset_identifier
64 if repository.class.respond_to? :changeset_identifier
65 repository.class.changeset_identifier self
65 repository.class.changeset_identifier self
66 else
66 else
67 revision.to_s
67 revision.to_s
68 end
68 end
69 end
69 end
70
70
71 def committed_on=(date)
71 def committed_on=(date)
72 self.commit_date = date
72 self.commit_date = date
73 super
73 super
74 end
74 end
75
75
76 # Returns the readable identifier
76 # Returns the readable identifier
77 def format_identifier
77 def format_identifier
78 if repository.class.respond_to? :format_changeset_identifier
78 if repository.class.respond_to? :format_changeset_identifier
79 repository.class.format_changeset_identifier self
79 repository.class.format_changeset_identifier self
80 else
80 else
81 identifier
81 identifier
82 end
82 end
83 end
83 end
84
84
85 def project
85 def project
86 repository.project
86 repository.project
87 end
87 end
88
88
89 def author
89 def author
90 user || committer.to_s.split('<').first
90 user || committer.to_s.split('<').first
91 end
91 end
92
92
93 def before_create_cs
93 def before_create_cs
94 self.committer = self.class.to_utf8(self.committer, repository.repo_log_encoding)
94 self.committer = self.class.to_utf8(self.committer, repository.repo_log_encoding)
95 self.comments = self.class.normalize_comments(
95 self.comments = self.class.normalize_comments(
96 self.comments, repository.repo_log_encoding)
96 self.comments, repository.repo_log_encoding)
97 self.user = repository.find_committer_user(self.committer)
97 self.user = repository.find_committer_user(self.committer)
98 end
98 end
99
99
100 def scan_for_issues
100 def scan_for_issues
101 scan_comment_for_issue_ids
101 scan_comment_for_issue_ids
102 end
102 end
103
103
104 TIMELOG_RE = /
104 TIMELOG_RE = /
105 (
105 (
106 ((\d+)(h|hours?))((\d+)(m|min)?)?
106 ((\d+)(h|hours?))((\d+)(m|min)?)?
107 |
107 |
108 ((\d+)(h|hours?|m|min))
108 ((\d+)(h|hours?|m|min))
109 |
109 |
110 (\d+):(\d+)
110 (\d+):(\d+)
111 |
111 |
112 (\d+([\.,]\d+)?)h?
112 (\d+([\.,]\d+)?)h?
113 )
113 )
114 /x
114 /x
115
115
116 def scan_comment_for_issue_ids
116 def scan_comment_for_issue_ids
117 return if comments.blank?
117 return if comments.blank?
118 # keywords used to reference issues
118 # keywords used to reference issues
119 ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip)
119 ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip)
120 ref_keywords_any = ref_keywords.delete('*')
120 ref_keywords_any = ref_keywords.delete('*')
121 # keywords used to fix issues
121 # keywords used to fix issues
122 fix_keywords = Setting.commit_fix_keywords.downcase.split(",").collect(&:strip)
122 fix_keywords = Setting.commit_fix_keywords.downcase.split(",").collect(&:strip)
123
123
124 kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|")
124 kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|")
125
125
126 referenced_issues = []
126 referenced_issues = []
127
127
128 comments.scan(/([\s\(\[,-]|^)((#{kw_regexp})[\s:]+)?(#\d+(\s+@#{TIMELOG_RE})?([\s,;&]+#\d+(\s+@#{TIMELOG_RE})?)*)(?=[[:punct:]]|\s|<|$)/i) do |match|
128 comments.scan(/([\s\(\[,-]|^)((#{kw_regexp})[\s:]+)?(#\d+(\s+@#{TIMELOG_RE})?([\s,;&]+#\d+(\s+@#{TIMELOG_RE})?)*)(?=[[:punct:]]|\s|<|$)/i) do |match|
129 action, refs = match[2], match[3]
129 action, refs = match[2], match[3]
130 next unless action.present? || ref_keywords_any
130 next unless action.present? || ref_keywords_any
131
131
132 refs.scan(/#(\d+)(\s+@#{TIMELOG_RE})?/).each do |m|
132 refs.scan(/#(\d+)(\s+@#{TIMELOG_RE})?/).each do |m|
133 issue, hours = find_referenced_issue_by_id(m[0].to_i), m[2]
133 issue, hours = find_referenced_issue_by_id(m[0].to_i), m[2]
134 if issue
134 if issue
135 referenced_issues << issue
135 referenced_issues << issue
136 fix_issue(issue) if fix_keywords.include?(action.to_s.downcase)
136 fix_issue(issue) if fix_keywords.include?(action.to_s.downcase)
137 log_time(issue, hours) if hours && Setting.commit_logtime_enabled?
137 log_time(issue, hours) if hours && Setting.commit_logtime_enabled?
138 end
138 end
139 end
139 end
140 end
140 end
141
141
142 referenced_issues.uniq!
142 referenced_issues.uniq!
143 self.issues = referenced_issues unless referenced_issues.empty?
143 self.issues = referenced_issues unless referenced_issues.empty?
144 end
144 end
145
145
146 def short_comments
146 def short_comments
147 @short_comments || split_comments.first
147 @short_comments || split_comments.first
148 end
148 end
149
149
150 def long_comments
150 def long_comments
151 @long_comments || split_comments.last
151 @long_comments || split_comments.last
152 end
152 end
153
153
154 def text_tag(ref_project=nil)
154 def text_tag(ref_project=nil)
155 tag = if scmid?
155 tag = if scmid?
156 "commit:#{scmid}"
156 "commit:#{scmid}"
157 else
157 else
158 "r#{revision}"
158 "r#{revision}"
159 end
159 end
160 if repository && repository.identifier.present?
161 tag = "#{repository.identifier}|#{tag}"
162 end
160 if ref_project && project && ref_project != project
163 if ref_project && project && ref_project != project
161 tag = "#{project.identifier}:#{tag}"
164 tag = "#{project.identifier}:#{tag}"
162 end
165 end
163 tag
166 tag
164 end
167 end
165
168
166 # Returns the previous changeset
169 # Returns the previous changeset
167 def previous
170 def previous
168 @previous ||= Changeset.find(:first,
171 @previous ||= Changeset.find(:first,
169 :conditions => ['id < ? AND repository_id = ?',
172 :conditions => ['id < ? AND repository_id = ?',
170 self.id, self.repository_id],
173 self.id, self.repository_id],
171 :order => 'id DESC')
174 :order => 'id DESC')
172 end
175 end
173
176
174 # Returns the next changeset
177 # Returns the next changeset
175 def next
178 def next
176 @next ||= Changeset.find(:first,
179 @next ||= Changeset.find(:first,
177 :conditions => ['id > ? AND repository_id = ?',
180 :conditions => ['id > ? AND repository_id = ?',
178 self.id, self.repository_id],
181 self.id, self.repository_id],
179 :order => 'id ASC')
182 :order => 'id ASC')
180 end
183 end
181
184
182 # Creates a new Change from it's common parameters
185 # Creates a new Change from it's common parameters
183 def create_change(change)
186 def create_change(change)
184 Change.create(:changeset => self,
187 Change.create(:changeset => self,
185 :action => change[:action],
188 :action => change[:action],
186 :path => change[:path],
189 :path => change[:path],
187 :from_path => change[:from_path],
190 :from_path => change[:from_path],
188 :from_revision => change[:from_revision])
191 :from_revision => change[:from_revision])
189 end
192 end
190
193
191 # Finds an issue that can be referenced by the commit message
194 # Finds an issue that can be referenced by the commit message
192 def find_referenced_issue_by_id(id)
195 def find_referenced_issue_by_id(id)
193 return nil if id.blank?
196 return nil if id.blank?
194 issue = Issue.find_by_id(id.to_i, :include => :project)
197 issue = Issue.find_by_id(id.to_i, :include => :project)
195 if Setting.commit_cross_project_ref?
198 if Setting.commit_cross_project_ref?
196 # all issues can be referenced/fixed
199 # all issues can be referenced/fixed
197 elsif issue
200 elsif issue
198 # issue that belong to the repository project, a subproject or a parent project only
201 # issue that belong to the repository project, a subproject or a parent project only
199 unless issue.project &&
202 unless issue.project &&
200 (project == issue.project || project.is_ancestor_of?(issue.project) ||
203 (project == issue.project || project.is_ancestor_of?(issue.project) ||
201 project.is_descendant_of?(issue.project))
204 project.is_descendant_of?(issue.project))
202 issue = nil
205 issue = nil
203 end
206 end
204 end
207 end
205 issue
208 issue
206 end
209 end
207
210
208 private
211 private
209
212
210 def fix_issue(issue)
213 def fix_issue(issue)
211 status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i)
214 status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i)
212 if status.nil?
215 if status.nil?
213 logger.warn("No status matches commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger
216 logger.warn("No status matches commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger
214 return issue
217 return issue
215 end
218 end
216
219
217 # the issue may have been updated by the closure of another one (eg. duplicate)
220 # the issue may have been updated by the closure of another one (eg. duplicate)
218 issue.reload
221 issue.reload
219 # don't change the status is the issue is closed
222 # don't change the status is the issue is closed
220 return if issue.status && issue.status.is_closed?
223 return if issue.status && issue.status.is_closed?
221
224
222 journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag(issue.project)))
225 journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag(issue.project)))
223 issue.status = status
226 issue.status = status
224 unless Setting.commit_fix_done_ratio.blank?
227 unless Setting.commit_fix_done_ratio.blank?
225 issue.done_ratio = Setting.commit_fix_done_ratio.to_i
228 issue.done_ratio = Setting.commit_fix_done_ratio.to_i
226 end
229 end
227 Redmine::Hook.call_hook(:model_changeset_scan_commit_for_issue_ids_pre_issue_update,
230 Redmine::Hook.call_hook(:model_changeset_scan_commit_for_issue_ids_pre_issue_update,
228 { :changeset => self, :issue => issue })
231 { :changeset => self, :issue => issue })
229 unless issue.save
232 unless issue.save
230 logger.warn("Issue ##{issue.id} could not be saved by changeset #{id}: #{issue.errors.full_messages}") if logger
233 logger.warn("Issue ##{issue.id} could not be saved by changeset #{id}: #{issue.errors.full_messages}") if logger
231 end
234 end
232 issue
235 issue
233 end
236 end
234
237
235 def log_time(issue, hours)
238 def log_time(issue, hours)
236 time_entry = TimeEntry.new(
239 time_entry = TimeEntry.new(
237 :user => user,
240 :user => user,
238 :hours => hours,
241 :hours => hours,
239 :issue => issue,
242 :issue => issue,
240 :spent_on => commit_date,
243 :spent_on => commit_date,
241 :comments => l(:text_time_logged_by_changeset, :value => text_tag(issue.project),
244 :comments => l(:text_time_logged_by_changeset, :value => text_tag(issue.project),
242 :locale => Setting.default_language)
245 :locale => Setting.default_language)
243 )
246 )
244 time_entry.activity = log_time_activity unless log_time_activity.nil?
247 time_entry.activity = log_time_activity unless log_time_activity.nil?
245
248
246 unless time_entry.save
249 unless time_entry.save
247 logger.warn("TimeEntry could not be created by changeset #{id}: #{time_entry.errors.full_messages}") if logger
250 logger.warn("TimeEntry could not be created by changeset #{id}: #{time_entry.errors.full_messages}") if logger
248 end
251 end
249 time_entry
252 time_entry
250 end
253 end
251
254
252 def log_time_activity
255 def log_time_activity
253 if Setting.commit_logtime_activity_id.to_i > 0
256 if Setting.commit_logtime_activity_id.to_i > 0
254 TimeEntryActivity.find_by_id(Setting.commit_logtime_activity_id.to_i)
257 TimeEntryActivity.find_by_id(Setting.commit_logtime_activity_id.to_i)
255 end
258 end
256 end
259 end
257
260
258 def split_comments
261 def split_comments
259 comments =~ /\A(.+?)\r?\n(.*)$/m
262 comments =~ /\A(.+?)\r?\n(.*)$/m
260 @short_comments = $1 || comments
263 @short_comments = $1 || comments
261 @long_comments = $2.to_s.strip
264 @long_comments = $2.to_s.strip
262 return @short_comments, @long_comments
265 return @short_comments, @long_comments
263 end
266 end
264
267
265 public
268 public
266
269
267 # Strips and reencodes a commit log before insertion into the database
270 # Strips and reencodes a commit log before insertion into the database
268 def self.normalize_comments(str, encoding)
271 def self.normalize_comments(str, encoding)
269 Changeset.to_utf8(str.to_s.strip, encoding)
272 Changeset.to_utf8(str.to_s.strip, encoding)
270 end
273 end
271
274
272 def self.to_utf8(str, encoding)
275 def self.to_utf8(str, encoding)
273 Redmine::CodesetUtil.to_utf8(str, encoding)
276 Redmine::CodesetUtil.to_utf8(str, encoding)
274 end
277 end
275 end
278 end
@@ -1,467 +1,478
1 # encoding: utf-8
1 # encoding: utf-8
2 #
2 #
3 # Redmine - project management software
3 # Redmine - project management software
4 # Copyright (C) 2006-2011 Jean-Philippe Lang
4 # Copyright (C) 2006-2011 Jean-Philippe Lang
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
9 # of the License, or (at your option) any later version.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
19
20 require File.expand_path('../../test_helper', __FILE__)
20 require File.expand_path('../../test_helper', __FILE__)
21
21
22 class ChangesetTest < ActiveSupport::TestCase
22 class ChangesetTest < ActiveSupport::TestCase
23 fixtures :projects, :repositories,
23 fixtures :projects, :repositories,
24 :issues, :issue_statuses, :issue_categories,
24 :issues, :issue_statuses, :issue_categories,
25 :changesets, :changes,
25 :changesets, :changes,
26 :enumerations,
26 :enumerations,
27 :custom_fields, :custom_values,
27 :custom_fields, :custom_values,
28 :users, :members, :member_roles, :trackers,
28 :users, :members, :member_roles, :trackers,
29 :enabled_modules, :roles
29 :enabled_modules, :roles
30
30
31 def setup
31 def setup
32 end
32 end
33
33
34 def test_ref_keywords_any
34 def test_ref_keywords_any
35 ActionMailer::Base.deliveries.clear
35 ActionMailer::Base.deliveries.clear
36 Setting.commit_fix_status_id = IssueStatus.find(
36 Setting.commit_fix_status_id = IssueStatus.find(
37 :first, :conditions => ["is_closed = ?", true]).id
37 :first, :conditions => ["is_closed = ?", true]).id
38 Setting.commit_fix_done_ratio = '90'
38 Setting.commit_fix_done_ratio = '90'
39 Setting.commit_ref_keywords = '*'
39 Setting.commit_ref_keywords = '*'
40 Setting.commit_fix_keywords = 'fixes , closes'
40 Setting.commit_fix_keywords = 'fixes , closes'
41
41
42 c = Changeset.new(:repository => Project.find(1).repository,
42 c = Changeset.new(:repository => Project.find(1).repository,
43 :committed_on => Time.now,
43 :committed_on => Time.now,
44 :comments => 'New commit (#2). Fixes #1',
44 :comments => 'New commit (#2). Fixes #1',
45 :revision => '12345')
45 :revision => '12345')
46 assert c.save
46 assert c.save
47 assert_equal [1, 2], c.issue_ids.sort
47 assert_equal [1, 2], c.issue_ids.sort
48 fixed = Issue.find(1)
48 fixed = Issue.find(1)
49 assert fixed.closed?
49 assert fixed.closed?
50 assert_equal 90, fixed.done_ratio
50 assert_equal 90, fixed.done_ratio
51 assert_equal 1, ActionMailer::Base.deliveries.size
51 assert_equal 1, ActionMailer::Base.deliveries.size
52 end
52 end
53
53
54 def test_ref_keywords
54 def test_ref_keywords
55 Setting.commit_ref_keywords = 'refs'
55 Setting.commit_ref_keywords = 'refs'
56 Setting.commit_fix_keywords = ''
56 Setting.commit_fix_keywords = ''
57 c = Changeset.new(:repository => Project.find(1).repository,
57 c = Changeset.new(:repository => Project.find(1).repository,
58 :committed_on => Time.now,
58 :committed_on => Time.now,
59 :comments => 'Ignores #2. Refs #1',
59 :comments => 'Ignores #2. Refs #1',
60 :revision => '12345')
60 :revision => '12345')
61 assert c.save
61 assert c.save
62 assert_equal [1], c.issue_ids.sort
62 assert_equal [1], c.issue_ids.sort
63 end
63 end
64
64
65 def test_ref_keywords_any_only
65 def test_ref_keywords_any_only
66 Setting.commit_ref_keywords = '*'
66 Setting.commit_ref_keywords = '*'
67 Setting.commit_fix_keywords = ''
67 Setting.commit_fix_keywords = ''
68 c = Changeset.new(:repository => Project.find(1).repository,
68 c = Changeset.new(:repository => Project.find(1).repository,
69 :committed_on => Time.now,
69 :committed_on => Time.now,
70 :comments => 'Ignores #2. Refs #1',
70 :comments => 'Ignores #2. Refs #1',
71 :revision => '12345')
71 :revision => '12345')
72 assert c.save
72 assert c.save
73 assert_equal [1, 2], c.issue_ids.sort
73 assert_equal [1, 2], c.issue_ids.sort
74 end
74 end
75
75
76 def test_ref_keywords_any_with_timelog
76 def test_ref_keywords_any_with_timelog
77 Setting.commit_ref_keywords = '*'
77 Setting.commit_ref_keywords = '*'
78 Setting.commit_logtime_enabled = '1'
78 Setting.commit_logtime_enabled = '1'
79
79
80 {
80 {
81 '2' => 2.0,
81 '2' => 2.0,
82 '2h' => 2.0,
82 '2h' => 2.0,
83 '2hours' => 2.0,
83 '2hours' => 2.0,
84 '15m' => 0.25,
84 '15m' => 0.25,
85 '15min' => 0.25,
85 '15min' => 0.25,
86 '3h15' => 3.25,
86 '3h15' => 3.25,
87 '3h15m' => 3.25,
87 '3h15m' => 3.25,
88 '3h15min' => 3.25,
88 '3h15min' => 3.25,
89 '3:15' => 3.25,
89 '3:15' => 3.25,
90 '3.25' => 3.25,
90 '3.25' => 3.25,
91 '3.25h' => 3.25,
91 '3.25h' => 3.25,
92 '3,25' => 3.25,
92 '3,25' => 3.25,
93 '3,25h' => 3.25,
93 '3,25h' => 3.25,
94 }.each do |syntax, expected_hours|
94 }.each do |syntax, expected_hours|
95 c = Changeset.new(:repository => Project.find(1).repository,
95 c = Changeset.new(:repository => Project.find(1).repository,
96 :committed_on => 24.hours.ago,
96 :committed_on => 24.hours.ago,
97 :comments => "Worked on this issue #1 @#{syntax}",
97 :comments => "Worked on this issue #1 @#{syntax}",
98 :revision => '520',
98 :revision => '520',
99 :user => User.find(2))
99 :user => User.find(2))
100 assert_difference 'TimeEntry.count' do
100 assert_difference 'TimeEntry.count' do
101 c.scan_comment_for_issue_ids
101 c.scan_comment_for_issue_ids
102 end
102 end
103 assert_equal [1], c.issue_ids.sort
103 assert_equal [1], c.issue_ids.sort
104
104
105 time = TimeEntry.first(:order => 'id desc')
105 time = TimeEntry.first(:order => 'id desc')
106 assert_equal 1, time.issue_id
106 assert_equal 1, time.issue_id
107 assert_equal 1, time.project_id
107 assert_equal 1, time.project_id
108 assert_equal 2, time.user_id
108 assert_equal 2, time.user_id
109 assert_equal expected_hours, time.hours,
109 assert_equal expected_hours, time.hours,
110 "@#{syntax} should be logged as #{expected_hours} hours but was #{time.hours}"
110 "@#{syntax} should be logged as #{expected_hours} hours but was #{time.hours}"
111 assert_equal Date.yesterday, time.spent_on
111 assert_equal Date.yesterday, time.spent_on
112 assert time.activity.is_default?
112 assert time.activity.is_default?
113 assert time.comments.include?('r520'),
113 assert time.comments.include?('r520'),
114 "r520 was expected in time_entry comments: #{time.comments}"
114 "r520 was expected in time_entry comments: #{time.comments}"
115 end
115 end
116 end
116 end
117
117
118 def test_ref_keywords_closing_with_timelog
118 def test_ref_keywords_closing_with_timelog
119 Setting.commit_fix_status_id = IssueStatus.find(
119 Setting.commit_fix_status_id = IssueStatus.find(
120 :first, :conditions => ["is_closed = ?", true]).id
120 :first, :conditions => ["is_closed = ?", true]).id
121 Setting.commit_ref_keywords = '*'
121 Setting.commit_ref_keywords = '*'
122 Setting.commit_fix_keywords = 'fixes , closes'
122 Setting.commit_fix_keywords = 'fixes , closes'
123 Setting.commit_logtime_enabled = '1'
123 Setting.commit_logtime_enabled = '1'
124
124
125 c = Changeset.new(:repository => Project.find(1).repository,
125 c = Changeset.new(:repository => Project.find(1).repository,
126 :committed_on => Time.now,
126 :committed_on => Time.now,
127 :comments => 'This is a comment. Fixes #1 @4.5, #2 @1',
127 :comments => 'This is a comment. Fixes #1 @4.5, #2 @1',
128 :user => User.find(2))
128 :user => User.find(2))
129 assert_difference 'TimeEntry.count', 2 do
129 assert_difference 'TimeEntry.count', 2 do
130 c.scan_comment_for_issue_ids
130 c.scan_comment_for_issue_ids
131 end
131 end
132
132
133 assert_equal [1, 2], c.issue_ids.sort
133 assert_equal [1, 2], c.issue_ids.sort
134 assert Issue.find(1).closed?
134 assert Issue.find(1).closed?
135 assert Issue.find(2).closed?
135 assert Issue.find(2).closed?
136
136
137 times = TimeEntry.all(:order => 'id desc', :limit => 2)
137 times = TimeEntry.all(:order => 'id desc', :limit => 2)
138 assert_equal [1, 2], times.collect(&:issue_id).sort
138 assert_equal [1, 2], times.collect(&:issue_id).sort
139 end
139 end
140
140
141 def test_ref_keywords_any_line_start
141 def test_ref_keywords_any_line_start
142 Setting.commit_ref_keywords = '*'
142 Setting.commit_ref_keywords = '*'
143 c = Changeset.new(:repository => Project.find(1).repository,
143 c = Changeset.new(:repository => Project.find(1).repository,
144 :committed_on => Time.now,
144 :committed_on => Time.now,
145 :comments => '#1 is the reason of this commit',
145 :comments => '#1 is the reason of this commit',
146 :revision => '12345')
146 :revision => '12345')
147 assert c.save
147 assert c.save
148 assert_equal [1], c.issue_ids.sort
148 assert_equal [1], c.issue_ids.sort
149 end
149 end
150
150
151 def test_ref_keywords_allow_brackets_around_a_issue_number
151 def test_ref_keywords_allow_brackets_around_a_issue_number
152 Setting.commit_ref_keywords = '*'
152 Setting.commit_ref_keywords = '*'
153 c = Changeset.new(:repository => Project.find(1).repository,
153 c = Changeset.new(:repository => Project.find(1).repository,
154 :committed_on => Time.now,
154 :committed_on => Time.now,
155 :comments => '[#1] Worked on this issue',
155 :comments => '[#1] Worked on this issue',
156 :revision => '12345')
156 :revision => '12345')
157 assert c.save
157 assert c.save
158 assert_equal [1], c.issue_ids.sort
158 assert_equal [1], c.issue_ids.sort
159 end
159 end
160
160
161 def test_ref_keywords_allow_brackets_around_multiple_issue_numbers
161 def test_ref_keywords_allow_brackets_around_multiple_issue_numbers
162 Setting.commit_ref_keywords = '*'
162 Setting.commit_ref_keywords = '*'
163 c = Changeset.new(:repository => Project.find(1).repository,
163 c = Changeset.new(:repository => Project.find(1).repository,
164 :committed_on => Time.now,
164 :committed_on => Time.now,
165 :comments => '[#1 #2, #3] Worked on these',
165 :comments => '[#1 #2, #3] Worked on these',
166 :revision => '12345')
166 :revision => '12345')
167 assert c.save
167 assert c.save
168 assert_equal [1,2,3], c.issue_ids.sort
168 assert_equal [1,2,3], c.issue_ids.sort
169 end
169 end
170
170
171 def test_commit_referencing_a_subproject_issue
171 def test_commit_referencing_a_subproject_issue
172 c = Changeset.new(:repository => Project.find(1).repository,
172 c = Changeset.new(:repository => Project.find(1).repository,
173 :committed_on => Time.now,
173 :committed_on => Time.now,
174 :comments => 'refs #5, a subproject issue',
174 :comments => 'refs #5, a subproject issue',
175 :revision => '12345')
175 :revision => '12345')
176 assert c.save
176 assert c.save
177 assert_equal [5], c.issue_ids.sort
177 assert_equal [5], c.issue_ids.sort
178 assert c.issues.first.project != c.project
178 assert c.issues.first.project != c.project
179 end
179 end
180
180
181 def test_commit_closing_a_subproject_issue
181 def test_commit_closing_a_subproject_issue
182 with_settings :commit_fix_status_id => 5, :commit_fix_keywords => 'closes' do
182 with_settings :commit_fix_status_id => 5, :commit_fix_keywords => 'closes' do
183 issue = Issue.find(5)
183 issue = Issue.find(5)
184 assert !issue.closed?
184 assert !issue.closed?
185 assert_difference 'Journal.count' do
185 assert_difference 'Journal.count' do
186 c = Changeset.new(:repository => Project.find(1).repository,
186 c = Changeset.new(:repository => Project.find(1).repository,
187 :committed_on => Time.now,
187 :committed_on => Time.now,
188 :comments => 'closes #5, a subproject issue',
188 :comments => 'closes #5, a subproject issue',
189 :revision => '12345')
189 :revision => '12345')
190 assert c.save
190 assert c.save
191 end
191 end
192 assert issue.reload.closed?
192 assert issue.reload.closed?
193 journal = Journal.first(:order => 'id DESC')
193 journal = Journal.first(:order => 'id DESC')
194 assert_equal issue, journal.issue
194 assert_equal issue, journal.issue
195 assert_include "Applied in changeset ecookbook:r12345.", journal.notes
195 assert_include "Applied in changeset ecookbook:r12345.", journal.notes
196 end
196 end
197 end
197 end
198
198
199 def test_commit_referencing_a_parent_project_issue
199 def test_commit_referencing_a_parent_project_issue
200 # repository of child project
200 # repository of child project
201 r = Repository::Subversion.create!(
201 r = Repository::Subversion.create!(
202 :project => Project.find(3),
202 :project => Project.find(3),
203 :url => 'svn://localhost/test')
203 :url => 'svn://localhost/test')
204 c = Changeset.new(:repository => r,
204 c = Changeset.new(:repository => r,
205 :committed_on => Time.now,
205 :committed_on => Time.now,
206 :comments => 'refs #2, an issue of a parent project',
206 :comments => 'refs #2, an issue of a parent project',
207 :revision => '12345')
207 :revision => '12345')
208 assert c.save
208 assert c.save
209 assert_equal [2], c.issue_ids.sort
209 assert_equal [2], c.issue_ids.sort
210 assert c.issues.first.project != c.project
210 assert c.issues.first.project != c.project
211 end
211 end
212
212
213 def test_commit_referencing_a_project_with_commit_cross_project_ref_disabled
213 def test_commit_referencing_a_project_with_commit_cross_project_ref_disabled
214 r = Repository::Subversion.create!(
214 r = Repository::Subversion.create!(
215 :project => Project.find(3),
215 :project => Project.find(3),
216 :url => 'svn://localhost/test')
216 :url => 'svn://localhost/test')
217
217
218 with_settings :commit_cross_project_ref => '0' do
218 with_settings :commit_cross_project_ref => '0' do
219 c = Changeset.new(:repository => r,
219 c = Changeset.new(:repository => r,
220 :committed_on => Time.now,
220 :committed_on => Time.now,
221 :comments => 'refs #4, an issue of a different project',
221 :comments => 'refs #4, an issue of a different project',
222 :revision => '12345')
222 :revision => '12345')
223 assert c.save
223 assert c.save
224 assert_equal [], c.issue_ids
224 assert_equal [], c.issue_ids
225 end
225 end
226 end
226 end
227
227
228 def test_commit_referencing_a_project_with_commit_cross_project_ref_enabled
228 def test_commit_referencing_a_project_with_commit_cross_project_ref_enabled
229 r = Repository::Subversion.create!(
229 r = Repository::Subversion.create!(
230 :project => Project.find(3),
230 :project => Project.find(3),
231 :url => 'svn://localhost/test')
231 :url => 'svn://localhost/test')
232
232
233 with_settings :commit_cross_project_ref => '1' do
233 with_settings :commit_cross_project_ref => '1' do
234 c = Changeset.new(:repository => r,
234 c = Changeset.new(:repository => r,
235 :committed_on => Time.now,
235 :committed_on => Time.now,
236 :comments => 'refs #4, an issue of a different project',
236 :comments => 'refs #4, an issue of a different project',
237 :revision => '12345')
237 :revision => '12345')
238 assert c.save
238 assert c.save
239 assert_equal [4], c.issue_ids
239 assert_equal [4], c.issue_ids
240 end
240 end
241 end
241 end
242
242
243 def test_text_tag_revision
243 def test_text_tag_revision
244 c = Changeset.new(:revision => '520')
244 c = Changeset.new(:revision => '520')
245 assert_equal 'r520', c.text_tag
245 assert_equal 'r520', c.text_tag
246 end
246 end
247
247
248 def test_text_tag_revision_with_same_project
248 def test_text_tag_revision_with_same_project
249 c = Changeset.new(:revision => '520', :repository => Project.find(1).repository)
249 c = Changeset.new(:revision => '520', :repository => Project.find(1).repository)
250 assert_equal 'r520', c.text_tag(Project.find(1))
250 assert_equal 'r520', c.text_tag(Project.find(1))
251 end
251 end
252
252
253 def test_text_tag_revision_with_different_project
253 def test_text_tag_revision_with_different_project
254 c = Changeset.new(:revision => '520', :repository => Project.find(1).repository)
254 c = Changeset.new(:revision => '520', :repository => Project.find(1).repository)
255 assert_equal 'ecookbook:r520', c.text_tag(Project.find(2))
255 assert_equal 'ecookbook:r520', c.text_tag(Project.find(2))
256 end
256 end
257
257
258 def test_text_tag_revision_with_repository_identifier
259 r = Repository::Subversion.create!(
260 :project_id => 1,
261 :url => 'svn://localhost/test',
262 :identifier => 'documents')
263
264 c = Changeset.new(:revision => '520', :repository => r)
265 assert_equal 'documents|r520', c.text_tag
266 assert_equal 'ecookbook:documents|r520', c.text_tag(Project.find(2))
267 end
268
258 def test_text_tag_hash
269 def test_text_tag_hash
259 c = Changeset.new(
270 c = Changeset.new(
260 :scmid => '7234cb2750b63f47bff735edc50a1c0a433c2518',
271 :scmid => '7234cb2750b63f47bff735edc50a1c0a433c2518',
261 :revision => '7234cb2750b63f47bff735edc50a1c0a433c2518')
272 :revision => '7234cb2750b63f47bff735edc50a1c0a433c2518')
262 assert_equal 'commit:7234cb2750b63f47bff735edc50a1c0a433c2518', c.text_tag
273 assert_equal 'commit:7234cb2750b63f47bff735edc50a1c0a433c2518', c.text_tag
263 end
274 end
264
275
265 def test_text_tag_hash_with_same_project
276 def test_text_tag_hash_with_same_project
266 c = Changeset.new(:revision => '7234cb27', :scmid => '7234cb27', :repository => Project.find(1).repository)
277 c = Changeset.new(:revision => '7234cb27', :scmid => '7234cb27', :repository => Project.find(1).repository)
267 assert_equal 'commit:7234cb27', c.text_tag(Project.find(1))
278 assert_equal 'commit:7234cb27', c.text_tag(Project.find(1))
268 end
279 end
269
280
270 def test_text_tag_hash_with_different_project
281 def test_text_tag_hash_with_different_project
271 c = Changeset.new(:revision => '7234cb27', :scmid => '7234cb27', :repository => Project.find(1).repository)
282 c = Changeset.new(:revision => '7234cb27', :scmid => '7234cb27', :repository => Project.find(1).repository)
272 assert_equal 'ecookbook:commit:7234cb27', c.text_tag(Project.find(2))
283 assert_equal 'ecookbook:commit:7234cb27', c.text_tag(Project.find(2))
273 end
284 end
274
285
275 def test_text_tag_hash_all_number
286 def test_text_tag_hash_all_number
276 c = Changeset.new(:scmid => '0123456789', :revision => '0123456789')
287 c = Changeset.new(:scmid => '0123456789', :revision => '0123456789')
277 assert_equal 'commit:0123456789', c.text_tag
288 assert_equal 'commit:0123456789', c.text_tag
278 end
289 end
279
290
280 def test_previous
291 def test_previous
281 changeset = Changeset.find_by_revision('3')
292 changeset = Changeset.find_by_revision('3')
282 assert_equal Changeset.find_by_revision('2'), changeset.previous
293 assert_equal Changeset.find_by_revision('2'), changeset.previous
283 end
294 end
284
295
285 def test_previous_nil
296 def test_previous_nil
286 changeset = Changeset.find_by_revision('1')
297 changeset = Changeset.find_by_revision('1')
287 assert_nil changeset.previous
298 assert_nil changeset.previous
288 end
299 end
289
300
290 def test_next
301 def test_next
291 changeset = Changeset.find_by_revision('2')
302 changeset = Changeset.find_by_revision('2')
292 assert_equal Changeset.find_by_revision('3'), changeset.next
303 assert_equal Changeset.find_by_revision('3'), changeset.next
293 end
304 end
294
305
295 def test_next_nil
306 def test_next_nil
296 changeset = Changeset.find_by_revision('10')
307 changeset = Changeset.find_by_revision('10')
297 assert_nil changeset.next
308 assert_nil changeset.next
298 end
309 end
299
310
300 def test_comments_should_be_converted_to_utf8
311 def test_comments_should_be_converted_to_utf8
301 proj = Project.find(3)
312 proj = Project.find(3)
302 # str = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
313 # str = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
303 str = "Texte encod\xe9 en ISO-8859-1."
314 str = "Texte encod\xe9 en ISO-8859-1."
304 str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
315 str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
305 r = Repository::Bazaar.create!(
316 r = Repository::Bazaar.create!(
306 :project => proj,
317 :project => proj,
307 :url => '/tmp/test/bazaar',
318 :url => '/tmp/test/bazaar',
308 :log_encoding => 'ISO-8859-1' )
319 :log_encoding => 'ISO-8859-1' )
309 assert r
320 assert r
310 c = Changeset.new(:repository => r,
321 c = Changeset.new(:repository => r,
311 :committed_on => Time.now,
322 :committed_on => Time.now,
312 :revision => '123',
323 :revision => '123',
313 :scmid => '12345',
324 :scmid => '12345',
314 :comments => str)
325 :comments => str)
315 assert( c.save )
326 assert( c.save )
316 str_utf8 = "Texte encod\xc3\xa9 en ISO-8859-1."
327 str_utf8 = "Texte encod\xc3\xa9 en ISO-8859-1."
317 str_utf8.force_encoding("UTF-8") if str_utf8.respond_to?(:force_encoding)
328 str_utf8.force_encoding("UTF-8") if str_utf8.respond_to?(:force_encoding)
318 assert_equal str_utf8, c.comments
329 assert_equal str_utf8, c.comments
319 end
330 end
320
331
321 def test_invalid_utf8_sequences_in_comments_should_be_replaced_latin1
332 def test_invalid_utf8_sequences_in_comments_should_be_replaced_latin1
322 proj = Project.find(3)
333 proj = Project.find(3)
323 # str = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
334 # str = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
324 str1 = "Texte encod\xe9 en ISO-8859-1."
335 str1 = "Texte encod\xe9 en ISO-8859-1."
325 str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test"
336 str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test"
326 str1.force_encoding("UTF-8") if str1.respond_to?(:force_encoding)
337 str1.force_encoding("UTF-8") if str1.respond_to?(:force_encoding)
327 str2.force_encoding("ASCII-8BIT") if str2.respond_to?(:force_encoding)
338 str2.force_encoding("ASCII-8BIT") if str2.respond_to?(:force_encoding)
328 r = Repository::Bazaar.create!(
339 r = Repository::Bazaar.create!(
329 :project => proj,
340 :project => proj,
330 :url => '/tmp/test/bazaar',
341 :url => '/tmp/test/bazaar',
331 :log_encoding => 'UTF-8' )
342 :log_encoding => 'UTF-8' )
332 assert r
343 assert r
333 c = Changeset.new(:repository => r,
344 c = Changeset.new(:repository => r,
334 :committed_on => Time.now,
345 :committed_on => Time.now,
335 :revision => '123',
346 :revision => '123',
336 :scmid => '12345',
347 :scmid => '12345',
337 :comments => str1,
348 :comments => str1,
338 :committer => str2)
349 :committer => str2)
339 assert( c.save )
350 assert( c.save )
340 assert_equal "Texte encod? en ISO-8859-1.", c.comments
351 assert_equal "Texte encod? en ISO-8859-1.", c.comments
341 assert_equal "?a?b?c?d?e test", c.committer
352 assert_equal "?a?b?c?d?e test", c.committer
342 end
353 end
343
354
344 def test_invalid_utf8_sequences_in_comments_should_be_replaced_ja_jis
355 def test_invalid_utf8_sequences_in_comments_should_be_replaced_ja_jis
345 proj = Project.find(3)
356 proj = Project.find(3)
346 str = "test\xb5\xfetest\xb5\xfe"
357 str = "test\xb5\xfetest\xb5\xfe"
347 if str.respond_to?(:force_encoding)
358 if str.respond_to?(:force_encoding)
348 str.force_encoding('ASCII-8BIT')
359 str.force_encoding('ASCII-8BIT')
349 end
360 end
350 r = Repository::Bazaar.create!(
361 r = Repository::Bazaar.create!(
351 :project => proj,
362 :project => proj,
352 :url => '/tmp/test/bazaar',
363 :url => '/tmp/test/bazaar',
353 :log_encoding => 'ISO-2022-JP' )
364 :log_encoding => 'ISO-2022-JP' )
354 assert r
365 assert r
355 c = Changeset.new(:repository => r,
366 c = Changeset.new(:repository => r,
356 :committed_on => Time.now,
367 :committed_on => Time.now,
357 :revision => '123',
368 :revision => '123',
358 :scmid => '12345',
369 :scmid => '12345',
359 :comments => str)
370 :comments => str)
360 assert( c.save )
371 assert( c.save )
361 assert_equal "test??test??", c.comments
372 assert_equal "test??test??", c.comments
362 end
373 end
363
374
364 def test_comments_should_be_converted_all_latin1_to_utf8
375 def test_comments_should_be_converted_all_latin1_to_utf8
365 s1 = "\xC2\x80"
376 s1 = "\xC2\x80"
366 s2 = "\xc3\x82\xc2\x80"
377 s2 = "\xc3\x82\xc2\x80"
367 s4 = s2.dup
378 s4 = s2.dup
368 if s1.respond_to?(:force_encoding)
379 if s1.respond_to?(:force_encoding)
369 s3 = s1.dup
380 s3 = s1.dup
370 s1.force_encoding('ASCII-8BIT')
381 s1.force_encoding('ASCII-8BIT')
371 s2.force_encoding('ASCII-8BIT')
382 s2.force_encoding('ASCII-8BIT')
372 s3.force_encoding('ISO-8859-1')
383 s3.force_encoding('ISO-8859-1')
373 s4.force_encoding('UTF-8')
384 s4.force_encoding('UTF-8')
374 assert_equal s3.encode('UTF-8'), s4
385 assert_equal s3.encode('UTF-8'), s4
375 end
386 end
376 proj = Project.find(3)
387 proj = Project.find(3)
377 r = Repository::Bazaar.create!(
388 r = Repository::Bazaar.create!(
378 :project => proj,
389 :project => proj,
379 :url => '/tmp/test/bazaar',
390 :url => '/tmp/test/bazaar',
380 :log_encoding => 'ISO-8859-1' )
391 :log_encoding => 'ISO-8859-1' )
381 assert r
392 assert r
382 c = Changeset.new(:repository => r,
393 c = Changeset.new(:repository => r,
383 :committed_on => Time.now,
394 :committed_on => Time.now,
384 :revision => '123',
395 :revision => '123',
385 :scmid => '12345',
396 :scmid => '12345',
386 :comments => s1)
397 :comments => s1)
387 assert( c.save )
398 assert( c.save )
388 assert_equal s4, c.comments
399 assert_equal s4, c.comments
389 end
400 end
390
401
391 def test_invalid_utf8_sequences_in_paths_should_be_replaced
402 def test_invalid_utf8_sequences_in_paths_should_be_replaced
392 proj = Project.find(3)
403 proj = Project.find(3)
393 str1 = "Texte encod\xe9 en ISO-8859-1"
404 str1 = "Texte encod\xe9 en ISO-8859-1"
394 str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test"
405 str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test"
395 str1.force_encoding("UTF-8") if str1.respond_to?(:force_encoding)
406 str1.force_encoding("UTF-8") if str1.respond_to?(:force_encoding)
396 str2.force_encoding("ASCII-8BIT") if str2.respond_to?(:force_encoding)
407 str2.force_encoding("ASCII-8BIT") if str2.respond_to?(:force_encoding)
397 r = Repository::Bazaar.create!(
408 r = Repository::Bazaar.create!(
398 :project => proj,
409 :project => proj,
399 :url => '/tmp/test/bazaar',
410 :url => '/tmp/test/bazaar',
400 :log_encoding => 'UTF-8' )
411 :log_encoding => 'UTF-8' )
401 assert r
412 assert r
402 cs = Changeset.new(
413 cs = Changeset.new(
403 :repository => r,
414 :repository => r,
404 :committed_on => Time.now,
415 :committed_on => Time.now,
405 :revision => '123',
416 :revision => '123',
406 :scmid => '12345',
417 :scmid => '12345',
407 :comments => "test")
418 :comments => "test")
408 assert(cs.save)
419 assert(cs.save)
409 ch = Change.new(
420 ch = Change.new(
410 :changeset => cs,
421 :changeset => cs,
411 :action => "A",
422 :action => "A",
412 :path => str1,
423 :path => str1,
413 :from_path => str2,
424 :from_path => str2,
414 :from_revision => "345")
425 :from_revision => "345")
415 assert(ch.save)
426 assert(ch.save)
416 assert_equal "Texte encod? en ISO-8859-1", ch.path
427 assert_equal "Texte encod? en ISO-8859-1", ch.path
417 assert_equal "?a?b?c?d?e test", ch.from_path
428 assert_equal "?a?b?c?d?e test", ch.from_path
418 end
429 end
419
430
420 def test_comments_nil
431 def test_comments_nil
421 proj = Project.find(3)
432 proj = Project.find(3)
422 r = Repository::Bazaar.create!(
433 r = Repository::Bazaar.create!(
423 :project => proj,
434 :project => proj,
424 :url => '/tmp/test/bazaar',
435 :url => '/tmp/test/bazaar',
425 :log_encoding => 'ISO-8859-1' )
436 :log_encoding => 'ISO-8859-1' )
426 assert r
437 assert r
427 c = Changeset.new(:repository => r,
438 c = Changeset.new(:repository => r,
428 :committed_on => Time.now,
439 :committed_on => Time.now,
429 :revision => '123',
440 :revision => '123',
430 :scmid => '12345',
441 :scmid => '12345',
431 :comments => nil,
442 :comments => nil,
432 :committer => nil)
443 :committer => nil)
433 assert( c.save )
444 assert( c.save )
434 assert_equal "", c.comments
445 assert_equal "", c.comments
435 assert_equal nil, c.committer
446 assert_equal nil, c.committer
436 if c.comments.respond_to?(:force_encoding)
447 if c.comments.respond_to?(:force_encoding)
437 assert_equal "UTF-8", c.comments.encoding.to_s
448 assert_equal "UTF-8", c.comments.encoding.to_s
438 end
449 end
439 end
450 end
440
451
441 def test_comments_empty
452 def test_comments_empty
442 proj = Project.find(3)
453 proj = Project.find(3)
443 r = Repository::Bazaar.create!(
454 r = Repository::Bazaar.create!(
444 :project => proj,
455 :project => proj,
445 :url => '/tmp/test/bazaar',
456 :url => '/tmp/test/bazaar',
446 :log_encoding => 'ISO-8859-1' )
457 :log_encoding => 'ISO-8859-1' )
447 assert r
458 assert r
448 c = Changeset.new(:repository => r,
459 c = Changeset.new(:repository => r,
449 :committed_on => Time.now,
460 :committed_on => Time.now,
450 :revision => '123',
461 :revision => '123',
451 :scmid => '12345',
462 :scmid => '12345',
452 :comments => "",
463 :comments => "",
453 :committer => "")
464 :committer => "")
454 assert( c.save )
465 assert( c.save )
455 assert_equal "", c.comments
466 assert_equal "", c.comments
456 assert_equal "", c.committer
467 assert_equal "", c.committer
457 if c.comments.respond_to?(:force_encoding)
468 if c.comments.respond_to?(:force_encoding)
458 assert_equal "UTF-8", c.comments.encoding.to_s
469 assert_equal "UTF-8", c.comments.encoding.to_s
459 assert_equal "UTF-8", c.committer.encoding.to_s
470 assert_equal "UTF-8", c.committer.encoding.to_s
460 end
471 end
461 end
472 end
462
473
463 def test_identifier
474 def test_identifier
464 c = Changeset.find_by_revision('1')
475 c = Changeset.find_by_revision('1')
465 assert_equal c.revision, c.identifier
476 assert_equal c.revision, c.identifier
466 end
477 end
467 end
478 end
General Comments 0
You need to be logged in to leave comments. Login now