@@ -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 | « |
|
2 | « | |
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 | » |
|
14 | » | |
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