Show More
@@ -1,5 +1,5 b'' | |||
|
1 | 1 | [bumpversion] |
|
2 |
current_version = 4. |
|
|
2 | current_version = 4.8.0 | |
|
3 | 3 | message = release: Bump version {current_version} to {new_version} |
|
4 | 4 | |
|
5 | 5 | [bumpversion:file:vcsserver/VERSION] |
@@ -5,12 +5,10 b' done = false' | |||
|
5 | 5 | done = true |
|
6 | 6 | |
|
7 | 7 | [task:fixes_on_stable] |
|
8 | done = true | |
|
9 | 8 | |
|
10 | 9 | [task:pip2nix_generated] |
|
11 | done = true | |
|
12 | 10 | |
|
13 | 11 | [release] |
|
14 |
state = |
|
|
15 |
version = 4. |
|
|
12 | state = in_progress | |
|
13 | version = 4.8.0 | |
|
16 | 14 |
@@ -32,7 +32,7 b' use = egg:waitress#main' | |||
|
32 | 32 | ### LOGGING CONFIGURATION #### |
|
33 | 33 | ################################ |
|
34 | 34 | [loggers] |
|
35 |
keys = root, vcsserver, |
|
|
35 | keys = root, vcsserver, beaker | |
|
36 | 36 | |
|
37 | 37 | [handlers] |
|
38 | 38 | keys = console |
@@ -59,12 +59,6 b' handlers =' | |||
|
59 | 59 | qualname = beaker |
|
60 | 60 | propagate = 1 |
|
61 | 61 | |
|
62 | [logger_pyro4] | |
|
63 | level = DEBUG | |
|
64 | handlers = | |
|
65 | qualname = Pyro4 | |
|
66 | propagate = 1 | |
|
67 | ||
|
68 | 62 | |
|
69 | 63 | ############## |
|
70 | 64 | ## HANDLERS ## |
@@ -20,8 +20,7 b' use = egg:gunicorn#main' | |||
|
20 | 20 | workers = 2 |
|
21 | 21 | ## process name |
|
22 | 22 | proc_name = rhodecode_vcsserver |
|
23 |
## type of worker class, |
|
|
24 | ## recommended for bigger setup is using of of other than sync one | |
|
23 | ## type of worker class, currently `sync` is the only option allowed. | |
|
25 | 24 | worker_class = sync |
|
26 | 25 | ## The maximum number of simultaneous clients. Valid only for Gevent |
|
27 | 26 | #worker_connections = 10 |
@@ -56,7 +55,7 b' beaker.cache.repo_object.enabled = true' | |||
|
56 | 55 | ### LOGGING CONFIGURATION #### |
|
57 | 56 | ################################ |
|
58 | 57 | [loggers] |
|
59 |
keys = root, vcsserver, |
|
|
58 | keys = root, vcsserver, beaker | |
|
60 | 59 | |
|
61 | 60 | [handlers] |
|
62 | 61 | keys = console |
@@ -83,12 +82,6 b' handlers =' | |||
|
83 | 82 | qualname = beaker |
|
84 | 83 | propagate = 1 |
|
85 | 84 | |
|
86 | [logger_pyro4] | |
|
87 | level = DEBUG | |
|
88 | handlers = | |
|
89 | qualname = Pyro4 | |
|
90 | propagate = 1 | |
|
91 | ||
|
92 | 85 | |
|
93 | 86 | ############## |
|
94 | 87 | ## HANDLERS ## |
@@ -120,6 +120,7 b' let' | |||
|
120 | 120 | cp -v vcsserver/VERSION $out/nix-support/rccontrol/version |
|
121 | 121 | echo "DONE: Meta information for rccontrol written" |
|
122 | 122 | |
|
123 | # python based programs need to be wrapped | |
|
123 | 124 | ln -s ${self.pyramid}/bin/* $out/bin/ |
|
124 | 125 | ln -s ${self.gunicorn}/bin/gunicorn $out/bin/ |
|
125 | 126 | |
@@ -132,12 +133,14 b' let' | |||
|
132 | 133 | ln -s ${self.mercurial}/bin/hg $out/bin |
|
133 | 134 | ln -s ${pkgs.subversion}/bin/svn* $out/bin |
|
134 | 135 | |
|
135 |
for file in $out/bin/*; |
|
|
136 | for file in $out/bin/*; | |
|
137 | do | |
|
136 | 138 | wrapProgram $file \ |
|
137 | 139 | --set PATH $PATH \ |
|
138 | 140 | --set PYTHONPATH $PYTHONPATH \ |
|
139 | 141 | --set PYTHONHASHSEED random |
|
140 | 142 | done |
|
143 | ||
|
141 | 144 | ''; |
|
142 | 145 | |
|
143 | 146 | }); |
@@ -67,19 +67,6 b'' | |||
|
67 | 67 | license = [ pkgs.lib.licenses.mit ]; |
|
68 | 68 | }; |
|
69 | 69 | }; |
|
70 | Pyro4 = super.buildPythonPackage { | |
|
71 | name = "Pyro4-4.41"; | |
|
72 | buildInputs = with self; []; | |
|
73 | doCheck = false; | |
|
74 | propagatedBuildInputs = with self; [serpent]; | |
|
75 | src = fetchurl { | |
|
76 | url = "https://pypi.python.org/packages/56/2b/89b566b4bf3e7f8ba790db2d1223852f8cb454c52cab7693dd41f608ca2a/Pyro4-4.41.tar.gz"; | |
|
77 | md5 = "ed69e9bfafa9c06c049a87cb0c4c2b6c"; | |
|
78 | }; | |
|
79 | meta = { | |
|
80 | license = [ pkgs.lib.licenses.mit ]; | |
|
81 | }; | |
|
82 | }; | |
|
83 | 70 | WebOb = super.buildPythonPackage { |
|
84 | 71 | name = "WebOb-1.3.1"; |
|
85 | 72 | buildInputs = with self; []; |
@@ -249,6 +236,19 b'' | |||
|
249 | 236 | license = [ pkgs.lib.licenses.mit ]; |
|
250 | 237 | }; |
|
251 | 238 | }; |
|
239 | hg-evolve = super.buildPythonPackage { | |
|
240 | name = "hg-evolve-6.0.1"; | |
|
241 | buildInputs = with self; []; | |
|
242 | doCheck = false; | |
|
243 | propagatedBuildInputs = with self; []; | |
|
244 | src = fetchurl { | |
|
245 | url = "https://pypi.python.org/packages/c4/31/0673a5657c201ebb46e63c4bba8668f96cf5d7a8a0f8a91892d022ccc32b/hg-evolve-6.0.1.tar.gz"; | |
|
246 | md5 = "9c1ce7ac24792abc0eedee09a3344d06"; | |
|
247 | }; | |
|
248 | meta = { | |
|
249 | license = [ { fullName = "GPLv2+"; } ]; | |
|
250 | }; | |
|
251 | }; | |
|
252 | 252 | hgsubversion = super.buildPythonPackage { |
|
253 | 253 | name = "hgsubversion-1.8.6"; |
|
254 | 254 | buildInputs = with self; []; |
@@ -302,13 +302,13 b'' | |||
|
302 | 302 | }; |
|
303 | 303 | }; |
|
304 | 304 | ipython-genutils = super.buildPythonPackage { |
|
305 |
name = "ipython-genutils-0. |
|
|
305 | name = "ipython-genutils-0.2.0"; | |
|
306 | 306 | buildInputs = with self; []; |
|
307 | 307 | doCheck = false; |
|
308 | 308 | propagatedBuildInputs = with self; []; |
|
309 | 309 | src = fetchurl { |
|
310 |
url = "https://pypi.python.org/packages/71 |
|
|
311 | md5 = "9a8afbe0978adbcbfcb3b35b2d015a56"; | |
|
310 | url = "https://pypi.python.org/packages/e8/69/fbeffffc05236398ebfcfb512b6d2511c622871dca1746361006da310399/ipython_genutils-0.2.0.tar.gz"; | |
|
311 | md5 = "5a4f9781f78466da0ea1a648f3e1f79f"; | |
|
312 | 312 | }; |
|
313 | 313 | meta = { |
|
314 | 314 | license = [ pkgs.lib.licenses.bsdOriginal ]; |
@@ -393,13 +393,13 b'' | |||
|
393 | 393 | }; |
|
394 | 394 | }; |
|
395 | 395 | prompt-toolkit = super.buildPythonPackage { |
|
396 |
name = "prompt-toolkit-1.0. |
|
|
396 | name = "prompt-toolkit-1.0.14"; | |
|
397 | 397 | buildInputs = with self; []; |
|
398 | 398 | doCheck = false; |
|
399 | 399 | propagatedBuildInputs = with self; [six wcwidth]; |
|
400 | 400 | src = fetchurl { |
|
401 |
url = "https://pypi.python.org/packages/83 |
|
|
402 | md5 = "a39f91a54308fb7446b1a421c11f227c"; | |
|
401 | url = "https://pypi.python.org/packages/55/56/8c39509b614bda53e638b7500f12577d663ac1b868aef53426fc6a26c3f5/prompt_toolkit-1.0.14.tar.gz"; | |
|
402 | md5 = "f24061ae133ed32c6b764e92bd48c496"; | |
|
403 | 403 | }; |
|
404 | 404 | meta = { |
|
405 | 405 | license = [ pkgs.lib.licenses.bsdOriginal ]; |
@@ -588,28 +588,15 b'' | |||
|
588 | 588 | }; |
|
589 | 589 | }; |
|
590 | 590 | rhodecode-vcsserver = super.buildPythonPackage { |
|
591 |
name = "rhodecode-vcsserver-4. |
|
|
591 | name = "rhodecode-vcsserver-4.8.0"; | |
|
592 | 592 | buildInputs = with self; [pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage configobj]; |
|
593 | 593 | doCheck = true; |
|
594 |
propagatedBuildInputs = with self; [Beaker configobj decorator dulwich hgsubversion infrae.cache mercurial msgpack-python pyramid pyramid-jinja2 pyramid-mako repoze.lru simplejson subprocess32 subvertpy six translationstring WebOb wheel zope.deprecation zope.interface ipdb ipython gevent greenlet gunicorn waitress |
|
|
594 | propagatedBuildInputs = with self; [Beaker configobj decorator dulwich hgsubversion hg-evolve infrae.cache mercurial msgpack-python pyramid pyramid-jinja2 pyramid-mako repoze.lru simplejson subprocess32 subvertpy six translationstring WebOb wheel zope.deprecation zope.interface ipdb ipython gevent greenlet gunicorn waitress pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage]; | |
|
595 | 595 | src = ./.; |
|
596 | 596 | meta = { |
|
597 | 597 | license = [ { fullName = "GPL V3"; } { fullName = "GNU General Public License v3 or later (GPLv3+)"; } ]; |
|
598 | 598 | }; |
|
599 | 599 | }; |
|
600 | serpent = super.buildPythonPackage { | |
|
601 | name = "serpent-1.15"; | |
|
602 | buildInputs = with self; []; | |
|
603 | doCheck = false; | |
|
604 | propagatedBuildInputs = with self; []; | |
|
605 | src = fetchurl { | |
|
606 | url = "https://pypi.python.org/packages/7b/38/b2b27673a882ff2ea5871bb3e3e6b496ebbaafd1612e51990ffb158b9254/serpent-1.15.tar.gz"; | |
|
607 | md5 = "e27b1aad5c218e16442f52abb7c7053a"; | |
|
608 | }; | |
|
609 | meta = { | |
|
610 | license = [ pkgs.lib.licenses.mit ]; | |
|
611 | }; | |
|
612 | }; | |
|
613 | 600 | setuptools = super.buildPythonPackage { |
|
614 | 601 | name = "setuptools-30.1.0"; |
|
615 | 602 | buildInputs = with self; []; |
@@ -702,13 +689,13 b'' | |||
|
702 | 689 | }; |
|
703 | 690 | }; |
|
704 | 691 | traitlets = super.buildPythonPackage { |
|
705 |
name = "traitlets-4.3. |
|
|
692 | name = "traitlets-4.3.2"; | |
|
706 | 693 | buildInputs = with self; []; |
|
707 | 694 | doCheck = false; |
|
708 | 695 | propagatedBuildInputs = with self; [ipython-genutils six decorator enum34]; |
|
709 | 696 | src = fetchurl { |
|
710 |
url = "https://pypi.python.org/packages/ |
|
|
711 | md5 = "dd0b1b6e5d31ce446d55a4b5e5083c98"; | |
|
697 | url = "https://pypi.python.org/packages/a5/98/7f5ef2fe9e9e071813aaf9cb91d1a732e0a68b6c44a32b38cb8e14c3f069/traitlets-4.3.2.tar.gz"; | |
|
698 | md5 = "3068663f2f38fd939a9eb3a500ccc154"; | |
|
712 | 699 | }; |
|
713 | 700 | meta = { |
|
714 | 701 | license = [ pkgs.lib.licenses.bsdOriginal ]; |
@@ -6,6 +6,7 b' configobj==5.0.6' | |||
|
6 | 6 | decorator==4.0.11 |
|
7 | 7 | dulwich==0.13.0 |
|
8 | 8 | hgsubversion==1.8.6 |
|
9 | hg-evolve==6.0.1 | |
|
9 | 10 | infrae.cache==1.0.1 |
|
10 | 11 | mercurial==4.1.2 |
|
11 | 12 | msgpack-python==0.4.8 |
@@ -35,9 +36,5 b' greenlet==0.4.10' | |||
|
35 | 36 | gunicorn==19.6.0 |
|
36 | 37 | waitress==1.0.1 |
|
37 | 38 | |
|
38 | # Pyro/Deprecated TODO(Marcink): remove in 4.7 release. | |
|
39 | Pyro4==4.41 | |
|
40 | serpent==1.15 | |
|
41 | ||
|
42 | 39 | ## test related requirements |
|
43 | 40 | -r requirements_test.txt |
@@ -26,7 +26,7 b' beaker.cache.repo_object.enabled = true' | |||
|
26 | 26 | ### LOGGING CONFIGURATION #### |
|
27 | 27 | ################################ |
|
28 | 28 | [loggers] |
|
29 |
keys = root, vcsserver, |
|
|
29 | keys = root, vcsserver, beaker | |
|
30 | 30 | |
|
31 | 31 | [handlers] |
|
32 | 32 | keys = console |
@@ -53,12 +53,6 b' handlers =' | |||
|
53 | 53 | qualname = beaker |
|
54 | 54 | propagate = 1 |
|
55 | 55 | |
|
56 | [logger_pyro4] | |
|
57 | level = DEBUG | |
|
58 | handlers = | |
|
59 | qualname = Pyro4 | |
|
60 | propagate = 1 | |
|
61 | ||
|
62 | 56 | |
|
63 | 57 | ############## |
|
64 | 58 | ## HANDLERS ## |
@@ -287,6 +287,25 b' class HgRemote(object):' | |||
|
287 | 287 | return [parent.rev() for parent in ctx.parents()] |
|
288 | 288 | |
|
289 | 289 | @reraise_safe_exceptions |
|
290 | def ctx_phase(self, wire, revision): | |
|
291 | repo = self._factory.repo(wire) | |
|
292 | ctx = repo[revision] | |
|
293 | # public=0, draft=1, secret=3 | |
|
294 | return ctx.phase() | |
|
295 | ||
|
296 | @reraise_safe_exceptions | |
|
297 | def ctx_obsolete(self, wire, revision): | |
|
298 | repo = self._factory.repo(wire) | |
|
299 | ctx = repo[revision] | |
|
300 | return ctx.obsolete() | |
|
301 | ||
|
302 | @reraise_safe_exceptions | |
|
303 | def ctx_hidden(self, wire, revision): | |
|
304 | repo = self._factory.repo(wire) | |
|
305 | ctx = repo[revision] | |
|
306 | return ctx.hidden() | |
|
307 | ||
|
308 | @reraise_safe_exceptions | |
|
290 | 309 | def ctx_substate(self, wire, revision): |
|
291 | 310 | repo = self._factory.repo(wire) |
|
292 | 311 | ctx = repo[revision] |
@@ -298,7 +317,7 b' class HgRemote(object):' | |||
|
298 | 317 | ctx = repo[revision] |
|
299 | 318 | status = repo[ctx.p1().node()].status(other=ctx.node()) |
|
300 | 319 | # object of status (odd, custom named tuple in mercurial) is not |
|
301 |
# correctly serializable |
|
|
320 | # correctly serializable, we make it a list, as the underling | |
|
302 | 321 | # API expects this to be a list |
|
303 | 322 | return list(status) |
|
304 | 323 |
@@ -30,7 +30,6 b' from httplib import HTTPConnection' | |||
|
30 | 30 | |
|
31 | 31 | import mercurial.scmutil |
|
32 | 32 | import mercurial.node |
|
33 | import Pyro4 | |
|
34 | 33 | import simplejson as json |
|
35 | 34 | |
|
36 | 35 | from vcsserver import exceptions |
@@ -68,18 +67,9 b' class HooksDummyClient(object):' | |||
|
68 | 67 | return getattr(hooks, hook_name)(extras) |
|
69 | 68 | |
|
70 | 69 | |
|
71 | class HooksPyro4Client(object): | |
|
72 | def __init__(self, hooks_uri): | |
|
73 | self.hooks_uri = hooks_uri | |
|
74 | ||
|
75 | def __call__(self, hook_name, extras): | |
|
76 | with Pyro4.Proxy(self.hooks_uri) as hooks: | |
|
77 | return getattr(hooks, hook_name)(extras) | |
|
78 | ||
|
79 | ||
|
80 | 70 | class RemoteMessageWriter(object): |
|
81 | 71 | """Writer base class.""" |
|
82 | def write(message): | |
|
72 | def write(self, message): | |
|
83 | 73 | raise NotImplementedError() |
|
84 | 74 | |
|
85 | 75 | |
@@ -126,11 +116,7 b' def _handle_exception(result):' | |||
|
126 | 116 | def _get_hooks_client(extras): |
|
127 | 117 | if 'hooks_uri' in extras: |
|
128 | 118 | protocol = extras.get('hooks_protocol') |
|
129 | return ( | |
|
130 | HooksHttpClient(extras['hooks_uri']) | |
|
131 | if protocol == 'http' | |
|
132 | else HooksPyro4Client(extras['hooks_uri']) | |
|
133 | ) | |
|
119 | return HooksHttpClient(extras['hooks_uri']) | |
|
134 | 120 | else: |
|
135 | 121 | return HooksDummyClient(extras['hooks_module']) |
|
136 | 122 | |
@@ -161,13 +147,25 b' def post_pull(ui, repo, **kwargs):' | |||
|
161 | 147 | return _call_hook('post_pull', _extras_from_ui(ui), HgMessageWriter(ui)) |
|
162 | 148 | |
|
163 | 149 | |
|
150 | def _rev_range_hash(repo, node): | |
|
151 | ||
|
152 | commits = [] | |
|
153 | for rev in xrange(repo[node], len(repo)): | |
|
154 | ctx = repo[rev] | |
|
155 | commit_id = mercurial.node.hex(ctx.node()) | |
|
156 | branch = ctx.branch() | |
|
157 | commits.append((commit_id, branch)) | |
|
158 | ||
|
159 | return commits | |
|
160 | ||
|
161 | ||
|
164 | 162 | def pre_push(ui, repo, node=None, **kwargs): |
|
165 | 163 | extras = _extras_from_ui(ui) |
|
166 | 164 | |
|
167 | 165 | rev_data = [] |
|
168 | 166 | if node and kwargs.get('hooktype') == 'pretxnchangegroup': |
|
169 | 167 | branches = collections.defaultdict(list) |
|
170 |
for commit_id, branch in _rev_range_hash(repo, node |
|
|
168 | for commit_id, branch in _rev_range_hash(repo, node): | |
|
171 | 169 | branches[branch].append(commit_id) |
|
172 | 170 | |
|
173 | 171 | for branch, commits in branches.iteritems(): |
@@ -184,30 +182,38 b' def pre_push(ui, repo, node=None, **kwar' | |||
|
184 | 182 | return _call_hook('pre_push', extras, HgMessageWriter(ui)) |
|
185 | 183 | |
|
186 | 184 | |
|
187 | def _rev_range_hash(repo, node, with_branch=False): | |
|
185 | def post_push(ui, repo, node, **kwargs): | |
|
186 | extras = _extras_from_ui(ui) | |
|
187 | ||
|
188 | commit_ids = [] | |
|
189 | branches = [] | |
|
190 | bookmarks = [] | |
|
191 | tags = [] | |
|
188 | 192 | |
|
189 | commits = [] | |
|
190 | for rev in xrange(repo[node], len(repo)): | |
|
191 | ctx = repo[rev] | |
|
192 | commit_id = mercurial.node.hex(ctx.node()) | |
|
193 | branch = ctx.branch() | |
|
194 | if with_branch: | |
|
195 | commits.append((commit_id, branch)) | |
|
196 | else: | |
|
197 | commits.append(commit_id) | |
|
193 | for commit_id, branch in _rev_range_hash(repo, node): | |
|
194 | commit_ids.append(commit_id) | |
|
195 | if branch not in branches: | |
|
196 | branches.append(branch) | |
|
198 | 197 | |
|
199 | return commits | |
|
200 | ||
|
198 | if hasattr(ui, '_rc_pushkey_branches'): | |
|
199 | bookmarks = ui._rc_pushkey_branches | |
|
201 | 200 | |
|
202 | def post_push(ui, repo, node, **kwargs): | |
|
203 | commit_ids = _rev_range_hash(repo, node) | |
|
204 | ||
|
205 | extras = _extras_from_ui(ui) | |
|
206 | 201 | extras['commit_ids'] = commit_ids |
|
202 | extras['new_refs'] = { | |
|
203 | 'branches': branches, | |
|
204 | 'bookmarks': bookmarks, | |
|
205 | 'tags': tags | |
|
206 | } | |
|
207 | 207 | |
|
208 | 208 | return _call_hook('post_push', extras, HgMessageWriter(ui)) |
|
209 | 209 | |
|
210 | 210 | |
|
211 | def key_push(ui, repo, **kwargs): | |
|
212 | if kwargs['new'] != '0' and kwargs['namespace'] == 'bookmarks': | |
|
213 | # store new bookmarks in our UI object propagated later to post_push | |
|
214 | ui._rc_pushkey_branches = repo[kwargs['key']].bookmarks() | |
|
215 | return | |
|
216 | ||
|
211 | 217 | # backward compat |
|
212 | 218 | log_pull_action = post_pull |
|
213 | 219 | |
@@ -327,12 +333,12 b' def _run_command(arguments):' | |||
|
327 | 333 | # Probably this should be using subprocessio. |
|
328 | 334 | process = subprocess.Popen( |
|
329 | 335 | arguments, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
|
330 |
stdout, |
|
|
336 | stdout, stderr = process.communicate() | |
|
331 | 337 | |
|
332 | 338 | if process.returncode != 0: |
|
333 | 339 | raise Exception( |
|
334 |
'Command %s exited with exit code %s' % ( |
|
|
335 | process.returncode)) | |
|
340 | 'Command %s exited with exit code %s: stderr:%s' % ( | |
|
341 | arguments, process.returncode, stderr)) | |
|
336 | 342 | |
|
337 | 343 | return stdout |
|
338 | 344 | |
@@ -359,10 +365,16 b' def git_post_receive(unused_repo_path, r' | |||
|
359 | 365 | # subcommand sets the PATH environment variable so that it point to the |
|
360 | 366 | # correct version of the git executable. |
|
361 | 367 | empty_commit_id = '0' * 40 |
|
368 | branches = [] | |
|
369 | tags = [] | |
|
362 | 370 | for push_ref in rev_data: |
|
363 | 371 | type_ = push_ref['type'] |
|
372 | ||
|
364 | 373 | if type_ == 'heads': |
|
365 | 374 | if push_ref['old_rev'] == empty_commit_id: |
|
375 | # starting new branch case | |
|
376 | if push_ref['name'] not in branches: | |
|
377 | branches.append(push_ref['name']) | |
|
366 | 378 | |
|
367 | 379 | # Fix up head revision if needed |
|
368 | 380 | cmd = ['git', 'show', 'HEAD'] |
@@ -386,14 +398,24 b' def git_post_receive(unused_repo_path, r' | |||
|
386 | 398 | # delete branch case |
|
387 | 399 | git_revs.append('delete_branch=>%s' % push_ref['name']) |
|
388 | 400 | else: |
|
401 | if push_ref['name'] not in branches: | |
|
402 | branches.append(push_ref['name']) | |
|
403 | ||
|
389 | 404 | cmd = ['git', 'log', |
|
390 | 405 | '{old_rev}..{new_rev}'.format(**push_ref), |
|
391 | 406 | '--reverse', '--pretty=format:%H'] |
|
392 | 407 | git_revs.extend(_run_command(cmd).splitlines()) |
|
393 | 408 | elif type_ == 'tags': |
|
409 | if push_ref['name'] not in tags: | |
|
410 | tags.append(push_ref['name']) | |
|
394 | 411 | git_revs.append('tag=>%s' % push_ref['name']) |
|
395 | 412 | |
|
396 | 413 | extras['commit_ids'] = git_revs |
|
414 | extras['new_refs'] = { | |
|
415 | 'branches': branches, | |
|
416 | 'bookmarks': [], | |
|
417 | 'tags': tags, | |
|
418 | } | |
|
397 | 419 | |
|
398 | 420 | if 'repo_size' in extras['hooks']: |
|
399 | 421 | try: |
@@ -95,7 +95,13 b' class GitRepository(object):' | |||
|
95 | 95 | |
|
96 | 96 | :param path: |
|
97 | 97 | """ |
|
98 |
|
|
|
98 | path = path.split(self.repo_name, 1)[-1] | |
|
99 | if path.startswith('.git'): | |
|
100 | # for bare repos we still get the .git prefix inside, we skip it | |
|
101 | # here, and remove from the service command | |
|
102 | path = path[4:] | |
|
103 | ||
|
104 | return path.strip('/') | |
|
99 | 105 | |
|
100 | 106 | def inforefs(self, request, unused_environ): |
|
101 | 107 | """ |
@@ -15,16 +15,5 b'' | |||
|
15 | 15 | # along with this program; if not, write to the Free Software Foundation, |
|
16 | 16 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
17 | 17 | |
|
18 | ||
|
19 | PYRO_PORT = 9900 | |
|
20 | ||
|
21 | PYRO_GIT = 'git_remote' | |
|
22 | PYRO_HG = 'hg_remote' | |
|
23 | PYRO_SVN = 'svn_remote' | |
|
24 | PYRO_VCSSERVER = 'vcs_server' | |
|
25 | PYRO_GIT_REMOTE_WSGI = 'git_remote_wsgi' | |
|
26 | PYRO_HG_REMOTE_WSGI = 'hg_remote_wsgi' | |
|
27 | ||
|
28 | 18 | WIRE_ENCODING = 'UTF-8' |
|
29 | ||
|
30 | 19 | GIT_EXECUTABLE = 'git' |
@@ -23,6 +23,7 b' import posixpath as vcspath' | |||
|
23 | 23 | import StringIO |
|
24 | 24 | import subprocess |
|
25 | 25 | import urllib |
|
26 | import traceback | |
|
26 | 27 | |
|
27 | 28 | import svn.client |
|
28 | 29 | import svn.core |
@@ -46,8 +47,17 b' svn_compatible_versions = set([' | |||
|
46 | 47 | 'pre-1.5-compatible', |
|
47 | 48 | 'pre-1.6-compatible', |
|
48 | 49 | 'pre-1.8-compatible', |
|
50 | 'pre-1.9-compatible', | |
|
49 | 51 | ]) |
|
50 | 52 | |
|
53 | svn_compatible_versions_map = { | |
|
54 | 'pre-1.4-compatible': '1.3', | |
|
55 | 'pre-1.5-compatible': '1.4', | |
|
56 | 'pre-1.6-compatible': '1.5', | |
|
57 | 'pre-1.8-compatible': '1.7', | |
|
58 | 'pre-1.9-compatible': '1.8', | |
|
59 | } | |
|
60 | ||
|
51 | 61 | |
|
52 | 62 | def reraise_safe_exceptions(func): |
|
53 | 63 | """Decorator for converting svn exceptions to something neutral.""" |
@@ -67,14 +77,15 b' class SubversionFactory(RepoFactory):' | |||
|
67 | 77 | def _create_repo(self, wire, create, compatible_version): |
|
68 | 78 | path = svn.core.svn_path_canonicalize(wire['path']) |
|
69 | 79 | if create: |
|
70 | fs_config = {} | |
|
80 | fs_config = {'compatible-version': '1.9'} | |
|
71 | 81 | if compatible_version: |
|
72 | 82 | if compatible_version not in svn_compatible_versions: |
|
73 | 83 | raise Exception('Unknown SVN compatible version "{}"' |
|
74 | 84 | .format(compatible_version)) |
|
75 | log.debug('Create SVN repo with compatible version "%s"', | |
|
76 |
|
|
|
77 | fs_config[compatible_version] = '1' | |
|
85 | fs_config['compatible-version'] = \ | |
|
86 | svn_compatible_versions_map[compatible_version] | |
|
87 | ||
|
88 | log.debug('Create SVN repo with config "%s"', fs_config) | |
|
78 | 89 | repo = svn.repos.create(path, "", "", None, fs_config) |
|
79 | 90 | else: |
|
80 | 91 | repo = svn.repos.open(path) |
@@ -87,7 +98,6 b' class SubversionFactory(RepoFactory):' | |||
|
87 | 98 | return self._repo(wire, create_new_repo) |
|
88 | 99 | |
|
89 | 100 | |
|
90 | ||
|
91 | 101 | NODE_TYPE_MAPPING = { |
|
92 | 102 | svn.core.svn_node_file: 'file', |
|
93 | 103 | svn.core.svn_node_dir: 'dir', |
@@ -120,8 +130,9 b' class SvnRemote(object):' | |||
|
120 | 130 | # throws exception |
|
121 | 131 | try: |
|
122 | 132 | svnrepo.svnremoterepo(baseui, url).svn.uuid |
|
123 | except: | |
|
124 | log.debug("Invalid svn url: %s", url) | |
|
133 | except Exception: | |
|
134 | tb = traceback.format_exc() | |
|
135 | log.debug("Invalid Subversion url: `%s`, tb: %s", url, tb) | |
|
125 | 136 | raise URLError( |
|
126 | 137 | '"%s" is not a valid Subversion source url.' % (url, )) |
|
127 | 138 | return True |
@@ -130,10 +141,23 b' class SvnRemote(object):' | |||
|
130 | 141 | try: |
|
131 | 142 | svn.repos.open(path) |
|
132 | 143 | except svn.core.SubversionException: |
|
133 | log.debug("Invalid Subversion path %s", path) | |
|
144 | tb = traceback.format_exc() | |
|
145 | log.debug("Invalid Subversion path `%s`, tb: %s", path, tb) | |
|
134 | 146 | return False |
|
135 | 147 | return True |
|
136 | 148 | |
|
149 | @reraise_safe_exceptions | |
|
150 | def verify(self, wire,): | |
|
151 | repo_path = wire['path'] | |
|
152 | if not self.is_path_valid_repository(wire, repo_path): | |
|
153 | raise Exception( | |
|
154 | "Path %s is not a valid Subversion repository." % repo_path) | |
|
155 | ||
|
156 | load = subprocess.Popen( | |
|
157 | ['svnadmin', 'info', repo_path], | |
|
158 | stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
|
159 | return ''.join(load.stdout) | |
|
160 | ||
|
137 | 161 | def lookup(self, wire, revision): |
|
138 | 162 | if revision not in [-1, None, 'HEAD']: |
|
139 | 163 | raise NotImplementedError |
@@ -29,46 +29,6 b' import simplejson as json' | |||
|
29 | 29 | from vcsserver import hooks |
|
30 | 30 | |
|
31 | 31 | |
|
32 | class HooksStub(object): | |
|
33 | """ | |
|
34 | Simulates a Proy4.Proxy object. | |
|
35 | ||
|
36 | Will always return `result`, no matter which hook has been called on it. | |
|
37 | """ | |
|
38 | ||
|
39 | def __init__(self, result): | |
|
40 | self._result = result | |
|
41 | ||
|
42 | def __call__(self, hooks_uri): | |
|
43 | return self | |
|
44 | ||
|
45 | def __enter__(self): | |
|
46 | return self | |
|
47 | ||
|
48 | def __exit__(self, exc_type, exc_value, traceback): | |
|
49 | pass | |
|
50 | ||
|
51 | def __getattr__(self, name): | |
|
52 | return mock.Mock(return_value=self._result) | |
|
53 | ||
|
54 | ||
|
55 | @contextlib.contextmanager | |
|
56 | def mock_hook_response( | |
|
57 | status=0, output='', exception=None, exception_args=None): | |
|
58 | response = { | |
|
59 | 'status': status, | |
|
60 | 'output': output, | |
|
61 | } | |
|
62 | if exception: | |
|
63 | response.update({ | |
|
64 | 'exception': exception, | |
|
65 | 'exception_args': exception_args, | |
|
66 | }) | |
|
67 | ||
|
68 | with mock.patch('Pyro4.Proxy', HooksStub(response)): | |
|
69 | yield | |
|
70 | ||
|
71 | ||
|
72 | 32 | def get_hg_ui(extras=None): |
|
73 | 33 | """Create a Config object with a valid RC_SCM_DATA entry.""" |
|
74 | 34 | extras = extras or {} |
@@ -89,126 +49,6 b' def get_hg_ui(extras=None):' | |||
|
89 | 49 | return hg_ui |
|
90 | 50 | |
|
91 | 51 | |
|
92 | def test_call_hook_no_error(capsys): | |
|
93 | extras = { | |
|
94 | 'hooks_uri': 'fake_hook_uri', | |
|
95 | } | |
|
96 | expected_output = 'My mock outptut' | |
|
97 | writer = mock.Mock() | |
|
98 | ||
|
99 | with mock_hook_response(status=1, output=expected_output): | |
|
100 | hooks._call_hook('hook_name', extras, writer) | |
|
101 | ||
|
102 | out, err = capsys.readouterr() | |
|
103 | ||
|
104 | writer.write.assert_called_with(expected_output) | |
|
105 | assert err == '' | |
|
106 | ||
|
107 | ||
|
108 | def test_call_hook_with_exception(capsys): | |
|
109 | extras = { | |
|
110 | 'hooks_uri': 'fake_hook_uri', | |
|
111 | } | |
|
112 | expected_output = 'My mock outptut' | |
|
113 | writer = mock.Mock() | |
|
114 | ||
|
115 | with mock_hook_response(status=1, output=expected_output, | |
|
116 | exception='TypeError', | |
|
117 | exception_args=('Mock exception', )): | |
|
118 | with pytest.raises(Exception) as excinfo: | |
|
119 | hooks._call_hook('hook_name', extras, writer) | |
|
120 | ||
|
121 | assert excinfo.type == Exception | |
|
122 | assert 'Mock exception' in str(excinfo.value) | |
|
123 | ||
|
124 | out, err = capsys.readouterr() | |
|
125 | ||
|
126 | writer.write.assert_called_with(expected_output) | |
|
127 | assert err == '' | |
|
128 | ||
|
129 | ||
|
130 | def test_call_hook_with_locked_exception(capsys): | |
|
131 | extras = { | |
|
132 | 'hooks_uri': 'fake_hook_uri', | |
|
133 | } | |
|
134 | expected_output = 'My mock outptut' | |
|
135 | writer = mock.Mock() | |
|
136 | ||
|
137 | with mock_hook_response(status=1, output=expected_output, | |
|
138 | exception='HTTPLockedRC', | |
|
139 | exception_args=('message',)): | |
|
140 | with pytest.raises(Exception) as excinfo: | |
|
141 | hooks._call_hook('hook_name', extras, writer) | |
|
142 | ||
|
143 | assert excinfo.value._vcs_kind == 'repo_locked' | |
|
144 | assert 'message' == str(excinfo.value) | |
|
145 | ||
|
146 | out, err = capsys.readouterr() | |
|
147 | ||
|
148 | writer.write.assert_called_with(expected_output) | |
|
149 | assert err == '' | |
|
150 | ||
|
151 | ||
|
152 | def test_call_hook_with_stdout(): | |
|
153 | extras = { | |
|
154 | 'hooks_uri': 'fake_hook_uri', | |
|
155 | } | |
|
156 | expected_output = 'My mock outptut' | |
|
157 | ||
|
158 | stdout = io.BytesIO() | |
|
159 | with mock_hook_response(status=1, output=expected_output): | |
|
160 | hooks._call_hook('hook_name', extras, stdout) | |
|
161 | ||
|
162 | assert stdout.getvalue() == expected_output | |
|
163 | ||
|
164 | ||
|
165 | def test_repo_size(): | |
|
166 | hg_ui = get_hg_ui() | |
|
167 | ||
|
168 | with mock_hook_response(status=1): | |
|
169 | assert hooks.repo_size(hg_ui, None) == 1 | |
|
170 | ||
|
171 | ||
|
172 | def test_pre_pull(): | |
|
173 | hg_ui = get_hg_ui() | |
|
174 | ||
|
175 | with mock_hook_response(status=1): | |
|
176 | assert hooks.pre_pull(hg_ui, None) == 1 | |
|
177 | ||
|
178 | ||
|
179 | def test_post_pull(): | |
|
180 | hg_ui = get_hg_ui() | |
|
181 | ||
|
182 | with mock_hook_response(status=1): | |
|
183 | assert hooks.post_pull(hg_ui, None) == 1 | |
|
184 | ||
|
185 | ||
|
186 | def test_pre_push(): | |
|
187 | hg_ui = get_hg_ui() | |
|
188 | ||
|
189 | with mock_hook_response(status=1): | |
|
190 | assert hooks.pre_push(hg_ui, None) == 1 | |
|
191 | ||
|
192 | ||
|
193 | def test_post_push(): | |
|
194 | hg_ui = get_hg_ui() | |
|
195 | ||
|
196 | with mock_hook_response(status=1): | |
|
197 | with mock.patch('vcsserver.hooks._rev_range_hash', return_value=[]): | |
|
198 | assert hooks.post_push(hg_ui, None, None) == 1 | |
|
199 | ||
|
200 | ||
|
201 | def test_git_pre_receive(): | |
|
202 | extras = { | |
|
203 | 'hooks': ['push'], | |
|
204 | 'hooks_uri': 'fake_hook_uri', | |
|
205 | } | |
|
206 | with mock_hook_response(status=1): | |
|
207 | response = hooks.git_pre_receive(None, None, | |
|
208 | {'RC_SCM_DATA': json.dumps(extras)}) | |
|
209 | assert response == 1 | |
|
210 | ||
|
211 | ||
|
212 | 52 | def test_git_pre_receive_is_disabled(): |
|
213 | 53 | extras = {'hooks': ['pull']} |
|
214 | 54 | response = hooks.git_pre_receive(None, None, |
@@ -217,18 +57,6 b' def test_git_pre_receive_is_disabled():' | |||
|
217 | 57 | assert response == 0 |
|
218 | 58 | |
|
219 | 59 | |
|
220 | def test_git_post_receive_no_subprocess_call(): | |
|
221 | extras = { | |
|
222 | 'hooks': ['push'], | |
|
223 | 'hooks_uri': 'fake_hook_uri', | |
|
224 | } | |
|
225 | # Setting revision_lines to '' avoid all subprocess_calls | |
|
226 | with mock_hook_response(status=1): | |
|
227 | response = hooks.git_post_receive(None, '', | |
|
228 | {'RC_SCM_DATA': json.dumps(extras)}) | |
|
229 | assert response == 1 | |
|
230 | ||
|
231 | ||
|
232 | 60 | def test_git_post_receive_is_disabled(): |
|
233 | 61 | extras = {'hooks': ['pull']} |
|
234 | 62 | response = hooks.git_post_receive(None, '', |
@@ -242,7 +70,8 b' def test_git_post_receive_calls_repo_siz' | |||
|
242 | 70 | with mock.patch.object(hooks, '_call_hook') as call_hook_mock: |
|
243 | 71 | hooks.git_post_receive( |
|
244 | 72 | None, '', {'RC_SCM_DATA': json.dumps(extras)}) |
|
245 |
extras.update({'commit_ids': [] |
|
|
73 | extras.update({'commit_ids': [], | |
|
74 | 'new_refs': {'bookmarks': [], 'branches': [], 'tags': []}}) | |
|
246 | 75 | expected_calls = [ |
|
247 | 76 | mock.call('repo_size', extras, mock.ANY), |
|
248 | 77 | mock.call('post_push', extras, mock.ANY), |
@@ -255,7 +84,8 b' def test_git_post_receive_does_not_call_' | |||
|
255 | 84 | with mock.patch.object(hooks, '_call_hook') as call_hook_mock: |
|
256 | 85 | hooks.git_post_receive( |
|
257 | 86 | None, '', {'RC_SCM_DATA': json.dumps(extras)}) |
|
258 |
extras.update({'commit_ids': [] |
|
|
87 | extras.update({'commit_ids': [], | |
|
88 | 'new_refs': {'bookmarks': [], 'branches': [], 'tags': []}}) | |
|
259 | 89 | expected_calls = [ |
|
260 | 90 | mock.call('post_push', extras, mock.ANY) |
|
261 | 91 | ] |
@@ -279,122 +109,16 b' def test_repo_size_exception_does_not_af' | |||
|
279 | 109 | assert result == status |
|
280 | 110 | |
|
281 | 111 | |
|
282 | @mock.patch('vcsserver.hooks._run_command') | |
|
283 | def test_git_post_receive_first_commit_sub_branch(cmd_mock): | |
|
284 | def cmd_mock_returns(args): | |
|
285 | if args == ['git', 'show', 'HEAD']: | |
|
286 | raise | |
|
287 | if args == ['git', 'for-each-ref', '--format=%(refname)', | |
|
288 | 'refs/heads/*']: | |
|
289 | return 'refs/heads/test-branch2/sub-branch' | |
|
290 | if args == ['git', 'log', '--reverse', '--pretty=format:%H', '--', | |
|
291 | '9695eef57205c17566a3ae543be187759b310bb7', '--not', | |
|
292 | 'refs/heads/test-branch2/sub-branch']: | |
|
293 | return '' | |
|
294 | ||
|
295 | cmd_mock.side_effect = cmd_mock_returns | |
|
296 | ||
|
297 | extras = { | |
|
298 | 'hooks': ['push'], | |
|
299 | 'hooks_uri': 'fake_hook_uri' | |
|
300 | } | |
|
301 | rev_lines = ['0000000000000000000000000000000000000000 ' | |
|
302 | '9695eef57205c17566a3ae543be187759b310bb7 ' | |
|
303 | 'refs/heads/feature/sub-branch\n'] | |
|
304 | with mock_hook_response(status=0): | |
|
305 | response = hooks.git_post_receive(None, rev_lines, | |
|
306 | {'RC_SCM_DATA': json.dumps(extras)}) | |
|
307 | ||
|
308 | calls = [ | |
|
309 | mock.call(['git', 'show', 'HEAD']), | |
|
310 | mock.call(['git', 'symbolic-ref', 'HEAD', | |
|
311 | 'refs/heads/feature/sub-branch']), | |
|
312 | ] | |
|
313 | cmd_mock.assert_has_calls(calls, any_order=True) | |
|
314 | assert response == 0 | |
|
315 | ||
|
316 | ||
|
317 | @mock.patch('vcsserver.hooks._run_command') | |
|
318 | def test_git_post_receive_first_commit_revs(cmd_mock): | |
|
319 | extras = { | |
|
320 | 'hooks': ['push'], | |
|
321 | 'hooks_uri': 'fake_hook_uri' | |
|
322 | } | |
|
323 | rev_lines = [ | |
|
324 | '0000000000000000000000000000000000000000 ' | |
|
325 | '9695eef57205c17566a3ae543be187759b310bb7 refs/heads/master\n'] | |
|
326 | with mock_hook_response(status=0): | |
|
327 | response = hooks.git_post_receive( | |
|
328 | None, rev_lines, {'RC_SCM_DATA': json.dumps(extras)}) | |
|
329 | ||
|
330 | calls = [ | |
|
331 | mock.call(['git', 'show', 'HEAD']), | |
|
332 | mock.call(['git', 'for-each-ref', '--format=%(refname)', | |
|
333 | 'refs/heads/*']), | |
|
334 | mock.call(['git', 'log', '--reverse', '--pretty=format:%H', | |
|
335 | '--', '9695eef57205c17566a3ae543be187759b310bb7', '--not', | |
|
336 | '']) | |
|
337 | ] | |
|
338 | cmd_mock.assert_has_calls(calls, any_order=True) | |
|
339 | ||
|
340 | assert response == 0 | |
|
341 | ||
|
342 | ||
|
343 | def test_git_pre_pull(): | |
|
344 | extras = { | |
|
345 | 'hooks': ['pull'], | |
|
346 | 'hooks_uri': 'fake_hook_uri', | |
|
347 | } | |
|
348 | with mock_hook_response(status=1, output='foo'): | |
|
349 | assert hooks.git_pre_pull(extras) == hooks.HookResponse(1, 'foo') | |
|
350 | ||
|
351 | ||
|
352 | def test_git_pre_pull_exception_is_caught(): | |
|
353 | extras = { | |
|
354 | 'hooks': ['pull'], | |
|
355 | 'hooks_uri': 'fake_hook_uri', | |
|
356 | } | |
|
357 | with mock_hook_response(status=2, exception=Exception('foo')): | |
|
358 | assert hooks.git_pre_pull(extras).status == 128 | |
|
359 | ||
|
360 | ||
|
361 | 112 | def test_git_pre_pull_is_disabled(): |
|
362 | 113 | assert hooks.git_pre_pull({'hooks': ['push']}) == hooks.HookResponse(0, '') |
|
363 | 114 | |
|
364 | 115 | |
|
365 | def test_git_post_pull(): | |
|
366 | extras = { | |
|
367 | 'hooks': ['pull'], | |
|
368 | 'hooks_uri': 'fake_hook_uri', | |
|
369 | } | |
|
370 | with mock_hook_response(status=1, output='foo'): | |
|
371 | assert hooks.git_post_pull(extras) == hooks.HookResponse(1, 'foo') | |
|
372 | ||
|
373 | ||
|
374 | def test_git_post_pull_exception_is_caught(): | |
|
375 | extras = { | |
|
376 | 'hooks': ['pull'], | |
|
377 | 'hooks_uri': 'fake_hook_uri', | |
|
378 | } | |
|
379 | with mock_hook_response(status=2, exception='Exception', | |
|
380 | exception_args=('foo',)): | |
|
381 | assert hooks.git_post_pull(extras).status == 128 | |
|
382 | ||
|
383 | ||
|
384 | 116 | def test_git_post_pull_is_disabled(): |
|
385 | 117 | assert ( |
|
386 | 118 | hooks.git_post_pull({'hooks': ['push']}) == hooks.HookResponse(0, '')) |
|
387 | 119 | |
|
388 | 120 | |
|
389 | 121 | class TestGetHooksClient(object): |
|
390 | def test_returns_pyro_client_when_protocol_matches(self): | |
|
391 | hooks_uri = 'localhost:8000' | |
|
392 | result = hooks._get_hooks_client({ | |
|
393 | 'hooks_uri': hooks_uri, | |
|
394 | 'hooks_protocol': 'pyro4' | |
|
395 | }) | |
|
396 | assert isinstance(result, hooks.HooksPyro4Client) | |
|
397 | assert result.hooks_uri == hooks_uri | |
|
398 | 122 | |
|
399 | 123 | def test_returns_http_client_when_protocol_matches(self): |
|
400 | 124 | hooks_uri = 'localhost:8000' |
@@ -405,14 +129,6 b' class TestGetHooksClient(object):' | |||
|
405 | 129 | assert isinstance(result, hooks.HooksHttpClient) |
|
406 | 130 | assert result.hooks_uri == hooks_uri |
|
407 | 131 | |
|
408 | def test_returns_pyro4_client_when_no_protocol_is_specified(self): | |
|
409 | hooks_uri = 'localhost:8000' | |
|
410 | result = hooks._get_hooks_client({ | |
|
411 | 'hooks_uri': hooks_uri | |
|
412 | }) | |
|
413 | assert isinstance(result, hooks.HooksPyro4Client) | |
|
414 | assert result.hooks_uri == hooks_uri | |
|
415 | ||
|
416 | 132 | def test_returns_dummy_client_when_hooks_uri_not_specified(self): |
|
417 | 133 | fake_module = mock.Mock() |
|
418 | 134 | import_patcher = mock.patch.object( |
@@ -487,30 +203,6 b' class TestHooksDummyClient(object):' | |||
|
487 | 203 | assert result == hooks_module.Hooks().__enter__().post_push() |
|
488 | 204 | |
|
489 | 205 | |
|
490 | class TestHooksPyro4Client(object): | |
|
491 | def test_init_sets_hooks_uri(self): | |
|
492 | uri = 'localhost:3000' | |
|
493 | client = hooks.HooksPyro4Client(uri) | |
|
494 | assert client.hooks_uri == uri | |
|
495 | ||
|
496 | def test_call_returns_hook_value(self): | |
|
497 | hooks_uri = 'localhost:3000' | |
|
498 | client = hooks.HooksPyro4Client(hooks_uri) | |
|
499 | hooks_module = mock.Mock() | |
|
500 | context_manager = mock.MagicMock() | |
|
501 | context_manager.__enter__.return_value = hooks_module | |
|
502 | pyro4_patcher = mock.patch.object( | |
|
503 | hooks.Pyro4, 'Proxy', return_value=context_manager) | |
|
504 | extras = { | |
|
505 | 'test': 'test' | |
|
506 | } | |
|
507 | with pyro4_patcher as pyro4_mock: | |
|
508 | result = client('post_push', extras) | |
|
509 | pyro4_mock.assert_called_once_with(hooks_uri) | |
|
510 | hooks_module.post_push.assert_called_once_with(extras) | |
|
511 | assert result == hooks_module.post_push.return_value | |
|
512 | ||
|
513 | ||
|
514 | 206 | @pytest.fixture |
|
515 | 207 | def http_mirror(request): |
|
516 | 208 | server = MirrorHttpServer() |
@@ -18,24 +18,24 b'' | |||
|
18 | 18 | import mock |
|
19 | 19 | import pytest |
|
20 | 20 | |
|
21 | from vcsserver import main | |
|
21 | from vcsserver import http_main | |
|
22 | 22 | from vcsserver.base import obfuscate_qs |
|
23 | 23 | |
|
24 | 24 | |
|
25 |
@mock.patch('vcsserver.main.V |
|
|
25 | @mock.patch('vcsserver.http_main.VCS', mock.Mock()) | |
|
26 | 26 | @mock.patch('vcsserver.hgpatches.patch_largefiles_capabilities') |
|
27 | 27 | def test_applies_largefiles_patch(patch_largefiles_capabilities): |
|
28 | main.main([]) | |
|
28 | http_main.main([]) | |
|
29 | 29 | patch_largefiles_capabilities.assert_called_once_with() |
|
30 | 30 | |
|
31 | 31 | |
|
32 |
@mock.patch('vcsserver.main.V |
|
|
33 | @mock.patch('vcsserver.main.MercurialFactory', None) | |
|
32 | @mock.patch('vcsserver.http_main.VCS', mock.Mock()) | |
|
33 | @mock.patch('vcsserver.http_main.MercurialFactory', None) | |
|
34 | 34 | @mock.patch( |
|
35 | 35 | 'vcsserver.hgpatches.patch_largefiles_capabilities', |
|
36 | 36 | mock.Mock(side_effect=Exception("Must not be called"))) |
|
37 | 37 | def test_applies_largefiles_patch_only_if_mercurial_is_available(): |
|
38 | main.main([]) | |
|
38 | http_main.main([]) | |
|
39 | 39 | |
|
40 | 40 | |
|
41 | 41 | @pytest.mark.parametrize('given, expected', [ |
@@ -46,7 +46,7 b' class RequestWrapperTween(object):' | |||
|
46 | 46 | finally: |
|
47 | 47 | end = time.time() |
|
48 | 48 | |
|
49 | log.info('IP: %s Request to %s time: %.3fs' % ( | |
|
49 | log.info('IP: %s Request to path: `%s` time: %.3fs' % ( | |
|
50 | 50 | '127.0.0.1', |
|
51 | 51 | safe_str(get_access_path(request)), end - start) |
|
52 | 52 | ) |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed | |
This diff has been collapsed as it changes many lines, (508 lines changed) Show them Hide them |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now