##// END OF EJS Templates
scm: mercurial: use long id in adapter level (#14361)...
Toshi MARUYAMA -
r12486:5872d079e632
parent child
Show More
@@ -1,12 +1,12
1 1 changeset = 'This template must be used with --debug option\n'
2 2 changeset_quiet = 'This template must be used with --debug option\n'
3 3 changeset_verbose = 'This template must be used with --debug option\n'
4 changeset_debug = '<logentry revision="{rev}" node="{node|short}">\n<author>{author|escape}</author>\n<date>{date|isodatesec}</date>\n<paths>\n{file_mods}{file_adds}{file_dels}{file_copies}</paths>\n<msg>{desc|escape}</msg>\n<parents>\n{parents}</parents>\n</logentry>\n\n'
4 changeset_debug = '<logentry revision="{rev}" node="{node}">\n<author>{author|escape}</author>\n<date>{date|isodatesec}</date>\n<paths>\n{file_mods}{file_adds}{file_dels}{file_copies}</paths>\n<msg>{desc|escape}</msg>\n<parents>\n{parents}</parents>\n</logentry>\n\n'
5 5
6 6 file_mod = '<path action="M">{file_mod|urlescape}</path>\n'
7 7 file_add = '<path action="A">{file_add|urlescape}</path>\n'
8 8 file_del = '<path action="D">{file_del|urlescape}</path>\n'
9 9 file_copy = '<path-copied copyfrom-path="{source|urlescape}">{name|urlescape}</path-copied>\n'
10 parent = '<parent>{node|short}</parent>\n'
10 parent = '<parent>{node}</parent>\n'
11 11 header='<?xml version="1.0" encoding="UTF-8" ?>\n<log>\n\n'
12 12 # footer="</log>"
@@ -1,220 +1,220
1 1 # redminehelper: Redmine helper extension for Mercurial
2 2 #
3 3 # Copyright 2010 Alessio Franceschelli (alefranz.net)
4 4 # Copyright 2010-2011 Yuya Nishihara <yuya@tcha.org>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8 """helper commands for Redmine to reduce the number of hg calls
9 9
10 10 To test this extension, please try::
11 11
12 12 $ hg --config extensions.redminehelper=redminehelper.py rhsummary
13 13
14 14 I/O encoding:
15 15
16 16 :file path: urlencoded, raw string
17 17 :tag name: utf-8
18 18 :branch name: utf-8
19 :node: 12-digits (short) hex string
19 :node: hex string
20 20
21 21 Output example of rhsummary::
22 22
23 23 <?xml version="1.0"?>
24 24 <rhsummary>
25 25 <repository root="/foo/bar">
26 26 <tip revision="1234" node="abcdef0123..."/>
27 27 <tag revision="123" node="34567abc..." name="1.1.1"/>
28 28 <branch .../>
29 29 ...
30 30 </repository>
31 31 </rhsummary>
32 32
33 33 Output example of rhmanifest::
34 34
35 35 <?xml version="1.0"?>
36 36 <rhmanifest>
37 37 <repository root="/foo/bar">
38 38 <manifest revision="1234" path="lib">
39 39 <file name="diff.rb" revision="123" node="34567abc..." time="12345"
40 40 size="100"/>
41 41 ...
42 42 <dir name="redmine"/>
43 43 ...
44 44 </manifest>
45 45 </repository>
46 46 </rhmanifest>
47 47 """
48 48 import re, time, cgi, urllib
49 49 from mercurial import cmdutil, commands, node, error, hg
50 50
51 51 _x = cgi.escape
52 52 _u = lambda s: cgi.escape(urllib.quote(s))
53 53
54 54 def _tip(ui, repo):
55 55 # see mercurial/commands.py:tip
56 56 def tiprev():
57 57 try:
58 58 return len(repo) - 1
59 59 except TypeError: # Mercurial < 1.1
60 60 return repo.changelog.count() - 1
61 61 tipctx = repo.changectx(tiprev())
62 62 ui.write('<tip revision="%d" node="%s"/>\n'
63 % (tipctx.rev(), _x(node.short(tipctx.node()))))
63 % (tipctx.rev(), _x(node.hex(tipctx.node()))))
64 64
65 65 _SPECIAL_TAGS = ('tip',)
66 66
67 67 def _tags(ui, repo):
68 68 # see mercurial/commands.py:tags
69 69 for t, n in reversed(repo.tagslist()):
70 70 if t in _SPECIAL_TAGS:
71 71 continue
72 72 try:
73 73 r = repo.changelog.rev(n)
74 74 except error.LookupError:
75 75 continue
76 76 ui.write('<tag revision="%d" node="%s" name="%s"/>\n'
77 % (r, _x(node.short(n)), _x(t)))
77 % (r, _x(node.hex(n)), _x(t)))
78 78
79 79 def _branches(ui, repo):
80 80 # see mercurial/commands.py:branches
81 81 def iterbranches():
82 82 for t, n in repo.branchtags().iteritems():
83 83 yield t, n, repo.changelog.rev(n)
84 84 def branchheads(branch):
85 85 try:
86 86 return repo.branchheads(branch, closed=False)
87 87 except TypeError: # Mercurial < 1.2
88 88 return repo.branchheads(branch)
89 89 for t, n, r in sorted(iterbranches(), key=lambda e: e[2], reverse=True):
90 90 if repo.lookup(r) in branchheads(t):
91 91 ui.write('<branch revision="%d" node="%s" name="%s"/>\n'
92 % (r, _x(node.short(n)), _x(t)))
92 % (r, _x(node.hex(n)), _x(t)))
93 93
94 94 def _manifest(ui, repo, path, rev):
95 95 ctx = repo.changectx(rev)
96 96 ui.write('<manifest revision="%d" path="%s">\n'
97 97 % (ctx.rev(), _u(path)))
98 98
99 99 known = set()
100 100 pathprefix = (path.rstrip('/') + '/').lstrip('/')
101 101 for f, n in sorted(ctx.manifest().iteritems(), key=lambda e: e[0]):
102 102 if not f.startswith(pathprefix):
103 103 continue
104 104 name = re.sub(r'/.*', '/', f[len(pathprefix):])
105 105 if name in known:
106 106 continue
107 107 known.add(name)
108 108
109 109 if name.endswith('/'):
110 110 ui.write('<dir name="%s"/>\n'
111 111 % _x(urllib.quote(name[:-1])))
112 112 else:
113 113 fctx = repo.filectx(f, fileid=n)
114 114 tm, tzoffset = fctx.date()
115 115 ui.write('<file name="%s" revision="%d" node="%s" '
116 116 'time="%d" size="%d"/>\n'
117 % (_u(name), fctx.rev(), _x(node.short(fctx.node())),
117 % (_u(name), fctx.rev(), _x(node.hex(fctx.node())),
118 118 tm, fctx.size(), ))
119 119
120 120 ui.write('</manifest>\n')
121 121
122 122 def rhannotate(ui, repo, *pats, **opts):
123 123 rev = urllib.unquote_plus(opts.pop('rev', None))
124 124 opts['rev'] = rev
125 125 return commands.annotate(ui, repo, *map(urllib.unquote_plus, pats), **opts)
126 126
127 127 def rhcat(ui, repo, file1, *pats, **opts):
128 128 rev = urllib.unquote_plus(opts.pop('rev', None))
129 129 opts['rev'] = rev
130 130 return commands.cat(ui, repo, urllib.unquote_plus(file1), *map(urllib.unquote_plus, pats), **opts)
131 131
132 132 def rhdiff(ui, repo, *pats, **opts):
133 133 """diff repository (or selected files)"""
134 134 change = opts.pop('change', None)
135 135 if change: # add -c option for Mercurial<1.1
136 136 base = repo.changectx(change).parents()[0].rev()
137 137 opts['rev'] = [str(base), change]
138 138 opts['nodates'] = True
139 139 return commands.diff(ui, repo, *map(urllib.unquote_plus, pats), **opts)
140 140
141 141 def rhlog(ui, repo, *pats, **opts):
142 142 rev = opts.pop('rev')
143 143 bra0 = opts.pop('branch')
144 144 from_rev = urllib.unquote_plus(opts.pop('from', None))
145 145 to_rev = urllib.unquote_plus(opts.pop('to' , None))
146 146 bra = urllib.unquote_plus(opts.pop('rhbranch', None))
147 147 from_rev = from_rev.replace('"', '\\"')
148 148 to_rev = to_rev.replace('"', '\\"')
149 149 if hg.util.version() >= '1.6':
150 150 opts['rev'] = ['"%s":"%s"' % (from_rev, to_rev)]
151 151 else:
152 152 opts['rev'] = ['%s:%s' % (from_rev, to_rev)]
153 153 opts['branch'] = [bra]
154 154 return commands.log(ui, repo, *map(urllib.unquote_plus, pats), **opts)
155 155
156 156 def rhmanifest(ui, repo, path='', **opts):
157 157 """output the sub-manifest of the specified directory"""
158 158 ui.write('<?xml version="1.0"?>\n')
159 159 ui.write('<rhmanifest>\n')
160 160 ui.write('<repository root="%s">\n' % _u(repo.root))
161 161 try:
162 162 _manifest(ui, repo, urllib.unquote_plus(path), urllib.unquote_plus(opts.get('rev')))
163 163 finally:
164 164 ui.write('</repository>\n')
165 165 ui.write('</rhmanifest>\n')
166 166
167 167 def rhsummary(ui, repo, **opts):
168 168 """output the summary of the repository"""
169 169 ui.write('<?xml version="1.0"?>\n')
170 170 ui.write('<rhsummary>\n')
171 171 ui.write('<repository root="%s">\n' % _u(repo.root))
172 172 try:
173 173 _tip(ui, repo)
174 174 _tags(ui, repo)
175 175 _branches(ui, repo)
176 176 # TODO: bookmarks in core (Mercurial>=1.8)
177 177 finally:
178 178 ui.write('</repository>\n')
179 179 ui.write('</rhsummary>\n')
180 180
181 181 cmdtable = {
182 182 'rhannotate': (rhannotate,
183 183 [('r', 'rev', '', 'revision'),
184 184 ('u', 'user', None, 'list the author (long with -v)'),
185 185 ('n', 'number', None, 'list the revision number (default)'),
186 186 ('c', 'changeset', None, 'list the changeset'),
187 187 ],
188 188 'hg rhannotate [-r REV] [-u] [-n] [-c] FILE...'),
189 189 'rhcat': (rhcat,
190 190 [('r', 'rev', '', 'revision')],
191 191 'hg rhcat ([-r REV] ...) FILE...'),
192 192 'rhdiff': (rhdiff,
193 193 [('r', 'rev', [], 'revision'),
194 194 ('c', 'change', '', 'change made by revision')],
195 195 'hg rhdiff ([-c REV] | [-r REV] ...) [FILE]...'),
196 196 'rhlog': (rhlog,
197 197 [
198 198 ('r', 'rev', [], 'show the specified revision'),
199 199 ('b', 'branch', [],
200 200 'show changesets within the given named branch'),
201 201 ('l', 'limit', '',
202 202 'limit number of changes displayed'),
203 203 ('d', 'date', '',
204 204 'show revisions matching date spec'),
205 205 ('u', 'user', [],
206 206 'revisions committed by user'),
207 207 ('', 'from', '',
208 208 ''),
209 209 ('', 'to', '',
210 210 ''),
211 211 ('', 'rhbranch', '',
212 212 ''),
213 213 ('', 'template', '',
214 214 'display with template')],
215 215 'hg rhlog [OPTION]... [FILE]'),
216 216 'rhmanifest': (rhmanifest,
217 217 [('r', 'rev', '', 'show the specified revision')],
218 218 'hg rhmanifest [-r REV] [PATH]'),
219 219 'rhsummary': (rhsummary, [], 'hg rhsummary'),
220 220 }
@@ -1,341 +1,341
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2014 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 require 'cgi'
20 20
21 21 module Redmine
22 22 module Scm
23 23 module Adapters
24 24 class MercurialAdapter < AbstractAdapter
25 25
26 26 # Mercurial executable name
27 27 HG_BIN = Redmine::Configuration['scm_mercurial_command'] || "hg"
28 28 HELPERS_DIR = File.dirname(__FILE__) + "/mercurial"
29 29 HG_HELPER_EXT = "#{HELPERS_DIR}/redminehelper.py"
30 30 TEMPLATE_NAME = "hg-template"
31 31 TEMPLATE_EXTENSION = "tmpl"
32 32
33 33 # raised if hg command exited with error, e.g. unknown revision.
34 34 class HgCommandAborted < CommandFailed; end
35 35
36 36 class << self
37 37 def client_command
38 38 @@bin ||= HG_BIN
39 39 end
40 40
41 41 def sq_bin
42 42 @@sq_bin ||= shell_quote_command
43 43 end
44 44
45 45 def client_version
46 46 @@client_version ||= (hgversion || [])
47 47 end
48 48
49 49 def client_available
50 50 client_version_above?([1, 2])
51 51 end
52 52
53 53 def hgversion
54 54 # The hg version is expressed either as a
55 55 # release number (eg 0.9.5 or 1.0) or as a revision
56 56 # id composed of 12 hexa characters.
57 57 theversion = hgversion_from_command_line.dup
58 58 if theversion.respond_to?(:force_encoding)
59 59 theversion.force_encoding('ASCII-8BIT')
60 60 end
61 61 if m = theversion.match(%r{\A(.*?)((\d+\.)+\d+)})
62 62 m[2].scan(%r{\d+}).collect(&:to_i)
63 63 end
64 64 end
65 65
66 66 def hgversion_from_command_line
67 67 shellout("#{sq_bin} --version") { |io| io.read }.to_s
68 68 end
69 69
70 70 def template_path
71 71 @@template_path ||= template_path_for(client_version)
72 72 end
73 73
74 74 def template_path_for(version)
75 75 "#{HELPERS_DIR}/#{TEMPLATE_NAME}-1.0.#{TEMPLATE_EXTENSION}"
76 76 end
77 77 end
78 78
79 79 def initialize(url, root_url=nil, login=nil, password=nil, path_encoding=nil)
80 80 super
81 81 @path_encoding = path_encoding.blank? ? 'UTF-8' : path_encoding
82 82 end
83 83
84 84 def path_encoding
85 85 @path_encoding
86 86 end
87 87
88 88 def info
89 89 tip = summary['repository']['tip']
90 90 Info.new(:root_url => CGI.unescape(summary['repository']['root']),
91 91 :lastrev => Revision.new(:revision => tip['revision'],
92 92 :scmid => tip['node']))
93 93 # rescue HgCommandAborted
94 94 rescue Exception => e
95 95 logger.error "hg: error during getting info: #{e.message}"
96 96 nil
97 97 end
98 98
99 99 def tags
100 100 as_ary(summary['repository']['tag']).map { |e| e['name'] }
101 101 end
102 102
103 103 # Returns map of {'tag' => 'nodeid', ...}
104 104 def tagmap
105 105 alist = as_ary(summary['repository']['tag']).map do |e|
106 106 e.values_at('name', 'node')
107 107 end
108 108 Hash[*alist.flatten]
109 109 end
110 110
111 111 def branches
112 112 brs = []
113 113 as_ary(summary['repository']['branch']).each do |e|
114 114 br = Branch.new(e['name'])
115 115 br.revision = e['revision']
116 116 br.scmid = e['node']
117 117 brs << br
118 118 end
119 119 brs
120 120 end
121 121
122 122 # Returns map of {'branch' => 'nodeid', ...}
123 123 def branchmap
124 124 alist = as_ary(summary['repository']['branch']).map do |e|
125 125 e.values_at('name', 'node')
126 126 end
127 127 Hash[*alist.flatten]
128 128 end
129 129
130 130 def summary
131 131 return @summary if @summary
132 132 hg 'rhsummary' do |io|
133 133 output = io.read
134 134 if output.respond_to?(:force_encoding)
135 135 output.force_encoding('UTF-8')
136 136 end
137 137 begin
138 138 @summary = parse_xml(output)['rhsummary']
139 139 rescue
140 140 end
141 141 end
142 142 end
143 143 private :summary
144 144
145 145 def entries(path=nil, identifier=nil, options={})
146 146 p1 = scm_iconv(@path_encoding, 'UTF-8', path)
147 147 manifest = hg('rhmanifest', '-r', CGI.escape(hgrev(identifier)),
148 148 CGI.escape(without_leading_slash(p1.to_s))) do |io|
149 149 output = io.read
150 150 if output.respond_to?(:force_encoding)
151 151 output.force_encoding('UTF-8')
152 152 end
153 153 begin
154 154 parse_xml(output)['rhmanifest']['repository']['manifest']
155 155 rescue
156 156 end
157 157 end
158 158 path_prefix = path.blank? ? '' : with_trailling_slash(path)
159 159
160 160 entries = Entries.new
161 161 as_ary(manifest['dir']).each do |e|
162 162 n = scm_iconv('UTF-8', @path_encoding, CGI.unescape(e['name']))
163 163 p = "#{path_prefix}#{n}"
164 164 entries << Entry.new(:name => n, :path => p, :kind => 'dir')
165 165 end
166 166
167 167 as_ary(manifest['file']).each do |e|
168 168 n = scm_iconv('UTF-8', @path_encoding, CGI.unescape(e['name']))
169 169 p = "#{path_prefix}#{n}"
170 170 lr = Revision.new(:revision => e['revision'], :scmid => e['node'],
171 171 :identifier => e['node'],
172 172 :time => Time.at(e['time'].to_i))
173 173 entries << Entry.new(:name => n, :path => p, :kind => 'file',
174 174 :size => e['size'].to_i, :lastrev => lr)
175 175 end
176 176
177 177 entries
178 178 rescue HgCommandAborted
179 179 nil # means not found
180 180 end
181 181
182 182 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
183 183 revs = Revisions.new
184 184 each_revision(path, identifier_from, identifier_to, options) { |e| revs << e }
185 185 revs
186 186 end
187 187
188 188 # Iterates the revisions by using a template file that
189 189 # makes Mercurial produce a xml output.
190 190 def each_revision(path=nil, identifier_from=nil, identifier_to=nil, options={})
191 191 hg_args = ['log', '--debug', '-C', '--style', self.class.template_path]
192 192 hg_args << '-r' << "#{hgrev(identifier_from)}:#{hgrev(identifier_to)}"
193 193 hg_args << '--limit' << options[:limit] if options[:limit]
194 194 hg_args << hgtarget(path) unless path.blank?
195 195 log = hg(*hg_args) do |io|
196 196 output = io.read
197 197 if output.respond_to?(:force_encoding)
198 198 output.force_encoding('UTF-8')
199 199 end
200 200 begin
201 201 # Mercurial < 1.5 does not support footer template for '</log>'
202 202 parse_xml("#{output}</log>")['log']
203 203 rescue
204 204 end
205 205 end
206 206 as_ary(log['logentry']).each do |le|
207 207 cpalist = as_ary(le['paths']['path-copied']).map do |e|
208 208 [e['__content__'], e['copyfrom-path']].map do |s|
209 209 scm_iconv('UTF-8', @path_encoding, CGI.unescape(s))
210 210 end
211 211 end
212 212 cpmap = Hash[*cpalist.flatten]
213 213 paths = as_ary(le['paths']['path']).map do |e|
214 214 p = scm_iconv('UTF-8', @path_encoding, CGI.unescape(e['__content__']) )
215 215 {:action => e['action'],
216 216 :path => with_leading_slash(p),
217 217 :from_path => (cpmap.member?(p) ? with_leading_slash(cpmap[p]) : nil),
218 218 :from_revision => (cpmap.member?(p) ? le['node'] : nil)}
219 219 end.sort { |a, b| a[:path] <=> b[:path] }
220 220 parents_ary = []
221 221 as_ary(le['parents']['parent']).map do |par|
222 parents_ary << par['__content__'] if par['__content__'] != "000000000000"
222 parents_ary << par['__content__'] if par['__content__'] != "0000000000000000000000000000000000000000"
223 223 end
224 224 yield Revision.new(:revision => le['revision'],
225 225 :scmid => le['node'],
226 226 :author => (le['author']['__content__'] rescue ''),
227 227 :time => Time.parse(le['date']['__content__']),
228 228 :message => le['msg']['__content__'],
229 229 :paths => paths,
230 230 :parents => parents_ary)
231 231 end
232 232 self
233 233 end
234 234
235 235 # Returns list of nodes in the specified branch
236 236 def nodes_in_branch(branch, options={})
237 hg_args = ['rhlog', '--template', '{node|short}\n', '--rhbranch', CGI.escape(branch)]
237 hg_args = ['rhlog', '--template', '{node}\n', '--rhbranch', CGI.escape(branch)]
238 238 hg_args << '--from' << CGI.escape(branch)
239 239 hg_args << '--to' << '0'
240 240 hg_args << '--limit' << options[:limit] if options[:limit]
241 241 hg(*hg_args) { |io| io.readlines.map { |e| e.chomp } }
242 242 end
243 243
244 244 def diff(path, identifier_from, identifier_to=nil)
245 245 hg_args = %w|rhdiff|
246 246 if identifier_to
247 247 hg_args << '-r' << hgrev(identifier_to) << '-r' << hgrev(identifier_from)
248 248 else
249 249 hg_args << '-c' << hgrev(identifier_from)
250 250 end
251 251 unless path.blank?
252 252 p = scm_iconv(@path_encoding, 'UTF-8', path)
253 253 hg_args << CGI.escape(hgtarget(p))
254 254 end
255 255 diff = []
256 256 hg *hg_args do |io|
257 257 io.each_line do |line|
258 258 diff << line
259 259 end
260 260 end
261 261 diff
262 262 rescue HgCommandAborted
263 263 nil # means not found
264 264 end
265 265
266 266 def cat(path, identifier=nil)
267 267 p = CGI.escape(scm_iconv(@path_encoding, 'UTF-8', path))
268 268 hg 'rhcat', '-r', CGI.escape(hgrev(identifier)), hgtarget(p) do |io|
269 269 io.binmode
270 270 io.read
271 271 end
272 272 rescue HgCommandAborted
273 273 nil # means not found
274 274 end
275 275
276 276 def annotate(path, identifier=nil)
277 277 p = CGI.escape(scm_iconv(@path_encoding, 'UTF-8', path))
278 278 blame = Annotate.new
279 279 hg 'rhannotate', '-ncu', '-r', CGI.escape(hgrev(identifier)), hgtarget(p) do |io|
280 280 io.each_line do |line|
281 281 line.force_encoding('ASCII-8BIT') if line.respond_to?(:force_encoding)
282 282 next unless line =~ %r{^([^:]+)\s(\d+)\s([0-9a-f]+):\s(.*)$}
283 283 r = Revision.new(:author => $1.strip, :revision => $2, :scmid => $3,
284 284 :identifier => $3)
285 285 blame.add_line($4.rstrip, r)
286 286 end
287 287 end
288 288 blame
289 289 rescue HgCommandAborted
290 290 # means not found or cannot be annotated
291 291 Annotate.new
292 292 end
293 293
294 294 class Revision < Redmine::Scm::Adapters::Revision
295 295 # Returns the readable identifier
296 296 def format_identifier
297 297 "#{revision}:#{scmid}"
298 298 end
299 299 end
300 300
301 301 # Runs 'hg' command with the given args
302 302 def hg(*args, &block)
303 303 repo_path = root_url || url
304 304 full_args = ['-R', repo_path, '--encoding', 'utf-8']
305 305 full_args << '--config' << "extensions.redminehelper=#{HG_HELPER_EXT}"
306 306 full_args << '--config' << 'diff.git=false'
307 307 full_args += args
308 308 ret = shellout(
309 309 self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '),
310 310 &block
311 311 )
312 312 if $? && $?.exitstatus != 0
313 313 raise HgCommandAborted, "hg exited with non-zero status: #{$?.exitstatus}"
314 314 end
315 315 ret
316 316 end
317 317 private :hg
318 318
319 319 # Returns correct revision identifier
320 320 def hgrev(identifier, sq=false)
321 321 rev = identifier.blank? ? 'tip' : identifier.to_s
322 322 rev = shell_quote(rev) if sq
323 323 rev
324 324 end
325 325 private :hgrev
326 326
327 327 def hgtarget(path)
328 328 path ||= ''
329 329 root_url + '/' + without_leading_slash(path)
330 330 end
331 331 private :hgtarget
332 332
333 333 def as_ary(o)
334 334 return [] unless o
335 335 o.is_a?(Array) ? o : Array[o]
336 336 end
337 337 private :as_ary
338 338 end
339 339 end
340 340 end
341 341 end
@@ -1,475 +1,475
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2014 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 begin
20 20 require 'mocha/setup'
21 21
22 22 class MercurialAdapterTest < ActiveSupport::TestCase
23 23 HELPERS_DIR = Redmine::Scm::Adapters::MercurialAdapter::HELPERS_DIR
24 24 TEMPLATE_NAME = Redmine::Scm::Adapters::MercurialAdapter::TEMPLATE_NAME
25 25 TEMPLATE_EXTENSION = Redmine::Scm::Adapters::MercurialAdapter::TEMPLATE_EXTENSION
26 26
27 27 REPOSITORY_PATH = Rails.root.join('tmp/test/mercurial_repository').to_s
28 28 CHAR_1_HEX = "\xc3\x9c"
29 29
30 30 if File.directory?(REPOSITORY_PATH)
31 31 def setup
32 32 adapter_class = Redmine::Scm::Adapters::MercurialAdapter
33 33 assert adapter_class
34 34 assert adapter_class.client_command
35 35 assert_equal true, adapter_class.client_available
36 36 assert_equal true, adapter_class.client_version_above?([0, 9, 5])
37 37
38 38 @adapter = Redmine::Scm::Adapters::MercurialAdapter.new(
39 39 REPOSITORY_PATH,
40 40 nil,
41 41 nil,
42 42 nil,
43 43 'ISO-8859-1')
44 44 @diff_c_support = true
45 45 @char_1 = CHAR_1_HEX.dup
46 46 @tag_char_1 = "tag-#{CHAR_1_HEX}-00"
47 47 @branch_char_0 = "branch-#{CHAR_1_HEX}-00"
48 48 @branch_char_1 = "branch-#{CHAR_1_HEX}-01"
49 49 if @tag_char_1.respond_to?(:force_encoding)
50 50 @char_1.force_encoding('UTF-8')
51 51 @tag_char_1.force_encoding('UTF-8')
52 52 @branch_char_0.force_encoding('UTF-8')
53 53 @branch_char_1.force_encoding('UTF-8')
54 54 end
55 55 end
56 56
57 57 def test_hgversion
58 58 to_test = { "Mercurial Distributed SCM (version 0.9.5)\n" => [0,9,5],
59 59 "Mercurial Distributed SCM (1.0)\n" => [1,0],
60 60 "Mercurial Distributed SCM (1e4ddc9ac9f7+20080325)\n" => nil,
61 61 "Mercurial Distributed SCM (1.0.1+20080525)\n" => [1,0,1],
62 62 "Mercurial Distributed SCM (1916e629a29d)\n" => nil,
63 63 "Mercurial SCM Distribuito (versione 0.9.5)\n" => [0,9,5],
64 64 "(1.6)\n(1.7)\n(1.8)" => [1,6],
65 65 "(1.7.1)\r\n(1.8.1)\r\n(1.9.1)" => [1,7,1]}
66 66
67 67 to_test.each do |s, v|
68 68 test_hgversion_for(s, v)
69 69 end
70 70 end
71 71
72 72 def test_template_path
73 73 to_test = {
74 74 [1,2] => "1.0",
75 75 [] => "1.0",
76 76 [1,2,1] => "1.0",
77 77 [1,7] => "1.0",
78 78 [1,7,1] => "1.0",
79 79 [2,0] => "1.0",
80 80 }
81 81 to_test.each do |v, template|
82 82 test_template_path_for(v, template)
83 83 end
84 84 end
85 85
86 86 def test_info
87 87 [REPOSITORY_PATH, REPOSITORY_PATH + "/",
88 88 REPOSITORY_PATH + "//"].each do |repo|
89 89 adp = Redmine::Scm::Adapters::MercurialAdapter.new(repo)
90 90 repo_path = adp.info.root_url.gsub(/\\/, "/")
91 91 assert_equal REPOSITORY_PATH, repo_path
92 92 assert_equal '31', adp.info.lastrev.revision
93 assert_equal '31eeee7395c8',adp.info.lastrev.scmid
93 assert_equal '31eeee7395c8c78e66dd54c50addd078d10b2355',adp.info.lastrev.scmid
94 94 end
95 95 end
96 96
97 97 def test_revisions
98 98 revisions = @adapter.revisions(nil, 2, 4)
99 99 assert_equal 3, revisions.size
100 100 assert_equal '2', revisions[0].revision
101 assert_equal '400bb8672109', revisions[0].scmid
101 assert_equal '400bb86721098697c7d17b3724c794c57636de70', revisions[0].scmid
102 102 assert_equal '4', revisions[2].revision
103 assert_equal 'def6d2f1254a', revisions[2].scmid
103 assert_equal 'def6d2f1254a56fb8fbe9ec3b5c0451674dbd8b8', revisions[2].scmid
104 104
105 105 revisions = @adapter.revisions(nil, 2, 4, {:limit => 2})
106 106 assert_equal 2, revisions.size
107 107 assert_equal '2', revisions[0].revision
108 assert_equal '400bb8672109', revisions[0].scmid
108 assert_equal '400bb86721098697c7d17b3724c794c57636de70', revisions[0].scmid
109 109 end
110 110
111 111 def test_parents
112 112 revs1 = @adapter.revisions(nil, 0, 0)
113 113 assert_equal 1, revs1.size
114 114 assert_equal [], revs1[0].parents
115 115 revs2 = @adapter.revisions(nil, 1, 1)
116 116 assert_equal 1, revs2.size
117 117 assert_equal 1, revs2[0].parents.size
118 assert_equal "0885933ad4f6", revs2[0].parents[0]
118 assert_equal "0885933ad4f68d77c2649cd11f8311276e7ef7ce", revs2[0].parents[0]
119 119 revs3 = @adapter.revisions(nil, 30, 30)
120 120 assert_equal 1, revs3.size
121 121 assert_equal 2, revs3[0].parents.size
122 assert_equal "a94b0528f24f", revs3[0].parents[0]
123 assert_equal "3a330eb32958", revs3[0].parents[1]
122 assert_equal "a94b0528f24fe05ebaef496ae0500bb050772e36", revs3[0].parents[0]
123 assert_equal "3a330eb329586ea2adb3f83237c23310e744ebe9", revs3[0].parents[1]
124 124 end
125 125
126 126 def test_diff
127 127 if @adapter.class.client_version_above?([1, 2])
128 128 assert_nil @adapter.diff(nil, '100000')
129 129 end
130 130 assert_nil @adapter.diff(nil, '100000', '200000')
131 131 [2, '400bb8672109', '400', 400].each do |r1|
132 132 diff1 = @adapter.diff(nil, r1)
133 133 if @diff_c_support
134 134 assert_equal 28, diff1.size
135 135 buf = diff1[24].gsub(/\r\n|\r|\n/, "")
136 136 assert_equal "+ return true unless klass.respond_to?('watched_by')", buf
137 137 else
138 138 assert_equal 0, diff1.size
139 139 end
140 140 [4, 'def6d2f1254a'].each do |r2|
141 141 diff2 = @adapter.diff(nil, r1, r2)
142 142 assert_equal 49, diff2.size
143 143 buf = diff2[41].gsub(/\r\n|\r|\n/, "")
144 144 assert_equal "+class WelcomeController < ApplicationController", buf
145 145 diff3 = @adapter.diff('sources/watchers_controller.rb', r1, r2)
146 146 assert_equal 20, diff3.size
147 147 buf = diff3[12].gsub(/\r\n|\r|\n/, "")
148 148 assert_equal "+ @watched.remove_watcher(user)", buf
149 149
150 150 diff4 = @adapter.diff(nil, r2, r1)
151 151 assert_equal 49, diff4.size
152 152 buf = diff4[41].gsub(/\r\n|\r|\n/, "")
153 153 assert_equal "-class WelcomeController < ApplicationController", buf
154 154 diff5 = @adapter.diff('sources/watchers_controller.rb', r2, r1)
155 155 assert_equal 20, diff5.size
156 156 buf = diff5[9].gsub(/\r\n|\r|\n/, "")
157 157 assert_equal "- @watched.remove_watcher(user)", buf
158 158 end
159 159 end
160 160 end
161 161
162 162 def test_diff_made_by_revision
163 163 if @diff_c_support
164 164 [24, '24', '4cddb4e45f52'].each do |r1|
165 165 diff1 = @adapter.diff(nil, r1)
166 166 assert_equal 5, diff1.size
167 167 buf = diff1[4].gsub(/\r\n|\r|\n/, "")
168 168 assert_equal '+0885933ad4f68d77c2649cd11f8311276e7ef7ce tag-init-revision', buf
169 169 end
170 170 end
171 171 end
172 172
173 173 def test_cat
174 174 [2, '400bb8672109', '400', 400].each do |r|
175 175 buf = @adapter.cat('sources/welcome_controller.rb', r)
176 176 assert buf
177 177 lines = buf.split("\r\n")
178 178 assert_equal 25, lines.length
179 179 assert_equal 'class WelcomeController < ApplicationController', lines[17]
180 180 end
181 181 assert_nil @adapter.cat('sources/welcome_controller.rb')
182 182 end
183 183
184 184 def test_annotate
185 185 assert_equal [], @adapter.annotate("sources/welcome_controller.rb").lines
186 186 [2, '400bb8672109', '400', 400].each do |r|
187 187 ann = @adapter.annotate('sources/welcome_controller.rb', r)
188 188 assert ann
189 189 assert_equal '1', ann.revisions[17].revision
190 190 assert_equal '9d5b5b004199', ann.revisions[17].identifier
191 191 assert_equal 'jsmith', ann.revisions[0].author
192 192 assert_equal 25, ann.lines.length
193 193 assert_equal 'class WelcomeController < ApplicationController', ann.lines[17]
194 194 end
195 195 end
196 196
197 197 def test_entries
198 198 assert_nil @adapter.entries(nil, '100000')
199 199
200 200 assert_equal 1, @adapter.entries("sources", 3).size
201 201 assert_equal 1, @adapter.entries("sources", 'b3a615152df8').size
202 202
203 203 [2, '400bb8672109', '400', 400].each do |r|
204 204 entries1 = @adapter.entries(nil, r)
205 205 assert entries1
206 206 assert_equal 3, entries1.size
207 207 assert_equal 'sources', entries1[1].name
208 208 assert_equal 'sources', entries1[1].path
209 209 assert_equal 'dir', entries1[1].kind
210 210 readme = entries1[2]
211 211 assert_equal 'README', readme.name
212 212 assert_equal 'README', readme.path
213 213 assert_equal 'file', readme.kind
214 214 assert_equal 27, readme.size
215 215 assert_equal '1', readme.lastrev.revision
216 assert_equal '9d5b5b004199', readme.lastrev.identifier
216 assert_equal '9d5b5b00419901478496242e0768deba1ce8c51e', readme.lastrev.identifier
217 217 # 2007-12-14 10:24:01 +0100
218 218 assert_equal Time.gm(2007, 12, 14, 9, 24, 1), readme.lastrev.time
219 219
220 220 entries2 = @adapter.entries('sources', r)
221 221 assert entries2
222 222 assert_equal 2, entries2.size
223 223 assert_equal 'watchers_controller.rb', entries2[0].name
224 224 assert_equal 'sources/watchers_controller.rb', entries2[0].path
225 225 assert_equal 'file', entries2[0].kind
226 226 assert_equal 'welcome_controller.rb', entries2[1].name
227 227 assert_equal 'sources/welcome_controller.rb', entries2[1].path
228 228 assert_equal 'file', entries2[1].kind
229 229 end
230 230 end
231 231
232 232 def test_entries_tag
233 233 entries1 = @adapter.entries(nil, 'tag_test.00')
234 234 assert entries1
235 235 assert_equal 3, entries1.size
236 236 assert_equal 'sources', entries1[1].name
237 237 assert_equal 'sources', entries1[1].path
238 238 assert_equal 'dir', entries1[1].kind
239 239 readme = entries1[2]
240 240 assert_equal 'README', readme.name
241 241 assert_equal 'README', readme.path
242 242 assert_equal 'file', readme.kind
243 243 assert_equal 21, readme.size
244 244 assert_equal '0', readme.lastrev.revision
245 assert_equal '0885933ad4f6', readme.lastrev.identifier
245 assert_equal '0885933ad4f68d77c2649cd11f8311276e7ef7ce', readme.lastrev.identifier
246 246 # 2007-12-14 10:22:52 +0100
247 247 assert_equal Time.gm(2007, 12, 14, 9, 22, 52), readme.lastrev.time
248 248 end
249 249
250 250 def test_entries_branch
251 251 entries1 = @adapter.entries(nil, 'test-branch-00')
252 252 assert entries1
253 253 assert_equal 5, entries1.size
254 254 assert_equal 'sql_escape', entries1[2].name
255 255 assert_equal 'sql_escape', entries1[2].path
256 256 assert_equal 'dir', entries1[2].kind
257 257 readme = entries1[4]
258 258 assert_equal 'README', readme.name
259 259 assert_equal 'README', readme.path
260 260 assert_equal 'file', readme.kind
261 261 assert_equal 365, readme.size
262 262 assert_equal '8', readme.lastrev.revision
263 assert_equal 'c51f5bb613cd', readme.lastrev.identifier
263 assert_equal 'c51f5bb613cd60793c2a9fe9df29332e74bb949f', readme.lastrev.identifier
264 264 # 2001-02-01 00:00:00 -0900
265 265 assert_equal Time.gm(2001, 2, 1, 9, 0, 0), readme.lastrev.time
266 266 end
267 267
268 268 def test_entry
269 269 entry = @adapter.entry()
270 270 assert_equal "", entry.path
271 271 assert_equal "dir", entry.kind
272 272 entry = @adapter.entry('')
273 273 assert_equal "", entry.path
274 274 assert_equal "dir", entry.kind
275 275 assert_nil @adapter.entry('invalid')
276 276 assert_nil @adapter.entry('/invalid')
277 277 assert_nil @adapter.entry('/invalid/')
278 278 assert_nil @adapter.entry('invalid/invalid')
279 279 assert_nil @adapter.entry('invalid/invalid/')
280 280 assert_nil @adapter.entry('/invalid/invalid')
281 281 assert_nil @adapter.entry('/invalid/invalid/')
282 282 ["README", "/README"].each do |path|
283 283 ["0", "0885933ad4f6", "0885933ad4f68d77c2649cd11f8311276e7ef7ce"].each do |rev|
284 284 entry = @adapter.entry(path, rev)
285 285 assert_equal "README", entry.path
286 286 assert_equal "file", entry.kind
287 287 assert_equal '0', entry.lastrev.revision
288 assert_equal '0885933ad4f6', entry.lastrev.identifier
288 assert_equal '0885933ad4f68d77c2649cd11f8311276e7ef7ce', entry.lastrev.identifier
289 289 end
290 290 end
291 291 ["sources", "/sources", "/sources/"].each do |path|
292 292 ["0", "0885933ad4f6", "0885933ad4f68d77c2649cd11f8311276e7ef7ce"].each do |rev|
293 293 entry = @adapter.entry(path, rev)
294 294 assert_equal "sources", entry.path
295 295 assert_equal "dir", entry.kind
296 296 end
297 297 end
298 298 ["sources/watchers_controller.rb", "/sources/watchers_controller.rb"].each do |path|
299 299 ["0", "0885933ad4f6", "0885933ad4f68d77c2649cd11f8311276e7ef7ce"].each do |rev|
300 300 entry = @adapter.entry(path, rev)
301 301 assert_equal "sources/watchers_controller.rb", entry.path
302 302 assert_equal "file", entry.kind
303 303 assert_equal '0', entry.lastrev.revision
304 assert_equal '0885933ad4f6', entry.lastrev.identifier
304 assert_equal '0885933ad4f68d77c2649cd11f8311276e7ef7ce', entry.lastrev.identifier
305 305 end
306 306 end
307 307 end
308 308
309 309 def test_locate_on_outdated_repository
310 310 assert_equal 1, @adapter.entries("images", 0).size
311 311 assert_equal 2, @adapter.entries("images").size
312 312 assert_equal 2, @adapter.entries("images", 2).size
313 313 end
314 314
315 315 def test_access_by_nodeid
316 316 path = 'sources/welcome_controller.rb'
317 317 assert_equal @adapter.cat(path, 2), @adapter.cat(path, '400bb8672109')
318 318 end
319 319
320 320 def test_access_by_fuzzy_nodeid
321 321 path = 'sources/welcome_controller.rb'
322 322 # falls back to nodeid
323 323 assert_equal @adapter.cat(path, 2), @adapter.cat(path, '400')
324 324 end
325 325
326 326 def test_tags
327 327 assert_equal [@tag_char_1, 'tag_test.00', 'tag-init-revision'], @adapter.tags
328 328 end
329 329
330 330 def test_tagmap
331 331 tm = {
332 @tag_char_1 => 'adf805632193',
333 'tag_test.00' => '6987191f453a',
334 'tag-init-revision' => '0885933ad4f6',
332 @tag_char_1 => 'adf805632193500ad3b615cd04f58f9b0769f576',
333 'tag_test.00' => '6987191f453a5f6557018d522feea2c450d5588d',
334 'tag-init-revision' => '0885933ad4f68d77c2649cd11f8311276e7ef7ce',
335 335 }
336 336 assert_equal tm, @adapter.tagmap
337 337 end
338 338
339 339 def test_branches
340 340 brs = []
341 341 @adapter.branches.each do |b|
342 342 brs << b
343 343 end
344 344 assert_equal 7, brs.length
345 345 assert_equal 'default', brs[0].to_s
346 346 assert_equal '31', brs[0].revision
347 assert_equal '31eeee7395c8', brs[0].scmid
347 assert_equal '31eeee7395c8c78e66dd54c50addd078d10b2355', brs[0].scmid
348 348 assert_equal 'test-branch-01', brs[1].to_s
349 349 assert_equal '30', brs[1].revision
350 assert_equal 'ad4dc4f80284', brs[1].scmid
350 assert_equal 'ad4dc4f80284a4f9168b77e0b6de288e5d207ee7', brs[1].scmid
351 351 assert_equal @branch_char_1, brs[2].to_s
352 352 assert_equal '27', brs[2].revision
353 assert_equal '7bbf4c738e71', brs[2].scmid
353 assert_equal '7bbf4c738e7145149d2e5eb1eed1d3a8ddd3b914', brs[2].scmid
354 354 assert_equal 'branch (1)[2]&,%.-3_4', brs[3].to_s
355 355 assert_equal '25', brs[3].revision
356 assert_equal 'afc61e85bde7', brs[3].scmid
356 assert_equal 'afc61e85bde74de930e5846c8451bd55b5bafc9c', brs[3].scmid
357 357 assert_equal @branch_char_0, brs[4].to_s
358 358 assert_equal '23', brs[4].revision
359 assert_equal 'c8d3e4887474', brs[4].scmid
359 assert_equal 'c8d3e4887474af6a589190140508037ebaa9d9c3', brs[4].scmid
360 360 assert_equal 'test_branch.latin-1', brs[5].to_s
361 361 assert_equal '22', brs[5].revision
362 assert_equal 'c2ffe7da686a', brs[5].scmid
362 assert_equal 'c2ffe7da686aa3d956e59f2a2854cf8980a8b768', brs[5].scmid
363 363 assert_equal 'test-branch-00', brs[6].to_s
364 364 assert_equal '13', brs[6].revision
365 assert_equal '3a330eb32958', brs[6].scmid
365 assert_equal '3a330eb329586ea2adb3f83237c23310e744ebe9', brs[6].scmid
366 366 end
367 367
368 368 def test_branchmap
369 369 bm = {
370 'default' => '31eeee7395c8',
371 'test_branch.latin-1' => 'c2ffe7da686a',
372 'branch (1)[2]&,%.-3_4' => 'afc61e85bde7',
373 'test-branch-00' => '3a330eb32958',
374 "test-branch-01" => 'ad4dc4f80284',
375 @branch_char_0 => 'c8d3e4887474',
376 @branch_char_1 => '7bbf4c738e71',
370 'default' => '31eeee7395c8c78e66dd54c50addd078d10b2355',
371 'test_branch.latin-1' => 'c2ffe7da686aa3d956e59f2a2854cf8980a8b768',
372 'branch (1)[2]&,%.-3_4' => 'afc61e85bde74de930e5846c8451bd55b5bafc9c',
373 'test-branch-00' => '3a330eb329586ea2adb3f83237c23310e744ebe9',
374 "test-branch-01" => 'ad4dc4f80284a4f9168b77e0b6de288e5d207ee7',
375 @branch_char_0 => 'c8d3e4887474af6a589190140508037ebaa9d9c3',
376 @branch_char_1 => '7bbf4c738e7145149d2e5eb1eed1d3a8ddd3b914',
377 377 }
378 378 assert_equal bm, @adapter.branchmap
379 379 end
380 380
381 381 def test_path_space
382 382 p = 'README (1)[2]&,%.-3_4'
383 383 [15, '933ca60293d7'].each do |r1|
384 384 assert @adapter.diff(p, r1)
385 385 assert @adapter.cat(p, r1)
386 386 assert_equal 1, @adapter.annotate(p, r1).lines.length
387 387 [25, 'afc61e85bde7'].each do |r2|
388 388 assert @adapter.diff(p, r1, r2)
389 389 end
390 390 end
391 391 end
392 392
393 393 def test_tag_non_ascii
394 394 p = "latin-1-dir/test-#{@char_1}-1.txt"
395 395 assert @adapter.cat(p, @tag_char_1)
396 396 assert_equal 1, @adapter.annotate(p, @tag_char_1).lines.length
397 397 end
398 398
399 399 def test_branch_non_ascii
400 400 p = "latin-1-dir/test-#{@char_1}-subdir/test-#{@char_1}-1.txt"
401 401 assert @adapter.cat(p, @branch_char_1)
402 402 assert_equal 1, @adapter.annotate(p, @branch_char_1).lines.length
403 403 end
404 404
405 405 def test_nodes_in_branch
406 406 [
407 407 'default',
408 408 @branch_char_1,
409 409 'branch (1)[2]&,%.-3_4',
410 410 @branch_char_0,
411 411 'test_branch.latin-1',
412 412 'test-branch-00',
413 413 ].each do |bra|
414 414 nib0 = @adapter.nodes_in_branch(bra)
415 415 assert nib0
416 416 nib1 = @adapter.nodes_in_branch(bra, :limit => 1)
417 417 assert_equal 1, nib1.size
418 418 case bra
419 419 when 'branch (1)[2]&,%.-3_4'
420 420 if @adapter.class.client_version_above?([1, 6])
421 421 assert_equal 3, nib0.size
422 assert_equal nib0[0], 'afc61e85bde7'
422 assert_equal 'afc61e85bde74de930e5846c8451bd55b5bafc9c', nib0[0]
423 423 nib2 = @adapter.nodes_in_branch(bra, :limit => 2)
424 424 assert_equal 2, nib2.size
425 assert_equal nib2[1], '933ca60293d7'
425 assert_equal '933ca60293d78f7c7979dd123cc0c02431683575', nib2[1]
426 426 end
427 427 when @branch_char_1
428 428 if @adapter.class.client_version_above?([1, 6])
429 429 assert_equal 2, nib0.size
430 assert_equal nib0[1], '08ff3227303e'
430 assert_equal '08ff3227303ec0dfcc818efa8e9cc652fe81859f', nib0[1]
431 431 nib2 = @adapter.nodes_in_branch(bra, :limit => 1)
432 432 assert_equal 1, nib2.size
433 assert_equal nib2[0], '7bbf4c738e71'
433 assert_equal '7bbf4c738e7145149d2e5eb1eed1d3a8ddd3b914', nib2[0]
434 434 end
435 435 end
436 436 end
437 437 end
438 438
439 439 def test_path_encoding_default_utf8
440 440 adpt1 = Redmine::Scm::Adapters::MercurialAdapter.new(
441 441 REPOSITORY_PATH
442 442 )
443 443 assert_equal "UTF-8", adpt1.path_encoding
444 444 adpt2 = Redmine::Scm::Adapters::MercurialAdapter.new(
445 445 REPOSITORY_PATH,
446 446 nil,
447 447 nil,
448 448 nil,
449 449 ""
450 450 )
451 451 assert_equal "UTF-8", adpt2.path_encoding
452 452 end
453 453
454 454 private
455 455
456 456 def test_hgversion_for(hgversion, version)
457 457 @adapter.class.expects(:hgversion_from_command_line).returns(hgversion)
458 458 assert_equal version, @adapter.class.hgversion
459 459 end
460 460
461 461 def test_template_path_for(version, template)
462 462 assert_equal "#{HELPERS_DIR}/#{TEMPLATE_NAME}-#{template}.#{TEMPLATE_EXTENSION}",
463 463 @adapter.class.template_path_for(version)
464 464 assert File.exist?(@adapter.class.template_path_for(version))
465 465 end
466 466 else
467 467 puts "Mercurial test repository NOT FOUND. Skipping unit tests !!!"
468 468 def test_fake; assert true end
469 469 end
470 470 end
471 471 rescue LoadError
472 472 class MercurialMochaFake < ActiveSupport::TestCase
473 473 def test_fake; assert(false, "Requires mocha to run those tests") end
474 474 end
475 475 end
General Comments 0
You need to be logged in to leave comments. Login now