##// END OF EJS Templates
scm: git: remove unused "--all" option of "git log" in lib revisions method...
Toshi MARUYAMA -
r8693:f319409abc95
parent child
Show More
@@ -1,387 +1,386
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require 'redmine/scm/adapters/abstract_adapter'
18 require 'redmine/scm/adapters/abstract_adapter'
19
19
20 module Redmine
20 module Redmine
21 module Scm
21 module Scm
22 module Adapters
22 module Adapters
23 class GitAdapter < AbstractAdapter
23 class GitAdapter < AbstractAdapter
24
24
25 # Git executable name
25 # Git executable name
26 GIT_BIN = Redmine::Configuration['scm_git_command'] || "git"
26 GIT_BIN = Redmine::Configuration['scm_git_command'] || "git"
27
27
28 class << self
28 class << self
29 def client_command
29 def client_command
30 @@bin ||= GIT_BIN
30 @@bin ||= GIT_BIN
31 end
31 end
32
32
33 def sq_bin
33 def sq_bin
34 @@sq_bin ||= shell_quote_command
34 @@sq_bin ||= shell_quote_command
35 end
35 end
36
36
37 def client_version
37 def client_version
38 @@client_version ||= (scm_command_version || [])
38 @@client_version ||= (scm_command_version || [])
39 end
39 end
40
40
41 def client_available
41 def client_available
42 !client_version.empty?
42 !client_version.empty?
43 end
43 end
44
44
45 def scm_command_version
45 def scm_command_version
46 scm_version = scm_version_from_command_line.dup
46 scm_version = scm_version_from_command_line.dup
47 if scm_version.respond_to?(:force_encoding)
47 if scm_version.respond_to?(:force_encoding)
48 scm_version.force_encoding('ASCII-8BIT')
48 scm_version.force_encoding('ASCII-8BIT')
49 end
49 end
50 if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)})
50 if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)})
51 m[2].scan(%r{\d+}).collect(&:to_i)
51 m[2].scan(%r{\d+}).collect(&:to_i)
52 end
52 end
53 end
53 end
54
54
55 def scm_version_from_command_line
55 def scm_version_from_command_line
56 shellout("#{sq_bin} --version --no-color") { |io| io.read }.to_s
56 shellout("#{sq_bin} --version --no-color") { |io| io.read }.to_s
57 end
57 end
58 end
58 end
59
59
60 def initialize(url, root_url=nil, login=nil, password=nil, path_encoding=nil)
60 def initialize(url, root_url=nil, login=nil, password=nil, path_encoding=nil)
61 super
61 super
62 @path_encoding = path_encoding.blank? ? 'UTF-8' : path_encoding
62 @path_encoding = path_encoding.blank? ? 'UTF-8' : path_encoding
63 end
63 end
64
64
65 def path_encoding
65 def path_encoding
66 @path_encoding
66 @path_encoding
67 end
67 end
68
68
69 def info
69 def info
70 begin
70 begin
71 Info.new(:root_url => url, :lastrev => lastrev('',nil))
71 Info.new(:root_url => url, :lastrev => lastrev('',nil))
72 rescue
72 rescue
73 nil
73 nil
74 end
74 end
75 end
75 end
76
76
77 def branches
77 def branches
78 return @branches if @branches
78 return @branches if @branches
79 @branches = []
79 @branches = []
80 cmd_args = %w|branch --no-color --verbose --no-abbrev|
80 cmd_args = %w|branch --no-color --verbose --no-abbrev|
81 scm_cmd(*cmd_args) do |io|
81 scm_cmd(*cmd_args) do |io|
82 io.each_line do |line|
82 io.each_line do |line|
83 branch_rev = line.match('\s*\*?\s*(.*?)\s*([0-9a-f]{40}).*$')
83 branch_rev = line.match('\s*\*?\s*(.*?)\s*([0-9a-f]{40}).*$')
84 bran = Branch.new(branch_rev[1])
84 bran = Branch.new(branch_rev[1])
85 bran.revision = branch_rev[2]
85 bran.revision = branch_rev[2]
86 bran.scmid = branch_rev[2]
86 bran.scmid = branch_rev[2]
87 @branches << bran
87 @branches << bran
88 end
88 end
89 end
89 end
90 @branches.sort!
90 @branches.sort!
91 rescue ScmCommandAborted
91 rescue ScmCommandAborted
92 nil
92 nil
93 end
93 end
94
94
95 def tags
95 def tags
96 return @tags if @tags
96 return @tags if @tags
97 cmd_args = %w|tag|
97 cmd_args = %w|tag|
98 scm_cmd(*cmd_args) do |io|
98 scm_cmd(*cmd_args) do |io|
99 @tags = io.readlines.sort!.map{|t| t.strip}
99 @tags = io.readlines.sort!.map{|t| t.strip}
100 end
100 end
101 rescue ScmCommandAborted
101 rescue ScmCommandAborted
102 nil
102 nil
103 end
103 end
104
104
105 def default_branch
105 def default_branch
106 bras = self.branches
106 bras = self.branches
107 return nil if bras.nil?
107 return nil if bras.nil?
108 bras.include?('master') ? 'master' : bras.first
108 bras.include?('master') ? 'master' : bras.first
109 end
109 end
110
110
111 def entry(path=nil, identifier=nil)
111 def entry(path=nil, identifier=nil)
112 parts = path.to_s.split(%r{[\/\\]}).select {|n| !n.blank?}
112 parts = path.to_s.split(%r{[\/\\]}).select {|n| !n.blank?}
113 search_path = parts[0..-2].join('/')
113 search_path = parts[0..-2].join('/')
114 search_name = parts[-1]
114 search_name = parts[-1]
115 if search_path.blank? && search_name.blank?
115 if search_path.blank? && search_name.blank?
116 # Root entry
116 # Root entry
117 Entry.new(:path => '', :kind => 'dir')
117 Entry.new(:path => '', :kind => 'dir')
118 else
118 else
119 # Search for the entry in the parent directory
119 # Search for the entry in the parent directory
120 es = entries(search_path, identifier,
120 es = entries(search_path, identifier,
121 options = {:report_last_commit => false})
121 options = {:report_last_commit => false})
122 es ? es.detect {|e| e.name == search_name} : nil
122 es ? es.detect {|e| e.name == search_name} : nil
123 end
123 end
124 end
124 end
125
125
126 def entries(path=nil, identifier=nil, options={})
126 def entries(path=nil, identifier=nil, options={})
127 path ||= ''
127 path ||= ''
128 p = scm_iconv(@path_encoding, 'UTF-8', path)
128 p = scm_iconv(@path_encoding, 'UTF-8', path)
129 entries = Entries.new
129 entries = Entries.new
130 cmd_args = %w|ls-tree -l|
130 cmd_args = %w|ls-tree -l|
131 cmd_args << "HEAD:#{p}" if identifier.nil?
131 cmd_args << "HEAD:#{p}" if identifier.nil?
132 cmd_args << "#{identifier}:#{p}" if identifier
132 cmd_args << "#{identifier}:#{p}" if identifier
133 scm_cmd(*cmd_args) do |io|
133 scm_cmd(*cmd_args) do |io|
134 io.each_line do |line|
134 io.each_line do |line|
135 e = line.chomp.to_s
135 e = line.chomp.to_s
136 if e =~ /^\d+\s+(\w+)\s+([0-9a-f]{40})\s+([0-9-]+)\t(.+)$/
136 if e =~ /^\d+\s+(\w+)\s+([0-9a-f]{40})\s+([0-9-]+)\t(.+)$/
137 type = $1
137 type = $1
138 sha = $2
138 sha = $2
139 size = $3
139 size = $3
140 name = $4
140 name = $4
141 if name.respond_to?(:force_encoding)
141 if name.respond_to?(:force_encoding)
142 name.force_encoding(@path_encoding)
142 name.force_encoding(@path_encoding)
143 end
143 end
144 full_path = p.empty? ? name : "#{p}/#{name}"
144 full_path = p.empty? ? name : "#{p}/#{name}"
145 n = scm_iconv('UTF-8', @path_encoding, name)
145 n = scm_iconv('UTF-8', @path_encoding, name)
146 full_p = scm_iconv('UTF-8', @path_encoding, full_path)
146 full_p = scm_iconv('UTF-8', @path_encoding, full_path)
147 entries << Entry.new({:name => n,
147 entries << Entry.new({:name => n,
148 :path => full_p,
148 :path => full_p,
149 :kind => (type == "tree") ? 'dir' : 'file',
149 :kind => (type == "tree") ? 'dir' : 'file',
150 :size => (type == "tree") ? nil : size,
150 :size => (type == "tree") ? nil : size,
151 :lastrev => options[:report_last_commit] ?
151 :lastrev => options[:report_last_commit] ?
152 lastrev(full_path, identifier) : Revision.new
152 lastrev(full_path, identifier) : Revision.new
153 }) unless entries.detect{|entry| entry.name == name}
153 }) unless entries.detect{|entry| entry.name == name}
154 end
154 end
155 end
155 end
156 end
156 end
157 entries.sort_by_name
157 entries.sort_by_name
158 rescue ScmCommandAborted
158 rescue ScmCommandAborted
159 nil
159 nil
160 end
160 end
161
161
162 def lastrev(path, rev)
162 def lastrev(path, rev)
163 return nil if path.nil?
163 return nil if path.nil?
164 cmd_args = %w|log --no-color --encoding=UTF-8 --date=iso --pretty=fuller --no-merges -n 1|
164 cmd_args = %w|log --no-color --encoding=UTF-8 --date=iso --pretty=fuller --no-merges -n 1|
165 cmd_args << rev if rev
165 cmd_args << rev if rev
166 cmd_args << "--" << path unless path.empty?
166 cmd_args << "--" << path unless path.empty?
167 lines = []
167 lines = []
168 scm_cmd(*cmd_args) { |io| lines = io.readlines }
168 scm_cmd(*cmd_args) { |io| lines = io.readlines }
169 begin
169 begin
170 id = lines[0].split[1]
170 id = lines[0].split[1]
171 author = lines[1].match('Author:\s+(.*)$')[1]
171 author = lines[1].match('Author:\s+(.*)$')[1]
172 time = Time.parse(lines[4].match('CommitDate:\s+(.*)$')[1])
172 time = Time.parse(lines[4].match('CommitDate:\s+(.*)$')[1])
173
173
174 Revision.new({
174 Revision.new({
175 :identifier => id,
175 :identifier => id,
176 :scmid => id,
176 :scmid => id,
177 :author => author,
177 :author => author,
178 :time => time,
178 :time => time,
179 :message => nil,
179 :message => nil,
180 :paths => nil
180 :paths => nil
181 })
181 })
182 rescue NoMethodError => e
182 rescue NoMethodError => e
183 logger.error("The revision '#{path}' has a wrong format")
183 logger.error("The revision '#{path}' has a wrong format")
184 return nil
184 return nil
185 end
185 end
186 rescue ScmCommandAborted
186 rescue ScmCommandAborted
187 nil
187 nil
188 end
188 end
189
189
190 def revisions(path, identifier_from, identifier_to, options={})
190 def revisions(path, identifier_from, identifier_to, options={})
191 revs = Revisions.new
191 revs = Revisions.new
192 cmd_args = %w|log --no-color --encoding=UTF-8 --raw --date=iso --pretty=fuller --parents|
192 cmd_args = %w|log --no-color --encoding=UTF-8 --raw --date=iso --pretty=fuller --parents|
193 cmd_args << "--reverse" if options[:reverse]
193 cmd_args << "--reverse" if options[:reverse]
194 cmd_args << "--all" if options[:all]
195 cmd_args << "-n" << "#{options[:limit].to_i}" if options[:limit]
194 cmd_args << "-n" << "#{options[:limit].to_i}" if options[:limit]
196 from_to = ""
195 from_to = ""
197 from_to << "#{identifier_from}.." if identifier_from
196 from_to << "#{identifier_from}.." if identifier_from
198 from_to << "#{identifier_to}" if identifier_to
197 from_to << "#{identifier_to}" if identifier_to
199 cmd_args << from_to if !from_to.empty?
198 cmd_args << from_to if !from_to.empty?
200 cmd_args << "--" << scm_iconv(@path_encoding, 'UTF-8', path) if path && !path.empty?
199 cmd_args << "--" << scm_iconv(@path_encoding, 'UTF-8', path) if path && !path.empty?
201
200
202 scm_cmd *cmd_args do |io|
201 scm_cmd *cmd_args do |io|
203 files=[]
202 files=[]
204 changeset = {}
203 changeset = {}
205 parsing_descr = 0 #0: not parsing desc or files, 1: parsing desc, 2: parsing files
204 parsing_descr = 0 #0: not parsing desc or files, 1: parsing desc, 2: parsing files
206
205
207 io.each_line do |line|
206 io.each_line do |line|
208 if line =~ /^commit ([0-9a-f]{40})(( [0-9a-f]{40})*)$/
207 if line =~ /^commit ([0-9a-f]{40})(( [0-9a-f]{40})*)$/
209 key = "commit"
208 key = "commit"
210 value = $1
209 value = $1
211 parents_str = $2
210 parents_str = $2
212 if (parsing_descr == 1 || parsing_descr == 2)
211 if (parsing_descr == 1 || parsing_descr == 2)
213 parsing_descr = 0
212 parsing_descr = 0
214 revision = Revision.new({
213 revision = Revision.new({
215 :identifier => changeset[:commit],
214 :identifier => changeset[:commit],
216 :scmid => changeset[:commit],
215 :scmid => changeset[:commit],
217 :author => changeset[:author],
216 :author => changeset[:author],
218 :time => Time.parse(changeset[:date]),
217 :time => Time.parse(changeset[:date]),
219 :message => changeset[:description],
218 :message => changeset[:description],
220 :paths => files,
219 :paths => files,
221 :parents => changeset[:parents]
220 :parents => changeset[:parents]
222 })
221 })
223 if block_given?
222 if block_given?
224 yield revision
223 yield revision
225 else
224 else
226 revs << revision
225 revs << revision
227 end
226 end
228 changeset = {}
227 changeset = {}
229 files = []
228 files = []
230 end
229 end
231 changeset[:commit] = $1
230 changeset[:commit] = $1
232 unless parents_str.nil? or parents_str == ""
231 unless parents_str.nil? or parents_str == ""
233 changeset[:parents] = parents_str.strip.split(' ')
232 changeset[:parents] = parents_str.strip.split(' ')
234 end
233 end
235 elsif (parsing_descr == 0) && line =~ /^(\w+):\s*(.*)$/
234 elsif (parsing_descr == 0) && line =~ /^(\w+):\s*(.*)$/
236 key = $1
235 key = $1
237 value = $2
236 value = $2
238 if key == "Author"
237 if key == "Author"
239 changeset[:author] = value
238 changeset[:author] = value
240 elsif key == "CommitDate"
239 elsif key == "CommitDate"
241 changeset[:date] = value
240 changeset[:date] = value
242 end
241 end
243 elsif (parsing_descr == 0) && line.chomp.to_s == ""
242 elsif (parsing_descr == 0) && line.chomp.to_s == ""
244 parsing_descr = 1
243 parsing_descr = 1
245 changeset[:description] = ""
244 changeset[:description] = ""
246 elsif (parsing_descr == 1 || parsing_descr == 2) \
245 elsif (parsing_descr == 1 || parsing_descr == 2) \
247 && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\t(.+)$/
246 && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\t(.+)$/
248 parsing_descr = 2
247 parsing_descr = 2
249 fileaction = $1
248 fileaction = $1
250 filepath = $2
249 filepath = $2
251 p = scm_iconv('UTF-8', @path_encoding, filepath)
250 p = scm_iconv('UTF-8', @path_encoding, filepath)
252 files << {:action => fileaction, :path => p}
251 files << {:action => fileaction, :path => p}
253 elsif (parsing_descr == 1 || parsing_descr == 2) \
252 elsif (parsing_descr == 1 || parsing_descr == 2) \
254 && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\d+\s+(\S+)\t(.+)$/
253 && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\d+\s+(\S+)\t(.+)$/
255 parsing_descr = 2
254 parsing_descr = 2
256 fileaction = $1
255 fileaction = $1
257 filepath = $3
256 filepath = $3
258 p = scm_iconv('UTF-8', @path_encoding, filepath)
257 p = scm_iconv('UTF-8', @path_encoding, filepath)
259 files << {:action => fileaction, :path => p}
258 files << {:action => fileaction, :path => p}
260 elsif (parsing_descr == 1) && line.chomp.to_s == ""
259 elsif (parsing_descr == 1) && line.chomp.to_s == ""
261 parsing_descr = 2
260 parsing_descr = 2
262 elsif (parsing_descr == 1)
261 elsif (parsing_descr == 1)
263 changeset[:description] << line[4..-1]
262 changeset[:description] << line[4..-1]
264 end
263 end
265 end
264 end
266
265
267 if changeset[:commit]
266 if changeset[:commit]
268 revision = Revision.new({
267 revision = Revision.new({
269 :identifier => changeset[:commit],
268 :identifier => changeset[:commit],
270 :scmid => changeset[:commit],
269 :scmid => changeset[:commit],
271 :author => changeset[:author],
270 :author => changeset[:author],
272 :time => Time.parse(changeset[:date]),
271 :time => Time.parse(changeset[:date]),
273 :message => changeset[:description],
272 :message => changeset[:description],
274 :paths => files,
273 :paths => files,
275 :parents => changeset[:parents]
274 :parents => changeset[:parents]
276 })
275 })
277 if block_given?
276 if block_given?
278 yield revision
277 yield revision
279 else
278 else
280 revs << revision
279 revs << revision
281 end
280 end
282 end
281 end
283 end
282 end
284 revs
283 revs
285 rescue ScmCommandAborted => e
284 rescue ScmCommandAborted => e
286 logger.error("git log #{from_to.to_s} error: #{e.message}")
285 logger.error("git log #{from_to.to_s} error: #{e.message}")
287 revs
286 revs
288 end
287 end
289
288
290 def diff(path, identifier_from, identifier_to=nil)
289 def diff(path, identifier_from, identifier_to=nil)
291 path ||= ''
290 path ||= ''
292 cmd_args = []
291 cmd_args = []
293 if identifier_to
292 if identifier_to
294 cmd_args << "diff" << "--no-color" << identifier_to << identifier_from
293 cmd_args << "diff" << "--no-color" << identifier_to << identifier_from
295 else
294 else
296 cmd_args << "show" << "--no-color" << identifier_from
295 cmd_args << "show" << "--no-color" << identifier_from
297 end
296 end
298 cmd_args << "--" << scm_iconv(@path_encoding, 'UTF-8', path) unless path.empty?
297 cmd_args << "--" << scm_iconv(@path_encoding, 'UTF-8', path) unless path.empty?
299 diff = []
298 diff = []
300 scm_cmd *cmd_args do |io|
299 scm_cmd *cmd_args do |io|
301 io.each_line do |line|
300 io.each_line do |line|
302 diff << line
301 diff << line
303 end
302 end
304 end
303 end
305 diff
304 diff
306 rescue ScmCommandAborted
305 rescue ScmCommandAborted
307 nil
306 nil
308 end
307 end
309
308
310 def annotate(path, identifier=nil)
309 def annotate(path, identifier=nil)
311 identifier = 'HEAD' if identifier.blank?
310 identifier = 'HEAD' if identifier.blank?
312 cmd_args = %w|blame|
311 cmd_args = %w|blame|
313 cmd_args << "-p" << identifier << "--" << scm_iconv(@path_encoding, 'UTF-8', path)
312 cmd_args << "-p" << identifier << "--" << scm_iconv(@path_encoding, 'UTF-8', path)
314 blame = Annotate.new
313 blame = Annotate.new
315 content = nil
314 content = nil
316 scm_cmd(*cmd_args) { |io| io.binmode; content = io.read }
315 scm_cmd(*cmd_args) { |io| io.binmode; content = io.read }
317 # git annotates binary files
316 # git annotates binary files
318 return nil if content.is_binary_data?
317 return nil if content.is_binary_data?
319 identifier = ''
318 identifier = ''
320 # git shows commit author on the first occurrence only
319 # git shows commit author on the first occurrence only
321 authors_by_commit = {}
320 authors_by_commit = {}
322 content.split("\n").each do |line|
321 content.split("\n").each do |line|
323 if line =~ /^([0-9a-f]{39,40})\s.*/
322 if line =~ /^([0-9a-f]{39,40})\s.*/
324 identifier = $1
323 identifier = $1
325 elsif line =~ /^author (.+)/
324 elsif line =~ /^author (.+)/
326 authors_by_commit[identifier] = $1.strip
325 authors_by_commit[identifier] = $1.strip
327 elsif line =~ /^\t(.*)/
326 elsif line =~ /^\t(.*)/
328 blame.add_line($1, Revision.new(
327 blame.add_line($1, Revision.new(
329 :identifier => identifier,
328 :identifier => identifier,
330 :revision => identifier,
329 :revision => identifier,
331 :scmid => identifier,
330 :scmid => identifier,
332 :author => authors_by_commit[identifier]
331 :author => authors_by_commit[identifier]
333 ))
332 ))
334 identifier = ''
333 identifier = ''
335 author = ''
334 author = ''
336 end
335 end
337 end
336 end
338 blame
337 blame
339 rescue ScmCommandAborted
338 rescue ScmCommandAborted
340 nil
339 nil
341 end
340 end
342
341
343 def cat(path, identifier=nil)
342 def cat(path, identifier=nil)
344 if identifier.nil?
343 if identifier.nil?
345 identifier = 'HEAD'
344 identifier = 'HEAD'
346 end
345 end
347 cmd_args = %w|show --no-color|
346 cmd_args = %w|show --no-color|
348 cmd_args << "#{identifier}:#{scm_iconv(@path_encoding, 'UTF-8', path)}"
347 cmd_args << "#{identifier}:#{scm_iconv(@path_encoding, 'UTF-8', path)}"
349 cat = nil
348 cat = nil
350 scm_cmd(*cmd_args) do |io|
349 scm_cmd(*cmd_args) do |io|
351 io.binmode
350 io.binmode
352 cat = io.read
351 cat = io.read
353 end
352 end
354 cat
353 cat
355 rescue ScmCommandAborted
354 rescue ScmCommandAborted
356 nil
355 nil
357 end
356 end
358
357
359 class Revision < Redmine::Scm::Adapters::Revision
358 class Revision < Redmine::Scm::Adapters::Revision
360 # Returns the readable identifier
359 # Returns the readable identifier
361 def format_identifier
360 def format_identifier
362 identifier[0,8]
361 identifier[0,8]
363 end
362 end
364 end
363 end
365
364
366 def scm_cmd(*args, &block)
365 def scm_cmd(*args, &block)
367 repo_path = root_url || url
366 repo_path = root_url || url
368 full_args = ['--git-dir', repo_path]
367 full_args = ['--git-dir', repo_path]
369 if self.class.client_version_above?([1, 7, 2])
368 if self.class.client_version_above?([1, 7, 2])
370 full_args << '-c' << 'core.quotepath=false'
369 full_args << '-c' << 'core.quotepath=false'
371 full_args << '-c' << 'log.decorate=no'
370 full_args << '-c' << 'log.decorate=no'
372 end
371 end
373 full_args += args
372 full_args += args
374 ret = shellout(
373 ret = shellout(
375 self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '),
374 self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '),
376 &block
375 &block
377 )
376 )
378 if $? && $?.exitstatus != 0
377 if $? && $?.exitstatus != 0
379 raise ScmCommandAborted, "git exited with non-zero status: #{$?.exitstatus}"
378 raise ScmCommandAborted, "git exited with non-zero status: #{$?.exitstatus}"
380 end
379 end
381 ret
380 ret
382 end
381 end
383 private :scm_cmd
382 private :scm_cmd
384 end
383 end
385 end
384 end
386 end
385 end
387 end
386 end
@@ -1,433 +1,422
1 # encoding: utf-8
1 # encoding: utf-8
2
2
3 # This file includes UTF-8 "Felix SchΓ€fer".
3 # This file includes UTF-8 "Felix SchΓ€fer".
4 # We need to consider Ruby 1.9 compatibility.
4 # We need to consider Ruby 1.9 compatibility.
5
5
6 require File.expand_path('../../../../../../test_helper', __FILE__)
6 require File.expand_path('../../../../../../test_helper', __FILE__)
7 begin
7 begin
8 require 'mocha'
8 require 'mocha'
9
9
10 class GitAdapterTest < ActiveSupport::TestCase
10 class GitAdapterTest < ActiveSupport::TestCase
11 REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
11 REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
12
12
13 FELIX_UTF8 = "Felix SchΓ€fer"
13 FELIX_UTF8 = "Felix SchΓ€fer"
14 FELIX_HEX = "Felix Sch\xC3\xA4fer"
14 FELIX_HEX = "Felix Sch\xC3\xA4fer"
15 CHAR_1_HEX = "\xc3\x9c"
15 CHAR_1_HEX = "\xc3\x9c"
16
16
17 ## Ruby uses ANSI api to fork a process on Windows.
17 ## Ruby uses ANSI api to fork a process on Windows.
18 ## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
18 ## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
19 ## and these are incompatible with ASCII.
19 ## and these are incompatible with ASCII.
20 # WINDOWS_PASS = Redmine::Platform.mswin?
20 # WINDOWS_PASS = Redmine::Platform.mswin?
21 WINDOWS_PASS = false
21 WINDOWS_PASS = false
22
22
23 ## Git, Mercurial and CVS path encodings are binary.
23 ## Git, Mercurial and CVS path encodings are binary.
24 ## Subversion supports URL encoding for path.
24 ## Subversion supports URL encoding for path.
25 ## Redmine Mercurial adapter and extension use URL encoding.
25 ## Redmine Mercurial adapter and extension use URL encoding.
26 ## Git accepts only binary path in command line parameter.
26 ## Git accepts only binary path in command line parameter.
27 ## So, there is no way to use binary command line parameter in JRuby.
27 ## So, there is no way to use binary command line parameter in JRuby.
28 JRUBY_SKIP = (RUBY_PLATFORM == 'java')
28 JRUBY_SKIP = (RUBY_PLATFORM == 'java')
29 JRUBY_SKIP_STR = "TODO: This test fails in JRuby"
29 JRUBY_SKIP_STR = "TODO: This test fails in JRuby"
30
30
31 if File.directory?(REPOSITORY_PATH)
31 if File.directory?(REPOSITORY_PATH)
32 def setup
32 def setup
33 adapter_class = Redmine::Scm::Adapters::GitAdapter
33 adapter_class = Redmine::Scm::Adapters::GitAdapter
34 assert adapter_class
34 assert adapter_class
35 assert adapter_class.client_command
35 assert adapter_class.client_command
36 assert_equal true, adapter_class.client_available
36 assert_equal true, adapter_class.client_available
37 assert_equal true, adapter_class.client_version_above?([1])
37 assert_equal true, adapter_class.client_version_above?([1])
38 assert_equal true, adapter_class.client_version_above?([1, 0])
38 assert_equal true, adapter_class.client_version_above?([1, 0])
39
39
40 @adapter = Redmine::Scm::Adapters::GitAdapter.new(
40 @adapter = Redmine::Scm::Adapters::GitAdapter.new(
41 REPOSITORY_PATH,
41 REPOSITORY_PATH,
42 nil,
42 nil,
43 nil,
43 nil,
44 nil,
44 nil,
45 'ISO-8859-1'
45 'ISO-8859-1'
46 )
46 )
47 assert @adapter
47 assert @adapter
48 @char_1 = CHAR_1_HEX.dup
48 @char_1 = CHAR_1_HEX.dup
49 if @char_1.respond_to?(:force_encoding)
49 if @char_1.respond_to?(:force_encoding)
50 @char_1.force_encoding('UTF-8')
50 @char_1.force_encoding('UTF-8')
51 end
51 end
52 end
52 end
53
53
54 def test_scm_version
54 def test_scm_version
55 to_test = { "git version 1.7.3.4\n" => [1,7,3,4],
55 to_test = { "git version 1.7.3.4\n" => [1,7,3,4],
56 "1.6.1\n1.7\n1.8" => [1,6,1],
56 "1.6.1\n1.7\n1.8" => [1,6,1],
57 "1.6.2\r\n1.8.1\r\n1.9.1" => [1,6,2]}
57 "1.6.2\r\n1.8.1\r\n1.9.1" => [1,6,2]}
58 to_test.each do |s, v|
58 to_test.each do |s, v|
59 test_scm_version_for(s, v)
59 test_scm_version_for(s, v)
60 end
60 end
61 end
61 end
62
62
63 def test_branches
63 def test_branches
64 brs = []
64 brs = []
65 @adapter.branches.each do |b|
65 @adapter.branches.each do |b|
66 brs << b
66 brs << b
67 end
67 end
68 assert_equal 4, brs.length
68 assert_equal 4, brs.length
69 assert_equal 'latin-1-path-encoding', brs[0].to_s
69 assert_equal 'latin-1-path-encoding', brs[0].to_s
70 assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', brs[0].revision
70 assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', brs[0].revision
71 assert_equal brs[0].scmid, brs[0].revision
71 assert_equal brs[0].scmid, brs[0].revision
72 assert_equal 'master', brs[1].to_s
72 assert_equal 'master', brs[1].to_s
73 assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', brs[1].revision
73 assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', brs[1].revision
74 assert_equal brs[1].scmid, brs[1].revision
74 assert_equal brs[1].scmid, brs[1].revision
75 assert_equal 'test-latin-1', brs[2].to_s
75 assert_equal 'test-latin-1', brs[2].to_s
76 assert_equal '67e7792ce20ccae2e4bb73eed09bb397819c8834', brs[2].revision
76 assert_equal '67e7792ce20ccae2e4bb73eed09bb397819c8834', brs[2].revision
77 assert_equal brs[2].scmid, brs[2].revision
77 assert_equal brs[2].scmid, brs[2].revision
78 assert_equal 'test_branch', brs[3].to_s
78 assert_equal 'test_branch', brs[3].to_s
79 assert_equal 'fba357b886984ee71185ad2065e65fc0417d9b92', brs[3].revision
79 assert_equal 'fba357b886984ee71185ad2065e65fc0417d9b92', brs[3].revision
80 assert_equal brs[3].scmid, brs[3].revision
80 assert_equal brs[3].scmid, brs[3].revision
81 end
81 end
82
82
83 def test_tags
83 def test_tags
84 assert_equal [
84 assert_equal [
85 "tag00.lightweight",
85 "tag00.lightweight",
86 "tag01.annotated",
86 "tag01.annotated",
87 ], @adapter.tags
87 ], @adapter.tags
88 end
88 end
89
89
90 def test_getting_all_revisions
91 assert_equal 21, @adapter.revisions('',nil,nil,:all => true).length
92 end
93
94 def test_revisions_reverse
95 revs1 = @adapter.revisions('',nil,nil,{:all => true, :reverse => true })
96 assert_equal 21, revs1.length
97 assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs1[0].identifier
98 assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', revs1[20].identifier
99 end
100
101 def test_revisions_master_all
90 def test_revisions_master_all
102 revs1 = []
91 revs1 = []
103 @adapter.revisions('', nil, "master",{}) do |rev|
92 @adapter.revisions('', nil, "master",{}) do |rev|
104 revs1 << rev
93 revs1 << rev
105 end
94 end
106 assert_equal 15, revs1.length
95 assert_equal 15, revs1.length
107 assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs1[ 0].identifier
96 assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs1[ 0].identifier
108 assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs1[-1].identifier
97 assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs1[-1].identifier
109
98
110 revs2 = []
99 revs2 = []
111 @adapter.revisions('', nil, "master",
100 @adapter.revisions('', nil, "master",
112 {:reverse => true}) do |rev|
101 {:reverse => true}) do |rev|
113 revs2 << rev
102 revs2 << rev
114 end
103 end
115 assert_equal 15, revs2.length
104 assert_equal 15, revs2.length
116 assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs2[-1].identifier
105 assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs2[-1].identifier
117 assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs2[ 0].identifier
106 assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs2[ 0].identifier
118 end
107 end
119
108
120 def test_revisions_master_merged_rev
109 def test_revisions_master_merged_rev
121 revs1 = []
110 revs1 = []
122 @adapter.revisions('',
111 @adapter.revisions('',
123 "713f4944648826f558cf548222f813dabe7cbb04",
112 "713f4944648826f558cf548222f813dabe7cbb04",
124 "master",
113 "master",
125 {:reverse => true}) do |rev|
114 {:reverse => true}) do |rev|
126 revs1 << rev
115 revs1 << rev
127 end
116 end
128 assert_equal 8, revs1.length
117 assert_equal 8, revs1.length
129 assert_equal 'fba357b886984ee71185ad2065e65fc0417d9b92', revs1[ 0].identifier
118 assert_equal 'fba357b886984ee71185ad2065e65fc0417d9b92', revs1[ 0].identifier
130 assert_equal '7e61ac704deecde634b51e59daa8110435dcb3da', revs1[ 1].identifier
119 assert_equal '7e61ac704deecde634b51e59daa8110435dcb3da', revs1[ 1].identifier
131 # 4a07fe31b is not a child of 713f49446
120 # 4a07fe31b is not a child of 713f49446
132 assert_equal '4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8', revs1[ 2].identifier
121 assert_equal '4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8', revs1[ 2].identifier
133 # Merged revision
122 # Merged revision
134 assert_equal '32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf', revs1[ 3].identifier
123 assert_equal '32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf', revs1[ 3].identifier
135 assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs1[-1].identifier
124 assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs1[-1].identifier
136
125
137 revs2 = []
126 revs2 = []
138 @adapter.revisions('',
127 @adapter.revisions('',
139 "fba357b886984ee71185ad2065e65fc0417d9b92",
128 "fba357b886984ee71185ad2065e65fc0417d9b92",
140 "master",
129 "master",
141 {:reverse => true}) do |rev|
130 {:reverse => true}) do |rev|
142 revs2 << rev
131 revs2 << rev
143 end
132 end
144 assert_equal 7, revs2.length
133 assert_equal 7, revs2.length
145 assert_equal '7e61ac704deecde634b51e59daa8110435dcb3da', revs2[ 0].identifier
134 assert_equal '7e61ac704deecde634b51e59daa8110435dcb3da', revs2[ 0].identifier
146 # 4a07fe31b is not a child of fba357b8869
135 # 4a07fe31b is not a child of fba357b8869
147 assert_equal '4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8', revs2[ 1].identifier
136 assert_equal '4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8', revs2[ 1].identifier
148 # Merged revision
137 # Merged revision
149 assert_equal '32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf', revs2[ 2].identifier
138 assert_equal '32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf', revs2[ 2].identifier
150 assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs2[-1].identifier
139 assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs2[-1].identifier
151 end
140 end
152
141
153 def test_revisions_branch_latin_1_path_encoding_all
142 def test_revisions_branch_latin_1_path_encoding_all
154 revs1 = []
143 revs1 = []
155 @adapter.revisions('', nil, "latin-1-path-encoding",{}) do |rev|
144 @adapter.revisions('', nil, "latin-1-path-encoding",{}) do |rev|
156 revs1 << rev
145 revs1 << rev
157 end
146 end
158 assert_equal 8, revs1.length
147 assert_equal 8, revs1.length
159 assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', revs1[ 0].identifier
148 assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', revs1[ 0].identifier
160 assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs1[-1].identifier
149 assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs1[-1].identifier
161
150
162 revs2 = []
151 revs2 = []
163 @adapter.revisions('', nil, "latin-1-path-encoding",
152 @adapter.revisions('', nil, "latin-1-path-encoding",
164 {:reverse => true}) do |rev|
153 {:reverse => true}) do |rev|
165 revs2 << rev
154 revs2 << rev
166 end
155 end
167 assert_equal 8, revs2.length
156 assert_equal 8, revs2.length
168 assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', revs2[-1].identifier
157 assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', revs2[-1].identifier
169 assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs2[ 0].identifier
158 assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs2[ 0].identifier
170 end
159 end
171
160
172 def test_revisions_branch_latin_1_path_encoding_with_rev
161 def test_revisions_branch_latin_1_path_encoding_with_rev
173 revs1 = []
162 revs1 = []
174 @adapter.revisions('',
163 @adapter.revisions('',
175 '7234cb2750b63f47bff735edc50a1c0a433c2518',
164 '7234cb2750b63f47bff735edc50a1c0a433c2518',
176 "latin-1-path-encoding",
165 "latin-1-path-encoding",
177 {:reverse => true}) do |rev|
166 {:reverse => true}) do |rev|
178 revs1 << rev
167 revs1 << rev
179 end
168 end
180 assert_equal 7, revs1.length
169 assert_equal 7, revs1.length
181 assert_equal '899a15dba03a3b350b89c3f537e4bbe02a03cdc9', revs1[ 0].identifier
170 assert_equal '899a15dba03a3b350b89c3f537e4bbe02a03cdc9', revs1[ 0].identifier
182 assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', revs1[-1].identifier
171 assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', revs1[-1].identifier
183
172
184 revs2 = []
173 revs2 = []
185 @adapter.revisions('',
174 @adapter.revisions('',
186 '57ca437c0acbbcb749821fdf3726a1367056d364',
175 '57ca437c0acbbcb749821fdf3726a1367056d364',
187 "latin-1-path-encoding",
176 "latin-1-path-encoding",
188 {:reverse => true}) do |rev|
177 {:reverse => true}) do |rev|
189 revs2 << rev
178 revs2 << rev
190 end
179 end
191 assert_equal 3, revs2.length
180 assert_equal 3, revs2.length
192 assert_equal '4fc55c43bf3d3dc2efb66145365ddc17639ce81e', revs2[ 0].identifier
181 assert_equal '4fc55c43bf3d3dc2efb66145365ddc17639ce81e', revs2[ 0].identifier
193 assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', revs2[-1].identifier
182 assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', revs2[-1].identifier
194 end
183 end
195
184
196 def test_revisions_invalid_rev
185 def test_revisions_invalid_rev
197 revs1 = []
186 revs1 = []
198 @adapter.revisions('',
187 @adapter.revisions('',
199 '1234abcd',
188 '1234abcd',
200 "master",
189 "master",
201 {:reverse => true}) do |rev|
190 {:reverse => true}) do |rev|
202 revs1 << rev
191 revs1 << rev
203 end
192 end
204 assert_equal [], revs1
193 assert_equal [], revs1
205 end
194 end
206
195
207 def test_getting_revisions_with_spaces_in_filename
196 def test_getting_revisions_with_spaces_in_filename
208 assert_equal 1, @adapter.revisions("filemane with spaces.txt",
197 assert_equal 1, @adapter.revisions("filemane with spaces.txt",
209 nil, "master").length
198 nil, "master").length
210 end
199 end
211
200
212 def test_parents
201 def test_parents
213 revs1 = []
202 revs1 = []
214 @adapter.revisions('',
203 @adapter.revisions('',
215 nil,
204 nil,
216 "master",
205 "master",
217 {:reverse => true}) do |rev|
206 {:reverse => true}) do |rev|
218 revs1 << rev
207 revs1 << rev
219 end
208 end
220 assert_equal 15, revs1.length
209 assert_equal 15, revs1.length
221 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518",
210 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518",
222 revs1[0].identifier
211 revs1[0].identifier
223 assert_equal nil, revs1[0].parents
212 assert_equal nil, revs1[0].parents
224 assert_equal "899a15dba03a3b350b89c3f537e4bbe02a03cdc9",
213 assert_equal "899a15dba03a3b350b89c3f537e4bbe02a03cdc9",
225 revs1[1].identifier
214 revs1[1].identifier
226 assert_equal 1, revs1[1].parents.length
215 assert_equal 1, revs1[1].parents.length
227 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518",
216 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518",
228 revs1[1].parents[0]
217 revs1[1].parents[0]
229 assert_equal "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
218 assert_equal "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
230 revs1[10].identifier
219 revs1[10].identifier
231 assert_equal 2, revs1[10].parents.length
220 assert_equal 2, revs1[10].parents.length
232 assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8",
221 assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8",
233 revs1[10].parents[0]
222 revs1[10].parents[0]
234 assert_equal "7e61ac704deecde634b51e59daa8110435dcb3da",
223 assert_equal "7e61ac704deecde634b51e59daa8110435dcb3da",
235 revs1[10].parents[1]
224 revs1[10].parents[1]
236 end
225 end
237
226
238 def test_getting_revisions_with_leading_and_trailing_spaces_in_filename
227 def test_getting_revisions_with_leading_and_trailing_spaces_in_filename
239 assert_equal " filename with a leading space.txt ",
228 assert_equal " filename with a leading space.txt ",
240 @adapter.revisions(" filename with a leading space.txt ",
229 @adapter.revisions(" filename with a leading space.txt ",
241 nil, "master")[0].paths[0][:path]
230 nil, "master")[0].paths[0][:path]
242 end
231 end
243
232
244 def test_getting_entries_with_leading_and_trailing_spaces_in_filename
233 def test_getting_entries_with_leading_and_trailing_spaces_in_filename
245 assert_equal " filename with a leading space.txt ",
234 assert_equal " filename with a leading space.txt ",
246 @adapter.entries('',
235 @adapter.entries('',
247 '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c')[3].name
236 '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c')[3].name
248 end
237 end
249
238
250 def test_annotate
239 def test_annotate
251 annotate = @adapter.annotate('sources/watchers_controller.rb')
240 annotate = @adapter.annotate('sources/watchers_controller.rb')
252 assert_kind_of Redmine::Scm::Adapters::Annotate, annotate
241 assert_kind_of Redmine::Scm::Adapters::Annotate, annotate
253 assert_equal 41, annotate.lines.size
242 assert_equal 41, annotate.lines.size
254 assert_equal "# This program is free software; you can redistribute it and/or",
243 assert_equal "# This program is free software; you can redistribute it and/or",
255 annotate.lines[4].strip
244 annotate.lines[4].strip
256 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518",
245 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518",
257 annotate.revisions[4].identifier
246 annotate.revisions[4].identifier
258 assert_equal "jsmith", annotate.revisions[4].author
247 assert_equal "jsmith", annotate.revisions[4].author
259 end
248 end
260
249
261 def test_annotate_moved_file
250 def test_annotate_moved_file
262 annotate = @adapter.annotate('renamed_test.txt')
251 annotate = @adapter.annotate('renamed_test.txt')
263 assert_kind_of Redmine::Scm::Adapters::Annotate, annotate
252 assert_kind_of Redmine::Scm::Adapters::Annotate, annotate
264 assert_equal 2, annotate.lines.size
253 assert_equal 2, annotate.lines.size
265 end
254 end
266
255
267 def test_last_rev
256 def test_last_rev
268 last_rev = @adapter.lastrev("README",
257 last_rev = @adapter.lastrev("README",
269 "4f26664364207fa8b1af9f8722647ab2d4ac5d43")
258 "4f26664364207fa8b1af9f8722647ab2d4ac5d43")
270 assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", last_rev.scmid
259 assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", last_rev.scmid
271 assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", last_rev.identifier
260 assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", last_rev.identifier
272 assert_equal "Adam Soltys <asoltys@gmail.com>", last_rev.author
261 assert_equal "Adam Soltys <asoltys@gmail.com>", last_rev.author
273 assert_equal "2009-06-24 05:27:38".to_time, last_rev.time
262 assert_equal "2009-06-24 05:27:38".to_time, last_rev.time
274 end
263 end
275
264
276 def test_last_rev_with_spaces_in_filename
265 def test_last_rev_with_spaces_in_filename
277 last_rev = @adapter.lastrev("filemane with spaces.txt",
266 last_rev = @adapter.lastrev("filemane with spaces.txt",
278 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b")
267 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b")
279 str_felix_utf8 = FELIX_UTF8.dup
268 str_felix_utf8 = FELIX_UTF8.dup
280 str_felix_hex = FELIX_HEX.dup
269 str_felix_hex = FELIX_HEX.dup
281 last_rev_author = last_rev.author
270 last_rev_author = last_rev.author
282 if last_rev_author.respond_to?(:force_encoding)
271 if last_rev_author.respond_to?(:force_encoding)
283 last_rev_author.force_encoding('UTF-8')
272 last_rev_author.force_encoding('UTF-8')
284 end
273 end
285 assert_equal "ed5bb786bbda2dee66a2d50faf51429dbc043a7b", last_rev.scmid
274 assert_equal "ed5bb786bbda2dee66a2d50faf51429dbc043a7b", last_rev.scmid
286 assert_equal "ed5bb786bbda2dee66a2d50faf51429dbc043a7b", last_rev.identifier
275 assert_equal "ed5bb786bbda2dee66a2d50faf51429dbc043a7b", last_rev.identifier
287 assert_equal "#{str_felix_utf8} <felix@fachschaften.org>",
276 assert_equal "#{str_felix_utf8} <felix@fachschaften.org>",
288 last_rev.author
277 last_rev.author
289 assert_equal "#{str_felix_hex} <felix@fachschaften.org>",
278 assert_equal "#{str_felix_hex} <felix@fachschaften.org>",
290 last_rev.author
279 last_rev.author
291 assert_equal "2010-09-18 19:59:46".to_time, last_rev.time
280 assert_equal "2010-09-18 19:59:46".to_time, last_rev.time
292 end
281 end
293
282
294 def test_latin_1_path
283 def test_latin_1_path
295 if WINDOWS_PASS
284 if WINDOWS_PASS
296 #
285 #
297 elsif JRUBY_SKIP
286 elsif JRUBY_SKIP
298 puts JRUBY_SKIP_STR
287 puts JRUBY_SKIP_STR
299 else
288 else
300 p2 = "latin-1-dir/test-#{@char_1}-2.txt"
289 p2 = "latin-1-dir/test-#{@char_1}-2.txt"
301 ['4fc55c43bf3d3dc2efb66145365ddc17639ce81e', '4fc55c43bf3'].each do |r1|
290 ['4fc55c43bf3d3dc2efb66145365ddc17639ce81e', '4fc55c43bf3'].each do |r1|
302 assert @adapter.diff(p2, r1)
291 assert @adapter.diff(p2, r1)
303 assert @adapter.cat(p2, r1)
292 assert @adapter.cat(p2, r1)
304 assert_equal 1, @adapter.annotate(p2, r1).lines.length
293 assert_equal 1, @adapter.annotate(p2, r1).lines.length
305 ['64f1f3e89ad1cb57976ff0ad99a107012ba3481d', '64f1f3e89ad1cb5797'].each do |r2|
294 ['64f1f3e89ad1cb57976ff0ad99a107012ba3481d', '64f1f3e89ad1cb5797'].each do |r2|
306 assert @adapter.diff(p2, r1, r2)
295 assert @adapter.diff(p2, r1, r2)
307 end
296 end
308 end
297 end
309 end
298 end
310 end
299 end
311
300
312 def test_entries_tag
301 def test_entries_tag
313 entries1 = @adapter.entries(nil, 'tag01.annotated',
302 entries1 = @adapter.entries(nil, 'tag01.annotated',
314 options = {:report_last_commit => true})
303 options = {:report_last_commit => true})
315 assert entries1
304 assert entries1
316 assert_equal 3, entries1.size
305 assert_equal 3, entries1.size
317 assert_equal 'sources', entries1[1].name
306 assert_equal 'sources', entries1[1].name
318 assert_equal 'sources', entries1[1].path
307 assert_equal 'sources', entries1[1].path
319 assert_equal 'dir', entries1[1].kind
308 assert_equal 'dir', entries1[1].kind
320 readme = entries1[2]
309 readme = entries1[2]
321 assert_equal 'README', readme.name
310 assert_equal 'README', readme.name
322 assert_equal 'README', readme.path
311 assert_equal 'README', readme.path
323 assert_equal 'file', readme.kind
312 assert_equal 'file', readme.kind
324 assert_equal 27, readme.size
313 assert_equal 27, readme.size
325 assert_equal '899a15dba03a3b350b89c3f537e4bbe02a03cdc9', readme.lastrev.identifier
314 assert_equal '899a15dba03a3b350b89c3f537e4bbe02a03cdc9', readme.lastrev.identifier
326 assert_equal Time.gm(2007, 12, 14, 9, 24, 1), readme.lastrev.time
315 assert_equal Time.gm(2007, 12, 14, 9, 24, 1), readme.lastrev.time
327 end
316 end
328
317
329 def test_entries_branch
318 def test_entries_branch
330 entries1 = @adapter.entries(nil, 'test_branch',
319 entries1 = @adapter.entries(nil, 'test_branch',
331 options = {:report_last_commit => true})
320 options = {:report_last_commit => true})
332 assert entries1
321 assert entries1
333 assert_equal 4, entries1.size
322 assert_equal 4, entries1.size
334 assert_equal 'sources', entries1[1].name
323 assert_equal 'sources', entries1[1].name
335 assert_equal 'sources', entries1[1].path
324 assert_equal 'sources', entries1[1].path
336 assert_equal 'dir', entries1[1].kind
325 assert_equal 'dir', entries1[1].kind
337 readme = entries1[2]
326 readme = entries1[2]
338 assert_equal 'README', readme.name
327 assert_equal 'README', readme.name
339 assert_equal 'README', readme.path
328 assert_equal 'README', readme.path
340 assert_equal 'file', readme.kind
329 assert_equal 'file', readme.kind
341 assert_equal 159, readme.size
330 assert_equal 159, readme.size
342 assert_equal '713f4944648826f558cf548222f813dabe7cbb04', readme.lastrev.identifier
331 assert_equal '713f4944648826f558cf548222f813dabe7cbb04', readme.lastrev.identifier
343 assert_equal Time.gm(2009, 6, 19, 4, 37, 23), readme.lastrev.time
332 assert_equal Time.gm(2009, 6, 19, 4, 37, 23), readme.lastrev.time
344 end
333 end
345
334
346 def test_entries_latin_1_files
335 def test_entries_latin_1_files
347 entries1 = @adapter.entries('latin-1-dir', '64f1f3e8')
336 entries1 = @adapter.entries('latin-1-dir', '64f1f3e8')
348 assert entries1
337 assert entries1
349 assert_equal 3, entries1.size
338 assert_equal 3, entries1.size
350 f1 = entries1[1]
339 f1 = entries1[1]
351 assert_equal "test-#{@char_1}-2.txt", f1.name
340 assert_equal "test-#{@char_1}-2.txt", f1.name
352 assert_equal "latin-1-dir/test-#{@char_1}-2.txt", f1.path
341 assert_equal "latin-1-dir/test-#{@char_1}-2.txt", f1.path
353 assert_equal 'file', f1.kind
342 assert_equal 'file', f1.kind
354 end
343 end
355
344
356 def test_entries_latin_1_dir
345 def test_entries_latin_1_dir
357 if WINDOWS_PASS
346 if WINDOWS_PASS
358 #
347 #
359 elsif JRUBY_SKIP
348 elsif JRUBY_SKIP
360 puts JRUBY_SKIP_STR
349 puts JRUBY_SKIP_STR
361 else
350 else
362 entries1 = @adapter.entries("latin-1-dir/test-#{@char_1}-subdir",
351 entries1 = @adapter.entries("latin-1-dir/test-#{@char_1}-subdir",
363 '1ca7f5ed')
352 '1ca7f5ed')
364 assert entries1
353 assert entries1
365 assert_equal 3, entries1.size
354 assert_equal 3, entries1.size
366 f1 = entries1[1]
355 f1 = entries1[1]
367 assert_equal "test-#{@char_1}-2.txt", f1.name
356 assert_equal "test-#{@char_1}-2.txt", f1.name
368 assert_equal "latin-1-dir/test-#{@char_1}-subdir/test-#{@char_1}-2.txt", f1.path
357 assert_equal "latin-1-dir/test-#{@char_1}-subdir/test-#{@char_1}-2.txt", f1.path
369 assert_equal 'file', f1.kind
358 assert_equal 'file', f1.kind
370 end
359 end
371 end
360 end
372
361
373 def test_path_encoding_default_utf8
362 def test_path_encoding_default_utf8
374 adpt1 = Redmine::Scm::Adapters::GitAdapter.new(
363 adpt1 = Redmine::Scm::Adapters::GitAdapter.new(
375 REPOSITORY_PATH
364 REPOSITORY_PATH
376 )
365 )
377 assert_equal "UTF-8", adpt1.path_encoding
366 assert_equal "UTF-8", adpt1.path_encoding
378 adpt2 = Redmine::Scm::Adapters::GitAdapter.new(
367 adpt2 = Redmine::Scm::Adapters::GitAdapter.new(
379 REPOSITORY_PATH,
368 REPOSITORY_PATH,
380 nil,
369 nil,
381 nil,
370 nil,
382 nil,
371 nil,
383 ""
372 ""
384 )
373 )
385 assert_equal "UTF-8", adpt2.path_encoding
374 assert_equal "UTF-8", adpt2.path_encoding
386 end
375 end
387
376
388 def test_cat_path_invalid
377 def test_cat_path_invalid
389 assert_nil @adapter.cat('invalid')
378 assert_nil @adapter.cat('invalid')
390 end
379 end
391
380
392 def test_cat_revision_invalid
381 def test_cat_revision_invalid
393 assert @adapter.cat('README')
382 assert @adapter.cat('README')
394 assert_nil @adapter.cat('README', 'abcd1234efgh')
383 assert_nil @adapter.cat('README', 'abcd1234efgh')
395 end
384 end
396
385
397 def test_diff_path_invalid
386 def test_diff_path_invalid
398 assert_equal [], @adapter.diff('invalid', '713f4944648826f5')
387 assert_equal [], @adapter.diff('invalid', '713f4944648826f5')
399 end
388 end
400
389
401 def test_diff_revision_invalid
390 def test_diff_revision_invalid
402 assert_nil @adapter.diff(nil, 'abcd1234efgh')
391 assert_nil @adapter.diff(nil, 'abcd1234efgh')
403 assert_nil @adapter.diff(nil, '713f4944648826f5', 'abcd1234efgh')
392 assert_nil @adapter.diff(nil, '713f4944648826f5', 'abcd1234efgh')
404 assert_nil @adapter.diff(nil, 'abcd1234efgh', '713f4944648826f5')
393 assert_nil @adapter.diff(nil, 'abcd1234efgh', '713f4944648826f5')
405 end
394 end
406
395
407 def test_annotate_path_invalid
396 def test_annotate_path_invalid
408 assert_nil @adapter.annotate('invalid')
397 assert_nil @adapter.annotate('invalid')
409 end
398 end
410
399
411 def test_annotate_revision_invalid
400 def test_annotate_revision_invalid
412 assert @adapter.annotate('README')
401 assert @adapter.annotate('README')
413 assert_nil @adapter.annotate('README', 'abcd1234efgh')
402 assert_nil @adapter.annotate('README', 'abcd1234efgh')
414 end
403 end
415
404
416 private
405 private
417
406
418 def test_scm_version_for(scm_command_version, version)
407 def test_scm_version_for(scm_command_version, version)
419 @adapter.class.expects(:scm_version_from_command_line).returns(scm_command_version)
408 @adapter.class.expects(:scm_version_from_command_line).returns(scm_command_version)
420 assert_equal version, @adapter.class.scm_command_version
409 assert_equal version, @adapter.class.scm_command_version
421 end
410 end
422
411
423 else
412 else
424 puts "Git test repository NOT FOUND. Skipping unit tests !!!"
413 puts "Git test repository NOT FOUND. Skipping unit tests !!!"
425 def test_fake; assert true end
414 def test_fake; assert true end
426 end
415 end
427 end
416 end
428
417
429 rescue LoadError
418 rescue LoadError
430 class GitMochaFake < ActiveSupport::TestCase
419 class GitMochaFake < ActiveSupport::TestCase
431 def test_fake; assert(false, "Requires mocha to run those tests") end
420 def test_fake; assert(false, "Requires mocha to run those tests") end
432 end
421 end
433 end
422 end
General Comments 0
You need to be logged in to leave comments. Login now