##// END OF EJS Templates
scm: git: use --encoding=UTF-8 in "git log" (#3396)....
Toshi MARUYAMA -
r4844:eb1271bb444c
parent child
Show More
@@ -1,119 +1,123
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 # Copyright (C) 2007 Patrick Aljord patcito@ŋmail.com
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require 'redmine/scm/adapters/git_adapter'
19 19
20 20 class Repository::Git < Repository
21 21 attr_protected :root_url
22 22 validates_presence_of :url
23 23
24 24 def self.scm_adapter_class
25 25 Redmine::Scm::Adapters::GitAdapter
26 26 end
27 27
28 28 def self.scm_name
29 29 'Git'
30 30 end
31 31
32 def repo_log_encoding
33 'UTF-8'
34 end
35
32 36 # Returns the identifier for the given git changeset
33 37 def self.changeset_identifier(changeset)
34 38 changeset.scmid
35 39 end
36 40
37 41 # Returns the readable identifier for the given git changeset
38 42 def self.format_changeset_identifier(changeset)
39 43 changeset.revision[0, 8]
40 44 end
41 45
42 46 def branches
43 47 scm.branches
44 48 end
45 49
46 50 def tags
47 51 scm.tags
48 52 end
49 53
50 54 def find_changeset_by_name(name)
51 55 return nil if name.nil? || name.empty?
52 56 e = changesets.find(:first, :conditions => ['revision = ?', name.to_s])
53 57 return e if e
54 58 changesets.find(:first, :conditions => ['scmid LIKE ?', "#{name}%"])
55 59 end
56 60
57 61 # With SCM's that have a sequential commit numbering, redmine is able to be
58 62 # clever and only fetch changesets going forward from the most recent one
59 63 # it knows about. However, with git, you never know if people have merged
60 64 # commits into the middle of the repository history, so we should parse
61 65 # the entire log. Since it's way too slow for large repositories, we only
62 66 # parse 1 week before the last known commit.
63 67 # The repository can still be fully reloaded by calling #clear_changesets
64 68 # before fetching changesets (eg. for offline resync)
65 69 def fetch_changesets
66 70 c = changesets.find(:first, :order => 'committed_on DESC')
67 71 since = (c ? c.committed_on - 7.days : nil)
68 72
69 73 revisions = scm.revisions('', nil, nil, :all => true, :since => since)
70 74 return if revisions.nil? || revisions.empty?
71 75
72 76 recent_changesets = changesets.find(:all, :conditions => ['committed_on >= ?', since])
73 77
74 78 # Clean out revisions that are no longer in git
75 79 recent_changesets.each {|c| c.destroy unless revisions.detect {|r| r.scmid.to_s == c.scmid.to_s }}
76 80
77 81 # Subtract revisions that redmine already knows about
78 82 recent_revisions = recent_changesets.map{|c| c.scmid}
79 83 revisions.reject!{|r| recent_revisions.include?(r.scmid)}
80 84
81 85 # Save the remaining ones to the database
82 86 unless revisions.nil?
83 87 revisions.each do |rev|
84 88 transaction do
85 89 changeset = Changeset.new(
86 90 :repository => self,
87 91 :revision => rev.identifier,
88 92 :scmid => rev.scmid,
89 93 :committer => rev.author,
90 94 :committed_on => rev.time,
91 95 :comments => rev.message)
92 96
93 97 if changeset.save
94 98 rev.paths.each do |file|
95 99 Change.create(
96 100 :changeset => changeset,
97 101 :action => file[:action],
98 102 :path => file[:path])
99 103 end
100 104 end
101 105 end
102 106 end
103 107 end
104 108 end
105 109
106 110 def latest_changesets(path,rev,limit=10)
107 111 revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false)
108 112 return [] if revisions.nil? || revisions.empty?
109 113
110 114 changesets.find(
111 115 :all,
112 116 :conditions => [
113 117 "scmid IN (?)",
114 118 revisions.map!{|c| c.scmid}
115 119 ],
116 120 :order => 'committed_on DESC'
117 121 )
118 122 end
119 123 end
@@ -1,334 +1,334
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require 'redmine/scm/adapters/abstract_adapter'
19 19
20 20 module Redmine
21 21 module Scm
22 22 module Adapters
23 23 class GitAdapter < AbstractAdapter
24 24
25 25 SCM_GIT_REPORT_LAST_COMMIT = true
26 26
27 27 # Git executable name
28 28 GIT_BIN = Redmine::Configuration['scm_git_command'] || "git"
29 29
30 30 # raised if scm command exited with error, e.g. unknown revision.
31 31 class ScmCommandAborted < CommandFailed; end
32 32
33 33 class << self
34 34 def client_command
35 35 @@bin ||= GIT_BIN
36 36 end
37 37
38 38 def sq_bin
39 39 @@sq_bin ||= shell_quote(GIT_BIN)
40 40 end
41 41
42 42 def client_version
43 43 @@client_version ||= (scm_command_version || [])
44 44 end
45 45
46 46 def client_available
47 47 !client_version.empty?
48 48 end
49 49
50 50 def scm_command_version
51 51 scm_version = scm_version_from_command_line
52 52 if scm_version.respond_to?(:force_encoding)
53 53 scm_version.force_encoding('ASCII-8BIT')
54 54 end
55 55 if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)})
56 56 m[2].scan(%r{\d+}).collect(&:to_i)
57 57 end
58 58 end
59 59
60 60 def scm_version_from_command_line
61 61 shellout("#{sq_bin} --version --no-color") { |io| io.read }.to_s
62 62 end
63 63 end
64 64
65 65 def initialize(url, root_url=nil, login=nil, password=nil, path_encoding=nil)
66 66 super
67 67 @flag_report_last_commit = SCM_GIT_REPORT_LAST_COMMIT
68 68 end
69 69
70 70 def info
71 71 begin
72 72 Info.new(:root_url => url, :lastrev => lastrev('',nil))
73 73 rescue
74 74 nil
75 75 end
76 76 end
77 77
78 78 def branches
79 79 return @branches if @branches
80 80 @branches = []
81 81 cmd = "#{self.class.sq_bin} --git-dir #{target('')} branch --no-color"
82 82 shellout(cmd) do |io|
83 83 io.each_line do |line|
84 84 @branches << line.match('\s*\*?\s*(.*)$')[1]
85 85 end
86 86 end
87 87 @branches.sort!
88 88 end
89 89
90 90 def tags
91 91 return @tags if @tags
92 92 cmd = "#{self.class.sq_bin} --git-dir #{target('')} tag"
93 93 shellout(cmd) do |io|
94 94 @tags = io.readlines.sort!.map{|t| t.strip}
95 95 end
96 96 end
97 97
98 98 def default_branch
99 99 branches.include?('master') ? 'master' : branches.first
100 100 end
101 101
102 102 def entries(path=nil, identifier=nil)
103 103 path ||= ''
104 104 entries = Entries.new
105 105 cmd = "#{self.class.sq_bin} --git-dir #{target('')} ls-tree -l "
106 106 cmd << shell_quote("HEAD:" + path) if identifier.nil?
107 107 cmd << shell_quote(identifier + ":" + path) if identifier
108 108 shellout(cmd) do |io|
109 109 io.each_line do |line|
110 110 e = line.chomp.to_s
111 111 if e =~ /^\d+\s+(\w+)\s+([0-9a-f]{40})\s+([0-9-]+)\t(.+)$/
112 112 type = $1
113 113 sha = $2
114 114 size = $3
115 115 name = $4
116 116 full_path = path.empty? ? name : "#{path}/#{name}"
117 117 entries << Entry.new({:name => name,
118 118 :path => full_path,
119 119 :kind => (type == "tree") ? 'dir' : 'file',
120 120 :size => (type == "tree") ? nil : size,
121 121 :lastrev => @flag_report_last_commit ? lastrev(full_path,identifier) : Revision.new
122 122 }) unless entries.detect{|entry| entry.name == name}
123 123 end
124 124 end
125 125 end
126 126 return nil if $? && $?.exitstatus != 0
127 127 entries.sort_by_name
128 128 end
129 129
130 130 def lastrev(path, rev)
131 131 return nil if path.nil?
132 cmd_args = %w|log --no-color --date=iso --pretty=fuller --no-merges -n 1|
132 cmd_args = %w|log --no-color --encoding=UTF-8 --date=iso --pretty=fuller --no-merges -n 1|
133 133 cmd_args << rev if rev
134 134 cmd_args << "--" << path unless path.empty?
135 135 lines = []
136 136 scm_cmd(*cmd_args) { |io| lines = io.readlines }
137 137 begin
138 138 id = lines[0].split[1]
139 139 author = lines[1].match('Author:\s+(.*)$')[1]
140 140 time = Time.parse(lines[4].match('CommitDate:\s+(.*)$')[1])
141 141
142 142 Revision.new({
143 143 :identifier => id,
144 144 :scmid => id,
145 145 :author => author,
146 146 :time => time,
147 147 :message => nil,
148 148 :paths => nil
149 149 })
150 150 rescue NoMethodError => e
151 151 logger.error("The revision '#{path}' has a wrong format")
152 152 return nil
153 153 end
154 154 rescue ScmCommandAborted
155 155 nil
156 156 end
157 157
158 158 def revisions(path, identifier_from, identifier_to, options={})
159 159 revisions = Revisions.new
160 cmd_args = %w|log --no-color --raw --date=iso --pretty=fuller|
160 cmd_args = %w|log --no-color --encoding=UTF-8 --raw --date=iso --pretty=fuller|
161 161 cmd_args << "--reverse" if options[:reverse]
162 162 cmd_args << "--all" if options[:all]
163 163 cmd_args << "-n" << "#{options[:limit].to_i}" if options[:limit]
164 164 from_to = ""
165 165 from_to << "#{identifier_from}.." if identifier_from
166 166 from_to << "#{identifier_to}" if identifier_to
167 167 cmd_args << from_to if !from_to.empty?
168 168 cmd_args << "--since=#{options[:since].strftime("%Y-%m-%d %H:%M:%S")}" if options[:since]
169 169 cmd_args << "--" << path if path && !path.empty?
170 170
171 171 scm_cmd *cmd_args do |io|
172 172 files=[]
173 173 changeset = {}
174 174 parsing_descr = 0 #0: not parsing desc or files, 1: parsing desc, 2: parsing files
175 175 revno = 1
176 176
177 177 io.each_line do |line|
178 178 if line =~ /^commit ([0-9a-f]{40})$/
179 179 key = "commit"
180 180 value = $1
181 181 if (parsing_descr == 1 || parsing_descr == 2)
182 182 parsing_descr = 0
183 183 revision = Revision.new({
184 184 :identifier => changeset[:commit],
185 185 :scmid => changeset[:commit],
186 186 :author => changeset[:author],
187 187 :time => Time.parse(changeset[:date]),
188 188 :message => changeset[:description],
189 189 :paths => files
190 190 })
191 191 if block_given?
192 192 yield revision
193 193 else
194 194 revisions << revision
195 195 end
196 196 changeset = {}
197 197 files = []
198 198 revno = revno + 1
199 199 end
200 200 changeset[:commit] = $1
201 201 elsif (parsing_descr == 0) && line =~ /^(\w+):\s*(.*)$/
202 202 key = $1
203 203 value = $2
204 204 if key == "Author"
205 205 changeset[:author] = value
206 206 elsif key == "CommitDate"
207 207 changeset[:date] = value
208 208 end
209 209 elsif (parsing_descr == 0) && line.chomp.to_s == ""
210 210 parsing_descr = 1
211 211 changeset[:description] = ""
212 212 elsif (parsing_descr == 1 || parsing_descr == 2) \
213 213 && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\t(.+)$/
214 214 parsing_descr = 2
215 215 fileaction = $1
216 216 filepath = $2
217 217 files << {:action => fileaction, :path => filepath}
218 218 elsif (parsing_descr == 1 || parsing_descr == 2) \
219 219 && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\d+\s+(\S+)\t(.+)$/
220 220 parsing_descr = 2
221 221 fileaction = $1
222 222 filepath = $3
223 223 files << {:action => fileaction, :path => filepath}
224 224 elsif (parsing_descr == 1) && line.chomp.to_s == ""
225 225 parsing_descr = 2
226 226 elsif (parsing_descr == 1)
227 227 changeset[:description] << line[4..-1]
228 228 end
229 229 end
230 230
231 231 if changeset[:commit]
232 232 revision = Revision.new({
233 233 :identifier => changeset[:commit],
234 234 :scmid => changeset[:commit],
235 235 :author => changeset[:author],
236 236 :time => Time.parse(changeset[:date]),
237 237 :message => changeset[:description],
238 238 :paths => files
239 239 })
240 240
241 241 if block_given?
242 242 yield revision
243 243 else
244 244 revisions << revision
245 245 end
246 246 end
247 247 end
248 248 revisions
249 249 rescue ScmCommandAborted
250 250 revisions
251 251 end
252 252
253 253 def diff(path, identifier_from, identifier_to=nil)
254 254 path ||= ''
255 255
256 256 if identifier_to
257 257 cmd = "#{self.class.sq_bin} --git-dir #{target('')} diff --no-color #{shell_quote identifier_to} #{shell_quote identifier_from}"
258 258 else
259 259 cmd = "#{self.class.sq_bin} --git-dir #{target('')} show --no-color #{shell_quote identifier_from}"
260 260 end
261 261
262 262 cmd << " -- #{shell_quote path}" unless path.empty?
263 263 diff = []
264 264 shellout(cmd) do |io|
265 265 io.each_line do |line|
266 266 diff << line
267 267 end
268 268 end
269 269 return nil if $? && $?.exitstatus != 0
270 270 diff
271 271 end
272 272
273 273 def annotate(path, identifier=nil)
274 274 identifier = 'HEAD' if identifier.blank?
275 275 cmd = "#{self.class.sq_bin} --git-dir #{target('')} blame -p #{shell_quote identifier} -- #{shell_quote path}"
276 276 blame = Annotate.new
277 277 content = nil
278 278 shellout(cmd) { |io| io.binmode; content = io.read }
279 279 return nil if $? && $?.exitstatus != 0
280 280 # git annotates binary files
281 281 return nil if content.is_binary_data?
282 282 identifier = ''
283 283 # git shows commit author on the first occurrence only
284 284 authors_by_commit = {}
285 285 content.split("\n").each do |line|
286 286 if line =~ /^([0-9a-f]{39,40})\s.*/
287 287 identifier = $1
288 288 elsif line =~ /^author (.+)/
289 289 authors_by_commit[identifier] = $1.strip
290 290 elsif line =~ /^\t(.*)/
291 291 blame.add_line($1, Revision.new(:identifier => identifier, :author => authors_by_commit[identifier]))
292 292 identifier = ''
293 293 author = ''
294 294 end
295 295 end
296 296 blame
297 297 end
298 298
299 299 def cat(path, identifier=nil)
300 300 if identifier.nil?
301 301 identifier = 'HEAD'
302 302 end
303 303 cmd = "#{self.class.sq_bin} --git-dir #{target('')} show --no-color #{shell_quote(identifier + ':' + path)}"
304 304 cat = nil
305 305 shellout(cmd) do |io|
306 306 io.binmode
307 307 cat = io.read
308 308 end
309 309 return nil if $? && $?.exitstatus != 0
310 310 cat
311 311 end
312 312
313 313 class Revision < Redmine::Scm::Adapters::Revision
314 314 # Returns the readable identifier
315 315 def format_identifier
316 316 identifier[0,8]
317 317 end
318 318 end
319 319
320 320 def scm_cmd(*args, &block)
321 321 repo_path = root_url || url
322 322 full_args = [GIT_BIN, '--git-dir', repo_path]
323 323 full_args += args
324 324 ret = shellout(full_args.map { |e| shell_quote e.to_s }.join(' '), &block)
325 325 if $? && $?.exitstatus != 0
326 326 raise ScmCommandAborted, "git exited with non-zero status: #{$?.exitstatus}"
327 327 end
328 328 ret
329 329 end
330 330 private :scm_cmd
331 331 end
332 332 end
333 333 end
334 334 end
1 NO CONTENT: modified file, binary diff hidden
@@ -1,120 +1,120
1 1 # encoding: utf-8
2 2
3 3 # This file includes UTF-8 "Felix Schäfer".
4 4 # We need to consider Ruby 1.9 compatibility.
5 5
6 6 require File.expand_path('../../../../../../test_helper', __FILE__)
7 7 begin
8 8 require 'mocha'
9 9
10 10 class GitAdapterTest < ActiveSupport::TestCase
11 11 REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/git_repository'
12 12
13 13 FELIX_UTF8 = "Felix Schäfer"
14 14 FELIX_HEX = "Felix Sch\xC3\xA4fer"
15 15
16 16 if File.directory?(REPOSITORY_PATH)
17 17 def setup
18 18 @adapter = Redmine::Scm::Adapters::GitAdapter.new(REPOSITORY_PATH)
19 19 end
20 20
21 21 def test_scm_version
22 22 to_test = { "git version 1.7.3.4\n" => [1,7,3,4],
23 23 "1.6.1\n1.7\n1.8" => [1,6,1],
24 24 "1.6.2\r\n1.8.1\r\n1.9.1" => [1,6,2]}
25 25 to_test.each do |s, v|
26 26 test_scm_version_for(s, v)
27 27 end
28 28 end
29 29
30 30 def test_branches
31 assert_equal @adapter.branches, ['master', 'test_branch']
31 assert_equal @adapter.branches, ['master', 'test-latin-1', 'test_branch']
32 32 end
33 33
34 34 def test_getting_all_revisions
35 assert_equal 15, @adapter.revisions('',nil,nil,:all => true).length
35 assert_equal 16, @adapter.revisions('',nil,nil,:all => true).length
36 36 end
37 37
38 38 def test_getting_certain_revisions
39 39 assert_equal 1, @adapter.revisions('','899a15d^','899a15d').length
40 40 end
41 41
42 42 def test_getting_revisions_with_spaces_in_filename
43 43 assert_equal 1, @adapter.revisions("filemane with spaces.txt",
44 44 nil, nil, :all => true).length
45 45 end
46 46
47 47 def test_getting_revisions_with_leading_and_trailing_spaces_in_filename
48 48 assert_equal " filename with a leading space.txt ",
49 49 @adapter.revisions(" filename with a leading space.txt ",
50 50 nil, nil, :all => true)[0].paths[0][:path]
51 51 end
52 52
53 53 def test_getting_entries_with_leading_and_trailing_spaces_in_filename
54 54 assert_equal " filename with a leading space.txt ",
55 55 @adapter.entries('',
56 56 '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c')[3].name
57 57 end
58 58
59 59 def test_annotate
60 60 annotate = @adapter.annotate('sources/watchers_controller.rb')
61 61 assert_kind_of Redmine::Scm::Adapters::Annotate, annotate
62 62 assert_equal 41, annotate.lines.size
63 63 assert_equal "# This program is free software; you can redistribute it and/or", annotate.lines[4].strip
64 64 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518",
65 65 annotate.revisions[4].identifier
66 66 assert_equal "jsmith", annotate.revisions[4].author
67 67 end
68 68
69 69 def test_annotate_moved_file
70 70 annotate = @adapter.annotate('renamed_test.txt')
71 71 assert_kind_of Redmine::Scm::Adapters::Annotate, annotate
72 72 assert_equal 2, annotate.lines.size
73 73 end
74 74
75 75 def test_last_rev
76 76 last_rev = @adapter.lastrev("README",
77 77 "4f26664364207fa8b1af9f8722647ab2d4ac5d43")
78 78 assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", last_rev.scmid
79 79 assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", last_rev.identifier
80 80 assert_equal "Adam Soltys <asoltys@gmail.com>", last_rev.author
81 81 assert_equal "2009-06-24 05:27:38".to_time, last_rev.time
82 82 end
83 83
84 84 def test_last_rev_with_spaces_in_filename
85 85 last_rev = @adapter.lastrev("filemane with spaces.txt",
86 86 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b")
87 87 str_felix_utf8 = FELIX_UTF8
88 88 str_felix_hex = FELIX_HEX
89 89 last_rev_author = last_rev.author
90 90 if last_rev_author.respond_to?(:force_encoding)
91 91 last_rev_author.force_encoding('UTF-8')
92 92 end
93 93 assert_equal "ed5bb786bbda2dee66a2d50faf51429dbc043a7b", last_rev.scmid
94 94 assert_equal "ed5bb786bbda2dee66a2d50faf51429dbc043a7b", last_rev.identifier
95 95 assert_equal "#{str_felix_utf8} <felix@fachschaften.org>",
96 96 last_rev.author
97 97 assert_equal "#{str_felix_hex} <felix@fachschaften.org>",
98 98 last_rev.author
99 99 assert_equal "2010-09-18 19:59:46".to_time, last_rev.time
100 100 end
101 101
102 102 private
103 103
104 104 def test_scm_version_for(scm_command_version, version)
105 105 @adapter.class.expects(:scm_version_from_command_line).returns(scm_command_version)
106 106 assert_equal version, @adapter.class.scm_command_version
107 107 end
108 108
109 109 else
110 110 puts "Git test repository NOT FOUND. Skipping unit tests !!!"
111 111 def test_fake; assert true end
112 112 end
113 113 end
114 114
115 115 rescue LoadError
116 116 class GitMochaFake < ActiveSupport::TestCase
117 117 def test_fake; assert(false, "Requires mocha to run those tests") end
118 118 end
119 119 end
120 120
@@ -1,125 +1,125
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../test_helper', __FILE__)
19 19
20 20 class RepositoryGitTest < ActiveSupport::TestCase
21 21 fixtures :projects, :repositories, :enabled_modules, :users, :roles
22 22
23 23 # No '..' in the repository path
24 24 REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/git_repository'
25 25 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
26 26
27 27 FELIX_HEX = "Felix Sch\xC3\xA4fer"
28 28
29 29 def setup
30 30 Setting.commit_logs_encoding = 'UTF-8'
31 31 @project = Project.find(3)
32 32 @repository = Repository::Git.create(:project => @project, :url => REPOSITORY_PATH)
33 33 assert @repository
34 34 end
35 35
36 36 if File.directory?(REPOSITORY_PATH)
37 37 def test_fetch_changesets_from_scratch
38 38 @repository.fetch_changesets
39 39 @repository.reload
40 40
41 assert_equal 15, @repository.changesets.count
42 assert_equal 24, @repository.changes.count
41 assert_equal 16, @repository.changesets.count
42 assert_equal 25, @repository.changes.count
43 43
44 44 commit = @repository.changesets.find(:first, :order => 'committed_on ASC')
45 45 assert_equal "Initial import.\nThe repository contains 3 files.", commit.comments
46 46 assert_equal "jsmith <jsmith@foo.bar>", commit.committer
47 47 assert_equal User.find_by_login('jsmith'), commit.user
48 48 # TODO: add a commit with commit time <> author time to the test repository
49 49 assert_equal "2007-12-14 09:22:52".to_time, commit.committed_on
50 50 assert_equal "2007-12-14".to_date, commit.commit_date
51 51 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", commit.revision
52 52 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", commit.scmid
53 53 assert_equal 3, commit.changes.count
54 54 change = commit.changes.sort_by(&:path).first
55 55 assert_equal "README", change.path
56 56 assert_equal "A", change.action
57 57 end
58 58
59 59 def test_fetch_changesets_incremental
60 60 @repository.fetch_changesets
61 61 # Remove the 3 latest changesets
62 62 @repository.changesets.find(:all, :order => 'committed_on DESC', :limit => 3).each(&:destroy)
63 63 @repository.reload
64 assert_equal 12, @repository.changesets.count
64 assert_equal 13, @repository.changesets.count
65 65
66 66 @repository.fetch_changesets
67 assert_equal 15, @repository.changesets.count
67 assert_equal 16, @repository.changesets.count
68 68 end
69 69
70 70 def test_find_changeset_by_name
71 71 @repository.fetch_changesets
72 72 @repository.reload
73 73 ['7234cb2750b63f47bff735edc50a1c0a433c2518', '7234cb2750b'].each do |r|
74 74 assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518',
75 75 @repository.find_changeset_by_name(r).revision
76 76 end
77 77 end
78 78
79 79 def test_find_changeset_by_empty_name
80 80 @repository.fetch_changesets
81 81 @repository.reload
82 82 ['', ' ', nil].each do |r|
83 83 assert_nil @repository.find_changeset_by_name(r)
84 84 end
85 85 end
86 86
87 87 def test_identifier
88 88 @repository.fetch_changesets
89 89 @repository.reload
90 90 c = @repository.changesets.find_by_revision('7234cb2750b63f47bff735edc50a1c0a433c2518')
91 91 assert_equal c.scmid, c.identifier
92 92 end
93 93
94 94 def test_format_identifier
95 95 @repository.fetch_changesets
96 96 @repository.reload
97 97 c = @repository.changesets.find_by_revision('7234cb2750b63f47bff735edc50a1c0a433c2518')
98 98 assert_equal '7234cb27', c.format_identifier
99 99 end
100 100
101 101 def test_activities
102 102 c = Changeset.new(:repository => @repository,
103 103 :committed_on => Time.now,
104 104 :revision => 'abc7234cb2750b63f47bff735edc50a1c0a433c2',
105 105 :scmid => 'abc7234cb2750b63f47bff735edc50a1c0a433c2',
106 106 :comments => 'test')
107 107 assert c.event_title.include?('abc7234c:')
108 108 assert_equal 'abc7234cb2750b63f47bff735edc50a1c0a433c2', c.event_url[:rev]
109 109 end
110 110
111 111 def test_log_utf8
112 112 @repository.fetch_changesets
113 113 @repository.reload
114 114 str_felix_hex = FELIX_HEX
115 115 if str_felix_hex.respond_to?(:force_encoding)
116 116 str_felix_hex.force_encoding('UTF-8')
117 117 end
118 118 c = @repository.changesets.find_by_revision('ed5bb786bbda2dee66a2d50faf51429dbc043a7b')
119 119 assert_equal "#{str_felix_hex} <felix@fachschaften.org>", c.committer
120 120 end
121 121 else
122 122 puts "Git test repository NOT FOUND. Skipping unit tests !!!"
123 123 def test_fake; assert true end
124 124 end
125 125 end
General Comments 0
You need to be logged in to leave comments. Login now