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