Show More
@@ -1,5 +1,5 b'' | |||||
1 | [bumpversion] |
|
1 | [bumpversion] | |
2 |
current_version = 4. |
|
2 | current_version = 4.8.0 | |
3 | message = release: Bump version {current_version} to {new_version} |
|
3 | message = release: Bump version {current_version} to {new_version} | |
4 |
|
4 | |||
5 | [bumpversion:file:vcsserver/VERSION] |
|
5 | [bumpversion:file:vcsserver/VERSION] |
@@ -5,12 +5,10 b' done = false' | |||||
5 | done = true |
|
5 | done = true | |
6 |
|
6 | |||
7 | [task:fixes_on_stable] |
|
7 | [task:fixes_on_stable] | |
8 | done = true |
|
|||
9 |
|
8 | |||
10 | [task:pip2nix_generated] |
|
9 | [task:pip2nix_generated] | |
11 | done = true |
|
|||
12 |
|
10 | |||
13 | [release] |
|
11 | [release] | |
14 |
state = |
|
12 | state = in_progress | |
15 |
version = 4. |
|
13 | version = 4.8.0 | |
16 |
|
14 |
@@ -32,7 +32,7 b' use = egg:waitress#main' | |||||
32 | ### LOGGING CONFIGURATION #### |
|
32 | ### LOGGING CONFIGURATION #### | |
33 | ################################ |
|
33 | ################################ | |
34 | [loggers] |
|
34 | [loggers] | |
35 |
keys = root, vcsserver, |
|
35 | keys = root, vcsserver, beaker | |
36 |
|
36 | |||
37 | [handlers] |
|
37 | [handlers] | |
38 | keys = console |
|
38 | keys = console | |
@@ -59,12 +59,6 b' handlers =' | |||||
59 | qualname = beaker |
|
59 | qualname = beaker | |
60 | propagate = 1 |
|
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 | ## HANDLERS ## |
|
64 | ## HANDLERS ## |
@@ -20,8 +20,7 b' use = egg:gunicorn#main' | |||||
20 | workers = 2 |
|
20 | workers = 2 | |
21 | ## process name |
|
21 | ## process name | |
22 | proc_name = rhodecode_vcsserver |
|
22 | proc_name = rhodecode_vcsserver | |
23 |
## type of worker class, |
|
23 | ## type of worker class, currently `sync` is the only option allowed. | |
24 | ## recommended for bigger setup is using of of other than sync one |
|
|||
25 | worker_class = sync |
|
24 | worker_class = sync | |
26 | ## The maximum number of simultaneous clients. Valid only for Gevent |
|
25 | ## The maximum number of simultaneous clients. Valid only for Gevent | |
27 | #worker_connections = 10 |
|
26 | #worker_connections = 10 | |
@@ -56,7 +55,7 b' beaker.cache.repo_object.enabled = true' | |||||
56 | ### LOGGING CONFIGURATION #### |
|
55 | ### LOGGING CONFIGURATION #### | |
57 | ################################ |
|
56 | ################################ | |
58 | [loggers] |
|
57 | [loggers] | |
59 |
keys = root, vcsserver, |
|
58 | keys = root, vcsserver, beaker | |
60 |
|
59 | |||
61 | [handlers] |
|
60 | [handlers] | |
62 | keys = console |
|
61 | keys = console | |
@@ -83,12 +82,6 b' handlers =' | |||||
83 | qualname = beaker |
|
82 | qualname = beaker | |
84 | propagate = 1 |
|
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 | ## HANDLERS ## |
|
87 | ## HANDLERS ## |
@@ -120,6 +120,7 b' let' | |||||
120 | cp -v vcsserver/VERSION $out/nix-support/rccontrol/version |
|
120 | cp -v vcsserver/VERSION $out/nix-support/rccontrol/version | |
121 | echo "DONE: Meta information for rccontrol written" |
|
121 | echo "DONE: Meta information for rccontrol written" | |
122 |
|
122 | |||
|
123 | # python based programs need to be wrapped | |||
123 | ln -s ${self.pyramid}/bin/* $out/bin/ |
|
124 | ln -s ${self.pyramid}/bin/* $out/bin/ | |
124 | ln -s ${self.gunicorn}/bin/gunicorn $out/bin/ |
|
125 | ln -s ${self.gunicorn}/bin/gunicorn $out/bin/ | |
125 |
|
126 | |||
@@ -132,12 +133,14 b' let' | |||||
132 | ln -s ${self.mercurial}/bin/hg $out/bin |
|
133 | ln -s ${self.mercurial}/bin/hg $out/bin | |
133 | ln -s ${pkgs.subversion}/bin/svn* $out/bin |
|
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 | wrapProgram $file \ |
|
138 | wrapProgram $file \ | |
137 | --set PATH $PATH \ |
|
139 | --set PATH $PATH \ | |
138 | --set PYTHONPATH $PYTHONPATH \ |
|
140 | --set PYTHONPATH $PYTHONPATH \ | |
139 | --set PYTHONHASHSEED random |
|
141 | --set PYTHONHASHSEED random | |
140 | done |
|
142 | done | |
|
143 | ||||
141 | ''; |
|
144 | ''; | |
142 |
|
145 | |||
143 | }); |
|
146 | }); |
@@ -67,19 +67,6 b'' | |||||
67 | license = [ pkgs.lib.licenses.mit ]; |
|
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 | WebOb = super.buildPythonPackage { |
|
70 | WebOb = super.buildPythonPackage { | |
84 | name = "WebOb-1.3.1"; |
|
71 | name = "WebOb-1.3.1"; | |
85 | buildInputs = with self; []; |
|
72 | buildInputs = with self; []; | |
@@ -249,6 +236,19 b'' | |||||
249 | license = [ pkgs.lib.licenses.mit ]; |
|
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 | hgsubversion = super.buildPythonPackage { |
|
252 | hgsubversion = super.buildPythonPackage { | |
253 | name = "hgsubversion-1.8.6"; |
|
253 | name = "hgsubversion-1.8.6"; | |
254 | buildInputs = with self; []; |
|
254 | buildInputs = with self; []; | |
@@ -302,13 +302,13 b'' | |||||
302 | }; |
|
302 | }; | |
303 | }; |
|
303 | }; | |
304 | ipython-genutils = super.buildPythonPackage { |
|
304 | ipython-genutils = super.buildPythonPackage { | |
305 |
name = "ipython-genutils-0. |
|
305 | name = "ipython-genutils-0.2.0"; | |
306 | buildInputs = with self; []; |
|
306 | buildInputs = with self; []; | |
307 | doCheck = false; |
|
307 | doCheck = false; | |
308 | propagatedBuildInputs = with self; []; |
|
308 | propagatedBuildInputs = with self; []; | |
309 | src = fetchurl { |
|
309 | src = fetchurl { | |
310 |
url = "https://pypi.python.org/packages/71 |
|
310 | url = "https://pypi.python.org/packages/e8/69/fbeffffc05236398ebfcfb512b6d2511c622871dca1746361006da310399/ipython_genutils-0.2.0.tar.gz"; | |
311 | md5 = "9a8afbe0978adbcbfcb3b35b2d015a56"; |
|
311 | md5 = "5a4f9781f78466da0ea1a648f3e1f79f"; | |
312 | }; |
|
312 | }; | |
313 | meta = { |
|
313 | meta = { | |
314 | license = [ pkgs.lib.licenses.bsdOriginal ]; |
|
314 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
@@ -393,13 +393,13 b'' | |||||
393 | }; |
|
393 | }; | |
394 | }; |
|
394 | }; | |
395 | prompt-toolkit = super.buildPythonPackage { |
|
395 | prompt-toolkit = super.buildPythonPackage { | |
396 |
name = "prompt-toolkit-1.0. |
|
396 | name = "prompt-toolkit-1.0.14"; | |
397 | buildInputs = with self; []; |
|
397 | buildInputs = with self; []; | |
398 | doCheck = false; |
|
398 | doCheck = false; | |
399 | propagatedBuildInputs = with self; [six wcwidth]; |
|
399 | propagatedBuildInputs = with self; [six wcwidth]; | |
400 | src = fetchurl { |
|
400 | src = fetchurl { | |
401 |
url = "https://pypi.python.org/packages/83 |
|
401 | url = "https://pypi.python.org/packages/55/56/8c39509b614bda53e638b7500f12577d663ac1b868aef53426fc6a26c3f5/prompt_toolkit-1.0.14.tar.gz"; | |
402 | md5 = "a39f91a54308fb7446b1a421c11f227c"; |
|
402 | md5 = "f24061ae133ed32c6b764e92bd48c496"; | |
403 | }; |
|
403 | }; | |
404 | meta = { |
|
404 | meta = { | |
405 | license = [ pkgs.lib.licenses.bsdOriginal ]; |
|
405 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
@@ -588,28 +588,15 b'' | |||||
588 | }; |
|
588 | }; | |
589 | }; |
|
589 | }; | |
590 | rhodecode-vcsserver = super.buildPythonPackage { |
|
590 | rhodecode-vcsserver = super.buildPythonPackage { | |
591 |
name = "rhodecode-vcsserver-4. |
|
591 | name = "rhodecode-vcsserver-4.8.0"; | |
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]; |
|
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 | doCheck = true; |
|
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 | src = ./.; |
|
595 | src = ./.; | |
596 | meta = { |
|
596 | meta = { | |
597 | license = [ { fullName = "GPL V3"; } { fullName = "GNU General Public License v3 or later (GPLv3+)"; } ]; |
|
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 | setuptools = super.buildPythonPackage { |
|
600 | setuptools = super.buildPythonPackage { | |
614 | name = "setuptools-30.1.0"; |
|
601 | name = "setuptools-30.1.0"; | |
615 | buildInputs = with self; []; |
|
602 | buildInputs = with self; []; | |
@@ -702,13 +689,13 b'' | |||||
702 | }; |
|
689 | }; | |
703 | }; |
|
690 | }; | |
704 | traitlets = super.buildPythonPackage { |
|
691 | traitlets = super.buildPythonPackage { | |
705 |
name = "traitlets-4.3. |
|
692 | name = "traitlets-4.3.2"; | |
706 | buildInputs = with self; []; |
|
693 | buildInputs = with self; []; | |
707 | doCheck = false; |
|
694 | doCheck = false; | |
708 | propagatedBuildInputs = with self; [ipython-genutils six decorator enum34]; |
|
695 | propagatedBuildInputs = with self; [ipython-genutils six decorator enum34]; | |
709 | src = fetchurl { |
|
696 | src = fetchurl { | |
710 |
url = "https://pypi.python.org/packages/ |
|
697 | url = "https://pypi.python.org/packages/a5/98/7f5ef2fe9e9e071813aaf9cb91d1a732e0a68b6c44a32b38cb8e14c3f069/traitlets-4.3.2.tar.gz"; | |
711 | md5 = "dd0b1b6e5d31ce446d55a4b5e5083c98"; |
|
698 | md5 = "3068663f2f38fd939a9eb3a500ccc154"; | |
712 | }; |
|
699 | }; | |
713 | meta = { |
|
700 | meta = { | |
714 | license = [ pkgs.lib.licenses.bsdOriginal ]; |
|
701 | license = [ pkgs.lib.licenses.bsdOriginal ]; |
@@ -6,6 +6,7 b' configobj==5.0.6' | |||||
6 | decorator==4.0.11 |
|
6 | decorator==4.0.11 | |
7 | dulwich==0.13.0 |
|
7 | dulwich==0.13.0 | |
8 | hgsubversion==1.8.6 |
|
8 | hgsubversion==1.8.6 | |
|
9 | hg-evolve==6.0.1 | |||
9 | infrae.cache==1.0.1 |
|
10 | infrae.cache==1.0.1 | |
10 | mercurial==4.1.2 |
|
11 | mercurial==4.1.2 | |
11 | msgpack-python==0.4.8 |
|
12 | msgpack-python==0.4.8 | |
@@ -35,9 +36,5 b' greenlet==0.4.10' | |||||
35 | gunicorn==19.6.0 |
|
36 | gunicorn==19.6.0 | |
36 | waitress==1.0.1 |
|
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 | ## test related requirements |
|
39 | ## test related requirements | |
43 | -r requirements_test.txt |
|
40 | -r requirements_test.txt |
@@ -26,7 +26,7 b' beaker.cache.repo_object.enabled = true' | |||||
26 | ### LOGGING CONFIGURATION #### |
|
26 | ### LOGGING CONFIGURATION #### | |
27 | ################################ |
|
27 | ################################ | |
28 | [loggers] |
|
28 | [loggers] | |
29 |
keys = root, vcsserver, |
|
29 | keys = root, vcsserver, beaker | |
30 |
|
30 | |||
31 | [handlers] |
|
31 | [handlers] | |
32 | keys = console |
|
32 | keys = console | |
@@ -53,12 +53,6 b' handlers =' | |||||
53 | qualname = beaker |
|
53 | qualname = beaker | |
54 | propagate = 1 |
|
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 | ## HANDLERS ## |
|
58 | ## HANDLERS ## |
@@ -287,6 +287,25 b' class HgRemote(object):' | |||||
287 | return [parent.rev() for parent in ctx.parents()] |
|
287 | return [parent.rev() for parent in ctx.parents()] | |
288 |
|
288 | |||
289 | @reraise_safe_exceptions |
|
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 | def ctx_substate(self, wire, revision): |
|
309 | def ctx_substate(self, wire, revision): | |
291 | repo = self._factory.repo(wire) |
|
310 | repo = self._factory.repo(wire) | |
292 | ctx = repo[revision] |
|
311 | ctx = repo[revision] | |
@@ -298,7 +317,7 b' class HgRemote(object):' | |||||
298 | ctx = repo[revision] |
|
317 | ctx = repo[revision] | |
299 | status = repo[ctx.p1().node()].status(other=ctx.node()) |
|
318 | status = repo[ctx.p1().node()].status(other=ctx.node()) | |
300 | # object of status (odd, custom named tuple in mercurial) is not |
|
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 | # API expects this to be a list |
|
321 | # API expects this to be a list | |
303 | return list(status) |
|
322 | return list(status) | |
304 |
|
323 |
@@ -30,7 +30,6 b' from httplib import HTTPConnection' | |||||
30 |
|
30 | |||
31 | import mercurial.scmutil |
|
31 | import mercurial.scmutil | |
32 | import mercurial.node |
|
32 | import mercurial.node | |
33 | import Pyro4 |
|
|||
34 | import simplejson as json |
|
33 | import simplejson as json | |
35 |
|
34 | |||
36 | from vcsserver import exceptions |
|
35 | from vcsserver import exceptions | |
@@ -68,18 +67,9 b' class HooksDummyClient(object):' | |||||
68 | return getattr(hooks, hook_name)(extras) |
|
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 | class RemoteMessageWriter(object): |
|
70 | class RemoteMessageWriter(object): | |
81 | """Writer base class.""" |
|
71 | """Writer base class.""" | |
82 | def write(message): |
|
72 | def write(self, message): | |
83 | raise NotImplementedError() |
|
73 | raise NotImplementedError() | |
84 |
|
74 | |||
85 |
|
75 | |||
@@ -126,11 +116,7 b' def _handle_exception(result):' | |||||
126 | def _get_hooks_client(extras): |
|
116 | def _get_hooks_client(extras): | |
127 | if 'hooks_uri' in extras: |
|
117 | if 'hooks_uri' in extras: | |
128 | protocol = extras.get('hooks_protocol') |
|
118 | protocol = extras.get('hooks_protocol') | |
129 | return ( |
|
119 | return HooksHttpClient(extras['hooks_uri']) | |
130 | HooksHttpClient(extras['hooks_uri']) |
|
|||
131 | if protocol == 'http' |
|
|||
132 | else HooksPyro4Client(extras['hooks_uri']) |
|
|||
133 | ) |
|
|||
134 | else: |
|
120 | else: | |
135 | return HooksDummyClient(extras['hooks_module']) |
|
121 | return HooksDummyClient(extras['hooks_module']) | |
136 |
|
122 | |||
@@ -161,13 +147,25 b' def post_pull(ui, repo, **kwargs):' | |||||
161 | return _call_hook('post_pull', _extras_from_ui(ui), HgMessageWriter(ui)) |
|
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 | def pre_push(ui, repo, node=None, **kwargs): |
|
162 | def pre_push(ui, repo, node=None, **kwargs): | |
165 | extras = _extras_from_ui(ui) |
|
163 | extras = _extras_from_ui(ui) | |
166 |
|
164 | |||
167 | rev_data = [] |
|
165 | rev_data = [] | |
168 | if node and kwargs.get('hooktype') == 'pretxnchangegroup': |
|
166 | if node and kwargs.get('hooktype') == 'pretxnchangegroup': | |
169 | branches = collections.defaultdict(list) |
|
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 | branches[branch].append(commit_id) |
|
169 | branches[branch].append(commit_id) | |
172 |
|
170 | |||
173 | for branch, commits in branches.iteritems(): |
|
171 | for branch, commits in branches.iteritems(): | |
@@ -184,30 +182,38 b' def pre_push(ui, repo, node=None, **kwar' | |||||
184 | return _call_hook('pre_push', extras, HgMessageWriter(ui)) |
|
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 = [] |
|
193 | for commit_id, branch in _rev_range_hash(repo, node): | |
190 | for rev in xrange(repo[node], len(repo)): |
|
194 | commit_ids.append(commit_id) | |
191 | ctx = repo[rev] |
|
195 | if branch not in branches: | |
192 | commit_id = mercurial.node.hex(ctx.node()) |
|
196 | branches.append(branch) | |
193 | branch = ctx.branch() |
|
|||
194 | if with_branch: |
|
|||
195 | commits.append((commit_id, branch)) |
|
|||
196 | else: |
|
|||
197 | commits.append(commit_id) |
|
|||
198 |
|
197 | |||
199 | return commits |
|
198 | if hasattr(ui, '_rc_pushkey_branches'): | |
200 |
|
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 | extras['commit_ids'] = commit_ids |
|
201 | extras['commit_ids'] = commit_ids | |
|
202 | extras['new_refs'] = { | |||
|
203 | 'branches': branches, | |||
|
204 | 'bookmarks': bookmarks, | |||
|
205 | 'tags': tags | |||
|
206 | } | |||
207 |
|
207 | |||
208 | return _call_hook('post_push', extras, HgMessageWriter(ui)) |
|
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 | # backward compat |
|
217 | # backward compat | |
212 | log_pull_action = post_pull |
|
218 | log_pull_action = post_pull | |
213 |
|
219 | |||
@@ -327,12 +333,12 b' def _run_command(arguments):' | |||||
327 | # Probably this should be using subprocessio. |
|
333 | # Probably this should be using subprocessio. | |
328 | process = subprocess.Popen( |
|
334 | process = subprocess.Popen( | |
329 | arguments, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
|
335 | arguments, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
330 |
stdout, |
|
336 | stdout, stderr = process.communicate() | |
331 |
|
337 | |||
332 | if process.returncode != 0: |
|
338 | if process.returncode != 0: | |
333 | raise Exception( |
|
339 | raise Exception( | |
334 |
'Command %s exited with exit code %s' % ( |
|
340 | 'Command %s exited with exit code %s: stderr:%s' % ( | |
335 | process.returncode)) |
|
341 | arguments, process.returncode, stderr)) | |
336 |
|
342 | |||
337 | return stdout |
|
343 | return stdout | |
338 |
|
344 | |||
@@ -359,10 +365,16 b' def git_post_receive(unused_repo_path, r' | |||||
359 | # subcommand sets the PATH environment variable so that it point to the |
|
365 | # subcommand sets the PATH environment variable so that it point to the | |
360 | # correct version of the git executable. |
|
366 | # correct version of the git executable. | |
361 | empty_commit_id = '0' * 40 |
|
367 | empty_commit_id = '0' * 40 | |
|
368 | branches = [] | |||
|
369 | tags = [] | |||
362 | for push_ref in rev_data: |
|
370 | for push_ref in rev_data: | |
363 | type_ = push_ref['type'] |
|
371 | type_ = push_ref['type'] | |
|
372 | ||||
364 | if type_ == 'heads': |
|
373 | if type_ == 'heads': | |
365 | if push_ref['old_rev'] == empty_commit_id: |
|
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 | # Fix up head revision if needed |
|
379 | # Fix up head revision if needed | |
368 | cmd = ['git', 'show', 'HEAD'] |
|
380 | cmd = ['git', 'show', 'HEAD'] | |
@@ -386,14 +398,24 b' def git_post_receive(unused_repo_path, r' | |||||
386 | # delete branch case |
|
398 | # delete branch case | |
387 | git_revs.append('delete_branch=>%s' % push_ref['name']) |
|
399 | git_revs.append('delete_branch=>%s' % push_ref['name']) | |
388 | else: |
|
400 | else: | |
|
401 | if push_ref['name'] not in branches: | |||
|
402 | branches.append(push_ref['name']) | |||
|
403 | ||||
389 | cmd = ['git', 'log', |
|
404 | cmd = ['git', 'log', | |
390 | '{old_rev}..{new_rev}'.format(**push_ref), |
|
405 | '{old_rev}..{new_rev}'.format(**push_ref), | |
391 | '--reverse', '--pretty=format:%H'] |
|
406 | '--reverse', '--pretty=format:%H'] | |
392 | git_revs.extend(_run_command(cmd).splitlines()) |
|
407 | git_revs.extend(_run_command(cmd).splitlines()) | |
393 | elif type_ == 'tags': |
|
408 | elif type_ == 'tags': | |
|
409 | if push_ref['name'] not in tags: | |||
|
410 | tags.append(push_ref['name']) | |||
394 | git_revs.append('tag=>%s' % push_ref['name']) |
|
411 | git_revs.append('tag=>%s' % push_ref['name']) | |
395 |
|
412 | |||
396 | extras['commit_ids'] = git_revs |
|
413 | extras['commit_ids'] = git_revs | |
|
414 | extras['new_refs'] = { | |||
|
415 | 'branches': branches, | |||
|
416 | 'bookmarks': [], | |||
|
417 | 'tags': tags, | |||
|
418 | } | |||
397 |
|
419 | |||
398 | if 'repo_size' in extras['hooks']: |
|
420 | if 'repo_size' in extras['hooks']: | |
399 | try: |
|
421 | try: |
@@ -95,7 +95,13 b' class GitRepository(object):' | |||||
95 |
|
95 | |||
96 | :param path: |
|
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 | def inforefs(self, request, unused_environ): |
|
106 | def inforefs(self, request, unused_environ): | |
101 | """ |
|
107 | """ |
@@ -15,16 +15,5 b'' | |||||
15 | # along with this program; if not, write to the Free Software Foundation, |
|
15 | # along with this program; if not, write to the Free Software Foundation, | |
16 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
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 | WIRE_ENCODING = 'UTF-8' |
|
18 | WIRE_ENCODING = 'UTF-8' | |
29 |
|
||||
30 | GIT_EXECUTABLE = 'git' |
|
19 | GIT_EXECUTABLE = 'git' |
@@ -23,6 +23,7 b' import posixpath as vcspath' | |||||
23 | import StringIO |
|
23 | import StringIO | |
24 | import subprocess |
|
24 | import subprocess | |
25 | import urllib |
|
25 | import urllib | |
|
26 | import traceback | |||
26 |
|
27 | |||
27 | import svn.client |
|
28 | import svn.client | |
28 | import svn.core |
|
29 | import svn.core | |
@@ -46,8 +47,17 b' svn_compatible_versions = set([' | |||||
46 | 'pre-1.5-compatible', |
|
47 | 'pre-1.5-compatible', | |
47 | 'pre-1.6-compatible', |
|
48 | 'pre-1.6-compatible', | |
48 | 'pre-1.8-compatible', |
|
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 | def reraise_safe_exceptions(func): |
|
62 | def reraise_safe_exceptions(func): | |
53 | """Decorator for converting svn exceptions to something neutral.""" |
|
63 | """Decorator for converting svn exceptions to something neutral.""" | |
@@ -67,14 +77,15 b' class SubversionFactory(RepoFactory):' | |||||
67 | def _create_repo(self, wire, create, compatible_version): |
|
77 | def _create_repo(self, wire, create, compatible_version): | |
68 | path = svn.core.svn_path_canonicalize(wire['path']) |
|
78 | path = svn.core.svn_path_canonicalize(wire['path']) | |
69 | if create: |
|
79 | if create: | |
70 | fs_config = {} |
|
80 | fs_config = {'compatible-version': '1.9'} | |
71 | if compatible_version: |
|
81 | if compatible_version: | |
72 | if compatible_version not in svn_compatible_versions: |
|
82 | if compatible_version not in svn_compatible_versions: | |
73 | raise Exception('Unknown SVN compatible version "{}"' |
|
83 | raise Exception('Unknown SVN compatible version "{}"' | |
74 | .format(compatible_version)) |
|
84 | .format(compatible_version)) | |
75 | log.debug('Create SVN repo with compatible version "%s"', |
|
85 | fs_config['compatible-version'] = \ | |
76 |
|
|
86 | svn_compatible_versions_map[compatible_version] | |
77 | fs_config[compatible_version] = '1' |
|
87 | ||
|
88 | log.debug('Create SVN repo with config "%s"', fs_config) | |||
78 | repo = svn.repos.create(path, "", "", None, fs_config) |
|
89 | repo = svn.repos.create(path, "", "", None, fs_config) | |
79 | else: |
|
90 | else: | |
80 | repo = svn.repos.open(path) |
|
91 | repo = svn.repos.open(path) | |
@@ -87,7 +98,6 b' class SubversionFactory(RepoFactory):' | |||||
87 | return self._repo(wire, create_new_repo) |
|
98 | return self._repo(wire, create_new_repo) | |
88 |
|
99 | |||
89 |
|
100 | |||
90 |
|
||||
91 | NODE_TYPE_MAPPING = { |
|
101 | NODE_TYPE_MAPPING = { | |
92 | svn.core.svn_node_file: 'file', |
|
102 | svn.core.svn_node_file: 'file', | |
93 | svn.core.svn_node_dir: 'dir', |
|
103 | svn.core.svn_node_dir: 'dir', | |
@@ -120,8 +130,9 b' class SvnRemote(object):' | |||||
120 | # throws exception |
|
130 | # throws exception | |
121 | try: |
|
131 | try: | |
122 | svnrepo.svnremoterepo(baseui, url).svn.uuid |
|
132 | svnrepo.svnremoterepo(baseui, url).svn.uuid | |
123 | except: |
|
133 | except Exception: | |
124 | log.debug("Invalid svn url: %s", url) |
|
134 | tb = traceback.format_exc() | |
|
135 | log.debug("Invalid Subversion url: `%s`, tb: %s", url, tb) | |||
125 | raise URLError( |
|
136 | raise URLError( | |
126 | '"%s" is not a valid Subversion source url.' % (url, )) |
|
137 | '"%s" is not a valid Subversion source url.' % (url, )) | |
127 | return True |
|
138 | return True | |
@@ -130,10 +141,23 b' class SvnRemote(object):' | |||||
130 | try: |
|
141 | try: | |
131 | svn.repos.open(path) |
|
142 | svn.repos.open(path) | |
132 | except svn.core.SubversionException: |
|
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 | return False |
|
146 | return False | |
135 | return True |
|
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 | def lookup(self, wire, revision): |
|
161 | def lookup(self, wire, revision): | |
138 | if revision not in [-1, None, 'HEAD']: |
|
162 | if revision not in [-1, None, 'HEAD']: | |
139 | raise NotImplementedError |
|
163 | raise NotImplementedError |
@@ -29,46 +29,6 b' import simplejson as json' | |||||
29 | from vcsserver import hooks |
|
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 | def get_hg_ui(extras=None): |
|
32 | def get_hg_ui(extras=None): | |
73 | """Create a Config object with a valid RC_SCM_DATA entry.""" |
|
33 | """Create a Config object with a valid RC_SCM_DATA entry.""" | |
74 | extras = extras or {} |
|
34 | extras = extras or {} | |
@@ -89,126 +49,6 b' def get_hg_ui(extras=None):' | |||||
89 | return hg_ui |
|
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 | def test_git_pre_receive_is_disabled(): |
|
52 | def test_git_pre_receive_is_disabled(): | |
213 | extras = {'hooks': ['pull']} |
|
53 | extras = {'hooks': ['pull']} | |
214 | response = hooks.git_pre_receive(None, None, |
|
54 | response = hooks.git_pre_receive(None, None, | |
@@ -217,18 +57,6 b' def test_git_pre_receive_is_disabled():' | |||||
217 | assert response == 0 |
|
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 | def test_git_post_receive_is_disabled(): |
|
60 | def test_git_post_receive_is_disabled(): | |
233 | extras = {'hooks': ['pull']} |
|
61 | extras = {'hooks': ['pull']} | |
234 | response = hooks.git_post_receive(None, '', |
|
62 | response = hooks.git_post_receive(None, '', | |
@@ -242,7 +70,8 b' def test_git_post_receive_calls_repo_siz' | |||||
242 | with mock.patch.object(hooks, '_call_hook') as call_hook_mock: |
|
70 | with mock.patch.object(hooks, '_call_hook') as call_hook_mock: | |
243 | hooks.git_post_receive( |
|
71 | hooks.git_post_receive( | |
244 | None, '', {'RC_SCM_DATA': json.dumps(extras)}) |
|
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 | expected_calls = [ |
|
75 | expected_calls = [ | |
247 | mock.call('repo_size', extras, mock.ANY), |
|
76 | mock.call('repo_size', extras, mock.ANY), | |
248 | mock.call('post_push', extras, mock.ANY), |
|
77 | mock.call('post_push', extras, mock.ANY), | |
@@ -255,7 +84,8 b' def test_git_post_receive_does_not_call_' | |||||
255 | with mock.patch.object(hooks, '_call_hook') as call_hook_mock: |
|
84 | with mock.patch.object(hooks, '_call_hook') as call_hook_mock: | |
256 | hooks.git_post_receive( |
|
85 | hooks.git_post_receive( | |
257 | None, '', {'RC_SCM_DATA': json.dumps(extras)}) |
|
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 | expected_calls = [ |
|
89 | expected_calls = [ | |
260 | mock.call('post_push', extras, mock.ANY) |
|
90 | mock.call('post_push', extras, mock.ANY) | |
261 | ] |
|
91 | ] | |
@@ -279,122 +109,16 b' def test_repo_size_exception_does_not_af' | |||||
279 | assert result == status |
|
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 | def test_git_pre_pull_is_disabled(): |
|
112 | def test_git_pre_pull_is_disabled(): | |
362 | assert hooks.git_pre_pull({'hooks': ['push']}) == hooks.HookResponse(0, '') |
|
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 | def test_git_post_pull_is_disabled(): |
|
116 | def test_git_post_pull_is_disabled(): | |
385 | assert ( |
|
117 | assert ( | |
386 | hooks.git_post_pull({'hooks': ['push']}) == hooks.HookResponse(0, '')) |
|
118 | hooks.git_post_pull({'hooks': ['push']}) == hooks.HookResponse(0, '')) | |
387 |
|
119 | |||
388 |
|
120 | |||
389 | class TestGetHooksClient(object): |
|
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 | def test_returns_http_client_when_protocol_matches(self): |
|
123 | def test_returns_http_client_when_protocol_matches(self): | |
400 | hooks_uri = 'localhost:8000' |
|
124 | hooks_uri = 'localhost:8000' | |
@@ -405,14 +129,6 b' class TestGetHooksClient(object):' | |||||
405 | assert isinstance(result, hooks.HooksHttpClient) |
|
129 | assert isinstance(result, hooks.HooksHttpClient) | |
406 | assert result.hooks_uri == hooks_uri |
|
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 | def test_returns_dummy_client_when_hooks_uri_not_specified(self): |
|
132 | def test_returns_dummy_client_when_hooks_uri_not_specified(self): | |
417 | fake_module = mock.Mock() |
|
133 | fake_module = mock.Mock() | |
418 | import_patcher = mock.patch.object( |
|
134 | import_patcher = mock.patch.object( | |
@@ -487,30 +203,6 b' class TestHooksDummyClient(object):' | |||||
487 | assert result == hooks_module.Hooks().__enter__().post_push() |
|
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 | @pytest.fixture |
|
206 | @pytest.fixture | |
515 | def http_mirror(request): |
|
207 | def http_mirror(request): | |
516 | server = MirrorHttpServer() |
|
208 | server = MirrorHttpServer() |
@@ -18,24 +18,24 b'' | |||||
18 | import mock |
|
18 | import mock | |
19 | import pytest |
|
19 | import pytest | |
20 |
|
20 | |||
21 | from vcsserver import main |
|
21 | from vcsserver import http_main | |
22 | from vcsserver.base import obfuscate_qs |
|
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 | @mock.patch('vcsserver.hgpatches.patch_largefiles_capabilities') |
|
26 | @mock.patch('vcsserver.hgpatches.patch_largefiles_capabilities') | |
27 | def test_applies_largefiles_patch(patch_largefiles_capabilities): |
|
27 | def test_applies_largefiles_patch(patch_largefiles_capabilities): | |
28 | main.main([]) |
|
28 | http_main.main([]) | |
29 | patch_largefiles_capabilities.assert_called_once_with() |
|
29 | patch_largefiles_capabilities.assert_called_once_with() | |
30 |
|
30 | |||
31 |
|
31 | |||
32 |
@mock.patch('vcsserver.main.V |
|
32 | @mock.patch('vcsserver.http_main.VCS', mock.Mock()) | |
33 | @mock.patch('vcsserver.main.MercurialFactory', None) |
|
33 | @mock.patch('vcsserver.http_main.MercurialFactory', None) | |
34 | @mock.patch( |
|
34 | @mock.patch( | |
35 | 'vcsserver.hgpatches.patch_largefiles_capabilities', |
|
35 | 'vcsserver.hgpatches.patch_largefiles_capabilities', | |
36 | mock.Mock(side_effect=Exception("Must not be called"))) |
|
36 | mock.Mock(side_effect=Exception("Must not be called"))) | |
37 | def test_applies_largefiles_patch_only_if_mercurial_is_available(): |
|
37 | def test_applies_largefiles_patch_only_if_mercurial_is_available(): | |
38 | main.main([]) |
|
38 | http_main.main([]) | |
39 |
|
39 | |||
40 |
|
40 | |||
41 | @pytest.mark.parametrize('given, expected', [ |
|
41 | @pytest.mark.parametrize('given, expected', [ |
@@ -46,7 +46,7 b' class RequestWrapperTween(object):' | |||||
46 | finally: |
|
46 | finally: | |
47 | end = time.time() |
|
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 | '127.0.0.1', |
|
50 | '127.0.0.1', | |
51 | safe_str(get_access_path(request)), end - start) |
|
51 | safe_str(get_access_path(request)), end - start) | |
52 | ) |
|
52 | ) |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
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 |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now