##// END OF EJS Templates
Renamed #changes association to #filechanges (clash with AR::Base.changes that triggers errors with Rails 3.2.5)....
Jean-Philippe Lang -
r9576:2cbf9c9cc481
parent child
Show More
@@ -1,318 +1,318
1 # encoding: utf-8
1 # encoding: utf-8
2 #
2 #
3 # Redmine - project management software
3 # Redmine - project management software
4 # Copyright (C) 2006-2012 Jean-Philippe Lang
4 # Copyright (C) 2006-2012 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 'iconv'
20 require 'iconv'
21 require 'redmine/codeset_util'
21 require 'redmine/codeset_util'
22
22
23 module RepositoriesHelper
23 module RepositoriesHelper
24 def format_revision(revision)
24 def format_revision(revision)
25 if revision.respond_to? :format_identifier
25 if revision.respond_to? :format_identifier
26 revision.format_identifier
26 revision.format_identifier
27 else
27 else
28 revision.to_s
28 revision.to_s
29 end
29 end
30 end
30 end
31
31
32 def truncate_at_line_break(text, length = 255)
32 def truncate_at_line_break(text, length = 255)
33 if text
33 if text
34 text.gsub(%r{^(.{#{length}}[^\n]*)\n.+$}m, '\\1...')
34 text.gsub(%r{^(.{#{length}}[^\n]*)\n.+$}m, '\\1...')
35 end
35 end
36 end
36 end
37
37
38 def render_properties(properties)
38 def render_properties(properties)
39 unless properties.nil? || properties.empty?
39 unless properties.nil? || properties.empty?
40 content = ''
40 content = ''
41 properties.keys.sort.each do |property|
41 properties.keys.sort.each do |property|
42 content << content_tag('li', "<b>#{h property}</b>: <span>#{h properties[property]}</span>".html_safe)
42 content << content_tag('li', "<b>#{h property}</b>: <span>#{h properties[property]}</span>".html_safe)
43 end
43 end
44 content_tag('ul', content.html_safe, :class => 'properties')
44 content_tag('ul', content.html_safe, :class => 'properties')
45 end
45 end
46 end
46 end
47
47
48 def render_changeset_changes
48 def render_changeset_changes
49 changes = @changeset.changes.find(:all, :limit => 1000, :order => 'path').collect do |change|
49 changes = @changeset.filechanges.find(:all, :limit => 1000, :order => 'path').collect do |change|
50 case change.action
50 case change.action
51 when 'A'
51 when 'A'
52 # Detects moved/copied files
52 # Detects moved/copied files
53 if !change.from_path.blank?
53 if !change.from_path.blank?
54 change.action =
54 change.action =
55 @changeset.changes.detect {|c| c.action == 'D' && c.path == change.from_path} ? 'R' : 'C'
55 @changeset.filechanges.detect {|c| c.action == 'D' && c.path == change.from_path} ? 'R' : 'C'
56 end
56 end
57 change
57 change
58 when 'D'
58 when 'D'
59 @changeset.changes.detect {|c| c.from_path == change.path} ? nil : change
59 @changeset.filechanges.detect {|c| c.from_path == change.path} ? nil : change
60 else
60 else
61 change
61 change
62 end
62 end
63 end.compact
63 end.compact
64
64
65 tree = { }
65 tree = { }
66 changes.each do |change|
66 changes.each do |change|
67 p = tree
67 p = tree
68 dirs = change.path.to_s.split('/').select {|d| !d.blank?}
68 dirs = change.path.to_s.split('/').select {|d| !d.blank?}
69 path = ''
69 path = ''
70 dirs.each do |dir|
70 dirs.each do |dir|
71 path += '/' + dir
71 path += '/' + dir
72 p[:s] ||= {}
72 p[:s] ||= {}
73 p = p[:s]
73 p = p[:s]
74 p[path] ||= {}
74 p[path] ||= {}
75 p = p[path]
75 p = p[path]
76 end
76 end
77 p[:c] = change
77 p[:c] = change
78 end
78 end
79 render_changes_tree(tree[:s])
79 render_changes_tree(tree[:s])
80 end
80 end
81
81
82 def render_changes_tree(tree)
82 def render_changes_tree(tree)
83 return '' if tree.nil?
83 return '' if tree.nil?
84 output = ''
84 output = ''
85 output << '<ul>'
85 output << '<ul>'
86 tree.keys.sort.each do |file|
86 tree.keys.sort.each do |file|
87 style = 'change'
87 style = 'change'
88 text = File.basename(h(file))
88 text = File.basename(h(file))
89 if s = tree[file][:s]
89 if s = tree[file][:s]
90 style << ' folder'
90 style << ' folder'
91 path_param = to_path_param(@repository.relative_path(file))
91 path_param = to_path_param(@repository.relative_path(file))
92 text = link_to(h(text), :controller => 'repositories',
92 text = link_to(h(text), :controller => 'repositories',
93 :action => 'show',
93 :action => 'show',
94 :id => @project,
94 :id => @project,
95 :repository_id => @repository.identifier_param,
95 :repository_id => @repository.identifier_param,
96 :path => path_param,
96 :path => path_param,
97 :rev => @changeset.identifier)
97 :rev => @changeset.identifier)
98 output << "<li class='#{style}'>#{text}"
98 output << "<li class='#{style}'>#{text}"
99 output << render_changes_tree(s)
99 output << render_changes_tree(s)
100 output << "</li>"
100 output << "</li>"
101 elsif c = tree[file][:c]
101 elsif c = tree[file][:c]
102 style << " change-#{c.action}"
102 style << " change-#{c.action}"
103 path_param = to_path_param(@repository.relative_path(c.path))
103 path_param = to_path_param(@repository.relative_path(c.path))
104 text = link_to(h(text), :controller => 'repositories',
104 text = link_to(h(text), :controller => 'repositories',
105 :action => 'entry',
105 :action => 'entry',
106 :id => @project,
106 :id => @project,
107 :repository_id => @repository.identifier_param,
107 :repository_id => @repository.identifier_param,
108 :path => path_param,
108 :path => path_param,
109 :rev => @changeset.identifier) unless c.action == 'D'
109 :rev => @changeset.identifier) unless c.action == 'D'
110 text << " - #{h(c.revision)}" unless c.revision.blank?
110 text << " - #{h(c.revision)}" unless c.revision.blank?
111 text << ' ('.html_safe + link_to(l(:label_diff), :controller => 'repositories',
111 text << ' ('.html_safe + link_to(l(:label_diff), :controller => 'repositories',
112 :action => 'diff',
112 :action => 'diff',
113 :id => @project,
113 :id => @project,
114 :repository_id => @repository.identifier_param,
114 :repository_id => @repository.identifier_param,
115 :path => path_param,
115 :path => path_param,
116 :rev => @changeset.identifier) + ') '.html_safe if c.action == 'M'
116 :rev => @changeset.identifier) + ') '.html_safe if c.action == 'M'
117 text << ' '.html_safe + content_tag('span', h(c.from_path), :class => 'copied-from') unless c.from_path.blank?
117 text << ' '.html_safe + content_tag('span', h(c.from_path), :class => 'copied-from') unless c.from_path.blank?
118 output << "<li class='#{style}'>#{text}</li>"
118 output << "<li class='#{style}'>#{text}</li>"
119 end
119 end
120 end
120 end
121 output << '</ul>'
121 output << '</ul>'
122 output.html_safe
122 output.html_safe
123 end
123 end
124
124
125 def repository_field_tags(form, repository)
125 def repository_field_tags(form, repository)
126 method = repository.class.name.demodulize.underscore + "_field_tags"
126 method = repository.class.name.demodulize.underscore + "_field_tags"
127 if repository.is_a?(Repository) &&
127 if repository.is_a?(Repository) &&
128 respond_to?(method) && method != 'repository_field_tags'
128 respond_to?(method) && method != 'repository_field_tags'
129 send(method, form, repository)
129 send(method, form, repository)
130 end
130 end
131 end
131 end
132
132
133 def scm_select_tag(repository)
133 def scm_select_tag(repository)
134 scm_options = [["--- #{l(:actionview_instancetag_blank_option)} ---", '']]
134 scm_options = [["--- #{l(:actionview_instancetag_blank_option)} ---", '']]
135 Redmine::Scm::Base.all.each do |scm|
135 Redmine::Scm::Base.all.each do |scm|
136 if Setting.enabled_scm.include?(scm) ||
136 if Setting.enabled_scm.include?(scm) ||
137 (repository && repository.class.name.demodulize == scm)
137 (repository && repository.class.name.demodulize == scm)
138 scm_options << ["Repository::#{scm}".constantize.scm_name, scm]
138 scm_options << ["Repository::#{scm}".constantize.scm_name, scm]
139 end
139 end
140 end
140 end
141 select_tag('repository_scm',
141 select_tag('repository_scm',
142 options_for_select(scm_options, repository.class.name.demodulize),
142 options_for_select(scm_options, repository.class.name.demodulize),
143 :disabled => (repository && !repository.new_record?),
143 :disabled => (repository && !repository.new_record?),
144 :onchange => remote_function(
144 :onchange => remote_function(
145 :url => new_project_repository_path(@project),
145 :url => new_project_repository_path(@project),
146 :method => :get,
146 :method => :get,
147 :update => 'content',
147 :update => 'content',
148 :with => "Form.serialize(this.form)")
148 :with => "Form.serialize(this.form)")
149 )
149 )
150 end
150 end
151
151
152 def with_leading_slash(path)
152 def with_leading_slash(path)
153 path.to_s.starts_with?('/') ? path : "/#{path}"
153 path.to_s.starts_with?('/') ? path : "/#{path}"
154 end
154 end
155
155
156 def without_leading_slash(path)
156 def without_leading_slash(path)
157 path.gsub(%r{^/+}, '')
157 path.gsub(%r{^/+}, '')
158 end
158 end
159
159
160 def subversion_field_tags(form, repository)
160 def subversion_field_tags(form, repository)
161 content_tag('p', form.text_field(:url, :size => 60, :required => true,
161 content_tag('p', form.text_field(:url, :size => 60, :required => true,
162 :disabled => (repository && !repository.root_url.blank?)) +
162 :disabled => (repository && !repository.root_url.blank?)) +
163 '<br />'.html_safe +
163 '<br />'.html_safe +
164 '(file:///, http://, https://, svn://, svn+[tunnelscheme]://)') +
164 '(file:///, http://, https://, svn://, svn+[tunnelscheme]://)') +
165 content_tag('p', form.text_field(:login, :size => 30)) +
165 content_tag('p', form.text_field(:login, :size => 30)) +
166 content_tag('p', form.password_field(
166 content_tag('p', form.password_field(
167 :password, :size => 30, :name => 'ignore',
167 :password, :size => 30, :name => 'ignore',
168 :value => ((repository.new_record? || repository.password.blank?) ? '' : ('x'*15)),
168 :value => ((repository.new_record? || repository.password.blank?) ? '' : ('x'*15)),
169 :onfocus => "this.value=''; this.name='repository[password]';",
169 :onfocus => "this.value=''; this.name='repository[password]';",
170 :onchange => "this.name='repository[password]';"))
170 :onchange => "this.name='repository[password]';"))
171 end
171 end
172
172
173 def darcs_field_tags(form, repository)
173 def darcs_field_tags(form, repository)
174 content_tag('p', form.text_field(
174 content_tag('p', form.text_field(
175 :url, :label => l(:field_path_to_repository),
175 :url, :label => l(:field_path_to_repository),
176 :size => 60, :required => true,
176 :size => 60, :required => true,
177 :disabled => (repository && !repository.new_record?))) +
177 :disabled => (repository && !repository.new_record?))) +
178 content_tag('p', form.select(
178 content_tag('p', form.select(
179 :log_encoding, [nil] + Setting::ENCODINGS,
179 :log_encoding, [nil] + Setting::ENCODINGS,
180 :label => l(:field_commit_logs_encoding), :required => true))
180 :label => l(:field_commit_logs_encoding), :required => true))
181 end
181 end
182
182
183 def mercurial_field_tags(form, repository)
183 def mercurial_field_tags(form, repository)
184 content_tag('p', form.text_field(
184 content_tag('p', form.text_field(
185 :url, :label => l(:field_path_to_repository),
185 :url, :label => l(:field_path_to_repository),
186 :size => 60, :required => true,
186 :size => 60, :required => true,
187 :disabled => (repository && !repository.root_url.blank?)
187 :disabled => (repository && !repository.root_url.blank?)
188 ) +
188 ) +
189 '<br />'.html_safe + l(:text_mercurial_repository_note)) +
189 '<br />'.html_safe + l(:text_mercurial_repository_note)) +
190 content_tag('p', form.select(
190 content_tag('p', form.select(
191 :path_encoding, [nil] + Setting::ENCODINGS,
191 :path_encoding, [nil] + Setting::ENCODINGS,
192 :label => l(:field_scm_path_encoding)
192 :label => l(:field_scm_path_encoding)
193 ) +
193 ) +
194 '<br />'.html_safe + l(:text_scm_path_encoding_note))
194 '<br />'.html_safe + l(:text_scm_path_encoding_note))
195 end
195 end
196
196
197 def git_field_tags(form, repository)
197 def git_field_tags(form, repository)
198 content_tag('p', form.text_field(
198 content_tag('p', form.text_field(
199 :url, :label => l(:field_path_to_repository),
199 :url, :label => l(:field_path_to_repository),
200 :size => 60, :required => true,
200 :size => 60, :required => true,
201 :disabled => (repository && !repository.root_url.blank?)
201 :disabled => (repository && !repository.root_url.blank?)
202 ) +
202 ) +
203 '<br />'.html_safe +
203 '<br />'.html_safe +
204 l(:text_git_repository_note)) +
204 l(:text_git_repository_note)) +
205 content_tag('p', form.select(
205 content_tag('p', form.select(
206 :path_encoding, [nil] + Setting::ENCODINGS,
206 :path_encoding, [nil] + Setting::ENCODINGS,
207 :label => l(:field_scm_path_encoding)
207 :label => l(:field_scm_path_encoding)
208 ) +
208 ) +
209 '<br />'.html_safe + l(:text_scm_path_encoding_note)) +
209 '<br />'.html_safe + l(:text_scm_path_encoding_note)) +
210 content_tag('p', form.check_box(
210 content_tag('p', form.check_box(
211 :extra_report_last_commit,
211 :extra_report_last_commit,
212 :label => l(:label_git_report_last_commit)
212 :label => l(:label_git_report_last_commit)
213 ))
213 ))
214 end
214 end
215
215
216 def cvs_field_tags(form, repository)
216 def cvs_field_tags(form, repository)
217 content_tag('p', form.text_field(
217 content_tag('p', form.text_field(
218 :root_url,
218 :root_url,
219 :label => l(:field_cvsroot),
219 :label => l(:field_cvsroot),
220 :size => 60, :required => true,
220 :size => 60, :required => true,
221 :disabled => !repository.new_record?)) +
221 :disabled => !repository.new_record?)) +
222 content_tag('p', form.text_field(
222 content_tag('p', form.text_field(
223 :url,
223 :url,
224 :label => l(:field_cvs_module),
224 :label => l(:field_cvs_module),
225 :size => 30, :required => true,
225 :size => 30, :required => true,
226 :disabled => !repository.new_record?)) +
226 :disabled => !repository.new_record?)) +
227 content_tag('p', form.select(
227 content_tag('p', form.select(
228 :log_encoding, [nil] + Setting::ENCODINGS,
228 :log_encoding, [nil] + Setting::ENCODINGS,
229 :label => l(:field_commit_logs_encoding), :required => true)) +
229 :label => l(:field_commit_logs_encoding), :required => true)) +
230 content_tag('p', form.select(
230 content_tag('p', form.select(
231 :path_encoding, [nil] + Setting::ENCODINGS,
231 :path_encoding, [nil] + Setting::ENCODINGS,
232 :label => l(:field_scm_path_encoding)
232 :label => l(:field_scm_path_encoding)
233 ) +
233 ) +
234 '<br />'.html_safe + l(:text_scm_path_encoding_note))
234 '<br />'.html_safe + l(:text_scm_path_encoding_note))
235 end
235 end
236
236
237 def bazaar_field_tags(form, repository)
237 def bazaar_field_tags(form, repository)
238 content_tag('p', form.text_field(
238 content_tag('p', form.text_field(
239 :url, :label => l(:field_path_to_repository),
239 :url, :label => l(:field_path_to_repository),
240 :size => 60, :required => true,
240 :size => 60, :required => true,
241 :disabled => (repository && !repository.new_record?))) +
241 :disabled => (repository && !repository.new_record?))) +
242 content_tag('p', form.select(
242 content_tag('p', form.select(
243 :log_encoding, [nil] + Setting::ENCODINGS,
243 :log_encoding, [nil] + Setting::ENCODINGS,
244 :label => l(:field_commit_logs_encoding), :required => true))
244 :label => l(:field_commit_logs_encoding), :required => true))
245 end
245 end
246
246
247 def filesystem_field_tags(form, repository)
247 def filesystem_field_tags(form, repository)
248 content_tag('p', form.text_field(
248 content_tag('p', form.text_field(
249 :url, :label => l(:field_root_directory),
249 :url, :label => l(:field_root_directory),
250 :size => 60, :required => true,
250 :size => 60, :required => true,
251 :disabled => (repository && !repository.root_url.blank?))) +
251 :disabled => (repository && !repository.root_url.blank?))) +
252 content_tag('p', form.select(
252 content_tag('p', form.select(
253 :path_encoding, [nil] + Setting::ENCODINGS,
253 :path_encoding, [nil] + Setting::ENCODINGS,
254 :label => l(:field_scm_path_encoding)
254 :label => l(:field_scm_path_encoding)
255 ) +
255 ) +
256 '<br />'.html_safe + l(:text_scm_path_encoding_note))
256 '<br />'.html_safe + l(:text_scm_path_encoding_note))
257 end
257 end
258
258
259 def index_commits(commits, heads)
259 def index_commits(commits, heads)
260 return nil if commits.nil? or commits.first.parents.nil?
260 return nil if commits.nil? or commits.first.parents.nil?
261
261
262 refs_map = {}
262 refs_map = {}
263 heads.each do |head|
263 heads.each do |head|
264 refs_map[head.scmid] ||= []
264 refs_map[head.scmid] ||= []
265 refs_map[head.scmid] << head
265 refs_map[head.scmid] << head
266 end
266 end
267
267
268 commits_by_scmid = {}
268 commits_by_scmid = {}
269 commits.reverse.each_with_index do |commit, commit_index|
269 commits.reverse.each_with_index do |commit, commit_index|
270
270
271 commits_by_scmid[commit.scmid] = {
271 commits_by_scmid[commit.scmid] = {
272 :parent_scmids => commit.parents.collect { |parent| parent.scmid },
272 :parent_scmids => commit.parents.collect { |parent| parent.scmid },
273 :rdmid => commit_index,
273 :rdmid => commit_index,
274 :refs => refs_map.include?(commit.scmid) ? refs_map[commit.scmid].join(" ") : nil,
274 :refs => refs_map.include?(commit.scmid) ? refs_map[commit.scmid].join(" ") : nil,
275 :scmid => commit.scmid,
275 :scmid => commit.scmid,
276 :href => block_given? ? yield(commit.scmid) : commit.scmid
276 :href => block_given? ? yield(commit.scmid) : commit.scmid
277 }
277 }
278 end
278 end
279
279
280 heads.sort! { |head1, head2| head1.to_s <=> head2.to_s }
280 heads.sort! { |head1, head2| head1.to_s <=> head2.to_s }
281
281
282 space = nil
282 space = nil
283 heads.each do |head|
283 heads.each do |head|
284 if commits_by_scmid.include? head.scmid
284 if commits_by_scmid.include? head.scmid
285 space = index_head((space || -1) + 1, head, commits_by_scmid)
285 space = index_head((space || -1) + 1, head, commits_by_scmid)
286 end
286 end
287 end
287 end
288
288
289 # when no head matched anything use first commit
289 # when no head matched anything use first commit
290 space ||= index_head(0, commits.first, commits_by_scmid)
290 space ||= index_head(0, commits.first, commits_by_scmid)
291
291
292 return commits_by_scmid, space
292 return commits_by_scmid, space
293 end
293 end
294
294
295 def index_head(space, commit, commits_by_scmid)
295 def index_head(space, commit, commits_by_scmid)
296
296
297 stack = [[space, commits_by_scmid[commit.scmid]]]
297 stack = [[space, commits_by_scmid[commit.scmid]]]
298 max_space = space
298 max_space = space
299
299
300 until stack.empty?
300 until stack.empty?
301 space, commit = stack.pop
301 space, commit = stack.pop
302 commit[:space] = space if commit[:space].nil?
302 commit[:space] = space if commit[:space].nil?
303
303
304 space -= 1
304 space -= 1
305 commit[:parent_scmids].each_with_index do |parent_scmid, parent_index|
305 commit[:parent_scmids].each_with_index do |parent_scmid, parent_index|
306
306
307 parent_commit = commits_by_scmid[parent_scmid]
307 parent_commit = commits_by_scmid[parent_scmid]
308
308
309 if parent_commit and parent_commit[:space].nil?
309 if parent_commit and parent_commit[:space].nil?
310
310
311 stack.unshift [space += 1, parent_commit]
311 stack.unshift [space += 1, parent_commit]
312 end
312 end
313 end
313 end
314 max_space = space if max_space < space
314 max_space = space if max_space < space
315 end
315 end
316 max_space
316 max_space
317 end
317 end
318 end
318 end
@@ -1,286 +1,286
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 :filechanges, :class_name => 'Change', :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| o.title},
34 acts_as_event :title => Proc.new {|o| o.title},
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 scope :visible,
52 scope :visible,
53 lambda {|*args| { :include => {:repository => :project},
53 lambda {|*args| { :include => {:repository => :project},
54 :conditions => Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args) } }
54 :conditions => Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args) } }
55
55
56 after_create :scan_for_issues
56 after_create :scan_for_issues
57 before_create :before_create_cs
57 before_create :before_create_cs
58
58
59 def revision=(r)
59 def revision=(r)
60 write_attribute :revision, (r.nil? ? nil : r.to_s)
60 write_attribute :revision, (r.nil? ? nil : r.to_s)
61 end
61 end
62
62
63 # Returns the identifier of this changeset; depending on repository backends
63 # Returns the identifier of this changeset; depending on repository backends
64 def identifier
64 def identifier
65 if repository.class.respond_to? :changeset_identifier
65 if repository.class.respond_to? :changeset_identifier
66 repository.class.changeset_identifier self
66 repository.class.changeset_identifier self
67 else
67 else
68 revision.to_s
68 revision.to_s
69 end
69 end
70 end
70 end
71
71
72 def committed_on=(date)
72 def committed_on=(date)
73 self.commit_date = date
73 self.commit_date = date
74 super
74 super
75 end
75 end
76
76
77 # Returns the readable identifier
77 # Returns the readable identifier
78 def format_identifier
78 def format_identifier
79 if repository.class.respond_to? :format_changeset_identifier
79 if repository.class.respond_to? :format_changeset_identifier
80 repository.class.format_changeset_identifier self
80 repository.class.format_changeset_identifier self
81 else
81 else
82 identifier
82 identifier
83 end
83 end
84 end
84 end
85
85
86 def project
86 def project
87 repository.project
87 repository.project
88 end
88 end
89
89
90 def author
90 def author
91 user || committer.to_s.split('<').first
91 user || committer.to_s.split('<').first
92 end
92 end
93
93
94 def before_create_cs
94 def before_create_cs
95 self.committer = self.class.to_utf8(self.committer, repository.repo_log_encoding)
95 self.committer = self.class.to_utf8(self.committer, repository.repo_log_encoding)
96 self.comments = self.class.normalize_comments(
96 self.comments = self.class.normalize_comments(
97 self.comments, repository.repo_log_encoding)
97 self.comments, repository.repo_log_encoding)
98 self.user = repository.find_committer_user(self.committer)
98 self.user = repository.find_committer_user(self.committer)
99 end
99 end
100
100
101 def scan_for_issues
101 def scan_for_issues
102 scan_comment_for_issue_ids
102 scan_comment_for_issue_ids
103 end
103 end
104
104
105 TIMELOG_RE = /
105 TIMELOG_RE = /
106 (
106 (
107 ((\d+)(h|hours?))((\d+)(m|min)?)?
107 ((\d+)(h|hours?))((\d+)(m|min)?)?
108 |
108 |
109 ((\d+)(h|hours?|m|min))
109 ((\d+)(h|hours?|m|min))
110 |
110 |
111 (\d+):(\d+)
111 (\d+):(\d+)
112 |
112 |
113 (\d+([\.,]\d+)?)h?
113 (\d+([\.,]\d+)?)h?
114 )
114 )
115 /x
115 /x
116
116
117 def scan_comment_for_issue_ids
117 def scan_comment_for_issue_ids
118 return if comments.blank?
118 return if comments.blank?
119 # keywords used to reference issues
119 # keywords used to reference issues
120 ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip)
120 ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip)
121 ref_keywords_any = ref_keywords.delete('*')
121 ref_keywords_any = ref_keywords.delete('*')
122 # keywords used to fix issues
122 # keywords used to fix issues
123 fix_keywords = Setting.commit_fix_keywords.downcase.split(",").collect(&:strip)
123 fix_keywords = Setting.commit_fix_keywords.downcase.split(",").collect(&:strip)
124
124
125 kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|")
125 kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|")
126
126
127 referenced_issues = []
127 referenced_issues = []
128
128
129 comments.scan(/([\s\(\[,-]|^)((#{kw_regexp})[\s:]+)?(#\d+(\s+@#{TIMELOG_RE})?([\s,;&]+#\d+(\s+@#{TIMELOG_RE})?)*)(?=[[:punct:]]|\s|<|$)/i) do |match|
129 comments.scan(/([\s\(\[,-]|^)((#{kw_regexp})[\s:]+)?(#\d+(\s+@#{TIMELOG_RE})?([\s,;&]+#\d+(\s+@#{TIMELOG_RE})?)*)(?=[[:punct:]]|\s|<|$)/i) do |match|
130 action, refs = match[2], match[3]
130 action, refs = match[2], match[3]
131 next unless action.present? || ref_keywords_any
131 next unless action.present? || ref_keywords_any
132
132
133 refs.scan(/#(\d+)(\s+@#{TIMELOG_RE})?/).each do |m|
133 refs.scan(/#(\d+)(\s+@#{TIMELOG_RE})?/).each do |m|
134 issue, hours = find_referenced_issue_by_id(m[0].to_i), m[2]
134 issue, hours = find_referenced_issue_by_id(m[0].to_i), m[2]
135 if issue
135 if issue
136 referenced_issues << issue
136 referenced_issues << issue
137 fix_issue(issue) if fix_keywords.include?(action.to_s.downcase)
137 fix_issue(issue) if fix_keywords.include?(action.to_s.downcase)
138 log_time(issue, hours) if hours && Setting.commit_logtime_enabled?
138 log_time(issue, hours) if hours && Setting.commit_logtime_enabled?
139 end
139 end
140 end
140 end
141 end
141 end
142
142
143 referenced_issues.uniq!
143 referenced_issues.uniq!
144 self.issues = referenced_issues unless referenced_issues.empty?
144 self.issues = referenced_issues unless referenced_issues.empty?
145 end
145 end
146
146
147 def short_comments
147 def short_comments
148 @short_comments || split_comments.first
148 @short_comments || split_comments.first
149 end
149 end
150
150
151 def long_comments
151 def long_comments
152 @long_comments || split_comments.last
152 @long_comments || split_comments.last
153 end
153 end
154
154
155 def text_tag(ref_project=nil)
155 def text_tag(ref_project=nil)
156 tag = if scmid?
156 tag = if scmid?
157 "commit:#{scmid}"
157 "commit:#{scmid}"
158 else
158 else
159 "r#{revision}"
159 "r#{revision}"
160 end
160 end
161 if repository && repository.identifier.present?
161 if repository && repository.identifier.present?
162 tag = "#{repository.identifier}|#{tag}"
162 tag = "#{repository.identifier}|#{tag}"
163 end
163 end
164 if ref_project && project && ref_project != project
164 if ref_project && project && ref_project != project
165 tag = "#{project.identifier}:#{tag}"
165 tag = "#{project.identifier}:#{tag}"
166 end
166 end
167 tag
167 tag
168 end
168 end
169
169
170 # Returns the title used for the changeset in the activity/search results
170 # Returns the title used for the changeset in the activity/search results
171 def title
171 def title
172 repo = (repository && repository.identifier.present?) ? " (#{repository.identifier})" : ''
172 repo = (repository && repository.identifier.present?) ? " (#{repository.identifier})" : ''
173 comm = short_comments.blank? ? '' : (': ' + short_comments)
173 comm = short_comments.blank? ? '' : (': ' + short_comments)
174 "#{l(:label_revision)} #{format_identifier}#{repo}#{comm}"
174 "#{l(:label_revision)} #{format_identifier}#{repo}#{comm}"
175 end
175 end
176
176
177 # Returns the previous changeset
177 # Returns the previous changeset
178 def previous
178 def previous
179 @previous ||= Changeset.find(:first,
179 @previous ||= Changeset.find(:first,
180 :conditions => ['id < ? AND repository_id = ?',
180 :conditions => ['id < ? AND repository_id = ?',
181 self.id, self.repository_id],
181 self.id, self.repository_id],
182 :order => 'id DESC')
182 :order => 'id DESC')
183 end
183 end
184
184
185 # Returns the next changeset
185 # Returns the next changeset
186 def next
186 def next
187 @next ||= Changeset.find(:first,
187 @next ||= Changeset.find(:first,
188 :conditions => ['id > ? AND repository_id = ?',
188 :conditions => ['id > ? AND repository_id = ?',
189 self.id, self.repository_id],
189 self.id, self.repository_id],
190 :order => 'id ASC')
190 :order => 'id ASC')
191 end
191 end
192
192
193 # Creates a new Change from it's common parameters
193 # Creates a new Change from it's common parameters
194 def create_change(change)
194 def create_change(change)
195 Change.create(:changeset => self,
195 Change.create(:changeset => self,
196 :action => change[:action],
196 :action => change[:action],
197 :path => change[:path],
197 :path => change[:path],
198 :from_path => change[:from_path],
198 :from_path => change[:from_path],
199 :from_revision => change[:from_revision])
199 :from_revision => change[:from_revision])
200 end
200 end
201
201
202 # Finds an issue that can be referenced by the commit message
202 # Finds an issue that can be referenced by the commit message
203 def find_referenced_issue_by_id(id)
203 def find_referenced_issue_by_id(id)
204 return nil if id.blank?
204 return nil if id.blank?
205 issue = Issue.find_by_id(id.to_i, :include => :project)
205 issue = Issue.find_by_id(id.to_i, :include => :project)
206 if Setting.commit_cross_project_ref?
206 if Setting.commit_cross_project_ref?
207 # all issues can be referenced/fixed
207 # all issues can be referenced/fixed
208 elsif issue
208 elsif issue
209 # issue that belong to the repository project, a subproject or a parent project only
209 # issue that belong to the repository project, a subproject or a parent project only
210 unless issue.project &&
210 unless issue.project &&
211 (project == issue.project || project.is_ancestor_of?(issue.project) ||
211 (project == issue.project || project.is_ancestor_of?(issue.project) ||
212 project.is_descendant_of?(issue.project))
212 project.is_descendant_of?(issue.project))
213 issue = nil
213 issue = nil
214 end
214 end
215 end
215 end
216 issue
216 issue
217 end
217 end
218
218
219 private
219 private
220
220
221 def fix_issue(issue)
221 def fix_issue(issue)
222 status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i)
222 status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i)
223 if status.nil?
223 if status.nil?
224 logger.warn("No status matches commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger
224 logger.warn("No status matches commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger
225 return issue
225 return issue
226 end
226 end
227
227
228 # the issue may have been updated by the closure of another one (eg. duplicate)
228 # the issue may have been updated by the closure of another one (eg. duplicate)
229 issue.reload
229 issue.reload
230 # don't change the status is the issue is closed
230 # don't change the status is the issue is closed
231 return if issue.status && issue.status.is_closed?
231 return if issue.status && issue.status.is_closed?
232
232
233 journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag(issue.project)))
233 journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag(issue.project)))
234 issue.status = status
234 issue.status = status
235 unless Setting.commit_fix_done_ratio.blank?
235 unless Setting.commit_fix_done_ratio.blank?
236 issue.done_ratio = Setting.commit_fix_done_ratio.to_i
236 issue.done_ratio = Setting.commit_fix_done_ratio.to_i
237 end
237 end
238 Redmine::Hook.call_hook(:model_changeset_scan_commit_for_issue_ids_pre_issue_update,
238 Redmine::Hook.call_hook(:model_changeset_scan_commit_for_issue_ids_pre_issue_update,
239 { :changeset => self, :issue => issue })
239 { :changeset => self, :issue => issue })
240 unless issue.save
240 unless issue.save
241 logger.warn("Issue ##{issue.id} could not be saved by changeset #{id}: #{issue.errors.full_messages}") if logger
241 logger.warn("Issue ##{issue.id} could not be saved by changeset #{id}: #{issue.errors.full_messages}") if logger
242 end
242 end
243 issue
243 issue
244 end
244 end
245
245
246 def log_time(issue, hours)
246 def log_time(issue, hours)
247 time_entry = TimeEntry.new(
247 time_entry = TimeEntry.new(
248 :user => user,
248 :user => user,
249 :hours => hours,
249 :hours => hours,
250 :issue => issue,
250 :issue => issue,
251 :spent_on => commit_date,
251 :spent_on => commit_date,
252 :comments => l(:text_time_logged_by_changeset, :value => text_tag(issue.project),
252 :comments => l(:text_time_logged_by_changeset, :value => text_tag(issue.project),
253 :locale => Setting.default_language)
253 :locale => Setting.default_language)
254 )
254 )
255 time_entry.activity = log_time_activity unless log_time_activity.nil?
255 time_entry.activity = log_time_activity unless log_time_activity.nil?
256
256
257 unless time_entry.save
257 unless time_entry.save
258 logger.warn("TimeEntry could not be created by changeset #{id}: #{time_entry.errors.full_messages}") if logger
258 logger.warn("TimeEntry could not be created by changeset #{id}: #{time_entry.errors.full_messages}") if logger
259 end
259 end
260 time_entry
260 time_entry
261 end
261 end
262
262
263 def log_time_activity
263 def log_time_activity
264 if Setting.commit_logtime_activity_id.to_i > 0
264 if Setting.commit_logtime_activity_id.to_i > 0
265 TimeEntryActivity.find_by_id(Setting.commit_logtime_activity_id.to_i)
265 TimeEntryActivity.find_by_id(Setting.commit_logtime_activity_id.to_i)
266 end
266 end
267 end
267 end
268
268
269 def split_comments
269 def split_comments
270 comments =~ /\A(.+?)\r?\n(.*)$/m
270 comments =~ /\A(.+?)\r?\n(.*)$/m
271 @short_comments = $1 || comments
271 @short_comments = $1 || comments
272 @long_comments = $2.to_s.strip
272 @long_comments = $2.to_s.strip
273 return @short_comments, @long_comments
273 return @short_comments, @long_comments
274 end
274 end
275
275
276 public
276 public
277
277
278 # Strips and reencodes a commit log before insertion into the database
278 # Strips and reencodes a commit log before insertion into the database
279 def self.normalize_comments(str, encoding)
279 def self.normalize_comments(str, encoding)
280 Changeset.to_utf8(str.to_s.strip, encoding)
280 Changeset.to_utf8(str.to_s.strip, encoding)
281 end
281 end
282
282
283 def self.to_utf8(str, encoding)
283 def self.to_utf8(str, encoding)
284 Redmine::CodesetUtil.to_utf8(str, encoding)
284 Redmine::CodesetUtil.to_utf8(str, encoding)
285 end
285 end
286 end
286 end
@@ -1,397 +1,397
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 ScmFetchError < Exception; end
18 class ScmFetchError < Exception; end
19
19
20 class Repository < ActiveRecord::Base
20 class Repository < ActiveRecord::Base
21 include Redmine::Ciphering
21 include Redmine::Ciphering
22
22
23 belongs_to :project
23 belongs_to :project
24 has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC"
24 has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC"
25 has_many :changes, :through => :changesets
25 has_many :filechanges, :class_name => 'Change', :through => :changesets
26
26
27 serialize :extra_info
27 serialize :extra_info
28
28
29 before_save :check_default
29 before_save :check_default
30
30
31 # Raw SQL to delete changesets and changes in the database
31 # Raw SQL to delete changesets and changes in the database
32 # has_many :changesets, :dependent => :destroy is too slow for big repositories
32 # has_many :changesets, :dependent => :destroy is too slow for big repositories
33 before_destroy :clear_changesets
33 before_destroy :clear_changesets
34
34
35 validates_length_of :password, :maximum => 255, :allow_nil => true
35 validates_length_of :password, :maximum => 255, :allow_nil => true
36 validates_length_of :identifier, :maximum => 255, :allow_blank => true
36 validates_length_of :identifier, :maximum => 255, :allow_blank => true
37 validates_presence_of :identifier, :unless => Proc.new { |r| r.is_default? || r.set_as_default? }
37 validates_presence_of :identifier, :unless => Proc.new { |r| r.is_default? || r.set_as_default? }
38 validates_uniqueness_of :identifier, :scope => :project_id, :allow_blank => true
38 validates_uniqueness_of :identifier, :scope => :project_id, :allow_blank => true
39 validates_exclusion_of :identifier, :in => %w(show entry raw changes annotate diff show stats graph)
39 validates_exclusion_of :identifier, :in => %w(show entry raw changes annotate diff show stats graph)
40 # donwcase letters, digits, dashes but not digits only
40 # donwcase letters, digits, dashes but not digits only
41 validates_format_of :identifier, :with => /^(?!\d+$)[a-z0-9\-]*$/, :allow_blank => true
41 validates_format_of :identifier, :with => /^(?!\d+$)[a-z0-9\-]*$/, :allow_blank => true
42 # Checks if the SCM is enabled when creating a repository
42 # Checks if the SCM is enabled when creating a repository
43 validate :repo_create_validation, :on => :create
43 validate :repo_create_validation, :on => :create
44
44
45 def repo_create_validation
45 def repo_create_validation
46 unless Setting.enabled_scm.include?(self.class.name.demodulize)
46 unless Setting.enabled_scm.include?(self.class.name.demodulize)
47 errors.add(:type, :invalid)
47 errors.add(:type, :invalid)
48 end
48 end
49 end
49 end
50
50
51 def self.human_attribute_name(attribute_key_name, *args)
51 def self.human_attribute_name(attribute_key_name, *args)
52 attr_name = attribute_key_name.to_s
52 attr_name = attribute_key_name.to_s
53 if attr_name == "log_encoding"
53 if attr_name == "log_encoding"
54 attr_name = "commit_logs_encoding"
54 attr_name = "commit_logs_encoding"
55 end
55 end
56 super(attr_name, *args)
56 super(attr_name, *args)
57 end
57 end
58
58
59 # Removes leading and trailing whitespace
59 # Removes leading and trailing whitespace
60 def url=(arg)
60 def url=(arg)
61 write_attribute(:url, arg ? arg.to_s.strip : nil)
61 write_attribute(:url, arg ? arg.to_s.strip : nil)
62 end
62 end
63
63
64 # Removes leading and trailing whitespace
64 # Removes leading and trailing whitespace
65 def root_url=(arg)
65 def root_url=(arg)
66 write_attribute(:root_url, arg ? arg.to_s.strip : nil)
66 write_attribute(:root_url, arg ? arg.to_s.strip : nil)
67 end
67 end
68
68
69 def password
69 def password
70 read_ciphered_attribute(:password)
70 read_ciphered_attribute(:password)
71 end
71 end
72
72
73 def password=(arg)
73 def password=(arg)
74 write_ciphered_attribute(:password, arg)
74 write_ciphered_attribute(:password, arg)
75 end
75 end
76
76
77 def scm_adapter
77 def scm_adapter
78 self.class.scm_adapter_class
78 self.class.scm_adapter_class
79 end
79 end
80
80
81 def scm
81 def scm
82 unless @scm
82 unless @scm
83 @scm = self.scm_adapter.new(url, root_url,
83 @scm = self.scm_adapter.new(url, root_url,
84 login, password, path_encoding)
84 login, password, path_encoding)
85 if root_url.blank? && @scm.root_url.present?
85 if root_url.blank? && @scm.root_url.present?
86 update_attribute(:root_url, @scm.root_url)
86 update_attribute(:root_url, @scm.root_url)
87 end
87 end
88 end
88 end
89 @scm
89 @scm
90 end
90 end
91
91
92 def scm_name
92 def scm_name
93 self.class.scm_name
93 self.class.scm_name
94 end
94 end
95
95
96 def name
96 def name
97 if identifier.present?
97 if identifier.present?
98 identifier
98 identifier
99 elsif is_default?
99 elsif is_default?
100 l(:field_repository_is_default)
100 l(:field_repository_is_default)
101 else
101 else
102 scm_name
102 scm_name
103 end
103 end
104 end
104 end
105
105
106 def identifier_param
106 def identifier_param
107 if is_default?
107 if is_default?
108 nil
108 nil
109 elsif identifier.present?
109 elsif identifier.present?
110 identifier
110 identifier
111 else
111 else
112 id.to_s
112 id.to_s
113 end
113 end
114 end
114 end
115
115
116 def <=>(repository)
116 def <=>(repository)
117 if is_default?
117 if is_default?
118 -1
118 -1
119 elsif repository.is_default?
119 elsif repository.is_default?
120 1
120 1
121 else
121 else
122 identifier.to_s <=> repository.identifier.to_s
122 identifier.to_s <=> repository.identifier.to_s
123 end
123 end
124 end
124 end
125
125
126 def self.find_by_identifier_param(param)
126 def self.find_by_identifier_param(param)
127 if param.to_s =~ /^\d+$/
127 if param.to_s =~ /^\d+$/
128 find_by_id(param)
128 find_by_id(param)
129 else
129 else
130 find_by_identifier(param)
130 find_by_identifier(param)
131 end
131 end
132 end
132 end
133
133
134 def merge_extra_info(arg)
134 def merge_extra_info(arg)
135 h = extra_info || {}
135 h = extra_info || {}
136 return h if arg.nil?
136 return h if arg.nil?
137 h.merge!(arg)
137 h.merge!(arg)
138 write_attribute(:extra_info, h)
138 write_attribute(:extra_info, h)
139 end
139 end
140
140
141 def report_last_commit
141 def report_last_commit
142 true
142 true
143 end
143 end
144
144
145 def supports_cat?
145 def supports_cat?
146 scm.supports_cat?
146 scm.supports_cat?
147 end
147 end
148
148
149 def supports_annotate?
149 def supports_annotate?
150 scm.supports_annotate?
150 scm.supports_annotate?
151 end
151 end
152
152
153 def supports_all_revisions?
153 def supports_all_revisions?
154 true
154 true
155 end
155 end
156
156
157 def supports_directory_revisions?
157 def supports_directory_revisions?
158 false
158 false
159 end
159 end
160
160
161 def supports_revision_graph?
161 def supports_revision_graph?
162 false
162 false
163 end
163 end
164
164
165 def entry(path=nil, identifier=nil)
165 def entry(path=nil, identifier=nil)
166 scm.entry(path, identifier)
166 scm.entry(path, identifier)
167 end
167 end
168
168
169 def entries(path=nil, identifier=nil)
169 def entries(path=nil, identifier=nil)
170 scm.entries(path, identifier)
170 scm.entries(path, identifier)
171 end
171 end
172
172
173 def branches
173 def branches
174 scm.branches
174 scm.branches
175 end
175 end
176
176
177 def tags
177 def tags
178 scm.tags
178 scm.tags
179 end
179 end
180
180
181 def default_branch
181 def default_branch
182 nil
182 nil
183 end
183 end
184
184
185 def properties(path, identifier=nil)
185 def properties(path, identifier=nil)
186 scm.properties(path, identifier)
186 scm.properties(path, identifier)
187 end
187 end
188
188
189 def cat(path, identifier=nil)
189 def cat(path, identifier=nil)
190 scm.cat(path, identifier)
190 scm.cat(path, identifier)
191 end
191 end
192
192
193 def diff(path, rev, rev_to)
193 def diff(path, rev, rev_to)
194 scm.diff(path, rev, rev_to)
194 scm.diff(path, rev, rev_to)
195 end
195 end
196
196
197 def diff_format_revisions(cs, cs_to, sep=':')
197 def diff_format_revisions(cs, cs_to, sep=':')
198 text = ""
198 text = ""
199 text << cs_to.format_identifier + sep if cs_to
199 text << cs_to.format_identifier + sep if cs_to
200 text << cs.format_identifier if cs
200 text << cs.format_identifier if cs
201 text
201 text
202 end
202 end
203
203
204 # Returns a path relative to the url of the repository
204 # Returns a path relative to the url of the repository
205 def relative_path(path)
205 def relative_path(path)
206 path
206 path
207 end
207 end
208
208
209 # Finds and returns a revision with a number or the beginning of a hash
209 # Finds and returns a revision with a number or the beginning of a hash
210 def find_changeset_by_name(name)
210 def find_changeset_by_name(name)
211 return nil if name.blank?
211 return nil if name.blank?
212 s = name.to_s
212 s = name.to_s
213 changesets.find(:first, :conditions => (s.match(/^\d*$/) ?
213 changesets.find(:first, :conditions => (s.match(/^\d*$/) ?
214 ["revision = ?", s] : ["revision LIKE ?", s + '%']))
214 ["revision = ?", s] : ["revision LIKE ?", s + '%']))
215 end
215 end
216
216
217 def latest_changeset
217 def latest_changeset
218 @latest_changeset ||= changesets.find(:first)
218 @latest_changeset ||= changesets.find(:first)
219 end
219 end
220
220
221 # Returns the latest changesets for +path+
221 # Returns the latest changesets for +path+
222 # Default behaviour is to search in cached changesets
222 # Default behaviour is to search in cached changesets
223 def latest_changesets(path, rev, limit=10)
223 def latest_changesets(path, rev, limit=10)
224 if path.blank?
224 if path.blank?
225 changesets.find(
225 changesets.find(
226 :all,
226 :all,
227 :include => :user,
227 :include => :user,
228 :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC",
228 :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC",
229 :limit => limit)
229 :limit => limit)
230 else
230 else
231 changes.find(
231 filechanges.find(
232 :all,
232 :all,
233 :include => {:changeset => :user},
233 :include => {:changeset => :user},
234 :conditions => ["path = ?", path.with_leading_slash],
234 :conditions => ["path = ?", path.with_leading_slash],
235 :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC",
235 :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC",
236 :limit => limit
236 :limit => limit
237 ).collect(&:changeset)
237 ).collect(&:changeset)
238 end
238 end
239 end
239 end
240
240
241 def scan_changesets_for_issue_ids
241 def scan_changesets_for_issue_ids
242 self.changesets.each(&:scan_comment_for_issue_ids)
242 self.changesets.each(&:scan_comment_for_issue_ids)
243 end
243 end
244
244
245 # Returns an array of committers usernames and associated user_id
245 # Returns an array of committers usernames and associated user_id
246 def committers
246 def committers
247 @committers ||= Changeset.connection.select_rows(
247 @committers ||= Changeset.connection.select_rows(
248 "SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}")
248 "SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}")
249 end
249 end
250
250
251 # Maps committers username to a user ids
251 # Maps committers username to a user ids
252 def committer_ids=(h)
252 def committer_ids=(h)
253 if h.is_a?(Hash)
253 if h.is_a?(Hash)
254 committers.each do |committer, user_id|
254 committers.each do |committer, user_id|
255 new_user_id = h[committer]
255 new_user_id = h[committer]
256 if new_user_id && (new_user_id.to_i != user_id.to_i)
256 if new_user_id && (new_user_id.to_i != user_id.to_i)
257 new_user_id = (new_user_id.to_i > 0 ? new_user_id.to_i : nil)
257 new_user_id = (new_user_id.to_i > 0 ? new_user_id.to_i : nil)
258 Changeset.update_all(
258 Changeset.update_all(
259 "user_id = #{ new_user_id.nil? ? 'NULL' : new_user_id }",
259 "user_id = #{ new_user_id.nil? ? 'NULL' : new_user_id }",
260 ["repository_id = ? AND committer = ?", id, committer])
260 ["repository_id = ? AND committer = ?", id, committer])
261 end
261 end
262 end
262 end
263 @committers = nil
263 @committers = nil
264 @found_committer_users = nil
264 @found_committer_users = nil
265 true
265 true
266 else
266 else
267 false
267 false
268 end
268 end
269 end
269 end
270
270
271 # Returns the Redmine User corresponding to the given +committer+
271 # Returns the Redmine User corresponding to the given +committer+
272 # It will return nil if the committer is not yet mapped and if no User
272 # It will return nil if the committer is not yet mapped and if no User
273 # with the same username or email was found
273 # with the same username or email was found
274 def find_committer_user(committer)
274 def find_committer_user(committer)
275 unless committer.blank?
275 unless committer.blank?
276 @found_committer_users ||= {}
276 @found_committer_users ||= {}
277 return @found_committer_users[committer] if @found_committer_users.has_key?(committer)
277 return @found_committer_users[committer] if @found_committer_users.has_key?(committer)
278
278
279 user = nil
279 user = nil
280 c = changesets.find(:first, :conditions => {:committer => committer}, :include => :user)
280 c = changesets.find(:first, :conditions => {:committer => committer}, :include => :user)
281 if c && c.user
281 if c && c.user
282 user = c.user
282 user = c.user
283 elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
283 elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
284 username, email = $1.strip, $3
284 username, email = $1.strip, $3
285 u = User.find_by_login(username)
285 u = User.find_by_login(username)
286 u ||= User.find_by_mail(email) unless email.blank?
286 u ||= User.find_by_mail(email) unless email.blank?
287 user = u
287 user = u
288 end
288 end
289 @found_committer_users[committer] = user
289 @found_committer_users[committer] = user
290 user
290 user
291 end
291 end
292 end
292 end
293
293
294 def repo_log_encoding
294 def repo_log_encoding
295 encoding = log_encoding.to_s.strip
295 encoding = log_encoding.to_s.strip
296 encoding.blank? ? 'UTF-8' : encoding
296 encoding.blank? ? 'UTF-8' : encoding
297 end
297 end
298
298
299 # Fetches new changesets for all repositories of active projects
299 # Fetches new changesets for all repositories of active projects
300 # Can be called periodically by an external script
300 # Can be called periodically by an external script
301 # eg. ruby script/runner "Repository.fetch_changesets"
301 # eg. ruby script/runner "Repository.fetch_changesets"
302 def self.fetch_changesets
302 def self.fetch_changesets
303 Project.active.has_module(:repository).all.each do |project|
303 Project.active.has_module(:repository).all.each do |project|
304 project.repositories.each do |repository|
304 project.repositories.each do |repository|
305 begin
305 begin
306 repository.fetch_changesets
306 repository.fetch_changesets
307 rescue Redmine::Scm::Adapters::CommandFailed => e
307 rescue Redmine::Scm::Adapters::CommandFailed => e
308 logger.error "scm: error during fetching changesets: #{e.message}"
308 logger.error "scm: error during fetching changesets: #{e.message}"
309 end
309 end
310 end
310 end
311 end
311 end
312 end
312 end
313
313
314 # scan changeset comments to find related and fixed issues for all repositories
314 # scan changeset comments to find related and fixed issues for all repositories
315 def self.scan_changesets_for_issue_ids
315 def self.scan_changesets_for_issue_ids
316 find(:all).each(&:scan_changesets_for_issue_ids)
316 find(:all).each(&:scan_changesets_for_issue_ids)
317 end
317 end
318
318
319 def self.scm_name
319 def self.scm_name
320 'Abstract'
320 'Abstract'
321 end
321 end
322
322
323 def self.available_scm
323 def self.available_scm
324 subclasses.collect {|klass| [klass.scm_name, klass.name]}
324 subclasses.collect {|klass| [klass.scm_name, klass.name]}
325 end
325 end
326
326
327 def self.factory(klass_name, *args)
327 def self.factory(klass_name, *args)
328 klass = "Repository::#{klass_name}".constantize
328 klass = "Repository::#{klass_name}".constantize
329 klass.new(*args)
329 klass.new(*args)
330 rescue
330 rescue
331 nil
331 nil
332 end
332 end
333
333
334 def self.scm_adapter_class
334 def self.scm_adapter_class
335 nil
335 nil
336 end
336 end
337
337
338 def self.scm_command
338 def self.scm_command
339 ret = ""
339 ret = ""
340 begin
340 begin
341 ret = self.scm_adapter_class.client_command if self.scm_adapter_class
341 ret = self.scm_adapter_class.client_command if self.scm_adapter_class
342 rescue Exception => e
342 rescue Exception => e
343 logger.error "scm: error during get command: #{e.message}"
343 logger.error "scm: error during get command: #{e.message}"
344 end
344 end
345 ret
345 ret
346 end
346 end
347
347
348 def self.scm_version_string
348 def self.scm_version_string
349 ret = ""
349 ret = ""
350 begin
350 begin
351 ret = self.scm_adapter_class.client_version_string if self.scm_adapter_class
351 ret = self.scm_adapter_class.client_version_string if self.scm_adapter_class
352 rescue Exception => e
352 rescue Exception => e
353 logger.error "scm: error during get version string: #{e.message}"
353 logger.error "scm: error during get version string: #{e.message}"
354 end
354 end
355 ret
355 ret
356 end
356 end
357
357
358 def self.scm_available
358 def self.scm_available
359 ret = false
359 ret = false
360 begin
360 begin
361 ret = self.scm_adapter_class.client_available if self.scm_adapter_class
361 ret = self.scm_adapter_class.client_available if self.scm_adapter_class
362 rescue Exception => e
362 rescue Exception => e
363 logger.error "scm: error during get scm available: #{e.message}"
363 logger.error "scm: error during get scm available: #{e.message}"
364 end
364 end
365 ret
365 ret
366 end
366 end
367
367
368 def set_as_default?
368 def set_as_default?
369 new_record? && project && !Repository.first(:conditions => {:project_id => project.id})
369 new_record? && project && !Repository.first(:conditions => {:project_id => project.id})
370 end
370 end
371
371
372 protected
372 protected
373
373
374 def check_default
374 def check_default
375 if !is_default? && set_as_default?
375 if !is_default? && set_as_default?
376 self.is_default = true
376 self.is_default = true
377 end
377 end
378 if is_default? && is_default_changed?
378 if is_default? && is_default_changed?
379 Repository.update_all(["is_default = ?", false], ["project_id = ?", project_id])
379 Repository.update_all(["is_default = ?", false], ["project_id = ?", project_id])
380 end
380 end
381 end
381 end
382
382
383 private
383 private
384
384
385 # Deletes repository data
385 # Deletes repository data
386 def clear_changesets
386 def clear_changesets
387 cs = Changeset.table_name
387 cs = Changeset.table_name
388 ch = Change.table_name
388 ch = Change.table_name
389 ci = "#{table_name_prefix}changesets_issues#{table_name_suffix}"
389 ci = "#{table_name_prefix}changesets_issues#{table_name_suffix}"
390 cp = "#{table_name_prefix}changeset_parents#{table_name_suffix}"
390 cp = "#{table_name_prefix}changeset_parents#{table_name_suffix}"
391
391
392 connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
392 connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
393 connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
393 connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
394 connection.delete("DELETE FROM #{cp} WHERE #{cp}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
394 connection.delete("DELETE FROM #{cp} WHERE #{cp}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
395 connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
395 connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
396 end
396 end
397 end
397 end
@@ -1,204 +1,204
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 'redmine/scm/adapters/cvs_adapter'
18 require 'redmine/scm/adapters/cvs_adapter'
19 require 'digest/sha1'
19 require 'digest/sha1'
20
20
21 class Repository::Cvs < Repository
21 class Repository::Cvs < Repository
22 validates_presence_of :url, :root_url, :log_encoding
22 validates_presence_of :url, :root_url, :log_encoding
23
23
24 def self.human_attribute_name(attribute_key_name, *args)
24 def self.human_attribute_name(attribute_key_name, *args)
25 attr_name = attribute_key_name.to_s
25 attr_name = attribute_key_name.to_s
26 if attr_name == "root_url"
26 if attr_name == "root_url"
27 attr_name = "cvsroot"
27 attr_name = "cvsroot"
28 elsif attr_name == "url"
28 elsif attr_name == "url"
29 attr_name = "cvs_module"
29 attr_name = "cvs_module"
30 end
30 end
31 super(attr_name, *args)
31 super(attr_name, *args)
32 end
32 end
33
33
34 def self.scm_adapter_class
34 def self.scm_adapter_class
35 Redmine::Scm::Adapters::CvsAdapter
35 Redmine::Scm::Adapters::CvsAdapter
36 end
36 end
37
37
38 def self.scm_name
38 def self.scm_name
39 'CVS'
39 'CVS'
40 end
40 end
41
41
42 def entry(path=nil, identifier=nil)
42 def entry(path=nil, identifier=nil)
43 rev = identifier.nil? ? nil : changesets.find_by_revision(identifier)
43 rev = identifier.nil? ? nil : changesets.find_by_revision(identifier)
44 scm.entry(path, rev.nil? ? nil : rev.committed_on)
44 scm.entry(path, rev.nil? ? nil : rev.committed_on)
45 end
45 end
46
46
47 def entries(path=nil, identifier=nil)
47 def entries(path=nil, identifier=nil)
48 rev = nil
48 rev = nil
49 if ! identifier.nil?
49 if ! identifier.nil?
50 rev = changesets.find_by_revision(identifier)
50 rev = changesets.find_by_revision(identifier)
51 return nil if rev.nil?
51 return nil if rev.nil?
52 end
52 end
53 entries = scm.entries(path, rev.nil? ? nil : rev.committed_on)
53 entries = scm.entries(path, rev.nil? ? nil : rev.committed_on)
54 if entries
54 if entries
55 entries.each() do |entry|
55 entries.each() do |entry|
56 if ( ! entry.lastrev.nil? ) && ( ! entry.lastrev.revision.nil? )
56 if ( ! entry.lastrev.nil? ) && ( ! entry.lastrev.revision.nil? )
57 change=changes.find_by_revision_and_path(
57 change = filechanges.find_by_revision_and_path(
58 entry.lastrev.revision,
58 entry.lastrev.revision,
59 scm.with_leading_slash(entry.path) )
59 scm.with_leading_slash(entry.path) )
60 if change
60 if change
61 entry.lastrev.identifier = change.changeset.revision
61 entry.lastrev.identifier = change.changeset.revision
62 entry.lastrev.revision = change.changeset.revision
62 entry.lastrev.revision = change.changeset.revision
63 entry.lastrev.author = change.changeset.committer
63 entry.lastrev.author = change.changeset.committer
64 # entry.lastrev.branch = change.branch
64 # entry.lastrev.branch = change.branch
65 end
65 end
66 end
66 end
67 end
67 end
68 end
68 end
69 entries
69 entries
70 end
70 end
71
71
72 def cat(path, identifier=nil)
72 def cat(path, identifier=nil)
73 rev = nil
73 rev = nil
74 if ! identifier.nil?
74 if ! identifier.nil?
75 rev = changesets.find_by_revision(identifier)
75 rev = changesets.find_by_revision(identifier)
76 return nil if rev.nil?
76 return nil if rev.nil?
77 end
77 end
78 scm.cat(path, rev.nil? ? nil : rev.committed_on)
78 scm.cat(path, rev.nil? ? nil : rev.committed_on)
79 end
79 end
80
80
81 def annotate(path, identifier=nil)
81 def annotate(path, identifier=nil)
82 rev = nil
82 rev = nil
83 if ! identifier.nil?
83 if ! identifier.nil?
84 rev = changesets.find_by_revision(identifier)
84 rev = changesets.find_by_revision(identifier)
85 return nil if rev.nil?
85 return nil if rev.nil?
86 end
86 end
87 scm.annotate(path, rev.nil? ? nil : rev.committed_on)
87 scm.annotate(path, rev.nil? ? nil : rev.committed_on)
88 end
88 end
89
89
90 def diff(path, rev, rev_to)
90 def diff(path, rev, rev_to)
91 # convert rev to revision. CVS can't handle changesets here
91 # convert rev to revision. CVS can't handle changesets here
92 diff=[]
92 diff=[]
93 changeset_from = changesets.find_by_revision(rev)
93 changeset_from = changesets.find_by_revision(rev)
94 if rev_to.to_i > 0
94 if rev_to.to_i > 0
95 changeset_to = changesets.find_by_revision(rev_to)
95 changeset_to = changesets.find_by_revision(rev_to)
96 end
96 end
97 changeset_from.changes.each() do |change_from|
97 changeset_from.filechanges.each() do |change_from|
98 revision_from = nil
98 revision_from = nil
99 revision_to = nil
99 revision_to = nil
100 if path.nil? || (change_from.path.starts_with? scm.with_leading_slash(path))
100 if path.nil? || (change_from.path.starts_with? scm.with_leading_slash(path))
101 revision_from = change_from.revision
101 revision_from = change_from.revision
102 end
102 end
103 if revision_from
103 if revision_from
104 if changeset_to
104 if changeset_to
105 changeset_to.changes.each() do |change_to|
105 changeset_to.filechanges.each() do |change_to|
106 revision_to = change_to.revision if change_to.path == change_from.path
106 revision_to = change_to.revision if change_to.path == change_from.path
107 end
107 end
108 end
108 end
109 unless revision_to
109 unless revision_to
110 revision_to = scm.get_previous_revision(revision_from)
110 revision_to = scm.get_previous_revision(revision_from)
111 end
111 end
112 file_diff = scm.diff(change_from.path, revision_from, revision_to)
112 file_diff = scm.diff(change_from.path, revision_from, revision_to)
113 diff = diff + file_diff unless file_diff.nil?
113 diff = diff + file_diff unless file_diff.nil?
114 end
114 end
115 end
115 end
116 return diff
116 return diff
117 end
117 end
118
118
119 def fetch_changesets
119 def fetch_changesets
120 # some nifty bits to introduce a commit-id with cvs
120 # some nifty bits to introduce a commit-id with cvs
121 # natively cvs doesn't provide any kind of changesets,
121 # natively cvs doesn't provide any kind of changesets,
122 # there is only a revision per file.
122 # there is only a revision per file.
123 # we now take a guess using the author, the commitlog and the commit-date.
123 # we now take a guess using the author, the commitlog and the commit-date.
124
124
125 # last one is the next step to take. the commit-date is not equal for all
125 # last one is the next step to take. the commit-date is not equal for all
126 # commits in one changeset. cvs update the commit-date when the *,v file was touched. so
126 # commits in one changeset. cvs update the commit-date when the *,v file was touched. so
127 # we use a small delta here, to merge all changes belonging to _one_ changeset
127 # we use a small delta here, to merge all changes belonging to _one_ changeset
128 time_delta = 10.seconds
128 time_delta = 10.seconds
129 fetch_since = latest_changeset ? latest_changeset.committed_on : nil
129 fetch_since = latest_changeset ? latest_changeset.committed_on : nil
130 transaction do
130 transaction do
131 tmp_rev_num = 1
131 tmp_rev_num = 1
132 scm.revisions('', fetch_since, nil, :log_encoding => repo_log_encoding) do |revision|
132 scm.revisions('', fetch_since, nil, :log_encoding => repo_log_encoding) do |revision|
133 # only add the change to the database, if it doen't exists. the cvs log
133 # only add the change to the database, if it doen't exists. the cvs log
134 # is not exclusive at all.
134 # is not exclusive at all.
135 tmp_time = revision.time.clone
135 tmp_time = revision.time.clone
136 unless changes.find_by_path_and_revision(
136 unless filechanges.find_by_path_and_revision(
137 scm.with_leading_slash(revision.paths[0][:path]),
137 scm.with_leading_slash(revision.paths[0][:path]),
138 revision.paths[0][:revision]
138 revision.paths[0][:revision]
139 )
139 )
140 cmt = Changeset.normalize_comments(revision.message, repo_log_encoding)
140 cmt = Changeset.normalize_comments(revision.message, repo_log_encoding)
141 author_utf8 = Changeset.to_utf8(revision.author, repo_log_encoding)
141 author_utf8 = Changeset.to_utf8(revision.author, repo_log_encoding)
142 cs = changesets.find(
142 cs = changesets.find(
143 :first,
143 :first,
144 :conditions => {
144 :conditions => {
145 :committed_on => tmp_time - time_delta .. tmp_time + time_delta,
145 :committed_on => tmp_time - time_delta .. tmp_time + time_delta,
146 :committer => author_utf8,
146 :committer => author_utf8,
147 :comments => cmt
147 :comments => cmt
148 }
148 }
149 )
149 )
150 # create a new changeset....
150 # create a new changeset....
151 unless cs
151 unless cs
152 # we use a temporaray revision number here (just for inserting)
152 # we use a temporaray revision number here (just for inserting)
153 # later on, we calculate a continous positive number
153 # later on, we calculate a continous positive number
154 tmp_time2 = tmp_time.clone.gmtime
154 tmp_time2 = tmp_time.clone.gmtime
155 branch = revision.paths[0][:branch]
155 branch = revision.paths[0][:branch]
156 scmid = branch + "-" + tmp_time2.strftime("%Y%m%d-%H%M%S")
156 scmid = branch + "-" + tmp_time2.strftime("%Y%m%d-%H%M%S")
157 cs = Changeset.create(:repository => self,
157 cs = Changeset.create(:repository => self,
158 :revision => "tmp#{tmp_rev_num}",
158 :revision => "tmp#{tmp_rev_num}",
159 :scmid => scmid,
159 :scmid => scmid,
160 :committer => revision.author,
160 :committer => revision.author,
161 :committed_on => tmp_time,
161 :committed_on => tmp_time,
162 :comments => revision.message)
162 :comments => revision.message)
163 tmp_rev_num += 1
163 tmp_rev_num += 1
164 end
164 end
165 # convert CVS-File-States to internal Action-abbrevations
165 # convert CVS-File-States to internal Action-abbrevations
166 # default action is (M)odified
166 # default action is (M)odified
167 action = "M"
167 action = "M"
168 if revision.paths[0][:action] == "Exp" && revision.paths[0][:revision] == "1.1"
168 if revision.paths[0][:action] == "Exp" && revision.paths[0][:revision] == "1.1"
169 action = "A" # add-action always at first revision (= 1.1)
169 action = "A" # add-action always at first revision (= 1.1)
170 elsif revision.paths[0][:action] == "dead"
170 elsif revision.paths[0][:action] == "dead"
171 action = "D" # dead-state is similar to Delete
171 action = "D" # dead-state is similar to Delete
172 end
172 end
173 Change.create(
173 Change.create(
174 :changeset => cs,
174 :changeset => cs,
175 :action => action,
175 :action => action,
176 :path => scm.with_leading_slash(revision.paths[0][:path]),
176 :path => scm.with_leading_slash(revision.paths[0][:path]),
177 :revision => revision.paths[0][:revision],
177 :revision => revision.paths[0][:revision],
178 :branch => revision.paths[0][:branch]
178 :branch => revision.paths[0][:branch]
179 )
179 )
180 end
180 end
181 end
181 end
182
182
183 # Renumber new changesets in chronological order
183 # Renumber new changesets in chronological order
184 Changeset.all(
184 Changeset.all(
185 :order => 'committed_on ASC, id ASC',
185 :order => 'committed_on ASC, id ASC',
186 :conditions => ["repository_id = ? AND revision LIKE 'tmp%'", id]
186 :conditions => ["repository_id = ? AND revision LIKE 'tmp%'", id]
187 ).each do |changeset|
187 ).each do |changeset|
188 changeset.update_attribute :revision, next_revision_number
188 changeset.update_attribute :revision, next_revision_number
189 end
189 end
190 end # transaction
190 end # transaction
191 @current_revision_number = nil
191 @current_revision_number = nil
192 end
192 end
193
193
194 private
194 private
195
195
196 # Returns the next revision number to assign to a CVS changeset
196 # Returns the next revision number to assign to a CVS changeset
197 def next_revision_number
197 def next_revision_number
198 # Need to retrieve existing revision numbers to sort them as integers
198 # Need to retrieve existing revision numbers to sort them as integers
199 sql = "SELECT revision FROM #{Changeset.table_name} "
199 sql = "SELECT revision FROM #{Changeset.table_name} "
200 sql << "WHERE repository_id = #{id} AND revision NOT LIKE 'tmp%'"
200 sql << "WHERE repository_id = #{id} AND revision NOT LIKE 'tmp%'"
201 @current_revision_number ||= (connection.select_values(sql).collect(&:to_i).max || 0)
201 @current_revision_number ||= (connection.select_values(sql).collect(&:to_i).max || 0)
202 @current_revision_number += 1
202 @current_revision_number += 1
203 end
203 end
204 end
204 end
@@ -1,113 +1,113
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 'redmine/scm/adapters/darcs_adapter'
18 require 'redmine/scm/adapters/darcs_adapter'
19
19
20 class Repository::Darcs < Repository
20 class Repository::Darcs < Repository
21 validates_presence_of :url, :log_encoding
21 validates_presence_of :url, :log_encoding
22
22
23 def self.human_attribute_name(attribute_key_name, *args)
23 def self.human_attribute_name(attribute_key_name, *args)
24 attr_name = attribute_key_name.to_s
24 attr_name = attribute_key_name.to_s
25 if attr_name == "url"
25 if attr_name == "url"
26 attr_name = "path_to_repository"
26 attr_name = "path_to_repository"
27 end
27 end
28 super(attr_name, *args)
28 super(attr_name, *args)
29 end
29 end
30
30
31 def self.scm_adapter_class
31 def self.scm_adapter_class
32 Redmine::Scm::Adapters::DarcsAdapter
32 Redmine::Scm::Adapters::DarcsAdapter
33 end
33 end
34
34
35 def self.scm_name
35 def self.scm_name
36 'Darcs'
36 'Darcs'
37 end
37 end
38
38
39 def supports_directory_revisions?
39 def supports_directory_revisions?
40 true
40 true
41 end
41 end
42
42
43 def entry(path=nil, identifier=nil)
43 def entry(path=nil, identifier=nil)
44 patch = identifier.nil? ? nil : changesets.find_by_revision(identifier)
44 patch = identifier.nil? ? nil : changesets.find_by_revision(identifier)
45 scm.entry(path, patch.nil? ? nil : patch.scmid)
45 scm.entry(path, patch.nil? ? nil : patch.scmid)
46 end
46 end
47
47
48 def entries(path=nil, identifier=nil)
48 def entries(path=nil, identifier=nil)
49 patch = nil
49 patch = nil
50 if ! identifier.nil?
50 if ! identifier.nil?
51 patch = changesets.find_by_revision(identifier)
51 patch = changesets.find_by_revision(identifier)
52 return nil if patch.nil?
52 return nil if patch.nil?
53 end
53 end
54 entries = scm.entries(path, patch.nil? ? nil : patch.scmid)
54 entries = scm.entries(path, patch.nil? ? nil : patch.scmid)
55 if entries
55 if entries
56 entries.each do |entry|
56 entries.each do |entry|
57 # Search the DB for the entry's last change
57 # Search the DB for the entry's last change
58 if entry.lastrev && !entry.lastrev.scmid.blank?
58 if entry.lastrev && !entry.lastrev.scmid.blank?
59 changeset = changesets.find_by_scmid(entry.lastrev.scmid)
59 changeset = changesets.find_by_scmid(entry.lastrev.scmid)
60 end
60 end
61 if changeset
61 if changeset
62 entry.lastrev.identifier = changeset.revision
62 entry.lastrev.identifier = changeset.revision
63 entry.lastrev.name = changeset.revision
63 entry.lastrev.name = changeset.revision
64 entry.lastrev.time = changeset.committed_on
64 entry.lastrev.time = changeset.committed_on
65 entry.lastrev.author = changeset.committer
65 entry.lastrev.author = changeset.committer
66 end
66 end
67 end
67 end
68 end
68 end
69 entries
69 entries
70 end
70 end
71
71
72 def cat(path, identifier=nil)
72 def cat(path, identifier=nil)
73 patch = identifier.nil? ? nil : changesets.find_by_revision(identifier.to_s)
73 patch = identifier.nil? ? nil : changesets.find_by_revision(identifier.to_s)
74 scm.cat(path, patch.nil? ? nil : patch.scmid)
74 scm.cat(path, patch.nil? ? nil : patch.scmid)
75 end
75 end
76
76
77 def diff(path, rev, rev_to)
77 def diff(path, rev, rev_to)
78 patch_from = changesets.find_by_revision(rev)
78 patch_from = changesets.find_by_revision(rev)
79 return nil if patch_from.nil?
79 return nil if patch_from.nil?
80 patch_to = changesets.find_by_revision(rev_to) if rev_to
80 patch_to = changesets.find_by_revision(rev_to) if rev_to
81 if path.blank?
81 if path.blank?
82 path = patch_from.changes.collect{|change| change.path}.join(' ')
82 path = patch_from.filechanges.collect{|change| change.path}.join(' ')
83 end
83 end
84 patch_from ? scm.diff(path, patch_from.scmid, patch_to ? patch_to.scmid : nil) : nil
84 patch_from ? scm.diff(path, patch_from.scmid, patch_to ? patch_to.scmid : nil) : nil
85 end
85 end
86
86
87 def fetch_changesets
87 def fetch_changesets
88 scm_info = scm.info
88 scm_info = scm.info
89 if scm_info
89 if scm_info
90 db_last_id = latest_changeset ? latest_changeset.scmid : nil
90 db_last_id = latest_changeset ? latest_changeset.scmid : nil
91 next_rev = latest_changeset ? latest_changeset.revision.to_i + 1 : 1
91 next_rev = latest_changeset ? latest_changeset.revision.to_i + 1 : 1
92 # latest revision in the repository
92 # latest revision in the repository
93 scm_revision = scm_info.lastrev.scmid
93 scm_revision = scm_info.lastrev.scmid
94 unless changesets.find_by_scmid(scm_revision)
94 unless changesets.find_by_scmid(scm_revision)
95 revisions = scm.revisions('', db_last_id, nil, :with_path => true)
95 revisions = scm.revisions('', db_last_id, nil, :with_path => true)
96 transaction do
96 transaction do
97 revisions.reverse_each do |revision|
97 revisions.reverse_each do |revision|
98 changeset = Changeset.create(:repository => self,
98 changeset = Changeset.create(:repository => self,
99 :revision => next_rev,
99 :revision => next_rev,
100 :scmid => revision.scmid,
100 :scmid => revision.scmid,
101 :committer => revision.author,
101 :committer => revision.author,
102 :committed_on => revision.time,
102 :committed_on => revision.time,
103 :comments => revision.message)
103 :comments => revision.message)
104 revision.paths.each do |change|
104 revision.paths.each do |change|
105 changeset.create_change(change)
105 changeset.create_change(change)
106 end
106 end
107 next_rev += 1
107 next_rev += 1
108 end if revisions
108 end if revisions
109 end
109 end
110 end
110 end
111 end
111 end
112 end
112 end
113 end
113 end
@@ -1,97 +1,97
1 <div class="contextual">
1 <div class="contextual">
2 &#171;
2 &#171;
3 <% unless @changeset.previous.nil? -%>
3 <% unless @changeset.previous.nil? -%>
4 <%= link_to_revision(@changeset.previous, @repository, :text => l(:label_previous)) %>
4 <%= link_to_revision(@changeset.previous, @repository, :text => l(:label_previous)) %>
5 <% else -%>
5 <% else -%>
6 <%= l(:label_previous) %>
6 <%= l(:label_previous) %>
7 <% end -%>
7 <% end -%>
8 |
8 |
9 <% unless @changeset.next.nil? -%>
9 <% unless @changeset.next.nil? -%>
10 <%= link_to_revision(@changeset.next, @repository, :text => l(:label_next)) %>
10 <%= link_to_revision(@changeset.next, @repository, :text => l(:label_next)) %>
11 <% else -%>
11 <% else -%>
12 <%= l(:label_next) %>
12 <%= l(:label_next) %>
13 <% end -%>
13 <% end -%>
14 &#187;&nbsp;
14 &#187;&nbsp;
15
15
16 <%= form_tag({:controller => 'repositories',
16 <%= form_tag({:controller => 'repositories',
17 :action => 'revision',
17 :action => 'revision',
18 :id => @project,
18 :id => @project,
19 :repository_id => @repository.identifier_param,
19 :repository_id => @repository.identifier_param,
20 :rev => nil},
20 :rev => nil},
21 :method => :get) do %>
21 :method => :get) do %>
22 <%= text_field_tag 'rev', @rev, :size => 8 %>
22 <%= text_field_tag 'rev', @rev, :size => 8 %>
23 <%= submit_tag 'OK', :name => nil %>
23 <%= submit_tag 'OK', :name => nil %>
24 <% end %>
24 <% end %>
25 </div>
25 </div>
26
26
27 <h2><%= avatar(@changeset.user, :size => "24") %><%= l(:label_revision) %> <%= format_revision(@changeset) %></h2>
27 <h2><%= avatar(@changeset.user, :size => "24") %><%= l(:label_revision) %> <%= format_revision(@changeset) %></h2>
28
28
29 <% if @changeset.scmid.present? || @changeset.parents.present? || @changeset.children.present? %>
29 <% if @changeset.scmid.present? || @changeset.parents.present? || @changeset.children.present? %>
30 <table class="revision-info">
30 <table class="revision-info">
31 <% if @changeset.scmid.present? %>
31 <% if @changeset.scmid.present? %>
32 <tr>
32 <tr>
33 <td>ID</td><td><%= h(@changeset.scmid) %></td>
33 <td>ID</td><td><%= h(@changeset.scmid) %></td>
34 </tr>
34 </tr>
35 <% end %>
35 <% end %>
36 <% if @changeset.parents.present? %>
36 <% if @changeset.parents.present? %>
37 <tr>
37 <tr>
38 <td><%= l(:label_parent_revision) %></td>
38 <td><%= l(:label_parent_revision) %></td>
39 <td>
39 <td>
40 <%= @changeset.parents.collect{
40 <%= @changeset.parents.collect{
41 |p| link_to_revision(p, @repository, :text => format_revision(p))
41 |p| link_to_revision(p, @repository, :text => format_revision(p))
42 }.join(", ").html_safe %>
42 }.join(", ").html_safe %>
43 </td>
43 </td>
44 </tr>
44 </tr>
45 <% end %>
45 <% end %>
46 <% if @changeset.children.present? %>
46 <% if @changeset.children.present? %>
47 <tr>
47 <tr>
48 <td><%= l(:label_child_revision) %></td>
48 <td><%= l(:label_child_revision) %></td>
49 <td>
49 <td>
50 <%= @changeset.children.collect{
50 <%= @changeset.children.collect{
51 |p| link_to_revision(p, @repository, :text => format_revision(p))
51 |p| link_to_revision(p, @repository, :text => format_revision(p))
52 }.join(", ").html_safe %>
52 }.join(", ").html_safe %>
53 </td>
53 </td>
54 </tr>
54 </tr>
55 <% end %>
55 <% end %>
56 </table>
56 </table>
57 <% end %>
57 <% end %>
58
58
59 <p>
59 <p>
60 <span class="author">
60 <span class="author">
61 <%= authoring(@changeset.committed_on, @changeset.author) %>
61 <%= authoring(@changeset.committed_on, @changeset.author) %>
62 </span>
62 </span>
63 </p>
63 </p>
64
64
65 <%= textilizable @changeset.comments %>
65 <%= textilizable @changeset.comments %>
66
66
67 <% if @changeset.issues.visible.any? || User.current.allowed_to?(:manage_related_issues, @repository.project) %>
67 <% if @changeset.issues.visible.any? || User.current.allowed_to?(:manage_related_issues, @repository.project) %>
68 <%= render :partial => 'related_issues' %>
68 <%= render :partial => 'related_issues' %>
69 <% end %>
69 <% end %>
70
70
71 <% if User.current.allowed_to?(:browse_repository, @project) %>
71 <% if User.current.allowed_to?(:browse_repository, @project) %>
72 <h3><%= l(:label_attachment_plural) %></h3>
72 <h3><%= l(:label_attachment_plural) %></h3>
73 <ul id="changes-legend">
73 <ul id="changes-legend">
74 <li class="change change-A"><%= l(:label_added) %></li>
74 <li class="change change-A"><%= l(:label_added) %></li>
75 <li class="change change-M"><%= l(:label_modified) %></li>
75 <li class="change change-M"><%= l(:label_modified) %></li>
76 <li class="change change-C"><%= l(:label_copied) %></li>
76 <li class="change change-C"><%= l(:label_copied) %></li>
77 <li class="change change-R"><%= l(:label_renamed) %></li>
77 <li class="change change-R"><%= l(:label_renamed) %></li>
78 <li class="change change-D"><%= l(:label_deleted) %></li>
78 <li class="change change-D"><%= l(:label_deleted) %></li>
79 </ul>
79 </ul>
80
80
81 <p><%= link_to(l(:label_view_diff),
81 <p><%= link_to(l(:label_view_diff),
82 :action => 'diff',
82 :action => 'diff',
83 :id => @project,
83 :id => @project,
84 :repository_id => @repository.identifier_param,
84 :repository_id => @repository.identifier_param,
85 :path => "",
85 :path => "",
86 :rev => @changeset.identifier) if @changeset.changes.any? %></p>
86 :rev => @changeset.identifier) if @changeset.filechanges.any? %></p>
87
87
88 <div class="changeset-changes">
88 <div class="changeset-changes">
89 <%= render_changeset_changes %>
89 <%= render_changeset_changes %>
90 </div>
90 </div>
91 <% end %>
91 <% end %>
92
92
93 <% content_for :header_tags do %>
93 <% content_for :header_tags do %>
94 <%= stylesheet_link_tag "scm" %>
94 <%= stylesheet_link_tag "scm" %>
95 <% end %>
95 <% end %>
96
96
97 <% html_title("#{l(:label_revision)} #{format_revision(@changeset)}") -%>
97 <% html_title("#{l(:label_revision)} #{format_revision(@changeset)}") -%>
@@ -1,147 +1,147
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class RepositoryBazaarTest < ActiveSupport::TestCase
20 class RepositoryBazaarTest < ActiveSupport::TestCase
21 fixtures :projects
21 fixtures :projects
22
22
23 include Redmine::I18n
23 include Redmine::I18n
24
24
25 REPOSITORY_PATH = Rails.root.join('tmp/test/bazaar_repository/trunk').to_s
25 REPOSITORY_PATH = Rails.root.join('tmp/test/bazaar_repository/trunk').to_s
26 REPOSITORY_PATH.gsub!(/\/+/, '/')
26 REPOSITORY_PATH.gsub!(/\/+/, '/')
27 NUM_REV = 4
27 NUM_REV = 4
28
28
29 def setup
29 def setup
30 @project = Project.find(3)
30 @project = Project.find(3)
31 @repository = Repository::Bazaar.create(
31 @repository = Repository::Bazaar.create(
32 :project => @project, :url => "file:///#{REPOSITORY_PATH}",
32 :project => @project, :url => "file:///#{REPOSITORY_PATH}",
33 :log_encoding => 'UTF-8')
33 :log_encoding => 'UTF-8')
34 assert @repository
34 assert @repository
35 end
35 end
36
36
37 def test_blank_path_to_repository_error_message
37 def test_blank_path_to_repository_error_message
38 set_language_if_valid 'en'
38 set_language_if_valid 'en'
39 repo = Repository::Bazaar.new(
39 repo = Repository::Bazaar.new(
40 :project => @project,
40 :project => @project,
41 :identifier => 'test',
41 :identifier => 'test',
42 :log_encoding => 'UTF-8'
42 :log_encoding => 'UTF-8'
43 )
43 )
44 assert !repo.save
44 assert !repo.save
45 assert_include "Path to repository can't be blank",
45 assert_include "Path to repository can't be blank",
46 repo.errors.full_messages
46 repo.errors.full_messages
47 end
47 end
48
48
49 def test_blank_path_to_repository_error_message_fr
49 def test_blank_path_to_repository_error_message_fr
50 set_language_if_valid 'fr'
50 set_language_if_valid 'fr'
51 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)"
51 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)"
52 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
52 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
53 repo = Repository::Bazaar.new(
53 repo = Repository::Bazaar.new(
54 :project => @project,
54 :project => @project,
55 :url => "",
55 :url => "",
56 :identifier => 'test',
56 :identifier => 'test',
57 :log_encoding => 'UTF-8'
57 :log_encoding => 'UTF-8'
58 )
58 )
59 assert !repo.save
59 assert !repo.save
60 assert_include str, repo.errors.full_messages
60 assert_include str, repo.errors.full_messages
61 end
61 end
62
62
63 if File.directory?(REPOSITORY_PATH)
63 if File.directory?(REPOSITORY_PATH)
64 def test_fetch_changesets_from_scratch
64 def test_fetch_changesets_from_scratch
65 assert_equal 0, @repository.changesets.count
65 assert_equal 0, @repository.changesets.count
66 @repository.fetch_changesets
66 @repository.fetch_changesets
67 @project.reload
67 @project.reload
68
68
69 assert_equal NUM_REV, @repository.changesets.count
69 assert_equal NUM_REV, @repository.changesets.count
70 assert_equal 9, @repository.changes.count
70 assert_equal 9, @repository.filechanges.count
71 assert_equal 'Initial import', @repository.changesets.find_by_revision('1').comments
71 assert_equal 'Initial import', @repository.changesets.find_by_revision('1').comments
72 end
72 end
73
73
74 def test_fetch_changesets_incremental
74 def test_fetch_changesets_incremental
75 assert_equal 0, @repository.changesets.count
75 assert_equal 0, @repository.changesets.count
76 @repository.fetch_changesets
76 @repository.fetch_changesets
77 @project.reload
77 @project.reload
78 assert_equal NUM_REV, @repository.changesets.count
78 assert_equal NUM_REV, @repository.changesets.count
79 # Remove changesets with revision > 5
79 # Remove changesets with revision > 5
80 @repository.changesets.find(:all).each {|c| c.destroy if c.revision.to_i > 2}
80 @repository.changesets.find(:all).each {|c| c.destroy if c.revision.to_i > 2}
81 @project.reload
81 @project.reload
82 assert_equal 2, @repository.changesets.count
82 assert_equal 2, @repository.changesets.count
83
83
84 @repository.fetch_changesets
84 @repository.fetch_changesets
85 @project.reload
85 @project.reload
86 assert_equal NUM_REV, @repository.changesets.count
86 assert_equal NUM_REV, @repository.changesets.count
87 end
87 end
88
88
89 def test_entries
89 def test_entries
90 entries = @repository.entries
90 entries = @repository.entries
91 assert_equal 2, entries.size
91 assert_equal 2, entries.size
92
92
93 assert_equal 'dir', entries[0].kind
93 assert_equal 'dir', entries[0].kind
94 assert_equal 'directory', entries[0].name
94 assert_equal 'directory', entries[0].name
95
95
96 assert_equal 'file', entries[1].kind
96 assert_equal 'file', entries[1].kind
97 assert_equal 'doc-mkdir.txt', entries[1].name
97 assert_equal 'doc-mkdir.txt', entries[1].name
98 end
98 end
99
99
100 def test_entries_in_subdirectory
100 def test_entries_in_subdirectory
101 entries = @repository.entries('directory')
101 entries = @repository.entries('directory')
102 assert_equal 3, entries.size
102 assert_equal 3, entries.size
103
103
104 assert_equal 'file', entries.last.kind
104 assert_equal 'file', entries.last.kind
105 assert_equal 'edit.png', entries.last.name
105 assert_equal 'edit.png', entries.last.name
106 end
106 end
107
107
108 def test_previous
108 def test_previous
109 assert_equal 0, @repository.changesets.count
109 assert_equal 0, @repository.changesets.count
110 @repository.fetch_changesets
110 @repository.fetch_changesets
111 @project.reload
111 @project.reload
112 assert_equal NUM_REV, @repository.changesets.count
112 assert_equal NUM_REV, @repository.changesets.count
113 changeset = @repository.find_changeset_by_name('3')
113 changeset = @repository.find_changeset_by_name('3')
114 assert_equal @repository.find_changeset_by_name('2'), changeset.previous
114 assert_equal @repository.find_changeset_by_name('2'), changeset.previous
115 end
115 end
116
116
117 def test_previous_nil
117 def test_previous_nil
118 assert_equal 0, @repository.changesets.count
118 assert_equal 0, @repository.changesets.count
119 @repository.fetch_changesets
119 @repository.fetch_changesets
120 @project.reload
120 @project.reload
121 assert_equal NUM_REV, @repository.changesets.count
121 assert_equal NUM_REV, @repository.changesets.count
122 changeset = @repository.find_changeset_by_name('1')
122 changeset = @repository.find_changeset_by_name('1')
123 assert_nil changeset.previous
123 assert_nil changeset.previous
124 end
124 end
125
125
126 def test_next
126 def test_next
127 assert_equal 0, @repository.changesets.count
127 assert_equal 0, @repository.changesets.count
128 @repository.fetch_changesets
128 @repository.fetch_changesets
129 @project.reload
129 @project.reload
130 assert_equal NUM_REV, @repository.changesets.count
130 assert_equal NUM_REV, @repository.changesets.count
131 changeset = @repository.find_changeset_by_name('2')
131 changeset = @repository.find_changeset_by_name('2')
132 assert_equal @repository.find_changeset_by_name('3'), changeset.next
132 assert_equal @repository.find_changeset_by_name('3'), changeset.next
133 end
133 end
134
134
135 def test_next_nil
135 def test_next_nil
136 assert_equal 0, @repository.changesets.count
136 assert_equal 0, @repository.changesets.count
137 @repository.fetch_changesets
137 @repository.fetch_changesets
138 @project.reload
138 @project.reload
139 assert_equal NUM_REV, @repository.changesets.count
139 assert_equal NUM_REV, @repository.changesets.count
140 changeset = @repository.find_changeset_by_name('4')
140 changeset = @repository.find_changeset_by_name('4')
141 assert_nil changeset.next
141 assert_nil changeset.next
142 end
142 end
143 else
143 else
144 puts "Bazaar test repository NOT FOUND. Skipping unit tests !!!"
144 puts "Bazaar test repository NOT FOUND. Skipping unit tests !!!"
145 def test_fake; assert true end
145 def test_fake; assert true end
146 end
146 end
147 end
147 end
@@ -1,240 +1,240
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19 require 'pp'
19 require 'pp'
20 class RepositoryCvsTest < ActiveSupport::TestCase
20 class RepositoryCvsTest < ActiveSupport::TestCase
21 fixtures :projects
21 fixtures :projects
22
22
23 include Redmine::I18n
23 include Redmine::I18n
24
24
25 REPOSITORY_PATH = Rails.root.join('tmp/test/cvs_repository').to_s
25 REPOSITORY_PATH = Rails.root.join('tmp/test/cvs_repository').to_s
26 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
26 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
27 # CVS module
27 # CVS module
28 MODULE_NAME = 'test'
28 MODULE_NAME = 'test'
29 CHANGESETS_NUM = 7
29 CHANGESETS_NUM = 7
30
30
31 def setup
31 def setup
32 @project = Project.find(3)
32 @project = Project.find(3)
33 @repository = Repository::Cvs.create(:project => @project,
33 @repository = Repository::Cvs.create(:project => @project,
34 :root_url => REPOSITORY_PATH,
34 :root_url => REPOSITORY_PATH,
35 :url => MODULE_NAME,
35 :url => MODULE_NAME,
36 :log_encoding => 'UTF-8')
36 :log_encoding => 'UTF-8')
37 assert @repository
37 assert @repository
38 end
38 end
39
39
40 def test_blank_module_error_message
40 def test_blank_module_error_message
41 set_language_if_valid 'en'
41 set_language_if_valid 'en'
42 repo = Repository::Cvs.new(
42 repo = Repository::Cvs.new(
43 :project => @project,
43 :project => @project,
44 :identifier => 'test',
44 :identifier => 'test',
45 :log_encoding => 'UTF-8',
45 :log_encoding => 'UTF-8',
46 :root_url => REPOSITORY_PATH
46 :root_url => REPOSITORY_PATH
47 )
47 )
48 assert !repo.save
48 assert !repo.save
49 assert_include "Module can't be blank",
49 assert_include "Module can't be blank",
50 repo.errors.full_messages
50 repo.errors.full_messages
51 end
51 end
52
52
53 def test_blank_module_error_message_fr
53 def test_blank_module_error_message_fr
54 set_language_if_valid 'fr'
54 set_language_if_valid 'fr'
55 str = "Module doit \xc3\xaatre renseign\xc3\xa9(e)"
55 str = "Module doit \xc3\xaatre renseign\xc3\xa9(e)"
56 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
56 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
57 repo = Repository::Cvs.new(
57 repo = Repository::Cvs.new(
58 :project => @project,
58 :project => @project,
59 :identifier => 'test',
59 :identifier => 'test',
60 :log_encoding => 'UTF-8',
60 :log_encoding => 'UTF-8',
61 :path_encoding => '',
61 :path_encoding => '',
62 :url => '',
62 :url => '',
63 :root_url => REPOSITORY_PATH
63 :root_url => REPOSITORY_PATH
64 )
64 )
65 assert !repo.save
65 assert !repo.save
66 assert_include str, repo.errors.full_messages
66 assert_include str, repo.errors.full_messages
67 end
67 end
68
68
69 def test_blank_cvsroot_error_message
69 def test_blank_cvsroot_error_message
70 set_language_if_valid 'en'
70 set_language_if_valid 'en'
71 repo = Repository::Cvs.new(
71 repo = Repository::Cvs.new(
72 :project => @project,
72 :project => @project,
73 :identifier => 'test',
73 :identifier => 'test',
74 :log_encoding => 'UTF-8',
74 :log_encoding => 'UTF-8',
75 :url => MODULE_NAME
75 :url => MODULE_NAME
76 )
76 )
77 assert !repo.save
77 assert !repo.save
78 assert_include "CVSROOT can't be blank",
78 assert_include "CVSROOT can't be blank",
79 repo.errors.full_messages
79 repo.errors.full_messages
80 end
80 end
81
81
82 def test_blank_cvsroot_error_message_fr
82 def test_blank_cvsroot_error_message_fr
83 set_language_if_valid 'fr'
83 set_language_if_valid 'fr'
84 str = "CVSROOT doit \xc3\xaatre renseign\xc3\xa9(e)"
84 str = "CVSROOT doit \xc3\xaatre renseign\xc3\xa9(e)"
85 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
85 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
86 repo = Repository::Cvs.new(
86 repo = Repository::Cvs.new(
87 :project => @project,
87 :project => @project,
88 :identifier => 'test',
88 :identifier => 'test',
89 :log_encoding => 'UTF-8',
89 :log_encoding => 'UTF-8',
90 :path_encoding => '',
90 :path_encoding => '',
91 :url => MODULE_NAME,
91 :url => MODULE_NAME,
92 :root_url => ''
92 :root_url => ''
93 )
93 )
94 assert !repo.save
94 assert !repo.save
95 assert_include str, repo.errors.full_messages
95 assert_include str, repo.errors.full_messages
96 end
96 end
97
97
98 if File.directory?(REPOSITORY_PATH)
98 if File.directory?(REPOSITORY_PATH)
99 def test_fetch_changesets_from_scratch
99 def test_fetch_changesets_from_scratch
100 assert_equal 0, @repository.changesets.count
100 assert_equal 0, @repository.changesets.count
101 @repository.fetch_changesets
101 @repository.fetch_changesets
102 @project.reload
102 @project.reload
103
103
104 assert_equal CHANGESETS_NUM, @repository.changesets.count
104 assert_equal CHANGESETS_NUM, @repository.changesets.count
105 assert_equal 16, @repository.changes.count
105 assert_equal 16, @repository.filechanges.count
106 assert_not_nil @repository.changesets.find_by_comments('Two files changed')
106 assert_not_nil @repository.changesets.find_by_comments('Two files changed')
107
107
108 r2 = @repository.changesets.find_by_revision('2')
108 r2 = @repository.changesets.find_by_revision('2')
109 assert_equal 'v1-20071213-162510', r2.scmid
109 assert_equal 'v1-20071213-162510', r2.scmid
110 end
110 end
111
111
112 def test_fetch_changesets_incremental
112 def test_fetch_changesets_incremental
113 assert_equal 0, @repository.changesets.count
113 assert_equal 0, @repository.changesets.count
114 @repository.fetch_changesets
114 @repository.fetch_changesets
115 @project.reload
115 @project.reload
116 assert_equal CHANGESETS_NUM, @repository.changesets.count
116 assert_equal CHANGESETS_NUM, @repository.changesets.count
117
117
118 # Remove changesets with revision > 3
118 # Remove changesets with revision > 3
119 @repository.changesets.find(:all).each {|c| c.destroy if c.revision.to_i > 3}
119 @repository.changesets.find(:all).each {|c| c.destroy if c.revision.to_i > 3}
120 @project.reload
120 @project.reload
121 assert_equal 3, @repository.changesets.count
121 assert_equal 3, @repository.changesets.count
122 assert_equal %w|3 2 1|, @repository.changesets.all.collect(&:revision)
122 assert_equal %w|3 2 1|, @repository.changesets.all.collect(&:revision)
123
123
124 rev3_commit = @repository.changesets.find(:first, :order => 'committed_on DESC')
124 rev3_commit = @repository.changesets.find(:first, :order => 'committed_on DESC')
125 assert_equal '3', rev3_commit.revision
125 assert_equal '3', rev3_commit.revision
126 # 2007-12-14 01:27:22 +0900
126 # 2007-12-14 01:27:22 +0900
127 rev3_committed_on = Time.gm(2007, 12, 13, 16, 27, 22)
127 rev3_committed_on = Time.gm(2007, 12, 13, 16, 27, 22)
128 assert_equal 'HEAD-20071213-162722', rev3_commit.scmid
128 assert_equal 'HEAD-20071213-162722', rev3_commit.scmid
129 assert_equal rev3_committed_on, rev3_commit.committed_on
129 assert_equal rev3_committed_on, rev3_commit.committed_on
130 latest_rev = @repository.latest_changeset
130 latest_rev = @repository.latest_changeset
131 assert_equal rev3_committed_on, latest_rev.committed_on
131 assert_equal rev3_committed_on, latest_rev.committed_on
132
132
133 @repository.fetch_changesets
133 @repository.fetch_changesets
134 @project.reload
134 @project.reload
135 assert_equal CHANGESETS_NUM, @repository.changesets.count
135 assert_equal CHANGESETS_NUM, @repository.changesets.count
136 assert_equal %w|7 6 5 4 3 2 1|, @repository.changesets.all.collect(&:revision)
136 assert_equal %w|7 6 5 4 3 2 1|, @repository.changesets.all.collect(&:revision)
137 rev5_commit = @repository.changesets.find_by_revision('5')
137 rev5_commit = @repository.changesets.find_by_revision('5')
138 assert_equal 'HEAD-20071213-163001', rev5_commit.scmid
138 assert_equal 'HEAD-20071213-163001', rev5_commit.scmid
139 # 2007-12-14 01:30:01 +0900
139 # 2007-12-14 01:30:01 +0900
140 rev5_committed_on = Time.gm(2007, 12, 13, 16, 30, 1)
140 rev5_committed_on = Time.gm(2007, 12, 13, 16, 30, 1)
141 assert_equal rev5_committed_on, rev5_commit.committed_on
141 assert_equal rev5_committed_on, rev5_commit.committed_on
142 end
142 end
143
143
144 def test_deleted_files_should_not_be_listed
144 def test_deleted_files_should_not_be_listed
145 assert_equal 0, @repository.changesets.count
145 assert_equal 0, @repository.changesets.count
146 @repository.fetch_changesets
146 @repository.fetch_changesets
147 @project.reload
147 @project.reload
148 assert_equal CHANGESETS_NUM, @repository.changesets.count
148 assert_equal CHANGESETS_NUM, @repository.changesets.count
149
149
150 entries = @repository.entries('sources')
150 entries = @repository.entries('sources')
151 assert entries.detect {|e| e.name == 'watchers_controller.rb'}
151 assert entries.detect {|e| e.name == 'watchers_controller.rb'}
152 assert_nil entries.detect {|e| e.name == 'welcome_controller.rb'}
152 assert_nil entries.detect {|e| e.name == 'welcome_controller.rb'}
153 end
153 end
154
154
155 def test_entries_rev3
155 def test_entries_rev3
156 assert_equal 0, @repository.changesets.count
156 assert_equal 0, @repository.changesets.count
157 @repository.fetch_changesets
157 @repository.fetch_changesets
158 @project.reload
158 @project.reload
159 assert_equal CHANGESETS_NUM, @repository.changesets.count
159 assert_equal CHANGESETS_NUM, @repository.changesets.count
160 entries = @repository.entries('', '3')
160 entries = @repository.entries('', '3')
161 assert_equal 3, entries.size
161 assert_equal 3, entries.size
162 assert_equal entries[2].name, "README"
162 assert_equal entries[2].name, "README"
163 assert_equal entries[2].lastrev.time, Time.gm(2007, 12, 13, 16, 27, 22)
163 assert_equal entries[2].lastrev.time, Time.gm(2007, 12, 13, 16, 27, 22)
164 assert_equal entries[2].lastrev.identifier, '3'
164 assert_equal entries[2].lastrev.identifier, '3'
165 assert_equal entries[2].lastrev.revision, '3'
165 assert_equal entries[2].lastrev.revision, '3'
166 assert_equal entries[2].lastrev.author, 'LANG'
166 assert_equal entries[2].lastrev.author, 'LANG'
167 end
167 end
168
168
169 def test_entries_invalid_path
169 def test_entries_invalid_path
170 assert_equal 0, @repository.changesets.count
170 assert_equal 0, @repository.changesets.count
171 @repository.fetch_changesets
171 @repository.fetch_changesets
172 @project.reload
172 @project.reload
173 assert_equal CHANGESETS_NUM, @repository.changesets.count
173 assert_equal CHANGESETS_NUM, @repository.changesets.count
174 assert_nil @repository.entries('missing')
174 assert_nil @repository.entries('missing')
175 assert_nil @repository.entries('missing', '3')
175 assert_nil @repository.entries('missing', '3')
176 end
176 end
177
177
178 def test_entries_invalid_revision
178 def test_entries_invalid_revision
179 assert_equal 0, @repository.changesets.count
179 assert_equal 0, @repository.changesets.count
180 @repository.fetch_changesets
180 @repository.fetch_changesets
181 @project.reload
181 @project.reload
182 assert_equal CHANGESETS_NUM, @repository.changesets.count
182 assert_equal CHANGESETS_NUM, @repository.changesets.count
183 assert_nil @repository.entries('', '123')
183 assert_nil @repository.entries('', '123')
184 end
184 end
185
185
186 def test_cat
186 def test_cat
187 assert_equal 0, @repository.changesets.count
187 assert_equal 0, @repository.changesets.count
188 @repository.fetch_changesets
188 @repository.fetch_changesets
189 @project.reload
189 @project.reload
190 assert_equal CHANGESETS_NUM, @repository.changesets.count
190 assert_equal CHANGESETS_NUM, @repository.changesets.count
191 buf = @repository.cat('README')
191 buf = @repository.cat('README')
192 assert buf
192 assert buf
193 lines = buf.split("\n")
193 lines = buf.split("\n")
194 assert_equal 3, lines.length
194 assert_equal 3, lines.length
195 buf = lines[1].gsub(/\r$/, "")
195 buf = lines[1].gsub(/\r$/, "")
196 assert_equal 'with one change', buf
196 assert_equal 'with one change', buf
197 buf = @repository.cat('README', '1')
197 buf = @repository.cat('README', '1')
198 assert buf
198 assert buf
199 lines = buf.split("\n")
199 lines = buf.split("\n")
200 assert_equal 1, lines.length
200 assert_equal 1, lines.length
201 buf = lines[0].gsub(/\r$/, "")
201 buf = lines[0].gsub(/\r$/, "")
202 assert_equal 'CVS test repository', buf
202 assert_equal 'CVS test repository', buf
203 assert_nil @repository.cat('missing.rb')
203 assert_nil @repository.cat('missing.rb')
204
204
205 # sources/welcome_controller.rb is removed at revision 5.
205 # sources/welcome_controller.rb is removed at revision 5.
206 assert @repository.cat('sources/welcome_controller.rb', '4')
206 assert @repository.cat('sources/welcome_controller.rb', '4')
207 assert @repository.cat('sources/welcome_controller.rb', '5').blank?
207 assert @repository.cat('sources/welcome_controller.rb', '5').blank?
208
208
209 # invalid revision
209 # invalid revision
210 assert @repository.cat('README', '123').blank?
210 assert @repository.cat('README', '123').blank?
211 end
211 end
212
212
213 def test_annotate
213 def test_annotate
214 assert_equal 0, @repository.changesets.count
214 assert_equal 0, @repository.changesets.count
215 @repository.fetch_changesets
215 @repository.fetch_changesets
216 @project.reload
216 @project.reload
217 assert_equal CHANGESETS_NUM, @repository.changesets.count
217 assert_equal CHANGESETS_NUM, @repository.changesets.count
218 ann = @repository.annotate('README')
218 ann = @repository.annotate('README')
219 assert ann
219 assert ann
220 assert_equal 3, ann.revisions.length
220 assert_equal 3, ann.revisions.length
221 assert_equal '1.2', ann.revisions[1].revision
221 assert_equal '1.2', ann.revisions[1].revision
222 assert_equal 'LANG', ann.revisions[1].author
222 assert_equal 'LANG', ann.revisions[1].author
223 assert_equal 'with one change', ann.lines[1]
223 assert_equal 'with one change', ann.lines[1]
224
224
225 ann = @repository.annotate('README', '1')
225 ann = @repository.annotate('README', '1')
226 assert ann
226 assert ann
227 assert_equal 1, ann.revisions.length
227 assert_equal 1, ann.revisions.length
228 assert_equal '1.1', ann.revisions[0].revision
228 assert_equal '1.1', ann.revisions[0].revision
229 assert_equal 'LANG', ann.revisions[0].author
229 assert_equal 'LANG', ann.revisions[0].author
230 assert_equal 'CVS test repository', ann.lines[0]
230 assert_equal 'CVS test repository', ann.lines[0]
231
231
232 # invalid revision
232 # invalid revision
233 assert_nil @repository.annotate('README', '123')
233 assert_nil @repository.annotate('README', '123')
234 end
234 end
235
235
236 else
236 else
237 puts "CVS test repository NOT FOUND. Skipping unit tests !!!"
237 puts "CVS test repository NOT FOUND. Skipping unit tests !!!"
238 def test_fake; assert true end
238 def test_fake; assert true end
239 end
239 end
240 end
240 end
@@ -1,124 +1,124
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class RepositoryDarcsTest < ActiveSupport::TestCase
20 class RepositoryDarcsTest < ActiveSupport::TestCase
21 fixtures :projects
21 fixtures :projects
22
22
23 include Redmine::I18n
23 include Redmine::I18n
24
24
25 REPOSITORY_PATH = Rails.root.join('tmp/test/darcs_repository').to_s
25 REPOSITORY_PATH = Rails.root.join('tmp/test/darcs_repository').to_s
26 NUM_REV = 6
26 NUM_REV = 6
27
27
28 def setup
28 def setup
29 @project = Project.find(3)
29 @project = Project.find(3)
30 @repository = Repository::Darcs.create(
30 @repository = Repository::Darcs.create(
31 :project => @project,
31 :project => @project,
32 :url => REPOSITORY_PATH,
32 :url => REPOSITORY_PATH,
33 :log_encoding => 'UTF-8'
33 :log_encoding => 'UTF-8'
34 )
34 )
35 assert @repository
35 assert @repository
36 end
36 end
37
37
38 def test_blank_path_to_repository_error_message
38 def test_blank_path_to_repository_error_message
39 set_language_if_valid 'en'
39 set_language_if_valid 'en'
40 repo = Repository::Darcs.new(
40 repo = Repository::Darcs.new(
41 :project => @project,
41 :project => @project,
42 :identifier => 'test',
42 :identifier => 'test',
43 :log_encoding => 'UTF-8'
43 :log_encoding => 'UTF-8'
44 )
44 )
45 assert !repo.save
45 assert !repo.save
46 assert_include "Path to repository can't be blank",
46 assert_include "Path to repository can't be blank",
47 repo.errors.full_messages
47 repo.errors.full_messages
48 end
48 end
49
49
50 def test_blank_path_to_repository_error_message_fr
50 def test_blank_path_to_repository_error_message_fr
51 set_language_if_valid 'fr'
51 set_language_if_valid 'fr'
52 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)"
52 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)"
53 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
53 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
54 repo = Repository::Darcs.new(
54 repo = Repository::Darcs.new(
55 :project => @project,
55 :project => @project,
56 :url => "",
56 :url => "",
57 :identifier => 'test',
57 :identifier => 'test',
58 :log_encoding => 'UTF-8'
58 :log_encoding => 'UTF-8'
59 )
59 )
60 assert !repo.save
60 assert !repo.save
61 assert_include str, repo.errors.full_messages
61 assert_include str, repo.errors.full_messages
62 end
62 end
63
63
64 if File.directory?(REPOSITORY_PATH)
64 if File.directory?(REPOSITORY_PATH)
65 def test_fetch_changesets_from_scratch
65 def test_fetch_changesets_from_scratch
66 assert_equal 0, @repository.changesets.count
66 assert_equal 0, @repository.changesets.count
67 @repository.fetch_changesets
67 @repository.fetch_changesets
68 @project.reload
68 @project.reload
69
69
70 assert_equal NUM_REV, @repository.changesets.count
70 assert_equal NUM_REV, @repository.changesets.count
71 assert_equal 13, @repository.changes.count
71 assert_equal 13, @repository.filechanges.count
72 assert_equal "Initial commit.", @repository.changesets.find_by_revision('1').comments
72 assert_equal "Initial commit.", @repository.changesets.find_by_revision('1').comments
73 end
73 end
74
74
75 def test_fetch_changesets_incremental
75 def test_fetch_changesets_incremental
76 assert_equal 0, @repository.changesets.count
76 assert_equal 0, @repository.changesets.count
77 @repository.fetch_changesets
77 @repository.fetch_changesets
78 @project.reload
78 @project.reload
79 assert_equal NUM_REV, @repository.changesets.count
79 assert_equal NUM_REV, @repository.changesets.count
80
80
81 # Remove changesets with revision > 3
81 # Remove changesets with revision > 3
82 @repository.changesets.find(:all).each {|c| c.destroy if c.revision.to_i > 3}
82 @repository.changesets.find(:all).each {|c| c.destroy if c.revision.to_i > 3}
83 @project.reload
83 @project.reload
84 assert_equal 3, @repository.changesets.count
84 assert_equal 3, @repository.changesets.count
85
85
86 @repository.fetch_changesets
86 @repository.fetch_changesets
87 @project.reload
87 @project.reload
88 assert_equal NUM_REV, @repository.changesets.count
88 assert_equal NUM_REV, @repository.changesets.count
89 end
89 end
90
90
91 def test_entries_invalid_revision
91 def test_entries_invalid_revision
92 assert_equal 0, @repository.changesets.count
92 assert_equal 0, @repository.changesets.count
93 @repository.fetch_changesets
93 @repository.fetch_changesets
94 @project.reload
94 @project.reload
95 assert_equal NUM_REV, @repository.changesets.count
95 assert_equal NUM_REV, @repository.changesets.count
96 assert_nil @repository.entries('', '123')
96 assert_nil @repository.entries('', '123')
97 end
97 end
98
98
99 def test_deleted_files_should_not_be_listed
99 def test_deleted_files_should_not_be_listed
100 assert_equal 0, @repository.changesets.count
100 assert_equal 0, @repository.changesets.count
101 @repository.fetch_changesets
101 @repository.fetch_changesets
102 @project.reload
102 @project.reload
103 assert_equal NUM_REV, @repository.changesets.count
103 assert_equal NUM_REV, @repository.changesets.count
104 entries = @repository.entries('sources')
104 entries = @repository.entries('sources')
105 assert entries.detect {|e| e.name == 'watchers_controller.rb'}
105 assert entries.detect {|e| e.name == 'watchers_controller.rb'}
106 assert_nil entries.detect {|e| e.name == 'welcome_controller.rb'}
106 assert_nil entries.detect {|e| e.name == 'welcome_controller.rb'}
107 end
107 end
108
108
109 def test_cat
109 def test_cat
110 if @repository.scm.supports_cat?
110 if @repository.scm.supports_cat?
111 assert_equal 0, @repository.changesets.count
111 assert_equal 0, @repository.changesets.count
112 @repository.fetch_changesets
112 @repository.fetch_changesets
113 @project.reload
113 @project.reload
114 assert_equal NUM_REV, @repository.changesets.count
114 assert_equal NUM_REV, @repository.changesets.count
115 cat = @repository.cat("sources/welcome_controller.rb", 2)
115 cat = @repository.cat("sources/welcome_controller.rb", 2)
116 assert_not_nil cat
116 assert_not_nil cat
117 assert cat.include?('class WelcomeController < ApplicationController')
117 assert cat.include?('class WelcomeController < ApplicationController')
118 end
118 end
119 end
119 end
120 else
120 else
121 puts "Darcs test repository NOT FOUND. Skipping unit tests !!!"
121 puts "Darcs test repository NOT FOUND. Skipping unit tests !!!"
122 def test_fake; assert true end
122 def test_fake; assert true end
123 end
123 end
124 end
124 end
@@ -1,84 +1,84
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class RepositoryFilesystemTest < ActiveSupport::TestCase
20 class RepositoryFilesystemTest < ActiveSupport::TestCase
21 fixtures :projects
21 fixtures :projects
22
22
23 include Redmine::I18n
23 include Redmine::I18n
24
24
25 REPOSITORY_PATH = Rails.root.join('tmp/test/filesystem_repository').to_s
25 REPOSITORY_PATH = Rails.root.join('tmp/test/filesystem_repository').to_s
26
26
27 def setup
27 def setup
28 @project = Project.find(3)
28 @project = Project.find(3)
29 Setting.enabled_scm << 'Filesystem' unless Setting.enabled_scm.include?('Filesystem')
29 Setting.enabled_scm << 'Filesystem' unless Setting.enabled_scm.include?('Filesystem')
30 @repository = Repository::Filesystem.create(
30 @repository = Repository::Filesystem.create(
31 :project => @project,
31 :project => @project,
32 :url => REPOSITORY_PATH
32 :url => REPOSITORY_PATH
33 )
33 )
34 assert @repository
34 assert @repository
35 end
35 end
36
36
37 def test_blank_root_directory_error_message
37 def test_blank_root_directory_error_message
38 set_language_if_valid 'en'
38 set_language_if_valid 'en'
39 repo = Repository::Filesystem.new(
39 repo = Repository::Filesystem.new(
40 :project => @project,
40 :project => @project,
41 :identifier => 'test'
41 :identifier => 'test'
42 )
42 )
43 assert !repo.save
43 assert !repo.save
44 assert_include "Root directory can't be blank",
44 assert_include "Root directory can't be blank",
45 repo.errors.full_messages
45 repo.errors.full_messages
46 end
46 end
47
47
48 def test_blank_root_directory_error_message_fr
48 def test_blank_root_directory_error_message_fr
49 set_language_if_valid 'fr'
49 set_language_if_valid 'fr'
50 str = "R\xc3\xa9pertoire racine doit \xc3\xaatre renseign\xc3\xa9(e)"
50 str = "R\xc3\xa9pertoire racine doit \xc3\xaatre renseign\xc3\xa9(e)"
51 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
51 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
52 repo = Repository::Filesystem.new(
52 repo = Repository::Filesystem.new(
53 :project => @project,
53 :project => @project,
54 :url => "",
54 :url => "",
55 :identifier => 'test',
55 :identifier => 'test',
56 :path_encoding => ''
56 :path_encoding => ''
57 )
57 )
58 assert !repo.save
58 assert !repo.save
59 assert_include str, repo.errors.full_messages
59 assert_include str, repo.errors.full_messages
60 end
60 end
61
61
62 if File.directory?(REPOSITORY_PATH)
62 if File.directory?(REPOSITORY_PATH)
63 def test_fetch_changesets
63 def test_fetch_changesets
64 assert_equal 0, @repository.changesets.count
64 assert_equal 0, @repository.changesets.count
65 assert_equal 0, @repository.changes.count
65 assert_equal 0, @repository.filechanges.count
66 @repository.fetch_changesets
66 @repository.fetch_changesets
67 @project.reload
67 @project.reload
68 assert_equal 0, @repository.changesets.count
68 assert_equal 0, @repository.changesets.count
69 assert_equal 0, @repository.changes.count
69 assert_equal 0, @repository.filechanges.count
70 end
70 end
71
71
72 def test_entries
72 def test_entries
73 assert_equal 3, @repository.entries("", 2).size
73 assert_equal 3, @repository.entries("", 2).size
74 assert_equal 2, @repository.entries("dir", 3).size
74 assert_equal 2, @repository.entries("dir", 3).size
75 end
75 end
76
76
77 def test_cat
77 def test_cat
78 assert_equal "TEST CAT\n", @repository.scm.cat("test")
78 assert_equal "TEST CAT\n", @repository.scm.cat("test")
79 end
79 end
80 else
80 else
81 puts "Filesystem test repository NOT FOUND. Skipping unit tests !!! See doc/RUNNING_TESTS."
81 puts "Filesystem test repository NOT FOUND. Skipping unit tests !!! See doc/RUNNING_TESTS."
82 def test_fake; assert true end
82 def test_fake; assert true end
83 end
83 end
84 end
84 end
@@ -1,562 +1,562
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class RepositoryGitTest < ActiveSupport::TestCase
20 class RepositoryGitTest < ActiveSupport::TestCase
21 fixtures :projects, :repositories, :enabled_modules, :users, :roles
21 fixtures :projects, :repositories, :enabled_modules, :users, :roles
22
22
23 include Redmine::I18n
23 include Redmine::I18n
24
24
25 REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
25 REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
26 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
26 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
27
27
28 NUM_REV = 28
28 NUM_REV = 28
29 NUM_HEAD = 6
29 NUM_HEAD = 6
30
30
31 FELIX_HEX = "Felix Sch\xC3\xA4fer"
31 FELIX_HEX = "Felix Sch\xC3\xA4fer"
32 CHAR_1_HEX = "\xc3\x9c"
32 CHAR_1_HEX = "\xc3\x9c"
33
33
34 ## Ruby uses ANSI api to fork a process on Windows.
34 ## Ruby uses ANSI api to fork a process on Windows.
35 ## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
35 ## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
36 ## and these are incompatible with ASCII.
36 ## and these are incompatible with ASCII.
37 ## Git for Windows (msysGit) changed internal API from ANSI to Unicode in 1.7.10
37 ## Git for Windows (msysGit) changed internal API from ANSI to Unicode in 1.7.10
38 ## http://code.google.com/p/msysgit/issues/detail?id=80
38 ## http://code.google.com/p/msysgit/issues/detail?id=80
39 ## So, Latin-1 path tests fail on Japanese Windows
39 ## So, Latin-1 path tests fail on Japanese Windows
40 WINDOWS_PASS = (Redmine::Platform.mswin? &&
40 WINDOWS_PASS = (Redmine::Platform.mswin? &&
41 Redmine::Scm::Adapters::GitAdapter.client_version_above?([1, 7, 10]))
41 Redmine::Scm::Adapters::GitAdapter.client_version_above?([1, 7, 10]))
42 WINDOWS_SKIP_STR = "TODO: This test fails in Git for Windows above 1.7.10"
42 WINDOWS_SKIP_STR = "TODO: This test fails in Git for Windows above 1.7.10"
43
43
44 ## Git, Mercurial and CVS path encodings are binary.
44 ## Git, Mercurial and CVS path encodings are binary.
45 ## Subversion supports URL encoding for path.
45 ## Subversion supports URL encoding for path.
46 ## Redmine Mercurial adapter and extension use URL encoding.
46 ## Redmine Mercurial adapter and extension use URL encoding.
47 ## Git accepts only binary path in command line parameter.
47 ## Git accepts only binary path in command line parameter.
48 ## So, there is no way to use binary command line parameter in JRuby.
48 ## So, there is no way to use binary command line parameter in JRuby.
49 JRUBY_SKIP = (RUBY_PLATFORM == 'java')
49 JRUBY_SKIP = (RUBY_PLATFORM == 'java')
50 JRUBY_SKIP_STR = "TODO: This test fails in JRuby"
50 JRUBY_SKIP_STR = "TODO: This test fails in JRuby"
51
51
52 def setup
52 def setup
53 @project = Project.find(3)
53 @project = Project.find(3)
54 @repository = Repository::Git.create(
54 @repository = Repository::Git.create(
55 :project => @project,
55 :project => @project,
56 :url => REPOSITORY_PATH,
56 :url => REPOSITORY_PATH,
57 :path_encoding => 'ISO-8859-1'
57 :path_encoding => 'ISO-8859-1'
58 )
58 )
59 assert @repository
59 assert @repository
60 @char_1 = CHAR_1_HEX.dup
60 @char_1 = CHAR_1_HEX.dup
61 if @char_1.respond_to?(:force_encoding)
61 if @char_1.respond_to?(:force_encoding)
62 @char_1.force_encoding('UTF-8')
62 @char_1.force_encoding('UTF-8')
63 end
63 end
64 end
64 end
65
65
66 def test_blank_path_to_repository_error_message
66 def test_blank_path_to_repository_error_message
67 set_language_if_valid 'en'
67 set_language_if_valid 'en'
68 repo = Repository::Git.new(
68 repo = Repository::Git.new(
69 :project => @project,
69 :project => @project,
70 :identifier => 'test'
70 :identifier => 'test'
71 )
71 )
72 assert !repo.save
72 assert !repo.save
73 assert_include "Path to repository can't be blank",
73 assert_include "Path to repository can't be blank",
74 repo.errors.full_messages
74 repo.errors.full_messages
75 end
75 end
76
76
77 def test_blank_path_to_repository_error_message_fr
77 def test_blank_path_to_repository_error_message_fr
78 set_language_if_valid 'fr'
78 set_language_if_valid 'fr'
79 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)"
79 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)"
80 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
80 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
81 repo = Repository::Git.new(
81 repo = Repository::Git.new(
82 :project => @project,
82 :project => @project,
83 :url => "",
83 :url => "",
84 :identifier => 'test',
84 :identifier => 'test',
85 :path_encoding => ''
85 :path_encoding => ''
86 )
86 )
87 assert !repo.save
87 assert !repo.save
88 assert_include str, repo.errors.full_messages
88 assert_include str, repo.errors.full_messages
89 end
89 end
90
90
91 if File.directory?(REPOSITORY_PATH)
91 if File.directory?(REPOSITORY_PATH)
92 def test_scm_available
92 def test_scm_available
93 klass = Repository::Git
93 klass = Repository::Git
94 assert_equal "Git", klass.scm_name
94 assert_equal "Git", klass.scm_name
95 assert klass.scm_adapter_class
95 assert klass.scm_adapter_class
96 assert_not_equal "", klass.scm_command
96 assert_not_equal "", klass.scm_command
97 assert_equal true, klass.scm_available
97 assert_equal true, klass.scm_available
98 end
98 end
99
99
100 def test_fetch_changesets_from_scratch
100 def test_fetch_changesets_from_scratch
101 assert_nil @repository.extra_info
101 assert_nil @repository.extra_info
102
102
103 assert_equal 0, @repository.changesets.count
103 assert_equal 0, @repository.changesets.count
104 @repository.fetch_changesets
104 @repository.fetch_changesets
105 @project.reload
105 @project.reload
106
106
107 assert_equal NUM_REV, @repository.changesets.count
107 assert_equal NUM_REV, @repository.changesets.count
108 assert_equal 39, @repository.changes.count
108 assert_equal 39, @repository.filechanges.count
109
109
110 commit = @repository.changesets.find_by_revision("7234cb2750b63f47bff735edc50a1c0a433c2518")
110 commit = @repository.changesets.find_by_revision("7234cb2750b63f47bff735edc50a1c0a433c2518")
111 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", commit.scmid
111 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", commit.scmid
112 assert_equal "Initial import.\nThe repository contains 3 files.", commit.comments
112 assert_equal "Initial import.\nThe repository contains 3 files.", commit.comments
113 assert_equal "jsmith <jsmith@foo.bar>", commit.committer
113 assert_equal "jsmith <jsmith@foo.bar>", commit.committer
114 assert_equal User.find_by_login('jsmith'), commit.user
114 assert_equal User.find_by_login('jsmith'), commit.user
115 # TODO: add a commit with commit time <> author time to the test repository
115 # TODO: add a commit with commit time <> author time to the test repository
116 assert_equal "2007-12-14 09:22:52".to_time, commit.committed_on
116 assert_equal "2007-12-14 09:22:52".to_time, commit.committed_on
117 assert_equal "2007-12-14".to_date, commit.commit_date
117 assert_equal "2007-12-14".to_date, commit.commit_date
118 assert_equal 3, commit.changes.count
118 assert_equal 3, commit.filechanges.count
119 change = commit.changes.sort_by(&:path).first
119 change = commit.filechanges.sort_by(&:path).first
120 assert_equal "README", change.path
120 assert_equal "README", change.path
121 assert_equal nil, change.from_path
121 assert_equal nil, change.from_path
122 assert_equal "A", change.action
122 assert_equal "A", change.action
123
123
124 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
124 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
125 end
125 end
126
126
127 def test_fetch_changesets_incremental
127 def test_fetch_changesets_incremental
128 assert_equal 0, @repository.changesets.count
128 assert_equal 0, @repository.changesets.count
129 @repository.fetch_changesets
129 @repository.fetch_changesets
130 @project.reload
130 @project.reload
131 assert_equal NUM_REV, @repository.changesets.count
131 assert_equal NUM_REV, @repository.changesets.count
132 extra_info_heads = @repository.extra_info["heads"].dup
132 extra_info_heads = @repository.extra_info["heads"].dup
133 assert_equal NUM_HEAD, extra_info_heads.size
133 assert_equal NUM_HEAD, extra_info_heads.size
134 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
134 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
135 assert_equal 4, extra_info_heads.size
135 assert_equal 4, extra_info_heads.size
136
136
137 del_revs = [
137 del_revs = [
138 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
138 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
139 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
139 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
140 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
140 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
141 "deff712f05a90d96edbd70facc47d944be5897e3",
141 "deff712f05a90d96edbd70facc47d944be5897e3",
142 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
142 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
143 "7e61ac704deecde634b51e59daa8110435dcb3da",
143 "7e61ac704deecde634b51e59daa8110435dcb3da",
144 ]
144 ]
145 @repository.changesets.each do |rev|
145 @repository.changesets.each do |rev|
146 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
146 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
147 end
147 end
148 @project.reload
148 @project.reload
149 cs1 = @repository.changesets
149 cs1 = @repository.changesets
150 assert_equal NUM_REV - 6, cs1.count
150 assert_equal NUM_REV - 6, cs1.count
151 extra_info_heads << "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8"
151 extra_info_heads << "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8"
152 h = {}
152 h = {}
153 h["heads"] = extra_info_heads
153 h["heads"] = extra_info_heads
154 @repository.merge_extra_info(h)
154 @repository.merge_extra_info(h)
155 @repository.save
155 @repository.save
156 @project.reload
156 @project.reload
157 assert @repository.extra_info["heads"].index("4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8")
157 assert @repository.extra_info["heads"].index("4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8")
158 @repository.fetch_changesets
158 @repository.fetch_changesets
159 @project.reload
159 @project.reload
160 assert_equal NUM_REV, @repository.changesets.count
160 assert_equal NUM_REV, @repository.changesets.count
161 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
161 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
162 assert @repository.extra_info["heads"].index("83ca5fd546063a3c7dc2e568ba3355661a9e2b2c")
162 assert @repository.extra_info["heads"].index("83ca5fd546063a3c7dc2e568ba3355661a9e2b2c")
163 end
163 end
164
164
165 def test_fetch_changesets_history_editing
165 def test_fetch_changesets_history_editing
166 assert_equal 0, @repository.changesets.count
166 assert_equal 0, @repository.changesets.count
167 @repository.fetch_changesets
167 @repository.fetch_changesets
168 @project.reload
168 @project.reload
169 assert_equal NUM_REV, @repository.changesets.count
169 assert_equal NUM_REV, @repository.changesets.count
170 extra_info_heads = @repository.extra_info["heads"].dup
170 extra_info_heads = @repository.extra_info["heads"].dup
171 assert_equal NUM_HEAD, extra_info_heads.size
171 assert_equal NUM_HEAD, extra_info_heads.size
172 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
172 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
173 assert_equal 4, extra_info_heads.size
173 assert_equal 4, extra_info_heads.size
174
174
175 del_revs = [
175 del_revs = [
176 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
176 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
177 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
177 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
178 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
178 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
179 "deff712f05a90d96edbd70facc47d944be5897e3",
179 "deff712f05a90d96edbd70facc47d944be5897e3",
180 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
180 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
181 "7e61ac704deecde634b51e59daa8110435dcb3da",
181 "7e61ac704deecde634b51e59daa8110435dcb3da",
182 ]
182 ]
183 @repository.changesets.each do |rev|
183 @repository.changesets.each do |rev|
184 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
184 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
185 end
185 end
186 @project.reload
186 @project.reload
187 assert_equal NUM_REV - 6, @repository.changesets.count
187 assert_equal NUM_REV - 6, @repository.changesets.count
188
188
189 c = Changeset.new(:repository => @repository,
189 c = Changeset.new(:repository => @repository,
190 :committed_on => Time.now,
190 :committed_on => Time.now,
191 :revision => "abcd1234efgh",
191 :revision => "abcd1234efgh",
192 :scmid => "abcd1234efgh",
192 :scmid => "abcd1234efgh",
193 :comments => 'test')
193 :comments => 'test')
194 assert c.save
194 assert c.save
195 @project.reload
195 @project.reload
196 assert_equal NUM_REV - 5, @repository.changesets.count
196 assert_equal NUM_REV - 5, @repository.changesets.count
197
197
198 extra_info_heads << "1234abcd5678"
198 extra_info_heads << "1234abcd5678"
199 h = {}
199 h = {}
200 h["heads"] = extra_info_heads
200 h["heads"] = extra_info_heads
201 @repository.merge_extra_info(h)
201 @repository.merge_extra_info(h)
202 @repository.save
202 @repository.save
203 @project.reload
203 @project.reload
204 h1 = @repository.extra_info["heads"].dup
204 h1 = @repository.extra_info["heads"].dup
205 assert h1.index("1234abcd5678")
205 assert h1.index("1234abcd5678")
206 assert_equal 5, h1.size
206 assert_equal 5, h1.size
207
207
208 @repository.fetch_changesets
208 @repository.fetch_changesets
209 @project.reload
209 @project.reload
210 assert_equal NUM_REV - 5, @repository.changesets.count
210 assert_equal NUM_REV - 5, @repository.changesets.count
211 h2 = @repository.extra_info["heads"].dup
211 h2 = @repository.extra_info["heads"].dup
212 assert_equal h1, h2
212 assert_equal h1, h2
213 end
213 end
214
214
215 def test_parents
215 def test_parents
216 assert_equal 0, @repository.changesets.count
216 assert_equal 0, @repository.changesets.count
217 @repository.fetch_changesets
217 @repository.fetch_changesets
218 @project.reload
218 @project.reload
219 assert_equal NUM_REV, @repository.changesets.count
219 assert_equal NUM_REV, @repository.changesets.count
220 r1 = @repository.find_changeset_by_name("7234cb2750b63")
220 r1 = @repository.find_changeset_by_name("7234cb2750b63")
221 assert_equal [], r1.parents
221 assert_equal [], r1.parents
222 r2 = @repository.find_changeset_by_name("899a15dba03a3")
222 r2 = @repository.find_changeset_by_name("899a15dba03a3")
223 assert_equal 1, r2.parents.length
223 assert_equal 1, r2.parents.length
224 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518",
224 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518",
225 r2.parents[0].identifier
225 r2.parents[0].identifier
226 r3 = @repository.find_changeset_by_name("32ae898b720c2")
226 r3 = @repository.find_changeset_by_name("32ae898b720c2")
227 assert_equal 2, r3.parents.length
227 assert_equal 2, r3.parents.length
228 r4 = [r3.parents[0].identifier, r3.parents[1].identifier].sort
228 r4 = [r3.parents[0].identifier, r3.parents[1].identifier].sort
229 assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", r4[0]
229 assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", r4[0]
230 assert_equal "7e61ac704deecde634b51e59daa8110435dcb3da", r4[1]
230 assert_equal "7e61ac704deecde634b51e59daa8110435dcb3da", r4[1]
231 end
231 end
232
232
233 def test_db_consistent_ordering_init
233 def test_db_consistent_ordering_init
234 assert_nil @repository.extra_info
234 assert_nil @repository.extra_info
235 assert_equal 0, @repository.changesets.count
235 assert_equal 0, @repository.changesets.count
236 @repository.fetch_changesets
236 @repository.fetch_changesets
237 @project.reload
237 @project.reload
238 assert_equal 1, @repository.extra_info["db_consistent"]["ordering"]
238 assert_equal 1, @repository.extra_info["db_consistent"]["ordering"]
239 end
239 end
240
240
241 def test_db_consistent_ordering_before_1_2
241 def test_db_consistent_ordering_before_1_2
242 assert_nil @repository.extra_info
242 assert_nil @repository.extra_info
243 assert_equal 0, @repository.changesets.count
243 assert_equal 0, @repository.changesets.count
244 @repository.fetch_changesets
244 @repository.fetch_changesets
245 @project.reload
245 @project.reload
246 assert_equal NUM_REV, @repository.changesets.count
246 assert_equal NUM_REV, @repository.changesets.count
247 assert_not_nil @repository.extra_info
247 assert_not_nil @repository.extra_info
248 h = {}
248 h = {}
249 h["heads"] = []
249 h["heads"] = []
250 h["branches"] = {}
250 h["branches"] = {}
251 h["db_consistent"] = {}
251 h["db_consistent"] = {}
252 @repository.merge_extra_info(h)
252 @repository.merge_extra_info(h)
253 @repository.save
253 @repository.save
254 assert_equal NUM_REV, @repository.changesets.count
254 assert_equal NUM_REV, @repository.changesets.count
255 @repository.fetch_changesets
255 @repository.fetch_changesets
256 @project.reload
256 @project.reload
257 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
257 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
258
258
259 extra_info_heads = @repository.extra_info["heads"].dup
259 extra_info_heads = @repository.extra_info["heads"].dup
260 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
260 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
261 del_revs = [
261 del_revs = [
262 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
262 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
263 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
263 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
264 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
264 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
265 "deff712f05a90d96edbd70facc47d944be5897e3",
265 "deff712f05a90d96edbd70facc47d944be5897e3",
266 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
266 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
267 "7e61ac704deecde634b51e59daa8110435dcb3da",
267 "7e61ac704deecde634b51e59daa8110435dcb3da",
268 ]
268 ]
269 @repository.changesets.each do |rev|
269 @repository.changesets.each do |rev|
270 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
270 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
271 end
271 end
272 @project.reload
272 @project.reload
273 cs1 = @repository.changesets
273 cs1 = @repository.changesets
274 assert_equal NUM_REV - 6, cs1.count
274 assert_equal NUM_REV - 6, cs1.count
275 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
275 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
276
276
277 extra_info_heads << "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8"
277 extra_info_heads << "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8"
278 h = {}
278 h = {}
279 h["heads"] = extra_info_heads
279 h["heads"] = extra_info_heads
280 @repository.merge_extra_info(h)
280 @repository.merge_extra_info(h)
281 @repository.save
281 @repository.save
282 @project.reload
282 @project.reload
283 assert @repository.extra_info["heads"].index("4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8")
283 assert @repository.extra_info["heads"].index("4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8")
284 @repository.fetch_changesets
284 @repository.fetch_changesets
285 @project.reload
285 @project.reload
286 assert_equal NUM_REV, @repository.changesets.count
286 assert_equal NUM_REV, @repository.changesets.count
287 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
287 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
288
288
289 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
289 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
290 end
290 end
291
291
292 def test_heads_from_branches_hash
292 def test_heads_from_branches_hash
293 assert_nil @repository.extra_info
293 assert_nil @repository.extra_info
294 assert_equal 0, @repository.changesets.count
294 assert_equal 0, @repository.changesets.count
295 assert_equal [], @repository.heads_from_branches_hash
295 assert_equal [], @repository.heads_from_branches_hash
296 h = {}
296 h = {}
297 h["branches"] = {}
297 h["branches"] = {}
298 h["branches"]["test1"] = {}
298 h["branches"]["test1"] = {}
299 h["branches"]["test1"]["last_scmid"] = "1234abcd"
299 h["branches"]["test1"]["last_scmid"] = "1234abcd"
300 h["branches"]["test2"] = {}
300 h["branches"]["test2"] = {}
301 h["branches"]["test2"]["last_scmid"] = "abcd1234"
301 h["branches"]["test2"]["last_scmid"] = "abcd1234"
302 @repository.merge_extra_info(h)
302 @repository.merge_extra_info(h)
303 @repository.save
303 @repository.save
304 @project.reload
304 @project.reload
305 assert_equal ["1234abcd", "abcd1234"], @repository.heads_from_branches_hash.sort
305 assert_equal ["1234abcd", "abcd1234"], @repository.heads_from_branches_hash.sort
306 end
306 end
307
307
308 def test_latest_changesets
308 def test_latest_changesets
309 assert_equal 0, @repository.changesets.count
309 assert_equal 0, @repository.changesets.count
310 @repository.fetch_changesets
310 @repository.fetch_changesets
311 @project.reload
311 @project.reload
312 assert_equal NUM_REV, @repository.changesets.count
312 assert_equal NUM_REV, @repository.changesets.count
313 # with limit
313 # with limit
314 changesets = @repository.latest_changesets('', 'master', 2)
314 changesets = @repository.latest_changesets('', 'master', 2)
315 assert_equal 2, changesets.size
315 assert_equal 2, changesets.size
316
316
317 # with path
317 # with path
318 changesets = @repository.latest_changesets('images', 'master')
318 changesets = @repository.latest_changesets('images', 'master')
319 assert_equal [
319 assert_equal [
320 'deff712f05a90d96edbd70facc47d944be5897e3',
320 'deff712f05a90d96edbd70facc47d944be5897e3',
321 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
321 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
322 '7234cb2750b63f47bff735edc50a1c0a433c2518',
322 '7234cb2750b63f47bff735edc50a1c0a433c2518',
323 ], changesets.collect(&:revision)
323 ], changesets.collect(&:revision)
324
324
325 changesets = @repository.latest_changesets('README', nil)
325 changesets = @repository.latest_changesets('README', nil)
326 assert_equal [
326 assert_equal [
327 '32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf',
327 '32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf',
328 '4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8',
328 '4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8',
329 '713f4944648826f558cf548222f813dabe7cbb04',
329 '713f4944648826f558cf548222f813dabe7cbb04',
330 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
330 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
331 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
331 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
332 '7234cb2750b63f47bff735edc50a1c0a433c2518',
332 '7234cb2750b63f47bff735edc50a1c0a433c2518',
333 ], changesets.collect(&:revision)
333 ], changesets.collect(&:revision)
334
334
335 # with path, revision and limit
335 # with path, revision and limit
336 changesets = @repository.latest_changesets('images', '899a15dba')
336 changesets = @repository.latest_changesets('images', '899a15dba')
337 assert_equal [
337 assert_equal [
338 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
338 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
339 '7234cb2750b63f47bff735edc50a1c0a433c2518',
339 '7234cb2750b63f47bff735edc50a1c0a433c2518',
340 ], changesets.collect(&:revision)
340 ], changesets.collect(&:revision)
341
341
342 changesets = @repository.latest_changesets('images', '899a15dba', 1)
342 changesets = @repository.latest_changesets('images', '899a15dba', 1)
343 assert_equal [
343 assert_equal [
344 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
344 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
345 ], changesets.collect(&:revision)
345 ], changesets.collect(&:revision)
346
346
347 changesets = @repository.latest_changesets('README', '899a15dba')
347 changesets = @repository.latest_changesets('README', '899a15dba')
348 assert_equal [
348 assert_equal [
349 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
349 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
350 '7234cb2750b63f47bff735edc50a1c0a433c2518',
350 '7234cb2750b63f47bff735edc50a1c0a433c2518',
351 ], changesets.collect(&:revision)
351 ], changesets.collect(&:revision)
352
352
353 changesets = @repository.latest_changesets('README', '899a15dba', 1)
353 changesets = @repository.latest_changesets('README', '899a15dba', 1)
354 assert_equal [
354 assert_equal [
355 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
355 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
356 ], changesets.collect(&:revision)
356 ], changesets.collect(&:revision)
357
357
358 # with path, tag and limit
358 # with path, tag and limit
359 changesets = @repository.latest_changesets('images', 'tag01.annotated')
359 changesets = @repository.latest_changesets('images', 'tag01.annotated')
360 assert_equal [
360 assert_equal [
361 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
361 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
362 '7234cb2750b63f47bff735edc50a1c0a433c2518',
362 '7234cb2750b63f47bff735edc50a1c0a433c2518',
363 ], changesets.collect(&:revision)
363 ], changesets.collect(&:revision)
364
364
365 changesets = @repository.latest_changesets('images', 'tag01.annotated', 1)
365 changesets = @repository.latest_changesets('images', 'tag01.annotated', 1)
366 assert_equal [
366 assert_equal [
367 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
367 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
368 ], changesets.collect(&:revision)
368 ], changesets.collect(&:revision)
369
369
370 changesets = @repository.latest_changesets('README', 'tag01.annotated')
370 changesets = @repository.latest_changesets('README', 'tag01.annotated')
371 assert_equal [
371 assert_equal [
372 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
372 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
373 '7234cb2750b63f47bff735edc50a1c0a433c2518',
373 '7234cb2750b63f47bff735edc50a1c0a433c2518',
374 ], changesets.collect(&:revision)
374 ], changesets.collect(&:revision)
375
375
376 changesets = @repository.latest_changesets('README', 'tag01.annotated', 1)
376 changesets = @repository.latest_changesets('README', 'tag01.annotated', 1)
377 assert_equal [
377 assert_equal [
378 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
378 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
379 ], changesets.collect(&:revision)
379 ], changesets.collect(&:revision)
380
380
381 # with path, branch and limit
381 # with path, branch and limit
382 changesets = @repository.latest_changesets('images', 'test_branch')
382 changesets = @repository.latest_changesets('images', 'test_branch')
383 assert_equal [
383 assert_equal [
384 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
384 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
385 '7234cb2750b63f47bff735edc50a1c0a433c2518',
385 '7234cb2750b63f47bff735edc50a1c0a433c2518',
386 ], changesets.collect(&:revision)
386 ], changesets.collect(&:revision)
387
387
388 changesets = @repository.latest_changesets('images', 'test_branch', 1)
388 changesets = @repository.latest_changesets('images', 'test_branch', 1)
389 assert_equal [
389 assert_equal [
390 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
390 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
391 ], changesets.collect(&:revision)
391 ], changesets.collect(&:revision)
392
392
393 changesets = @repository.latest_changesets('README', 'test_branch')
393 changesets = @repository.latest_changesets('README', 'test_branch')
394 assert_equal [
394 assert_equal [
395 '713f4944648826f558cf548222f813dabe7cbb04',
395 '713f4944648826f558cf548222f813dabe7cbb04',
396 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
396 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
397 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
397 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
398 '7234cb2750b63f47bff735edc50a1c0a433c2518',
398 '7234cb2750b63f47bff735edc50a1c0a433c2518',
399 ], changesets.collect(&:revision)
399 ], changesets.collect(&:revision)
400
400
401 changesets = @repository.latest_changesets('README', 'test_branch', 2)
401 changesets = @repository.latest_changesets('README', 'test_branch', 2)
402 assert_equal [
402 assert_equal [
403 '713f4944648826f558cf548222f813dabe7cbb04',
403 '713f4944648826f558cf548222f813dabe7cbb04',
404 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
404 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
405 ], changesets.collect(&:revision)
405 ], changesets.collect(&:revision)
406
406
407 if WINDOWS_PASS
407 if WINDOWS_PASS
408 puts WINDOWS_SKIP_STR
408 puts WINDOWS_SKIP_STR
409 elsif JRUBY_SKIP
409 elsif JRUBY_SKIP
410 puts JRUBY_SKIP_STR
410 puts JRUBY_SKIP_STR
411 else
411 else
412 # latin-1 encoding path
412 # latin-1 encoding path
413 changesets = @repository.latest_changesets(
413 changesets = @repository.latest_changesets(
414 "latin-1-dir/test-#{@char_1}-2.txt", '64f1f3e89')
414 "latin-1-dir/test-#{@char_1}-2.txt", '64f1f3e89')
415 assert_equal [
415 assert_equal [
416 '64f1f3e89ad1cb57976ff0ad99a107012ba3481d',
416 '64f1f3e89ad1cb57976ff0ad99a107012ba3481d',
417 '4fc55c43bf3d3dc2efb66145365ddc17639ce81e',
417 '4fc55c43bf3d3dc2efb66145365ddc17639ce81e',
418 ], changesets.collect(&:revision)
418 ], changesets.collect(&:revision)
419
419
420 changesets = @repository.latest_changesets(
420 changesets = @repository.latest_changesets(
421 "latin-1-dir/test-#{@char_1}-2.txt", '64f1f3e89', 1)
421 "latin-1-dir/test-#{@char_1}-2.txt", '64f1f3e89', 1)
422 assert_equal [
422 assert_equal [
423 '64f1f3e89ad1cb57976ff0ad99a107012ba3481d',
423 '64f1f3e89ad1cb57976ff0ad99a107012ba3481d',
424 ], changesets.collect(&:revision)
424 ], changesets.collect(&:revision)
425 end
425 end
426 end
426 end
427
427
428 def test_latest_changesets_latin_1_dir
428 def test_latest_changesets_latin_1_dir
429 if WINDOWS_PASS
429 if WINDOWS_PASS
430 puts WINDOWS_SKIP_STR
430 puts WINDOWS_SKIP_STR
431 elsif JRUBY_SKIP
431 elsif JRUBY_SKIP
432 puts JRUBY_SKIP_STR
432 puts JRUBY_SKIP_STR
433 else
433 else
434 assert_equal 0, @repository.changesets.count
434 assert_equal 0, @repository.changesets.count
435 @repository.fetch_changesets
435 @repository.fetch_changesets
436 @project.reload
436 @project.reload
437 assert_equal NUM_REV, @repository.changesets.count
437 assert_equal NUM_REV, @repository.changesets.count
438 changesets = @repository.latest_changesets(
438 changesets = @repository.latest_changesets(
439 "latin-1-dir/test-#{@char_1}-subdir", '1ca7f5ed')
439 "latin-1-dir/test-#{@char_1}-subdir", '1ca7f5ed')
440 assert_equal [
440 assert_equal [
441 '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127',
441 '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127',
442 ], changesets.collect(&:revision)
442 ], changesets.collect(&:revision)
443 end
443 end
444 end
444 end
445
445
446 def test_find_changeset_by_name
446 def test_find_changeset_by_name
447 assert_equal 0, @repository.changesets.count
447 assert_equal 0, @repository.changesets.count
448 @repository.fetch_changesets
448 @repository.fetch_changesets
449 @project.reload
449 @project.reload
450 assert_equal NUM_REV, @repository.changesets.count
450 assert_equal NUM_REV, @repository.changesets.count
451 ['7234cb2750b63f47bff735edc50a1c0a433c2518', '7234cb2750b'].each do |r|
451 ['7234cb2750b63f47bff735edc50a1c0a433c2518', '7234cb2750b'].each do |r|
452 assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518',
452 assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518',
453 @repository.find_changeset_by_name(r).revision
453 @repository.find_changeset_by_name(r).revision
454 end
454 end
455 end
455 end
456
456
457 def test_find_changeset_by_empty_name
457 def test_find_changeset_by_empty_name
458 assert_equal 0, @repository.changesets.count
458 assert_equal 0, @repository.changesets.count
459 @repository.fetch_changesets
459 @repository.fetch_changesets
460 @project.reload
460 @project.reload
461 assert_equal NUM_REV, @repository.changesets.count
461 assert_equal NUM_REV, @repository.changesets.count
462 ['', ' ', nil].each do |r|
462 ['', ' ', nil].each do |r|
463 assert_nil @repository.find_changeset_by_name(r)
463 assert_nil @repository.find_changeset_by_name(r)
464 end
464 end
465 end
465 end
466
466
467 def test_identifier
467 def test_identifier
468 assert_equal 0, @repository.changesets.count
468 assert_equal 0, @repository.changesets.count
469 @repository.fetch_changesets
469 @repository.fetch_changesets
470 @project.reload
470 @project.reload
471 assert_equal NUM_REV, @repository.changesets.count
471 assert_equal NUM_REV, @repository.changesets.count
472 c = @repository.changesets.find_by_revision(
472 c = @repository.changesets.find_by_revision(
473 '7234cb2750b63f47bff735edc50a1c0a433c2518')
473 '7234cb2750b63f47bff735edc50a1c0a433c2518')
474 assert_equal c.scmid, c.identifier
474 assert_equal c.scmid, c.identifier
475 end
475 end
476
476
477 def test_format_identifier
477 def test_format_identifier
478 assert_equal 0, @repository.changesets.count
478 assert_equal 0, @repository.changesets.count
479 @repository.fetch_changesets
479 @repository.fetch_changesets
480 @project.reload
480 @project.reload
481 assert_equal NUM_REV, @repository.changesets.count
481 assert_equal NUM_REV, @repository.changesets.count
482 c = @repository.changesets.find_by_revision(
482 c = @repository.changesets.find_by_revision(
483 '7234cb2750b63f47bff735edc50a1c0a433c2518')
483 '7234cb2750b63f47bff735edc50a1c0a433c2518')
484 assert_equal '7234cb27', c.format_identifier
484 assert_equal '7234cb27', c.format_identifier
485 end
485 end
486
486
487 def test_activities
487 def test_activities
488 c = Changeset.new(:repository => @repository,
488 c = Changeset.new(:repository => @repository,
489 :committed_on => Time.now,
489 :committed_on => Time.now,
490 :revision => 'abc7234cb2750b63f47bff735edc50a1c0a433c2',
490 :revision => 'abc7234cb2750b63f47bff735edc50a1c0a433c2',
491 :scmid => 'abc7234cb2750b63f47bff735edc50a1c0a433c2',
491 :scmid => 'abc7234cb2750b63f47bff735edc50a1c0a433c2',
492 :comments => 'test')
492 :comments => 'test')
493 assert c.event_title.include?('abc7234c:')
493 assert c.event_title.include?('abc7234c:')
494 assert_equal 'abc7234cb2750b63f47bff735edc50a1c0a433c2', c.event_url[:rev]
494 assert_equal 'abc7234cb2750b63f47bff735edc50a1c0a433c2', c.event_url[:rev]
495 end
495 end
496
496
497 def test_log_utf8
497 def test_log_utf8
498 assert_equal 0, @repository.changesets.count
498 assert_equal 0, @repository.changesets.count
499 @repository.fetch_changesets
499 @repository.fetch_changesets
500 @project.reload
500 @project.reload
501 assert_equal NUM_REV, @repository.changesets.count
501 assert_equal NUM_REV, @repository.changesets.count
502 str_felix_hex = FELIX_HEX.dup
502 str_felix_hex = FELIX_HEX.dup
503 if str_felix_hex.respond_to?(:force_encoding)
503 if str_felix_hex.respond_to?(:force_encoding)
504 str_felix_hex.force_encoding('UTF-8')
504 str_felix_hex.force_encoding('UTF-8')
505 end
505 end
506 c = @repository.changesets.find_by_revision(
506 c = @repository.changesets.find_by_revision(
507 'ed5bb786bbda2dee66a2d50faf51429dbc043a7b')
507 'ed5bb786bbda2dee66a2d50faf51429dbc043a7b')
508 assert_equal "#{str_felix_hex} <felix@fachschaften.org>", c.committer
508 assert_equal "#{str_felix_hex} <felix@fachschaften.org>", c.committer
509 end
509 end
510
510
511 def test_previous
511 def test_previous
512 assert_equal 0, @repository.changesets.count
512 assert_equal 0, @repository.changesets.count
513 @repository.fetch_changesets
513 @repository.fetch_changesets
514 @project.reload
514 @project.reload
515 assert_equal NUM_REV, @repository.changesets.count
515 assert_equal NUM_REV, @repository.changesets.count
516 %w|1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127 1ca7f5ed|.each do |r1|
516 %w|1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127 1ca7f5ed|.each do |r1|
517 changeset = @repository.find_changeset_by_name(r1)
517 changeset = @repository.find_changeset_by_name(r1)
518 %w|64f1f3e89ad1cb57976ff0ad99a107012ba3481d 64f1f3e89ad1|.each do |r2|
518 %w|64f1f3e89ad1cb57976ff0ad99a107012ba3481d 64f1f3e89ad1|.each do |r2|
519 assert_equal @repository.find_changeset_by_name(r2), changeset.previous
519 assert_equal @repository.find_changeset_by_name(r2), changeset.previous
520 end
520 end
521 end
521 end
522 end
522 end
523
523
524 def test_previous_nil
524 def test_previous_nil
525 assert_equal 0, @repository.changesets.count
525 assert_equal 0, @repository.changesets.count
526 @repository.fetch_changesets
526 @repository.fetch_changesets
527 @project.reload
527 @project.reload
528 assert_equal NUM_REV, @repository.changesets.count
528 assert_equal NUM_REV, @repository.changesets.count
529 %w|7234cb2750b63f47bff735edc50a1c0a433c2518 7234cb275|.each do |r1|
529 %w|7234cb2750b63f47bff735edc50a1c0a433c2518 7234cb275|.each do |r1|
530 changeset = @repository.find_changeset_by_name(r1)
530 changeset = @repository.find_changeset_by_name(r1)
531 assert_nil changeset.previous
531 assert_nil changeset.previous
532 end
532 end
533 end
533 end
534
534
535 def test_next
535 def test_next
536 assert_equal 0, @repository.changesets.count
536 assert_equal 0, @repository.changesets.count
537 @repository.fetch_changesets
537 @repository.fetch_changesets
538 @project.reload
538 @project.reload
539 assert_equal NUM_REV, @repository.changesets.count
539 assert_equal NUM_REV, @repository.changesets.count
540 %w|64f1f3e89ad1cb57976ff0ad99a107012ba3481d 64f1f3e89ad1|.each do |r2|
540 %w|64f1f3e89ad1cb57976ff0ad99a107012ba3481d 64f1f3e89ad1|.each do |r2|
541 changeset = @repository.find_changeset_by_name(r2)
541 changeset = @repository.find_changeset_by_name(r2)
542 %w|1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127 1ca7f5ed|.each do |r1|
542 %w|1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127 1ca7f5ed|.each do |r1|
543 assert_equal @repository.find_changeset_by_name(r1), changeset.next
543 assert_equal @repository.find_changeset_by_name(r1), changeset.next
544 end
544 end
545 end
545 end
546 end
546 end
547
547
548 def test_next_nil
548 def test_next_nil
549 assert_equal 0, @repository.changesets.count
549 assert_equal 0, @repository.changesets.count
550 @repository.fetch_changesets
550 @repository.fetch_changesets
551 @project.reload
551 @project.reload
552 assert_equal NUM_REV, @repository.changesets.count
552 assert_equal NUM_REV, @repository.changesets.count
553 %w|2a682156a3b6e77a8bf9cd4590e8db757f3c6c78 2a682156a3b6e77a|.each do |r1|
553 %w|2a682156a3b6e77a8bf9cd4590e8db757f3c6c78 2a682156a3b6e77a|.each do |r1|
554 changeset = @repository.find_changeset_by_name(r1)
554 changeset = @repository.find_changeset_by_name(r1)
555 assert_nil changeset.next
555 assert_nil changeset.next
556 end
556 end
557 end
557 end
558 else
558 else
559 puts "Git test repository NOT FOUND. Skipping unit tests !!!"
559 puts "Git test repository NOT FOUND. Skipping unit tests !!!"
560 def test_fake; assert true end
560 def test_fake; assert true end
561 end
561 end
562 end
562 end
@@ -1,372 +1,372
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class RepositoryMercurialTest < ActiveSupport::TestCase
20 class RepositoryMercurialTest < ActiveSupport::TestCase
21 fixtures :projects
21 fixtures :projects
22
22
23 include Redmine::I18n
23 include Redmine::I18n
24
24
25 REPOSITORY_PATH = Rails.root.join('tmp/test/mercurial_repository').to_s
25 REPOSITORY_PATH = Rails.root.join('tmp/test/mercurial_repository').to_s
26 NUM_REV = 32
26 NUM_REV = 32
27 CHAR_1_HEX = "\xc3\x9c"
27 CHAR_1_HEX = "\xc3\x9c"
28
28
29 def setup
29 def setup
30 @project = Project.find(3)
30 @project = Project.find(3)
31 @repository = Repository::Mercurial.create(
31 @repository = Repository::Mercurial.create(
32 :project => @project,
32 :project => @project,
33 :url => REPOSITORY_PATH,
33 :url => REPOSITORY_PATH,
34 :path_encoding => 'ISO-8859-1'
34 :path_encoding => 'ISO-8859-1'
35 )
35 )
36 assert @repository
36 assert @repository
37 @char_1 = CHAR_1_HEX.dup
37 @char_1 = CHAR_1_HEX.dup
38 @tag_char_1 = "tag-#{CHAR_1_HEX}-00"
38 @tag_char_1 = "tag-#{CHAR_1_HEX}-00"
39 @branch_char_0 = "branch-#{CHAR_1_HEX}-00"
39 @branch_char_0 = "branch-#{CHAR_1_HEX}-00"
40 @branch_char_1 = "branch-#{CHAR_1_HEX}-01"
40 @branch_char_1 = "branch-#{CHAR_1_HEX}-01"
41 if @char_1.respond_to?(:force_encoding)
41 if @char_1.respond_to?(:force_encoding)
42 @char_1.force_encoding('UTF-8')
42 @char_1.force_encoding('UTF-8')
43 @tag_char_1.force_encoding('UTF-8')
43 @tag_char_1.force_encoding('UTF-8')
44 @branch_char_0.force_encoding('UTF-8')
44 @branch_char_0.force_encoding('UTF-8')
45 @branch_char_1.force_encoding('UTF-8')
45 @branch_char_1.force_encoding('UTF-8')
46 end
46 end
47 end
47 end
48
48
49
49
50 def test_blank_path_to_repository_error_message
50 def test_blank_path_to_repository_error_message
51 set_language_if_valid 'en'
51 set_language_if_valid 'en'
52 repo = Repository::Mercurial.new(
52 repo = Repository::Mercurial.new(
53 :project => @project,
53 :project => @project,
54 :identifier => 'test'
54 :identifier => 'test'
55 )
55 )
56 assert !repo.save
56 assert !repo.save
57 assert_include "Path to repository can't be blank",
57 assert_include "Path to repository can't be blank",
58 repo.errors.full_messages
58 repo.errors.full_messages
59 end
59 end
60
60
61 def test_blank_path_to_repository_error_message_fr
61 def test_blank_path_to_repository_error_message_fr
62 set_language_if_valid 'fr'
62 set_language_if_valid 'fr'
63 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)"
63 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)"
64 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
64 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
65 repo = Repository::Mercurial.new(
65 repo = Repository::Mercurial.new(
66 :project => @project,
66 :project => @project,
67 :url => "",
67 :url => "",
68 :identifier => 'test',
68 :identifier => 'test',
69 :path_encoding => ''
69 :path_encoding => ''
70 )
70 )
71 assert !repo.save
71 assert !repo.save
72 assert_include str, repo.errors.full_messages
72 assert_include str, repo.errors.full_messages
73 end
73 end
74
74
75 if File.directory?(REPOSITORY_PATH)
75 if File.directory?(REPOSITORY_PATH)
76 def test_scm_available
76 def test_scm_available
77 klass = Repository::Mercurial
77 klass = Repository::Mercurial
78 assert_equal "Mercurial", klass.scm_name
78 assert_equal "Mercurial", klass.scm_name
79 assert klass.scm_adapter_class
79 assert klass.scm_adapter_class
80 assert_not_equal "", klass.scm_command
80 assert_not_equal "", klass.scm_command
81 assert_equal true, klass.scm_available
81 assert_equal true, klass.scm_available
82 end
82 end
83
83
84 def test_fetch_changesets_from_scratch
84 def test_fetch_changesets_from_scratch
85 assert_equal 0, @repository.changesets.count
85 assert_equal 0, @repository.changesets.count
86 @repository.fetch_changesets
86 @repository.fetch_changesets
87 @project.reload
87 @project.reload
88 assert_equal NUM_REV, @repository.changesets.count
88 assert_equal NUM_REV, @repository.changesets.count
89 assert_equal 46, @repository.changes.count
89 assert_equal 46, @repository.filechanges.count
90 assert_equal "Initial import.\nThe repository contains 3 files.",
90 assert_equal "Initial import.\nThe repository contains 3 files.",
91 @repository.changesets.find_by_revision('0').comments
91 @repository.changesets.find_by_revision('0').comments
92 end
92 end
93
93
94 def test_fetch_changesets_incremental
94 def test_fetch_changesets_incremental
95 assert_equal 0, @repository.changesets.count
95 assert_equal 0, @repository.changesets.count
96 @repository.fetch_changesets
96 @repository.fetch_changesets
97 @project.reload
97 @project.reload
98 assert_equal NUM_REV, @repository.changesets.count
98 assert_equal NUM_REV, @repository.changesets.count
99 # Remove changesets with revision > 2
99 # Remove changesets with revision > 2
100 @repository.changesets.find(:all).each {|c| c.destroy if c.revision.to_i > 2}
100 @repository.changesets.find(:all).each {|c| c.destroy if c.revision.to_i > 2}
101 @project.reload
101 @project.reload
102 assert_equal 3, @repository.changesets.count
102 assert_equal 3, @repository.changesets.count
103
103
104 @repository.fetch_changesets
104 @repository.fetch_changesets
105 @project.reload
105 @project.reload
106 assert_equal NUM_REV, @repository.changesets.count
106 assert_equal NUM_REV, @repository.changesets.count
107 end
107 end
108
108
109 def test_isodatesec
109 def test_isodatesec
110 # Template keyword 'isodatesec' supported in Mercurial 1.0 and higher
110 # Template keyword 'isodatesec' supported in Mercurial 1.0 and higher
111 if @repository.scm.class.client_version_above?([1, 0])
111 if @repository.scm.class.client_version_above?([1, 0])
112 assert_equal 0, @repository.changesets.count
112 assert_equal 0, @repository.changesets.count
113 @repository.fetch_changesets
113 @repository.fetch_changesets
114 @project.reload
114 @project.reload
115 assert_equal NUM_REV, @repository.changesets.count
115 assert_equal NUM_REV, @repository.changesets.count
116 rev0_committed_on = Time.gm(2007, 12, 14, 9, 22, 52)
116 rev0_committed_on = Time.gm(2007, 12, 14, 9, 22, 52)
117 assert_equal @repository.changesets.find_by_revision('0').committed_on, rev0_committed_on
117 assert_equal @repository.changesets.find_by_revision('0').committed_on, rev0_committed_on
118 end
118 end
119 end
119 end
120
120
121 def test_changeset_order_by_revision
121 def test_changeset_order_by_revision
122 assert_equal 0, @repository.changesets.count
122 assert_equal 0, @repository.changesets.count
123 @repository.fetch_changesets
123 @repository.fetch_changesets
124 @project.reload
124 @project.reload
125 assert_equal NUM_REV, @repository.changesets.count
125 assert_equal NUM_REV, @repository.changesets.count
126
126
127 c0 = @repository.latest_changeset
127 c0 = @repository.latest_changeset
128 c1 = @repository.changesets.find_by_revision('0')
128 c1 = @repository.changesets.find_by_revision('0')
129 # sorted by revision (id), not by date
129 # sorted by revision (id), not by date
130 assert c0.revision.to_i > c1.revision.to_i
130 assert c0.revision.to_i > c1.revision.to_i
131 assert c0.committed_on < c1.committed_on
131 assert c0.committed_on < c1.committed_on
132 end
132 end
133
133
134 def test_latest_changesets
134 def test_latest_changesets
135 assert_equal 0, @repository.changesets.count
135 assert_equal 0, @repository.changesets.count
136 @repository.fetch_changesets
136 @repository.fetch_changesets
137 @project.reload
137 @project.reload
138 assert_equal NUM_REV, @repository.changesets.count
138 assert_equal NUM_REV, @repository.changesets.count
139
139
140 # with_limit
140 # with_limit
141 changesets = @repository.latest_changesets('', nil, 2)
141 changesets = @repository.latest_changesets('', nil, 2)
142 assert_equal %w|31 30|, changesets.collect(&:revision)
142 assert_equal %w|31 30|, changesets.collect(&:revision)
143
143
144 # with_filepath
144 # with_filepath
145 changesets = @repository.latest_changesets(
145 changesets = @repository.latest_changesets(
146 '/sql_escape/percent%dir/percent%file1.txt', nil)
146 '/sql_escape/percent%dir/percent%file1.txt', nil)
147 assert_equal %w|30 11 10 9|, changesets.collect(&:revision)
147 assert_equal %w|30 11 10 9|, changesets.collect(&:revision)
148
148
149 changesets = @repository.latest_changesets(
149 changesets = @repository.latest_changesets(
150 '/sql_escape/underscore_dir/understrike_file.txt', nil)
150 '/sql_escape/underscore_dir/understrike_file.txt', nil)
151 assert_equal %w|30 12 9|, changesets.collect(&:revision)
151 assert_equal %w|30 12 9|, changesets.collect(&:revision)
152
152
153 changesets = @repository.latest_changesets('README', nil)
153 changesets = @repository.latest_changesets('README', nil)
154 assert_equal %w|31 30 28 17 8 6 1 0|, changesets.collect(&:revision)
154 assert_equal %w|31 30 28 17 8 6 1 0|, changesets.collect(&:revision)
155
155
156 changesets = @repository.latest_changesets('README','8')
156 changesets = @repository.latest_changesets('README','8')
157 assert_equal %w|8 6 1 0|, changesets.collect(&:revision)
157 assert_equal %w|8 6 1 0|, changesets.collect(&:revision)
158
158
159 changesets = @repository.latest_changesets('README','8', 2)
159 changesets = @repository.latest_changesets('README','8', 2)
160 assert_equal %w|8 6|, changesets.collect(&:revision)
160 assert_equal %w|8 6|, changesets.collect(&:revision)
161
161
162 # with_dirpath
162 # with_dirpath
163 changesets = @repository.latest_changesets('images', nil)
163 changesets = @repository.latest_changesets('images', nil)
164 assert_equal %w|1 0|, changesets.collect(&:revision)
164 assert_equal %w|1 0|, changesets.collect(&:revision)
165
165
166 path = 'sql_escape/percent%dir'
166 path = 'sql_escape/percent%dir'
167 changesets = @repository.latest_changesets(path, nil)
167 changesets = @repository.latest_changesets(path, nil)
168 assert_equal %w|30 13 11 10 9|, changesets.collect(&:revision)
168 assert_equal %w|30 13 11 10 9|, changesets.collect(&:revision)
169
169
170 changesets = @repository.latest_changesets(path, '11')
170 changesets = @repository.latest_changesets(path, '11')
171 assert_equal %w|11 10 9|, changesets.collect(&:revision)
171 assert_equal %w|11 10 9|, changesets.collect(&:revision)
172
172
173 changesets = @repository.latest_changesets(path, '11', 2)
173 changesets = @repository.latest_changesets(path, '11', 2)
174 assert_equal %w|11 10|, changesets.collect(&:revision)
174 assert_equal %w|11 10|, changesets.collect(&:revision)
175
175
176 path = 'sql_escape/underscore_dir'
176 path = 'sql_escape/underscore_dir'
177 changesets = @repository.latest_changesets(path, nil)
177 changesets = @repository.latest_changesets(path, nil)
178 assert_equal %w|30 13 12 9|, changesets.collect(&:revision)
178 assert_equal %w|30 13 12 9|, changesets.collect(&:revision)
179
179
180 changesets = @repository.latest_changesets(path, '12')
180 changesets = @repository.latest_changesets(path, '12')
181 assert_equal %w|12 9|, changesets.collect(&:revision)
181 assert_equal %w|12 9|, changesets.collect(&:revision)
182
182
183 changesets = @repository.latest_changesets(path, '12', 1)
183 changesets = @repository.latest_changesets(path, '12', 1)
184 assert_equal %w|12|, changesets.collect(&:revision)
184 assert_equal %w|12|, changesets.collect(&:revision)
185
185
186 # tag
186 # tag
187 changesets = @repository.latest_changesets('', 'tag_test.00')
187 changesets = @repository.latest_changesets('', 'tag_test.00')
188 assert_equal %w|5 4 3 2 1 0|, changesets.collect(&:revision)
188 assert_equal %w|5 4 3 2 1 0|, changesets.collect(&:revision)
189
189
190 changesets = @repository.latest_changesets('', 'tag_test.00', 2)
190 changesets = @repository.latest_changesets('', 'tag_test.00', 2)
191 assert_equal %w|5 4|, changesets.collect(&:revision)
191 assert_equal %w|5 4|, changesets.collect(&:revision)
192
192
193 changesets = @repository.latest_changesets('sources', 'tag_test.00')
193 changesets = @repository.latest_changesets('sources', 'tag_test.00')
194 assert_equal %w|4 3 2 1 0|, changesets.collect(&:revision)
194 assert_equal %w|4 3 2 1 0|, changesets.collect(&:revision)
195
195
196 changesets = @repository.latest_changesets('sources', 'tag_test.00', 2)
196 changesets = @repository.latest_changesets('sources', 'tag_test.00', 2)
197 assert_equal %w|4 3|, changesets.collect(&:revision)
197 assert_equal %w|4 3|, changesets.collect(&:revision)
198
198
199 # named branch
199 # named branch
200 if @repository.scm.class.client_version_above?([1, 6])
200 if @repository.scm.class.client_version_above?([1, 6])
201 changesets = @repository.latest_changesets('', @branch_char_1)
201 changesets = @repository.latest_changesets('', @branch_char_1)
202 assert_equal %w|27 26|, changesets.collect(&:revision)
202 assert_equal %w|27 26|, changesets.collect(&:revision)
203 end
203 end
204
204
205 changesets = @repository.latest_changesets("latin-1-dir/test-#{@char_1}-subdir", @branch_char_1)
205 changesets = @repository.latest_changesets("latin-1-dir/test-#{@char_1}-subdir", @branch_char_1)
206 assert_equal %w|27|, changesets.collect(&:revision)
206 assert_equal %w|27|, changesets.collect(&:revision)
207 end
207 end
208
208
209 def test_copied_files
209 def test_copied_files
210 assert_equal 0, @repository.changesets.count
210 assert_equal 0, @repository.changesets.count
211 @repository.fetch_changesets
211 @repository.fetch_changesets
212 @project.reload
212 @project.reload
213 assert_equal NUM_REV, @repository.changesets.count
213 assert_equal NUM_REV, @repository.changesets.count
214
214
215 cs1 = @repository.changesets.find_by_revision('13')
215 cs1 = @repository.changesets.find_by_revision('13')
216 assert_not_nil cs1
216 assert_not_nil cs1
217 c1 = cs1.changes.sort_by(&:path)
217 c1 = cs1.filechanges.sort_by(&:path)
218 assert_equal 2, c1.size
218 assert_equal 2, c1.size
219
219
220 assert_equal 'A', c1[0].action
220 assert_equal 'A', c1[0].action
221 assert_equal '/sql_escape/percent%dir/percentfile1.txt', c1[0].path
221 assert_equal '/sql_escape/percent%dir/percentfile1.txt', c1[0].path
222 assert_equal '/sql_escape/percent%dir/percent%file1.txt', c1[0].from_path
222 assert_equal '/sql_escape/percent%dir/percent%file1.txt', c1[0].from_path
223 assert_equal '3a330eb32958', c1[0].from_revision
223 assert_equal '3a330eb32958', c1[0].from_revision
224
224
225 assert_equal 'A', c1[1].action
225 assert_equal 'A', c1[1].action
226 assert_equal '/sql_escape/underscore_dir/understrike-file.txt', c1[1].path
226 assert_equal '/sql_escape/underscore_dir/understrike-file.txt', c1[1].path
227 assert_equal '/sql_escape/underscore_dir/understrike_file.txt', c1[1].from_path
227 assert_equal '/sql_escape/underscore_dir/understrike_file.txt', c1[1].from_path
228
228
229 cs2 = @repository.changesets.find_by_revision('15')
229 cs2 = @repository.changesets.find_by_revision('15')
230 c2 = cs2.changes
230 c2 = cs2.filechanges
231 assert_equal 1, c2.size
231 assert_equal 1, c2.size
232
232
233 assert_equal 'A', c2[0].action
233 assert_equal 'A', c2[0].action
234 assert_equal '/README (1)[2]&,%.-3_4', c2[0].path
234 assert_equal '/README (1)[2]&,%.-3_4', c2[0].path
235 assert_equal '/README', c2[0].from_path
235 assert_equal '/README', c2[0].from_path
236 assert_equal '933ca60293d7', c2[0].from_revision
236 assert_equal '933ca60293d7', c2[0].from_revision
237
237
238 cs3 = @repository.changesets.find_by_revision('19')
238 cs3 = @repository.changesets.find_by_revision('19')
239 c3 = cs3.changes
239 c3 = cs3.filechanges
240 assert_equal 1, c3.size
240 assert_equal 1, c3.size
241 assert_equal 'A', c3[0].action
241 assert_equal 'A', c3[0].action
242 assert_equal "/latin-1-dir/test-#{@char_1}-1.txt", c3[0].path
242 assert_equal "/latin-1-dir/test-#{@char_1}-1.txt", c3[0].path
243 assert_equal "/latin-1-dir/test-#{@char_1}.txt", c3[0].from_path
243 assert_equal "/latin-1-dir/test-#{@char_1}.txt", c3[0].from_path
244 assert_equal '5d9891a1b425', c3[0].from_revision
244 assert_equal '5d9891a1b425', c3[0].from_revision
245 end
245 end
246
246
247 def test_find_changeset_by_name
247 def test_find_changeset_by_name
248 assert_equal 0, @repository.changesets.count
248 assert_equal 0, @repository.changesets.count
249 @repository.fetch_changesets
249 @repository.fetch_changesets
250 @project.reload
250 @project.reload
251 assert_equal NUM_REV, @repository.changesets.count
251 assert_equal NUM_REV, @repository.changesets.count
252 %w|2 400bb8672109 400|.each do |r|
252 %w|2 400bb8672109 400|.each do |r|
253 assert_equal '2', @repository.find_changeset_by_name(r).revision
253 assert_equal '2', @repository.find_changeset_by_name(r).revision
254 end
254 end
255 end
255 end
256
256
257 def test_find_changeset_by_invalid_name
257 def test_find_changeset_by_invalid_name
258 assert_equal 0, @repository.changesets.count
258 assert_equal 0, @repository.changesets.count
259 @repository.fetch_changesets
259 @repository.fetch_changesets
260 @project.reload
260 @project.reload
261 assert_equal NUM_REV, @repository.changesets.count
261 assert_equal NUM_REV, @repository.changesets.count
262 assert_nil @repository.find_changeset_by_name('100000')
262 assert_nil @repository.find_changeset_by_name('100000')
263 end
263 end
264
264
265 def test_identifier
265 def test_identifier
266 assert_equal 0, @repository.changesets.count
266 assert_equal 0, @repository.changesets.count
267 @repository.fetch_changesets
267 @repository.fetch_changesets
268 @project.reload
268 @project.reload
269 assert_equal NUM_REV, @repository.changesets.count
269 assert_equal NUM_REV, @repository.changesets.count
270 c = @repository.changesets.find_by_revision('2')
270 c = @repository.changesets.find_by_revision('2')
271 assert_equal c.scmid, c.identifier
271 assert_equal c.scmid, c.identifier
272 end
272 end
273
273
274 def test_format_identifier
274 def test_format_identifier
275 assert_equal 0, @repository.changesets.count
275 assert_equal 0, @repository.changesets.count
276 @repository.fetch_changesets
276 @repository.fetch_changesets
277 @project.reload
277 @project.reload
278 assert_equal NUM_REV, @repository.changesets.count
278 assert_equal NUM_REV, @repository.changesets.count
279 c = @repository.changesets.find_by_revision('2')
279 c = @repository.changesets.find_by_revision('2')
280 assert_equal '2:400bb8672109', c.format_identifier
280 assert_equal '2:400bb8672109', c.format_identifier
281 end
281 end
282
282
283 def test_find_changeset_by_empty_name
283 def test_find_changeset_by_empty_name
284 assert_equal 0, @repository.changesets.count
284 assert_equal 0, @repository.changesets.count
285 @repository.fetch_changesets
285 @repository.fetch_changesets
286 @project.reload
286 @project.reload
287 assert_equal NUM_REV, @repository.changesets.count
287 assert_equal NUM_REV, @repository.changesets.count
288 ['', ' ', nil].each do |r|
288 ['', ' ', nil].each do |r|
289 assert_nil @repository.find_changeset_by_name(r)
289 assert_nil @repository.find_changeset_by_name(r)
290 end
290 end
291 end
291 end
292
292
293 def test_parents
293 def test_parents
294 assert_equal 0, @repository.changesets.count
294 assert_equal 0, @repository.changesets.count
295 @repository.fetch_changesets
295 @repository.fetch_changesets
296 @project.reload
296 @project.reload
297 assert_equal NUM_REV, @repository.changesets.count
297 assert_equal NUM_REV, @repository.changesets.count
298 r1 = @repository.changesets.find_by_revision('0')
298 r1 = @repository.changesets.find_by_revision('0')
299 assert_equal [], r1.parents
299 assert_equal [], r1.parents
300 r2 = @repository.changesets.find_by_revision('1')
300 r2 = @repository.changesets.find_by_revision('1')
301 assert_equal 1, r2.parents.length
301 assert_equal 1, r2.parents.length
302 assert_equal "0885933ad4f6",
302 assert_equal "0885933ad4f6",
303 r2.parents[0].identifier
303 r2.parents[0].identifier
304 r3 = @repository.changesets.find_by_revision('30')
304 r3 = @repository.changesets.find_by_revision('30')
305 assert_equal 2, r3.parents.length
305 assert_equal 2, r3.parents.length
306 r4 = [r3.parents[0].identifier, r3.parents[1].identifier].sort
306 r4 = [r3.parents[0].identifier, r3.parents[1].identifier].sort
307 assert_equal "3a330eb32958", r4[0]
307 assert_equal "3a330eb32958", r4[0]
308 assert_equal "a94b0528f24f", r4[1]
308 assert_equal "a94b0528f24f", r4[1]
309 end
309 end
310
310
311 def test_activities
311 def test_activities
312 c = Changeset.new(:repository => @repository,
312 c = Changeset.new(:repository => @repository,
313 :committed_on => Time.now,
313 :committed_on => Time.now,
314 :revision => '123',
314 :revision => '123',
315 :scmid => 'abc400bb8672',
315 :scmid => 'abc400bb8672',
316 :comments => 'test')
316 :comments => 'test')
317 assert c.event_title.include?('123:abc400bb8672:')
317 assert c.event_title.include?('123:abc400bb8672:')
318 assert_equal 'abc400bb8672', c.event_url[:rev]
318 assert_equal 'abc400bb8672', c.event_url[:rev]
319 end
319 end
320
320
321 def test_previous
321 def test_previous
322 assert_equal 0, @repository.changesets.count
322 assert_equal 0, @repository.changesets.count
323 @repository.fetch_changesets
323 @repository.fetch_changesets
324 @project.reload
324 @project.reload
325 assert_equal NUM_REV, @repository.changesets.count
325 assert_equal NUM_REV, @repository.changesets.count
326 %w|28 3ae45e2d177d 3ae45|.each do |r1|
326 %w|28 3ae45e2d177d 3ae45|.each do |r1|
327 changeset = @repository.find_changeset_by_name(r1)
327 changeset = @repository.find_changeset_by_name(r1)
328 %w|27 7bbf4c738e71 7bbf|.each do |r2|
328 %w|27 7bbf4c738e71 7bbf|.each do |r2|
329 assert_equal @repository.find_changeset_by_name(r2), changeset.previous
329 assert_equal @repository.find_changeset_by_name(r2), changeset.previous
330 end
330 end
331 end
331 end
332 end
332 end
333
333
334 def test_previous_nil
334 def test_previous_nil
335 assert_equal 0, @repository.changesets.count
335 assert_equal 0, @repository.changesets.count
336 @repository.fetch_changesets
336 @repository.fetch_changesets
337 @project.reload
337 @project.reload
338 assert_equal NUM_REV, @repository.changesets.count
338 assert_equal NUM_REV, @repository.changesets.count
339 %w|0 0885933ad4f6 0885|.each do |r1|
339 %w|0 0885933ad4f6 0885|.each do |r1|
340 changeset = @repository.find_changeset_by_name(r1)
340 changeset = @repository.find_changeset_by_name(r1)
341 assert_nil changeset.previous
341 assert_nil changeset.previous
342 end
342 end
343 end
343 end
344
344
345 def test_next
345 def test_next
346 assert_equal 0, @repository.changesets.count
346 assert_equal 0, @repository.changesets.count
347 @repository.fetch_changesets
347 @repository.fetch_changesets
348 @project.reload
348 @project.reload
349 assert_equal NUM_REV, @repository.changesets.count
349 assert_equal NUM_REV, @repository.changesets.count
350 %w|27 7bbf4c738e71 7bbf|.each do |r2|
350 %w|27 7bbf4c738e71 7bbf|.each do |r2|
351 changeset = @repository.find_changeset_by_name(r2)
351 changeset = @repository.find_changeset_by_name(r2)
352 %w|28 3ae45e2d177d 3ae45|.each do |r1|
352 %w|28 3ae45e2d177d 3ae45|.each do |r1|
353 assert_equal @repository.find_changeset_by_name(r1), changeset.next
353 assert_equal @repository.find_changeset_by_name(r1), changeset.next
354 end
354 end
355 end
355 end
356 end
356 end
357
357
358 def test_next_nil
358 def test_next_nil
359 assert_equal 0, @repository.changesets.count
359 assert_equal 0, @repository.changesets.count
360 @repository.fetch_changesets
360 @repository.fetch_changesets
361 @project.reload
361 @project.reload
362 assert_equal NUM_REV, @repository.changesets.count
362 assert_equal NUM_REV, @repository.changesets.count
363 %w|31 31eeee7395c8 31eee|.each do |r1|
363 %w|31 31eeee7395c8 31eee|.each do |r1|
364 changeset = @repository.find_changeset_by_name(r1)
364 changeset = @repository.find_changeset_by_name(r1)
365 assert_nil changeset.next
365 assert_nil changeset.next
366 end
366 end
367 end
367 end
368 else
368 else
369 puts "Mercurial test repository NOT FOUND. Skipping unit tests !!!"
369 puts "Mercurial test repository NOT FOUND. Skipping unit tests !!!"
370 def test_fake; assert true end
370 def test_fake; assert true end
371 end
371 end
372 end
372 end
@@ -1,221 +1,221
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class RepositorySubversionTest < ActiveSupport::TestCase
20 class RepositorySubversionTest < ActiveSupport::TestCase
21 fixtures :projects, :repositories, :enabled_modules, :users, :roles
21 fixtures :projects, :repositories, :enabled_modules, :users, :roles
22
22
23 NUM_REV = 11
23 NUM_REV = 11
24
24
25 def setup
25 def setup
26 @project = Project.find(3)
26 @project = Project.find(3)
27 @repository = Repository::Subversion.create(:project => @project,
27 @repository = Repository::Subversion.create(:project => @project,
28 :url => self.class.subversion_repository_url)
28 :url => self.class.subversion_repository_url)
29 assert @repository
29 assert @repository
30 end
30 end
31
31
32 if repository_configured?('subversion')
32 if repository_configured?('subversion')
33 def test_fetch_changesets_from_scratch
33 def test_fetch_changesets_from_scratch
34 assert_equal 0, @repository.changesets.count
34 assert_equal 0, @repository.changesets.count
35 @repository.fetch_changesets
35 @repository.fetch_changesets
36 @project.reload
36 @project.reload
37
37
38 assert_equal NUM_REV, @repository.changesets.count
38 assert_equal NUM_REV, @repository.changesets.count
39 assert_equal 20, @repository.changes.count
39 assert_equal 20, @repository.filechanges.count
40 assert_equal 'Initial import.', @repository.changesets.find_by_revision('1').comments
40 assert_equal 'Initial import.', @repository.changesets.find_by_revision('1').comments
41 end
41 end
42
42
43 def test_fetch_changesets_incremental
43 def test_fetch_changesets_incremental
44 assert_equal 0, @repository.changesets.count
44 assert_equal 0, @repository.changesets.count
45 @repository.fetch_changesets
45 @repository.fetch_changesets
46 @project.reload
46 @project.reload
47 assert_equal NUM_REV, @repository.changesets.count
47 assert_equal NUM_REV, @repository.changesets.count
48
48
49 # Remove changesets with revision > 5
49 # Remove changesets with revision > 5
50 @repository.changesets.find(:all).each {|c| c.destroy if c.revision.to_i > 5}
50 @repository.changesets.find(:all).each {|c| c.destroy if c.revision.to_i > 5}
51 @project.reload
51 @project.reload
52 assert_equal 5, @repository.changesets.count
52 assert_equal 5, @repository.changesets.count
53
53
54 @repository.fetch_changesets
54 @repository.fetch_changesets
55 @project.reload
55 @project.reload
56 assert_equal NUM_REV, @repository.changesets.count
56 assert_equal NUM_REV, @repository.changesets.count
57 end
57 end
58
58
59 def test_latest_changesets
59 def test_latest_changesets
60 assert_equal 0, @repository.changesets.count
60 assert_equal 0, @repository.changesets.count
61 @repository.fetch_changesets
61 @repository.fetch_changesets
62 @project.reload
62 @project.reload
63 assert_equal NUM_REV, @repository.changesets.count
63 assert_equal NUM_REV, @repository.changesets.count
64
64
65 # with limit
65 # with limit
66 changesets = @repository.latest_changesets('', nil, 2)
66 changesets = @repository.latest_changesets('', nil, 2)
67 assert_equal 2, changesets.size
67 assert_equal 2, changesets.size
68 assert_equal @repository.latest_changesets('', nil).slice(0,2), changesets
68 assert_equal @repository.latest_changesets('', nil).slice(0,2), changesets
69
69
70 # with path
70 # with path
71 changesets = @repository.latest_changesets('subversion_test/folder', nil)
71 changesets = @repository.latest_changesets('subversion_test/folder', nil)
72 assert_equal ["10", "9", "7", "6", "5", "2"], changesets.collect(&:revision)
72 assert_equal ["10", "9", "7", "6", "5", "2"], changesets.collect(&:revision)
73
73
74 # with path and revision
74 # with path and revision
75 changesets = @repository.latest_changesets('subversion_test/folder', 8)
75 changesets = @repository.latest_changesets('subversion_test/folder', 8)
76 assert_equal ["7", "6", "5", "2"], changesets.collect(&:revision)
76 assert_equal ["7", "6", "5", "2"], changesets.collect(&:revision)
77 end
77 end
78
78
79 def test_directory_listing_with_square_brackets_in_path
79 def test_directory_listing_with_square_brackets_in_path
80 assert_equal 0, @repository.changesets.count
80 assert_equal 0, @repository.changesets.count
81 @repository.fetch_changesets
81 @repository.fetch_changesets
82 @project.reload
82 @project.reload
83 assert_equal NUM_REV, @repository.changesets.count
83 assert_equal NUM_REV, @repository.changesets.count
84
84
85 entries = @repository.entries('subversion_test/[folder_with_brackets]')
85 entries = @repository.entries('subversion_test/[folder_with_brackets]')
86 assert_not_nil entries, 'Expect to find entries in folder_with_brackets'
86 assert_not_nil entries, 'Expect to find entries in folder_with_brackets'
87 assert_equal 1, entries.size, 'Expect one entry in folder_with_brackets'
87 assert_equal 1, entries.size, 'Expect one entry in folder_with_brackets'
88 assert_equal 'README.txt', entries.first.name
88 assert_equal 'README.txt', entries.first.name
89 end
89 end
90
90
91 def test_directory_listing_with_square_brackets_in_base
91 def test_directory_listing_with_square_brackets_in_base
92 @project = Project.find(3)
92 @project = Project.find(3)
93 @repository = Repository::Subversion.create(
93 @repository = Repository::Subversion.create(
94 :project => @project,
94 :project => @project,
95 :url => "file:///#{self.class.repository_path('subversion')}/subversion_test/[folder_with_brackets]")
95 :url => "file:///#{self.class.repository_path('subversion')}/subversion_test/[folder_with_brackets]")
96
96
97 assert_equal 0, @repository.changesets.count
97 assert_equal 0, @repository.changesets.count
98 @repository.fetch_changesets
98 @repository.fetch_changesets
99 @project.reload
99 @project.reload
100
100
101 assert_equal 1, @repository.changesets.count, 'Expected to see 1 revision'
101 assert_equal 1, @repository.changesets.count, 'Expected to see 1 revision'
102 assert_equal 2, @repository.changes.count, 'Expected to see 2 changes, dir add and file add'
102 assert_equal 2, @repository.filechanges.count, 'Expected to see 2 changes, dir add and file add'
103
103
104 entries = @repository.entries('')
104 entries = @repository.entries('')
105 assert_not_nil entries, 'Expect to find entries'
105 assert_not_nil entries, 'Expect to find entries'
106 assert_equal 1, entries.size, 'Expect a single entry'
106 assert_equal 1, entries.size, 'Expect a single entry'
107 assert_equal 'README.txt', entries.first.name
107 assert_equal 'README.txt', entries.first.name
108 end
108 end
109
109
110 def test_identifier
110 def test_identifier
111 assert_equal 0, @repository.changesets.count
111 assert_equal 0, @repository.changesets.count
112 @repository.fetch_changesets
112 @repository.fetch_changesets
113 @project.reload
113 @project.reload
114 assert_equal NUM_REV, @repository.changesets.count
114 assert_equal NUM_REV, @repository.changesets.count
115 c = @repository.changesets.find_by_revision('1')
115 c = @repository.changesets.find_by_revision('1')
116 assert_equal c.revision, c.identifier
116 assert_equal c.revision, c.identifier
117 end
117 end
118
118
119 def test_find_changeset_by_empty_name
119 def test_find_changeset_by_empty_name
120 assert_equal 0, @repository.changesets.count
120 assert_equal 0, @repository.changesets.count
121 @repository.fetch_changesets
121 @repository.fetch_changesets
122 @project.reload
122 @project.reload
123 assert_equal NUM_REV, @repository.changesets.count
123 assert_equal NUM_REV, @repository.changesets.count
124 ['', ' ', nil].each do |r|
124 ['', ' ', nil].each do |r|
125 assert_nil @repository.find_changeset_by_name(r)
125 assert_nil @repository.find_changeset_by_name(r)
126 end
126 end
127 end
127 end
128
128
129 def test_identifier_nine_digit
129 def test_identifier_nine_digit
130 c = Changeset.new(:repository => @repository, :committed_on => Time.now,
130 c = Changeset.new(:repository => @repository, :committed_on => Time.now,
131 :revision => '123456789', :comments => 'test')
131 :revision => '123456789', :comments => 'test')
132 assert_equal c.identifier, c.revision
132 assert_equal c.identifier, c.revision
133 end
133 end
134
134
135 def test_format_identifier
135 def test_format_identifier
136 assert_equal 0, @repository.changesets.count
136 assert_equal 0, @repository.changesets.count
137 @repository.fetch_changesets
137 @repository.fetch_changesets
138 @project.reload
138 @project.reload
139 assert_equal NUM_REV, @repository.changesets.count
139 assert_equal NUM_REV, @repository.changesets.count
140 c = @repository.changesets.find_by_revision('1')
140 c = @repository.changesets.find_by_revision('1')
141 assert_equal c.format_identifier, c.revision
141 assert_equal c.format_identifier, c.revision
142 end
142 end
143
143
144 def test_format_identifier_nine_digit
144 def test_format_identifier_nine_digit
145 c = Changeset.new(:repository => @repository, :committed_on => Time.now,
145 c = Changeset.new(:repository => @repository, :committed_on => Time.now,
146 :revision => '123456789', :comments => 'test')
146 :revision => '123456789', :comments => 'test')
147 assert_equal c.format_identifier, c.revision
147 assert_equal c.format_identifier, c.revision
148 end
148 end
149
149
150 def test_activities
150 def test_activities
151 c = Changeset.new(:repository => @repository, :committed_on => Time.now,
151 c = Changeset.new(:repository => @repository, :committed_on => Time.now,
152 :revision => '1', :comments => 'test')
152 :revision => '1', :comments => 'test')
153 assert c.event_title.include?('1:')
153 assert c.event_title.include?('1:')
154 assert_equal '1', c.event_url[:rev]
154 assert_equal '1', c.event_url[:rev]
155 end
155 end
156
156
157 def test_activities_nine_digit
157 def test_activities_nine_digit
158 c = Changeset.new(:repository => @repository, :committed_on => Time.now,
158 c = Changeset.new(:repository => @repository, :committed_on => Time.now,
159 :revision => '123456789', :comments => 'test')
159 :revision => '123456789', :comments => 'test')
160 assert c.event_title.include?('123456789:')
160 assert c.event_title.include?('123456789:')
161 assert_equal '123456789', c.event_url[:rev]
161 assert_equal '123456789', c.event_url[:rev]
162 end
162 end
163
163
164 def test_log_encoding_ignore_setting
164 def test_log_encoding_ignore_setting
165 with_settings :commit_logs_encoding => 'windows-1252' do
165 with_settings :commit_logs_encoding => 'windows-1252' do
166 s1 = "\xC2\x80"
166 s1 = "\xC2\x80"
167 s2 = "\xc3\x82\xc2\x80"
167 s2 = "\xc3\x82\xc2\x80"
168 if s1.respond_to?(:force_encoding)
168 if s1.respond_to?(:force_encoding)
169 s1.force_encoding('ISO-8859-1')
169 s1.force_encoding('ISO-8859-1')
170 s2.force_encoding('UTF-8')
170 s2.force_encoding('UTF-8')
171 assert_equal s1.encode('UTF-8'), s2
171 assert_equal s1.encode('UTF-8'), s2
172 end
172 end
173 c = Changeset.new(:repository => @repository,
173 c = Changeset.new(:repository => @repository,
174 :comments => s2,
174 :comments => s2,
175 :revision => '123',
175 :revision => '123',
176 :committed_on => Time.now)
176 :committed_on => Time.now)
177 assert c.save
177 assert c.save
178 assert_equal s2, c.comments
178 assert_equal s2, c.comments
179 end
179 end
180 end
180 end
181
181
182 def test_previous
182 def test_previous
183 assert_equal 0, @repository.changesets.count
183 assert_equal 0, @repository.changesets.count
184 @repository.fetch_changesets
184 @repository.fetch_changesets
185 @project.reload
185 @project.reload
186 assert_equal NUM_REV, @repository.changesets.count
186 assert_equal NUM_REV, @repository.changesets.count
187 changeset = @repository.find_changeset_by_name('3')
187 changeset = @repository.find_changeset_by_name('3')
188 assert_equal @repository.find_changeset_by_name('2'), changeset.previous
188 assert_equal @repository.find_changeset_by_name('2'), changeset.previous
189 end
189 end
190
190
191 def test_previous_nil
191 def test_previous_nil
192 assert_equal 0, @repository.changesets.count
192 assert_equal 0, @repository.changesets.count
193 @repository.fetch_changesets
193 @repository.fetch_changesets
194 @project.reload
194 @project.reload
195 assert_equal NUM_REV, @repository.changesets.count
195 assert_equal NUM_REV, @repository.changesets.count
196 changeset = @repository.find_changeset_by_name('1')
196 changeset = @repository.find_changeset_by_name('1')
197 assert_nil changeset.previous
197 assert_nil changeset.previous
198 end
198 end
199
199
200 def test_next
200 def test_next
201 assert_equal 0, @repository.changesets.count
201 assert_equal 0, @repository.changesets.count
202 @repository.fetch_changesets
202 @repository.fetch_changesets
203 @project.reload
203 @project.reload
204 assert_equal NUM_REV, @repository.changesets.count
204 assert_equal NUM_REV, @repository.changesets.count
205 changeset = @repository.find_changeset_by_name('2')
205 changeset = @repository.find_changeset_by_name('2')
206 assert_equal @repository.find_changeset_by_name('3'), changeset.next
206 assert_equal @repository.find_changeset_by_name('3'), changeset.next
207 end
207 end
208
208
209 def test_next_nil
209 def test_next_nil
210 assert_equal 0, @repository.changesets.count
210 assert_equal 0, @repository.changesets.count
211 @repository.fetch_changesets
211 @repository.fetch_changesets
212 @project.reload
212 @project.reload
213 assert_equal NUM_REV, @repository.changesets.count
213 assert_equal NUM_REV, @repository.changesets.count
214 changeset = @repository.find_changeset_by_name('11')
214 changeset = @repository.find_changeset_by_name('11')
215 assert_nil changeset.next
215 assert_nil changeset.next
216 end
216 end
217 else
217 else
218 puts "Subversion test repository NOT FOUND. Skipping unit tests !!!"
218 puts "Subversion test repository NOT FOUND. Skipping unit tests !!!"
219 def test_fake; assert true end
219 def test_fake; assert true end
220 end
220 end
221 end
221 end
@@ -1,329 +1,331
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class RepositoryTest < ActiveSupport::TestCase
20 class RepositoryTest < ActiveSupport::TestCase
21 fixtures :projects,
21 fixtures :projects,
22 :trackers,
22 :trackers,
23 :projects_trackers,
23 :projects_trackers,
24 :enabled_modules,
24 :enabled_modules,
25 :repositories,
25 :repositories,
26 :issues,
26 :issues,
27 :issue_statuses,
27 :issue_statuses,
28 :issue_categories,
28 :issue_categories,
29 :changesets,
29 :changesets,
30 :changes,
30 :changes,
31 :users,
31 :users,
32 :members,
32 :members,
33 :member_roles,
33 :member_roles,
34 :roles,
34 :roles,
35 :enumerations
35 :enumerations
36
36
37 include Redmine::I18n
37 include Redmine::I18n
38
38
39 def setup
39 def setup
40 @repository = Project.find(1).repository
40 @repository = Project.find(1).repository
41 end
41 end
42
42
43 def test_blank_log_encoding_error_message
43 def test_blank_log_encoding_error_message
44 set_language_if_valid 'en'
44 set_language_if_valid 'en'
45 repo = Repository::Bazaar.new(
45 repo = Repository::Bazaar.new(
46 :project => Project.find(3),
46 :project => Project.find(3),
47 :url => "/test",
47 :url => "/test",
48 :log_encoding => ''
48 :log_encoding => ''
49 )
49 )
50 assert !repo.save
50 assert !repo.save
51 assert_include "Commit messages encoding can't be blank",
51 assert_include "Commit messages encoding can't be blank",
52 repo.errors.full_messages
52 repo.errors.full_messages
53 end
53 end
54
54
55 def test_blank_log_encoding_error_message_fr
55 def test_blank_log_encoding_error_message_fr
56 set_language_if_valid 'fr'
56 set_language_if_valid 'fr'
57 str = "Encodage des messages de commit doit \xc3\xaatre renseign\xc3\xa9(e)"
57 str = "Encodage des messages de commit doit \xc3\xaatre renseign\xc3\xa9(e)"
58 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
58 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
59 repo = Repository::Bazaar.new(
59 repo = Repository::Bazaar.new(
60 :project => Project.find(3),
60 :project => Project.find(3),
61 :url => "/test"
61 :url => "/test"
62 )
62 )
63 assert !repo.save
63 assert !repo.save
64 assert_include str, repo.errors.full_messages
64 assert_include str, repo.errors.full_messages
65 end
65 end
66
66
67 def test_create
67 def test_create
68 repository = Repository::Subversion.new(:project => Project.find(3))
68 repository = Repository::Subversion.new(:project => Project.find(3))
69 assert !repository.save
69 assert !repository.save
70
70
71 repository.url = "svn://localhost"
71 repository.url = "svn://localhost"
72 assert repository.save
72 assert repository.save
73 repository.reload
73 repository.reload
74
74
75 project = Project.find(3)
75 project = Project.find(3)
76 assert_equal repository, project.repository
76 assert_equal repository, project.repository
77 end
77 end
78
78
79 def test_first_repository_should_be_set_as_default
79 def test_first_repository_should_be_set_as_default
80 repository1 = Repository::Subversion.new(
80 repository1 = Repository::Subversion.new(
81 :project => Project.find(3),
81 :project => Project.find(3),
82 :identifier => 'svn1',
82 :identifier => 'svn1',
83 :url => 'file:///svn1'
83 :url => 'file:///svn1'
84 )
84 )
85 assert repository1.save
85 assert repository1.save
86 assert repository1.is_default?
86 assert repository1.is_default?
87
87
88 repository2 = Repository::Subversion.new(
88 repository2 = Repository::Subversion.new(
89 :project => Project.find(3),
89 :project => Project.find(3),
90 :identifier => 'svn2',
90 :identifier => 'svn2',
91 :url => 'file:///svn2'
91 :url => 'file:///svn2'
92 )
92 )
93 assert repository2.save
93 assert repository2.save
94 assert !repository2.is_default?
94 assert !repository2.is_default?
95
95
96 assert_equal repository1, Project.find(3).repository
96 assert_equal repository1, Project.find(3).repository
97 assert_equal [repository1, repository2], Project.find(3).repositories.sort
97 assert_equal [repository1, repository2], Project.find(3).repositories.sort
98 end
98 end
99
99
100 def test_destroy
100 def test_destroy
101 changesets = Changeset.where("repository_id = 10").all.count
101 repository = Repository.find(10)
102 changes = Changeset.joins([:changes]).where("repository_id = 10").all.count
102 changesets = repository.changesets.count
103 changes = repository.filechanges.count
104
103 assert_difference 'Changeset.count', -changesets do
105 assert_difference 'Changeset.count', -changesets do
104 assert_difference 'Change.count', -changes do
106 assert_difference 'Change.count', -changes do
105 Repository.find(10).destroy
107 Repository.find(10).destroy
106 end
108 end
107 end
109 end
108 end
110 end
109
111
110 def test_destroy_should_delete_parents_associations
112 def test_destroy_should_delete_parents_associations
111 changeset = Changeset.find(102)
113 changeset = Changeset.find(102)
112 changeset.parents = Changeset.find_all_by_id([100, 101])
114 changeset.parents = Changeset.find_all_by_id([100, 101])
113
115
114 assert_difference 'Changeset.connection.select_all("select * from changeset_parents").size', -2 do
116 assert_difference 'Changeset.connection.select_all("select * from changeset_parents").size', -2 do
115 Repository.find(10).destroy
117 Repository.find(10).destroy
116 end
118 end
117 end
119 end
118
120
119 def test_destroy_should_delete_issues_associations
121 def test_destroy_should_delete_issues_associations
120 changeset = Changeset.find(102)
122 changeset = Changeset.find(102)
121 changeset.issues = Issue.find_all_by_id([1, 2])
123 changeset.issues = Issue.find_all_by_id([1, 2])
122
124
123 assert_difference 'Changeset.connection.select_all("select * from changesets_issues").size', -2 do
125 assert_difference 'Changeset.connection.select_all("select * from changesets_issues").size', -2 do
124 Repository.find(10).destroy
126 Repository.find(10).destroy
125 end
127 end
126 end
128 end
127
129
128 def test_should_not_create_with_disabled_scm
130 def test_should_not_create_with_disabled_scm
129 # disable Subversion
131 # disable Subversion
130 with_settings :enabled_scm => ['Darcs', 'Git'] do
132 with_settings :enabled_scm => ['Darcs', 'Git'] do
131 repository = Repository::Subversion.new(
133 repository = Repository::Subversion.new(
132 :project => Project.find(3), :url => "svn://localhost")
134 :project => Project.find(3), :url => "svn://localhost")
133 assert !repository.save
135 assert !repository.save
134 assert_include I18n.translate('activerecord.errors.messages.invalid'),
136 assert_include I18n.translate('activerecord.errors.messages.invalid'),
135 repository.errors[:type]
137 repository.errors[:type]
136 end
138 end
137 end
139 end
138
140
139 def test_scan_changesets_for_issue_ids
141 def test_scan_changesets_for_issue_ids
140 Setting.default_language = 'en'
142 Setting.default_language = 'en'
141 Setting.notified_events = ['issue_added','issue_updated']
143 Setting.notified_events = ['issue_added','issue_updated']
142
144
143 # choosing a status to apply to fix issues
145 # choosing a status to apply to fix issues
144 Setting.commit_fix_status_id = IssueStatus.find(
146 Setting.commit_fix_status_id = IssueStatus.find(
145 :first,
147 :first,
146 :conditions => ["is_closed = ?", true]).id
148 :conditions => ["is_closed = ?", true]).id
147 Setting.commit_fix_done_ratio = "90"
149 Setting.commit_fix_done_ratio = "90"
148 Setting.commit_ref_keywords = 'refs , references, IssueID'
150 Setting.commit_ref_keywords = 'refs , references, IssueID'
149 Setting.commit_fix_keywords = 'fixes , closes'
151 Setting.commit_fix_keywords = 'fixes , closes'
150 Setting.default_language = 'en'
152 Setting.default_language = 'en'
151 ActionMailer::Base.deliveries.clear
153 ActionMailer::Base.deliveries.clear
152
154
153 # make sure issue 1 is not already closed
155 # make sure issue 1 is not already closed
154 fixed_issue = Issue.find(1)
156 fixed_issue = Issue.find(1)
155 assert !fixed_issue.status.is_closed?
157 assert !fixed_issue.status.is_closed?
156 old_status = fixed_issue.status
158 old_status = fixed_issue.status
157
159
158 Repository.scan_changesets_for_issue_ids
160 Repository.scan_changesets_for_issue_ids
159 assert_equal [101, 102], Issue.find(3).changeset_ids
161 assert_equal [101, 102], Issue.find(3).changeset_ids
160
162
161 # fixed issues
163 # fixed issues
162 fixed_issue.reload
164 fixed_issue.reload
163 assert fixed_issue.status.is_closed?
165 assert fixed_issue.status.is_closed?
164 assert_equal 90, fixed_issue.done_ratio
166 assert_equal 90, fixed_issue.done_ratio
165 assert_equal [101], fixed_issue.changeset_ids
167 assert_equal [101], fixed_issue.changeset_ids
166
168
167 # issue change
169 # issue change
168 journal = fixed_issue.journals.find(:first, :order => 'created_on desc')
170 journal = fixed_issue.journals.find(:first, :order => 'created_on desc')
169 assert_equal User.find_by_login('dlopper'), journal.user
171 assert_equal User.find_by_login('dlopper'), journal.user
170 assert_equal 'Applied in changeset r2.', journal.notes
172 assert_equal 'Applied in changeset r2.', journal.notes
171
173
172 # 2 email notifications
174 # 2 email notifications
173 assert_equal 2, ActionMailer::Base.deliveries.size
175 assert_equal 2, ActionMailer::Base.deliveries.size
174 mail = ActionMailer::Base.deliveries.first
176 mail = ActionMailer::Base.deliveries.first
175 assert_not_nil mail
177 assert_not_nil mail
176 assert mail.subject.starts_with?(
178 assert mail.subject.starts_with?(
177 "[#{fixed_issue.project.name} - #{fixed_issue.tracker.name} ##{fixed_issue.id}]")
179 "[#{fixed_issue.project.name} - #{fixed_issue.tracker.name} ##{fixed_issue.id}]")
178 assert_mail_body_match(
180 assert_mail_body_match(
179 "Status changed from #{old_status} to #{fixed_issue.status}", mail)
181 "Status changed from #{old_status} to #{fixed_issue.status}", mail)
180
182
181 # ignoring commits referencing an issue of another project
183 # ignoring commits referencing an issue of another project
182 assert_equal [], Issue.find(4).changesets
184 assert_equal [], Issue.find(4).changesets
183 end
185 end
184
186
185 def test_for_changeset_comments_strip
187 def test_for_changeset_comments_strip
186 repository = Repository::Mercurial.create(
188 repository = Repository::Mercurial.create(
187 :project => Project.find( 4 ),
189 :project => Project.find( 4 ),
188 :url => '/foo/bar/baz' )
190 :url => '/foo/bar/baz' )
189 comment = <<-COMMENT
191 comment = <<-COMMENT
190 This is a loooooooooooooooooooooooooooong comment
192 This is a loooooooooooooooooooooooooooong comment
191
193
192
194
193 COMMENT
195 COMMENT
194 changeset = Changeset.new(
196 changeset = Changeset.new(
195 :comments => comment, :commit_date => Time.now,
197 :comments => comment, :commit_date => Time.now,
196 :revision => 0, :scmid => 'f39b7922fb3c',
198 :revision => 0, :scmid => 'f39b7922fb3c',
197 :committer => 'foo <foo@example.com>',
199 :committer => 'foo <foo@example.com>',
198 :committed_on => Time.now, :repository => repository )
200 :committed_on => Time.now, :repository => repository )
199 assert( changeset.save )
201 assert( changeset.save )
200 assert_not_equal( comment, changeset.comments )
202 assert_not_equal( comment, changeset.comments )
201 assert_equal( 'This is a loooooooooooooooooooooooooooong comment',
203 assert_equal( 'This is a loooooooooooooooooooooooooooong comment',
202 changeset.comments )
204 changeset.comments )
203 end
205 end
204
206
205 def test_for_urls_strip_cvs
207 def test_for_urls_strip_cvs
206 repository = Repository::Cvs.create(
208 repository = Repository::Cvs.create(
207 :project => Project.find(4),
209 :project => Project.find(4),
208 :url => ' :pserver:login:password@host:/path/to/the/repository',
210 :url => ' :pserver:login:password@host:/path/to/the/repository',
209 :root_url => 'foo ',
211 :root_url => 'foo ',
210 :log_encoding => 'UTF-8')
212 :log_encoding => 'UTF-8')
211 assert repository.save
213 assert repository.save
212 repository.reload
214 repository.reload
213 assert_equal ':pserver:login:password@host:/path/to/the/repository',
215 assert_equal ':pserver:login:password@host:/path/to/the/repository',
214 repository.url
216 repository.url
215 assert_equal 'foo', repository.root_url
217 assert_equal 'foo', repository.root_url
216 end
218 end
217
219
218 def test_for_urls_strip_subversion
220 def test_for_urls_strip_subversion
219 repository = Repository::Subversion.create(
221 repository = Repository::Subversion.create(
220 :project => Project.find(4),
222 :project => Project.find(4),
221 :url => ' file:///dummy ')
223 :url => ' file:///dummy ')
222 assert repository.save
224 assert repository.save
223 repository.reload
225 repository.reload
224 assert_equal 'file:///dummy', repository.url
226 assert_equal 'file:///dummy', repository.url
225 end
227 end
226
228
227 def test_for_urls_strip_git
229 def test_for_urls_strip_git
228 repository = Repository::Git.create(
230 repository = Repository::Git.create(
229 :project => Project.find(4),
231 :project => Project.find(4),
230 :url => ' c:\dummy ')
232 :url => ' c:\dummy ')
231 assert repository.save
233 assert repository.save
232 repository.reload
234 repository.reload
233 assert_equal 'c:\dummy', repository.url
235 assert_equal 'c:\dummy', repository.url
234 end
236 end
235
237
236 def test_manual_user_mapping
238 def test_manual_user_mapping
237 assert_no_difference "Changeset.count(:conditions => 'user_id <> 2')" do
239 assert_no_difference "Changeset.count(:conditions => 'user_id <> 2')" do
238 c = Changeset.create!(
240 c = Changeset.create!(
239 :repository => @repository,
241 :repository => @repository,
240 :committer => 'foo',
242 :committer => 'foo',
241 :committed_on => Time.now,
243 :committed_on => Time.now,
242 :revision => 100,
244 :revision => 100,
243 :comments => 'Committed by foo.'
245 :comments => 'Committed by foo.'
244 )
246 )
245 assert_nil c.user
247 assert_nil c.user
246 @repository.committer_ids = {'foo' => '2'}
248 @repository.committer_ids = {'foo' => '2'}
247 assert_equal User.find(2), c.reload.user
249 assert_equal User.find(2), c.reload.user
248 # committer is now mapped
250 # committer is now mapped
249 c = Changeset.create!(
251 c = Changeset.create!(
250 :repository => @repository,
252 :repository => @repository,
251 :committer => 'foo',
253 :committer => 'foo',
252 :committed_on => Time.now,
254 :committed_on => Time.now,
253 :revision => 101,
255 :revision => 101,
254 :comments => 'Another commit by foo.'
256 :comments => 'Another commit by foo.'
255 )
257 )
256 assert_equal User.find(2), c.user
258 assert_equal User.find(2), c.user
257 end
259 end
258 end
260 end
259
261
260 def test_auto_user_mapping_by_username
262 def test_auto_user_mapping_by_username
261 c = Changeset.create!(
263 c = Changeset.create!(
262 :repository => @repository,
264 :repository => @repository,
263 :committer => 'jsmith',
265 :committer => 'jsmith',
264 :committed_on => Time.now,
266 :committed_on => Time.now,
265 :revision => 100,
267 :revision => 100,
266 :comments => 'Committed by john.'
268 :comments => 'Committed by john.'
267 )
269 )
268 assert_equal User.find(2), c.user
270 assert_equal User.find(2), c.user
269 end
271 end
270
272
271 def test_auto_user_mapping_by_email
273 def test_auto_user_mapping_by_email
272 c = Changeset.create!(
274 c = Changeset.create!(
273 :repository => @repository,
275 :repository => @repository,
274 :committer => 'john <jsmith@somenet.foo>',
276 :committer => 'john <jsmith@somenet.foo>',
275 :committed_on => Time.now,
277 :committed_on => Time.now,
276 :revision => 100,
278 :revision => 100,
277 :comments => 'Committed by john.'
279 :comments => 'Committed by john.'
278 )
280 )
279 assert_equal User.find(2), c.user
281 assert_equal User.find(2), c.user
280 end
282 end
281
283
282 def test_filesystem_avaialbe
284 def test_filesystem_avaialbe
283 klass = Repository::Filesystem
285 klass = Repository::Filesystem
284 assert klass.scm_adapter_class
286 assert klass.scm_adapter_class
285 assert_equal true, klass.scm_available
287 assert_equal true, klass.scm_available
286 end
288 end
287
289
288 def test_merge_extra_info
290 def test_merge_extra_info
289 repo = Repository::Subversion.new(:project => Project.find(3))
291 repo = Repository::Subversion.new(:project => Project.find(3))
290 assert !repo.save
292 assert !repo.save
291 repo.url = "svn://localhost"
293 repo.url = "svn://localhost"
292 assert repo.save
294 assert repo.save
293 repo.reload
295 repo.reload
294 project = Project.find(3)
296 project = Project.find(3)
295 assert_equal repo, project.repository
297 assert_equal repo, project.repository
296 assert_nil repo.extra_info
298 assert_nil repo.extra_info
297 h1 = {"test_1" => {"test_11" => "test_value_11"}}
299 h1 = {"test_1" => {"test_11" => "test_value_11"}}
298 repo.merge_extra_info(h1)
300 repo.merge_extra_info(h1)
299 assert_equal h1, repo.extra_info
301 assert_equal h1, repo.extra_info
300 h2 = {"test_2" => {
302 h2 = {"test_2" => {
301 "test_21" => "test_value_21",
303 "test_21" => "test_value_21",
302 "test_22" => "test_value_22",
304 "test_22" => "test_value_22",
303 }}
305 }}
304 repo.merge_extra_info(h2)
306 repo.merge_extra_info(h2)
305 assert_equal (h = {"test_11" => "test_value_11"}),
307 assert_equal (h = {"test_11" => "test_value_11"}),
306 repo.extra_info["test_1"]
308 repo.extra_info["test_1"]
307 assert_equal "test_value_21",
309 assert_equal "test_value_21",
308 repo.extra_info["test_2"]["test_21"]
310 repo.extra_info["test_2"]["test_21"]
309 h3 = {"test_2" => {
311 h3 = {"test_2" => {
310 "test_23" => "test_value_23",
312 "test_23" => "test_value_23",
311 "test_24" => "test_value_24",
313 "test_24" => "test_value_24",
312 }}
314 }}
313 repo.merge_extra_info(h3)
315 repo.merge_extra_info(h3)
314 assert_equal (h = {"test_11" => "test_value_11"}),
316 assert_equal (h = {"test_11" => "test_value_11"}),
315 repo.extra_info["test_1"]
317 repo.extra_info["test_1"]
316 assert_nil repo.extra_info["test_2"]["test_21"]
318 assert_nil repo.extra_info["test_2"]["test_21"]
317 assert_equal "test_value_23",
319 assert_equal "test_value_23",
318 repo.extra_info["test_2"]["test_23"]
320 repo.extra_info["test_2"]["test_23"]
319 end
321 end
320
322
321 def test_sort_should_not_raise_an_error_with_nil_identifiers
323 def test_sort_should_not_raise_an_error_with_nil_identifiers
322 r1 = Repository.new
324 r1 = Repository.new
323 r2 = Repository.new
325 r2 = Repository.new
324
326
325 assert_nothing_raised do
327 assert_nothing_raised do
326 [r1, r2].sort
328 [r1, r2].sort
327 end
329 end
328 end
330 end
329 end
331 end
General Comments 0
You need to be logged in to leave comments. Login now