##// END OF EJS Templates
Support spaces in the files or directories in the git adapter. #6054...
Eric Davis -
r4074:bd511194607b
parent child
Show More
@@ -1,270 +1,270
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 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 # Git executable name
24 # Git executable name
25 GIT_BIN = "git"
25 GIT_BIN = "git"
26
26
27 def info
27 def info
28 begin
28 begin
29 Info.new(:root_url => url, :lastrev => lastrev('',nil))
29 Info.new(:root_url => url, :lastrev => lastrev('',nil))
30 rescue
30 rescue
31 nil
31 nil
32 end
32 end
33 end
33 end
34
34
35 def branches
35 def branches
36 return @branches if @branches
36 return @branches if @branches
37 @branches = []
37 @branches = []
38 cmd = "#{GIT_BIN} --git-dir #{target('')} branch"
38 cmd = "#{GIT_BIN} --git-dir #{target('')} branch"
39 shellout(cmd) do |io|
39 shellout(cmd) do |io|
40 io.each_line do |line|
40 io.each_line do |line|
41 @branches << line.match('\s*\*?\s*(.*)$')[1]
41 @branches << line.match('\s*\*?\s*(.*)$')[1]
42 end
42 end
43 end
43 end
44 @branches.sort!
44 @branches.sort!
45 end
45 end
46
46
47 def tags
47 def tags
48 return @tags if @tags
48 return @tags if @tags
49 cmd = "#{GIT_BIN} --git-dir #{target('')} tag"
49 cmd = "#{GIT_BIN} --git-dir #{target('')} tag"
50 shellout(cmd) do |io|
50 shellout(cmd) do |io|
51 @tags = io.readlines.sort!.map{|t| t.strip}
51 @tags = io.readlines.sort!.map{|t| t.strip}
52 end
52 end
53 end
53 end
54
54
55 def default_branch
55 def default_branch
56 branches.include?('master') ? 'master' : branches.first
56 branches.include?('master') ? 'master' : branches.first
57 end
57 end
58
58
59 def entries(path=nil, identifier=nil)
59 def entries(path=nil, identifier=nil)
60 path ||= ''
60 path ||= ''
61 entries = Entries.new
61 entries = Entries.new
62 cmd = "#{GIT_BIN} --git-dir #{target('')} ls-tree -l "
62 cmd = "#{GIT_BIN} --git-dir #{target('')} ls-tree -l "
63 cmd << shell_quote("HEAD:" + path) if identifier.nil?
63 cmd << shell_quote("HEAD:" + path) if identifier.nil?
64 cmd << shell_quote(identifier + ":" + path) if identifier
64 cmd << shell_quote(identifier + ":" + path) if identifier
65 shellout(cmd) do |io|
65 shellout(cmd) do |io|
66 io.each_line do |line|
66 io.each_line do |line|
67 e = line.chomp.to_s
67 e = line.chomp.to_s
68 if e =~ /^\d+\s+(\w+)\s+([0-9a-f]{40})\s+([0-9-]+)\s+(.+)$/
68 if e =~ /^\d+\s+(\w+)\s+([0-9a-f]{40})\s+([0-9-]+)\s+(.+)$/
69 type = $1
69 type = $1
70 sha = $2
70 sha = $2
71 size = $3
71 size = $3
72 name = $4
72 name = $4
73 full_path = path.empty? ? name : "#{path}/#{name}"
73 full_path = path.empty? ? name : "#{path}/#{name}"
74 entries << Entry.new({:name => name,
74 entries << Entry.new({:name => name,
75 :path => full_path,
75 :path => full_path,
76 :kind => (type == "tree") ? 'dir' : 'file',
76 :kind => (type == "tree") ? 'dir' : 'file',
77 :size => (type == "tree") ? nil : size,
77 :size => (type == "tree") ? nil : size,
78 :lastrev => lastrev(full_path,identifier)
78 :lastrev => lastrev(full_path,identifier)
79 }) unless entries.detect{|entry| entry.name == name}
79 }) unless entries.detect{|entry| entry.name == name}
80 end
80 end
81 end
81 end
82 end
82 end
83 return nil if $? && $?.exitstatus != 0
83 return nil if $? && $?.exitstatus != 0
84 entries.sort_by_name
84 entries.sort_by_name
85 end
85 end
86
86
87 def lastrev(path,rev)
87 def lastrev(path,rev)
88 return nil if path.nil?
88 return nil if path.nil?
89 cmd = "#{GIT_BIN} --git-dir #{target('')} log --date=iso --pretty=fuller --no-merges -n 1 "
89 cmd = "#{GIT_BIN} --git-dir #{target('')} log --date=iso --pretty=fuller --no-merges -n 1 "
90 cmd << " #{shell_quote rev} " if rev
90 cmd << " #{shell_quote rev} " if rev
91 cmd << "-- #{path} " unless path.empty?
91 cmd << "-- #{shell_quote path} " unless path.empty?
92 shellout(cmd) do |io|
92 shellout(cmd) do |io|
93 begin
93 begin
94 id = io.gets.split[1]
94 id = io.gets.split[1]
95 author = io.gets.match('Author:\s+(.*)$')[1]
95 author = io.gets.match('Author:\s+(.*)$')[1]
96 2.times { io.gets }
96 2.times { io.gets }
97 time = Time.parse(io.gets.match('CommitDate:\s+(.*)$')[1]).localtime
97 time = Time.parse(io.gets.match('CommitDate:\s+(.*)$')[1]).localtime
98
98
99 Revision.new({
99 Revision.new({
100 :identifier => id,
100 :identifier => id,
101 :scmid => id,
101 :scmid => id,
102 :author => author,
102 :author => author,
103 :time => time,
103 :time => time,
104 :message => nil,
104 :message => nil,
105 :paths => nil
105 :paths => nil
106 })
106 })
107 rescue NoMethodError => e
107 rescue NoMethodError => e
108 logger.error("The revision '#{path}' has a wrong format")
108 logger.error("The revision '#{path}' has a wrong format")
109 return nil
109 return nil
110 end
110 end
111 end
111 end
112 end
112 end
113
113
114 def revisions(path, identifier_from, identifier_to, options={})
114 def revisions(path, identifier_from, identifier_to, options={})
115 revisions = Revisions.new
115 revisions = Revisions.new
116
116
117 cmd = "#{GIT_BIN} --git-dir #{target('')} log --raw --date=iso --pretty=fuller "
117 cmd = "#{GIT_BIN} --git-dir #{target('')} log --raw --date=iso --pretty=fuller "
118 cmd << " --reverse " if options[:reverse]
118 cmd << " --reverse " if options[:reverse]
119 cmd << " --all " if options[:all]
119 cmd << " --all " if options[:all]
120 cmd << " -n #{options[:limit]} " if options[:limit]
120 cmd << " -n #{options[:limit]} " if options[:limit]
121 cmd << "#{shell_quote(identifier_from + '..')}" if identifier_from
121 cmd << "#{shell_quote(identifier_from + '..')}" if identifier_from
122 cmd << "#{shell_quote identifier_to}" if identifier_to
122 cmd << "#{shell_quote identifier_to}" if identifier_to
123 cmd << " --since=#{shell_quote(options[:since].strftime("%Y-%m-%d %H:%M:%S"))}" if options[:since]
123 cmd << " --since=#{shell_quote(options[:since].strftime("%Y-%m-%d %H:%M:%S"))}" if options[:since]
124 cmd << " -- #{path}" if path && !path.empty?
124 cmd << " -- #{shell_quote path}" if path && !path.empty?
125
125
126 shellout(cmd) do |io|
126 shellout(cmd) do |io|
127 files=[]
127 files=[]
128 changeset = {}
128 changeset = {}
129 parsing_descr = 0 #0: not parsing desc or files, 1: parsing desc, 2: parsing files
129 parsing_descr = 0 #0: not parsing desc or files, 1: parsing desc, 2: parsing files
130 revno = 1
130 revno = 1
131
131
132 io.each_line do |line|
132 io.each_line do |line|
133 if line =~ /^commit ([0-9a-f]{40})$/
133 if line =~ /^commit ([0-9a-f]{40})$/
134 key = "commit"
134 key = "commit"
135 value = $1
135 value = $1
136 if (parsing_descr == 1 || parsing_descr == 2)
136 if (parsing_descr == 1 || parsing_descr == 2)
137 parsing_descr = 0
137 parsing_descr = 0
138 revision = Revision.new({
138 revision = Revision.new({
139 :identifier => changeset[:commit],
139 :identifier => changeset[:commit],
140 :scmid => changeset[:commit],
140 :scmid => changeset[:commit],
141 :author => changeset[:author],
141 :author => changeset[:author],
142 :time => Time.parse(changeset[:date]),
142 :time => Time.parse(changeset[:date]),
143 :message => changeset[:description],
143 :message => changeset[:description],
144 :paths => files
144 :paths => files
145 })
145 })
146 if block_given?
146 if block_given?
147 yield revision
147 yield revision
148 else
148 else
149 revisions << revision
149 revisions << revision
150 end
150 end
151 changeset = {}
151 changeset = {}
152 files = []
152 files = []
153 revno = revno + 1
153 revno = revno + 1
154 end
154 end
155 changeset[:commit] = $1
155 changeset[:commit] = $1
156 elsif (parsing_descr == 0) && line =~ /^(\w+):\s*(.*)$/
156 elsif (parsing_descr == 0) && line =~ /^(\w+):\s*(.*)$/
157 key = $1
157 key = $1
158 value = $2
158 value = $2
159 if key == "Author"
159 if key == "Author"
160 changeset[:author] = value
160 changeset[:author] = value
161 elsif key == "CommitDate"
161 elsif key == "CommitDate"
162 changeset[:date] = value
162 changeset[:date] = value
163 end
163 end
164 elsif (parsing_descr == 0) && line.chomp.to_s == ""
164 elsif (parsing_descr == 0) && line.chomp.to_s == ""
165 parsing_descr = 1
165 parsing_descr = 1
166 changeset[:description] = ""
166 changeset[:description] = ""
167 elsif (parsing_descr == 1 || parsing_descr == 2) \
167 elsif (parsing_descr == 1 || parsing_descr == 2) \
168 && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\s+(.+)$/
168 && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\s+(.+)$/
169 parsing_descr = 2
169 parsing_descr = 2
170 fileaction = $1
170 fileaction = $1
171 filepath = $2
171 filepath = $2
172 files << {:action => fileaction, :path => filepath}
172 files << {:action => fileaction, :path => filepath}
173 elsif (parsing_descr == 1 || parsing_descr == 2) \
173 elsif (parsing_descr == 1 || parsing_descr == 2) \
174 && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\d+\s+(\S+)\s+(.+)$/
174 && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\d+\s+(\S+)\s+(.+)$/
175 parsing_descr = 2
175 parsing_descr = 2
176 fileaction = $1
176 fileaction = $1
177 filepath = $3
177 filepath = $3
178 files << {:action => fileaction, :path => filepath}
178 files << {:action => fileaction, :path => filepath}
179 elsif (parsing_descr == 1) && line.chomp.to_s == ""
179 elsif (parsing_descr == 1) && line.chomp.to_s == ""
180 parsing_descr = 2
180 parsing_descr = 2
181 elsif (parsing_descr == 1)
181 elsif (parsing_descr == 1)
182 changeset[:description] << line[4..-1]
182 changeset[:description] << line[4..-1]
183 end
183 end
184 end
184 end
185
185
186 if changeset[:commit]
186 if changeset[:commit]
187 revision = Revision.new({
187 revision = Revision.new({
188 :identifier => changeset[:commit],
188 :identifier => changeset[:commit],
189 :scmid => changeset[:commit],
189 :scmid => changeset[:commit],
190 :author => changeset[:author],
190 :author => changeset[:author],
191 :time => Time.parse(changeset[:date]),
191 :time => Time.parse(changeset[:date]),
192 :message => changeset[:description],
192 :message => changeset[:description],
193 :paths => files
193 :paths => files
194 })
194 })
195
195
196 if block_given?
196 if block_given?
197 yield revision
197 yield revision
198 else
198 else
199 revisions << revision
199 revisions << revision
200 end
200 end
201 end
201 end
202 end
202 end
203
203
204 return nil if $? && $?.exitstatus != 0
204 return nil if $? && $?.exitstatus != 0
205 revisions
205 revisions
206 end
206 end
207
207
208 def diff(path, identifier_from, identifier_to=nil)
208 def diff(path, identifier_from, identifier_to=nil)
209 path ||= ''
209 path ||= ''
210
210
211 if identifier_to
211 if identifier_to
212 cmd = "#{GIT_BIN} --git-dir #{target('')} diff #{shell_quote identifier_to} #{shell_quote identifier_from}"
212 cmd = "#{GIT_BIN} --git-dir #{target('')} diff #{shell_quote identifier_to} #{shell_quote identifier_from}"
213 else
213 else
214 cmd = "#{GIT_BIN} --git-dir #{target('')} show #{shell_quote identifier_from}"
214 cmd = "#{GIT_BIN} --git-dir #{target('')} show #{shell_quote identifier_from}"
215 end
215 end
216
216
217 cmd << " -- #{shell_quote path}" unless path.empty?
217 cmd << " -- #{shell_quote path}" unless path.empty?
218 diff = []
218 diff = []
219 shellout(cmd) do |io|
219 shellout(cmd) do |io|
220 io.each_line do |line|
220 io.each_line do |line|
221 diff << line
221 diff << line
222 end
222 end
223 end
223 end
224 return nil if $? && $?.exitstatus != 0
224 return nil if $? && $?.exitstatus != 0
225 diff
225 diff
226 end
226 end
227
227
228 def annotate(path, identifier=nil)
228 def annotate(path, identifier=nil)
229 identifier = 'HEAD' if identifier.blank?
229 identifier = 'HEAD' if identifier.blank?
230 cmd = "#{GIT_BIN} --git-dir #{target('')} blame -p #{shell_quote identifier} -- #{shell_quote path}"
230 cmd = "#{GIT_BIN} --git-dir #{target('')} blame -p #{shell_quote identifier} -- #{shell_quote path}"
231 blame = Annotate.new
231 blame = Annotate.new
232 content = nil
232 content = nil
233 shellout(cmd) { |io| io.binmode; content = io.read }
233 shellout(cmd) { |io| io.binmode; content = io.read }
234 return nil if $? && $?.exitstatus != 0
234 return nil if $? && $?.exitstatus != 0
235 # git annotates binary files
235 # git annotates binary files
236 return nil if content.is_binary_data?
236 return nil if content.is_binary_data?
237 identifier = ''
237 identifier = ''
238 # git shows commit author on the first occurrence only
238 # git shows commit author on the first occurrence only
239 authors_by_commit = {}
239 authors_by_commit = {}
240 content.split("\n").each do |line|
240 content.split("\n").each do |line|
241 if line =~ /^([0-9a-f]{39,40})\s.*/
241 if line =~ /^([0-9a-f]{39,40})\s.*/
242 identifier = $1
242 identifier = $1
243 elsif line =~ /^author (.+)/
243 elsif line =~ /^author (.+)/
244 authors_by_commit[identifier] = $1.strip
244 authors_by_commit[identifier] = $1.strip
245 elsif line =~ /^\t(.*)/
245 elsif line =~ /^\t(.*)/
246 blame.add_line($1, Revision.new(:identifier => identifier, :author => authors_by_commit[identifier]))
246 blame.add_line($1, Revision.new(:identifier => identifier, :author => authors_by_commit[identifier]))
247 identifier = ''
247 identifier = ''
248 author = ''
248 author = ''
249 end
249 end
250 end
250 end
251 blame
251 blame
252 end
252 end
253
253
254 def cat(path, identifier=nil)
254 def cat(path, identifier=nil)
255 if identifier.nil?
255 if identifier.nil?
256 identifier = 'HEAD'
256 identifier = 'HEAD'
257 end
257 end
258 cmd = "#{GIT_BIN} --git-dir #{target('')} show #{shell_quote(identifier + ':' + path)}"
258 cmd = "#{GIT_BIN} --git-dir #{target('')} show #{shell_quote(identifier + ':' + path)}"
259 cat = nil
259 cat = nil
260 shellout(cmd) do |io|
260 shellout(cmd) do |io|
261 io.binmode
261 io.binmode
262 cat = io.read
262 cat = io.read
263 end
263 end
264 return nil if $? && $?.exitstatus != 0
264 return nil if $? && $?.exitstatus != 0
265 cat
265 cat
266 end
266 end
267 end
267 end
268 end
268 end
269 end
269 end
270 end
270 end
1 NO CONTENT: modified file, binary diff hidden
NO CONTENT: modified file, binary diff hidden
@@ -1,162 +1,163
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
2 # Copyright (C) 2006-2008 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.dirname(__FILE__) + '/../test_helper'
18 require File.dirname(__FILE__) + '/../test_helper'
19 require 'repositories_controller'
19 require 'repositories_controller'
20
20
21 # Re-raise errors caught by the controller.
21 # Re-raise errors caught by the controller.
22 class RepositoriesController; def rescue_action(e) raise e end; end
22 class RepositoriesController; def rescue_action(e) raise e end; end
23
23
24 class RepositoriesGitControllerTest < ActionController::TestCase
24 class RepositoriesGitControllerTest < ActionController::TestCase
25 fixtures :projects, :users, :roles, :members, :member_roles, :repositories, :enabled_modules
25 fixtures :projects, :users, :roles, :members, :member_roles, :repositories, :enabled_modules
26
26
27 # No '..' in the repository path
27 # No '..' in the repository path
28 REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/git_repository'
28 REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/git_repository'
29 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
29 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
30
30
31 def setup
31 def setup
32 @controller = RepositoriesController.new
32 @controller = RepositoriesController.new
33 @request = ActionController::TestRequest.new
33 @request = ActionController::TestRequest.new
34 @response = ActionController::TestResponse.new
34 @response = ActionController::TestResponse.new
35 User.current = nil
35 User.current = nil
36 Repository::Git.create(:project => Project.find(3), :url => REPOSITORY_PATH)
36 Repository::Git.create(:project => Project.find(3), :url => REPOSITORY_PATH)
37 end
37 end
38
38
39 if File.directory?(REPOSITORY_PATH)
39 if File.directory?(REPOSITORY_PATH)
40 def test_show
40 def test_show
41 get :show, :id => 3
41 get :show, :id => 3
42 assert_response :success
42 assert_response :success
43 assert_template 'show'
43 assert_template 'show'
44 assert_not_nil assigns(:entries)
44 assert_not_nil assigns(:entries)
45 assert_not_nil assigns(:changesets)
45 assert_not_nil assigns(:changesets)
46 end
46 end
47
47
48 def test_browse_root
48 def test_browse_root
49 get :show, :id => 3
49 get :show, :id => 3
50 assert_response :success
50 assert_response :success
51 assert_template 'show'
51 assert_template 'show'
52 assert_not_nil assigns(:entries)
52 assert_not_nil assigns(:entries)
53 assert_equal 7, assigns(:entries).size
53 assert_equal 8, assigns(:entries).size
54 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
54 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
55 assert assigns(:entries).detect {|e| e.name == 'this_is_a_really_long_and_verbose_directory_name' && e.kind == 'dir'}
55 assert assigns(:entries).detect {|e| e.name == 'this_is_a_really_long_and_verbose_directory_name' && e.kind == 'dir'}
56 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
56 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
57 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
57 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
58 assert assigns(:entries).detect {|e| e.name == 'copied_README' && e.kind == 'file'}
58 assert assigns(:entries).detect {|e| e.name == 'copied_README' && e.kind == 'file'}
59 assert assigns(:entries).detect {|e| e.name == 'new_file.txt' && e.kind == 'file'}
59 assert assigns(:entries).detect {|e| e.name == 'new_file.txt' && e.kind == 'file'}
60 assert assigns(:entries).detect {|e| e.name == 'renamed_test.txt' && e.kind == 'file'}
60 assert assigns(:entries).detect {|e| e.name == 'renamed_test.txt' && e.kind == 'file'}
61 assert assigns(:entries).detect {|e| e.name == 'filemane with spaces.txt' && e.kind == 'file'}
61 end
62 end
62
63
63 def test_browse_branch
64 def test_browse_branch
64 get :show, :id => 3, :rev => 'test_branch'
65 get :show, :id => 3, :rev => 'test_branch'
65 assert_response :success
66 assert_response :success
66 assert_template 'show'
67 assert_template 'show'
67 assert_not_nil assigns(:entries)
68 assert_not_nil assigns(:entries)
68 assert_equal 4, assigns(:entries).size
69 assert_equal 4, assigns(:entries).size
69 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
70 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
70 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
71 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
71 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
72 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
72 assert assigns(:entries).detect {|e| e.name == 'test.txt' && e.kind == 'file'}
73 assert assigns(:entries).detect {|e| e.name == 'test.txt' && e.kind == 'file'}
73 end
74 end
74
75
75 def test_browse_directory
76 def test_browse_directory
76 get :show, :id => 3, :path => ['images']
77 get :show, :id => 3, :path => ['images']
77 assert_response :success
78 assert_response :success
78 assert_template 'show'
79 assert_template 'show'
79 assert_not_nil assigns(:entries)
80 assert_not_nil assigns(:entries)
80 assert_equal ['edit.png'], assigns(:entries).collect(&:name)
81 assert_equal ['edit.png'], assigns(:entries).collect(&:name)
81 entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
82 entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
82 assert_not_nil entry
83 assert_not_nil entry
83 assert_equal 'file', entry.kind
84 assert_equal 'file', entry.kind
84 assert_equal 'images/edit.png', entry.path
85 assert_equal 'images/edit.png', entry.path
85 end
86 end
86
87
87 def test_browse_at_given_revision
88 def test_browse_at_given_revision
88 get :show, :id => 3, :path => ['images'], :rev => '7234cb2750b63f47bff735edc50a1c0a433c2518'
89 get :show, :id => 3, :path => ['images'], :rev => '7234cb2750b63f47bff735edc50a1c0a433c2518'
89 assert_response :success
90 assert_response :success
90 assert_template 'show'
91 assert_template 'show'
91 assert_not_nil assigns(:entries)
92 assert_not_nil assigns(:entries)
92 assert_equal ['delete.png'], assigns(:entries).collect(&:name)
93 assert_equal ['delete.png'], assigns(:entries).collect(&:name)
93 end
94 end
94
95
95 def test_changes
96 def test_changes
96 get :changes, :id => 3, :path => ['images', 'edit.png']
97 get :changes, :id => 3, :path => ['images', 'edit.png']
97 assert_response :success
98 assert_response :success
98 assert_template 'changes'
99 assert_template 'changes'
99 assert_tag :tag => 'h2', :content => 'edit.png'
100 assert_tag :tag => 'h2', :content => 'edit.png'
100 end
101 end
101
102
102 def test_entry_show
103 def test_entry_show
103 get :entry, :id => 3, :path => ['sources', 'watchers_controller.rb']
104 get :entry, :id => 3, :path => ['sources', 'watchers_controller.rb']
104 assert_response :success
105 assert_response :success
105 assert_template 'entry'
106 assert_template 'entry'
106 # Line 19
107 # Line 19
107 assert_tag :tag => 'th',
108 assert_tag :tag => 'th',
108 :content => /11/,
109 :content => /11/,
109 :attributes => { :class => /line-num/ },
110 :attributes => { :class => /line-num/ },
110 :sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ }
111 :sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ }
111 end
112 end
112
113
113 def test_entry_download
114 def test_entry_download
114 get :entry, :id => 3, :path => ['sources', 'watchers_controller.rb'], :format => 'raw'
115 get :entry, :id => 3, :path => ['sources', 'watchers_controller.rb'], :format => 'raw'
115 assert_response :success
116 assert_response :success
116 # File content
117 # File content
117 assert @response.body.include?('WITHOUT ANY WARRANTY')
118 assert @response.body.include?('WITHOUT ANY WARRANTY')
118 end
119 end
119
120
120 def test_directory_entry
121 def test_directory_entry
121 get :entry, :id => 3, :path => ['sources']
122 get :entry, :id => 3, :path => ['sources']
122 assert_response :success
123 assert_response :success
123 assert_template 'show'
124 assert_template 'show'
124 assert_not_nil assigns(:entry)
125 assert_not_nil assigns(:entry)
125 assert_equal 'sources', assigns(:entry).name
126 assert_equal 'sources', assigns(:entry).name
126 end
127 end
127
128
128 def test_diff
129 def test_diff
129 # Full diff of changeset 2f9c0091
130 # Full diff of changeset 2f9c0091
130 get :diff, :id => 3, :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
131 get :diff, :id => 3, :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
131 assert_response :success
132 assert_response :success
132 assert_template 'diff'
133 assert_template 'diff'
133 # Line 22 removed
134 # Line 22 removed
134 assert_tag :tag => 'th',
135 assert_tag :tag => 'th',
135 :content => /22/,
136 :content => /22/,
136 :sibling => { :tag => 'td',
137 :sibling => { :tag => 'td',
137 :attributes => { :class => /diff_out/ },
138 :attributes => { :class => /diff_out/ },
138 :content => /def remove/ }
139 :content => /def remove/ }
139 end
140 end
140
141
141 def test_annotate
142 def test_annotate
142 get :annotate, :id => 3, :path => ['sources', 'watchers_controller.rb']
143 get :annotate, :id => 3, :path => ['sources', 'watchers_controller.rb']
143 assert_response :success
144 assert_response :success
144 assert_template 'annotate'
145 assert_template 'annotate'
145 # Line 23, changeset 2f9c0091
146 # Line 23, changeset 2f9c0091
146 assert_tag :tag => 'th', :content => /24/,
147 assert_tag :tag => 'th', :content => /24/,
147 :sibling => { :tag => 'td', :child => { :tag => 'a', :content => /2f9c0091/ } },
148 :sibling => { :tag => 'td', :child => { :tag => 'a', :content => /2f9c0091/ } },
148 :sibling => { :tag => 'td', :content => /jsmith/ },
149 :sibling => { :tag => 'td', :content => /jsmith/ },
149 :sibling => { :tag => 'td', :content => /watcher =/ }
150 :sibling => { :tag => 'td', :content => /watcher =/ }
150 end
151 end
151
152
152 def test_annotate_binary_file
153 def test_annotate_binary_file
153 get :annotate, :id => 3, :path => ['images', 'edit.png']
154 get :annotate, :id => 3, :path => ['images', 'edit.png']
154 assert_response 500
155 assert_response 500
155 assert_tag :tag => 'div', :attributes => { :class => /error/ },
156 assert_tag :tag => 'div', :attributes => { :class => /error/ },
156 :content => /can not be annotated/
157 :content => /can not be annotated/
157 end
158 end
158 else
159 else
159 puts "Git test repository NOT FOUND. Skipping functional tests !!!"
160 puts "Git test repository NOT FOUND. Skipping functional tests !!!"
160 def test_fake; assert true end
161 def test_fake; assert true end
161 end
162 end
162 end
163 end
@@ -1,49 +1,61
1 require File.dirname(__FILE__) + '/../../../../../test_helper'
1 require File.dirname(__FILE__) + '/../../../../../test_helper'
2
2
3 class GitAdapterTest < ActiveSupport::TestCase
3 class GitAdapterTest < ActiveSupport::TestCase
4 REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/git_repository'
4 REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/git_repository'
5
5
6 if File.directory?(REPOSITORY_PATH)
6 if File.directory?(REPOSITORY_PATH)
7 def setup
7 def setup
8 @adapter = Redmine::Scm::Adapters::GitAdapter.new(REPOSITORY_PATH)
8 @adapter = Redmine::Scm::Adapters::GitAdapter.new(REPOSITORY_PATH)
9 end
9 end
10
10
11 def test_branches
11 def test_branches
12 assert_equal @adapter.branches, ['master', 'test_branch']
12 assert_equal @adapter.branches, ['master', 'test_branch']
13 end
13 end
14
14
15 def test_getting_all_revisions
15 def test_getting_all_revisions
16 assert_equal 13, @adapter.revisions('',nil,nil,:all => true).length
16 assert_equal 14, @adapter.revisions('',nil,nil,:all => true).length
17 end
17 end
18
18
19 def test_getting_certain_revisions
19 def test_getting_certain_revisions
20 assert_equal 1, @adapter.revisions('','899a15d^','899a15d').length
20 assert_equal 1, @adapter.revisions('','899a15d^','899a15d').length
21 end
21 end
22
22
23 def test_getting_revisions_with_spaces_in_filename
24 assert_equal 1, @adapter.revisions("filemane with spaces.txt", nil, nil, :all => true).length
25 end
26
23 def test_annotate
27 def test_annotate
24 annotate = @adapter.annotate('sources/watchers_controller.rb')
28 annotate = @adapter.annotate('sources/watchers_controller.rb')
25 assert_kind_of Redmine::Scm::Adapters::Annotate, annotate
29 assert_kind_of Redmine::Scm::Adapters::Annotate, annotate
26 assert_equal 41, annotate.lines.size
30 assert_equal 41, annotate.lines.size
27 assert_equal "# This program is free software; you can redistribute it and/or", annotate.lines[4].strip
31 assert_equal "# This program is free software; you can redistribute it and/or", annotate.lines[4].strip
28 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", annotate.revisions[4].identifier
32 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", annotate.revisions[4].identifier
29 assert_equal "jsmith", annotate.revisions[4].author
33 assert_equal "jsmith", annotate.revisions[4].author
30 end
34 end
31
35
36 def test_annotate_moved_file
37 annotate = @adapter.annotate('renamed_test.txt')
38 assert_kind_of Redmine::Scm::Adapters::Annotate, annotate
39 assert_equal 2, annotate.lines.size
40 end
41
32 def test_last_rev
42 def test_last_rev
33 last_rev = @adapter.lastrev("README", "4f26664364207fa8b1af9f8722647ab2d4ac5d43")
43 last_rev = @adapter.lastrev("README", "4f26664364207fa8b1af9f8722647ab2d4ac5d43")
34 assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", last_rev.scmid
44 assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", last_rev.scmid
35 assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", last_rev.identifier
45 assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", last_rev.identifier
36 assert_equal "Adam Soltys <asoltys@gmail.com>", last_rev.author
46 assert_equal "Adam Soltys <asoltys@gmail.com>", last_rev.author
37 assert_equal "2009-06-24 05:27:38".to_time, last_rev.time
47 assert_equal "2009-06-24 05:27:38".to_time, last_rev.time
38 end
48 end
39
49
40 def test_annotate_moved_file
50 def test_last_rev_with_spaces_in_filename
41 annotate = @adapter.annotate('renamed_test.txt')
51 last_rev = @adapter.lastrev("filemane with spaces.txt", "ed5bb786bbda2dee66a2d50faf51429dbc043a7b")
42 assert_kind_of Redmine::Scm::Adapters::Annotate, annotate
52 assert_equal "ed5bb786bbda2dee66a2d50faf51429dbc043a7b", last_rev.scmid
43 assert_equal 2, annotate.lines.size
53 assert_equal "ed5bb786bbda2dee66a2d50faf51429dbc043a7b", last_rev.identifier
54 assert_equal "Felix Schäfer <felix@fachschaften.org>", last_rev.author
55 assert_equal "2010-09-18 19:59:46".to_time, last_rev.time
44 end
56 end
45 else
57 else
46 puts "Git test repository NOT FOUND. Skipping unit tests !!!"
58 puts "Git test repository NOT FOUND. Skipping unit tests !!!"
47 def test_fake; assert true end
59 def test_fake; assert true end
48 end
60 end
49 end
61 end
@@ -1,69 +1,69
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 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.dirname(__FILE__) + '/../test_helper'
18 require File.dirname(__FILE__) + '/../test_helper'
19
19
20 class RepositoryGitTest < ActiveSupport::TestCase
20 class RepositoryGitTest < ActiveSupport::TestCase
21 fixtures :projects
21 fixtures :projects
22
22
23 # No '..' in the repository path
23 # No '..' in the repository path
24 REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/git_repository'
24 REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/git_repository'
25 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
25 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
26
26
27 def setup
27 def setup
28 @project = Project.find(1)
28 @project = Project.find(1)
29 assert @repository = Repository::Git.create(:project => @project, :url => REPOSITORY_PATH)
29 assert @repository = Repository::Git.create(:project => @project, :url => REPOSITORY_PATH)
30 end
30 end
31
31
32 if File.directory?(REPOSITORY_PATH)
32 if File.directory?(REPOSITORY_PATH)
33 def test_fetch_changesets_from_scratch
33 def test_fetch_changesets_from_scratch
34 @repository.fetch_changesets
34 @repository.fetch_changesets
35 @repository.reload
35 @repository.reload
36
36
37 assert_equal 13, @repository.changesets.count
37 assert_equal 14, @repository.changesets.count
38 assert_equal 22, @repository.changes.count
38 assert_equal 23, @repository.changes.count
39
39
40 commit = @repository.changesets.find(:first, :order => 'committed_on ASC')
40 commit = @repository.changesets.find(:first, :order => 'committed_on ASC')
41 assert_equal "Initial import.\nThe repository contains 3 files.", commit.comments
41 assert_equal "Initial import.\nThe repository contains 3 files.", commit.comments
42 assert_equal "jsmith <jsmith@foo.bar>", commit.committer
42 assert_equal "jsmith <jsmith@foo.bar>", commit.committer
43 assert_equal User.find_by_login('jsmith'), commit.user
43 assert_equal User.find_by_login('jsmith'), commit.user
44 # TODO: add a commit with commit time <> author time to the test repository
44 # TODO: add a commit with commit time <> author time to the test repository
45 assert_equal "2007-12-14 09:22:52".to_time, commit.committed_on
45 assert_equal "2007-12-14 09:22:52".to_time, commit.committed_on
46 assert_equal "2007-12-14".to_date, commit.commit_date
46 assert_equal "2007-12-14".to_date, commit.commit_date
47 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", commit.revision
47 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", commit.revision
48 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", commit.scmid
48 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", commit.scmid
49 assert_equal 3, commit.changes.count
49 assert_equal 3, commit.changes.count
50 change = commit.changes.sort_by(&:path).first
50 change = commit.changes.sort_by(&:path).first
51 assert_equal "README", change.path
51 assert_equal "README", change.path
52 assert_equal "A", change.action
52 assert_equal "A", change.action
53 end
53 end
54
54
55 def test_fetch_changesets_incremental
55 def test_fetch_changesets_incremental
56 @repository.fetch_changesets
56 @repository.fetch_changesets
57 # Remove the 3 latest changesets
57 # Remove the 3 latest changesets
58 @repository.changesets.find(:all, :order => 'committed_on DESC', :limit => 3).each(&:destroy)
58 @repository.changesets.find(:all, :order => 'committed_on DESC', :limit => 3).each(&:destroy)
59 @repository.reload
59 @repository.reload
60 assert_equal 10, @repository.changesets.count
60 assert_equal 11, @repository.changesets.count
61
61
62 @repository.fetch_changesets
62 @repository.fetch_changesets
63 assert_equal 13, @repository.changesets.count
63 assert_equal 14, @repository.changesets.count
64 end
64 end
65 else
65 else
66 puts "Git test repository NOT FOUND. Skipping unit tests !!!"
66 puts "Git test repository NOT FOUND. Skipping unit tests !!!"
67 def test_fake; assert true end
67 def test_fake; assert true end
68 end
68 end
69 end
69 end
General Comments 0
You need to be logged in to leave comments. Login now