##// END OF EJS Templates
release: Merge default into stable for release preparation
marcink -
r1396:20388f8c merge stable
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -0,0 +1,60 b''
1 .. _user-session-ref:
2
3 Increase User Session Performance
4 ---------------------------------
5
6 The default file-based sessions are only suitable for smaller setups, or
7 instances that doesn't have a lot of users or traffic.
8 They are set as default option because it's setup-free solution.
9
10 The most common issue of file based sessions are file limit errors which occur
11 if there are lots of session files.
12
13 Therefore, in a large scale deployment, to give better performance,
14 scalability, and maintainability we recommend switching from file-based
15 sessions to database-based user sessions or memcached sessions.
16
17 To switch to database-based user sessions uncomment the following section in
18 your :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file.
19
20
21 .. code-block:: ini
22
23 ## db based session, fast, and allows easy management over logged in users
24 beaker.session.type = ext:database
25 beaker.session.table_name = db_session
26
27 # use just one of the following accoring to the type of database
28 beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
29 beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
30
31 beaker.session.sa.pool_recycle = 3600
32 beaker.session.sa.echo = false
33
34
35 and make sure you comment out the file based sessions.
36
37 .. code-block:: ini
38
39 ## types are file, ext:memcached, ext:database, and memory (default).
40 #beaker.session.type = file
41 #beaker.session.data_dir = %(here)s/data/sessions/data
42
43
44 To switch to memcached-based user sessions uncomment the following section in
45 your :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file.
46
47 .. code-block:: ini
48
49 ## memcached sessions
50 beaker.session.type = ext:memcached
51 beaker.session.url = localhost:11211
52
53
54 and make sure you comment out the file based sessions.
55
56 .. code-block:: ini
57
58 ## types are file, ext:memcached, ext:database, and memory (default).
59 #beaker.session.type = file
60 #beaker.session.data_dir = %(here)s/data/sessions/data No newline at end of file
@@ -0,0 +1,158 b''
1 |RCE| 4.6.0 |RNS|
2 -----------------
3
4 Release Date
5 ^^^^^^^^^^^^
6
7 - 2017-02-03
8
9
10 New Features
11 ^^^^^^^^^^^^
12
13 - Pull requests: introduced versioning for pull requests.
14 Each update of pull requests creates and exposes a new version of it.
15 Users can navigate each version to show the previous state of pull request, or
16 generate diffs between versions to show what changed since the last update.
17 Also on each update attached comments are pinned to versions, so users can
18 tell at which state particular comment was made.
19 Various UI/UX fixes on PR page.
20
21 - Pull requests: introduced new merge-checks.
22 Merge checks show nicer UI for the status of merge approval.
23 Merge checks now also forbid a merge if TODO notes are present.
24 Submitting a status will auto-refresh merge checks, it means that it's no
25 longer required to re-load diff to merge a PR.
26 Same logic is now used for API, pre-conditions on show, and checks on
27 actual merge API call.
28
29 - Code review: approval state is now bound to pull request versioning. Users
30 can track their last approval and only show changes of pull requests between
31 their last approval and latest state.
32 - Code review: inline and main comments have now two types. a `note` and `todo`.
33 unresolved TODO comments show up in pull requests or commit view.
34 Unresolved TODO also prevents a PR from being merged.
35 - Code review: added navigation on outdated comments.
36
37 - Diffs: compare mode overhaul.
38 Made compare and commit range pages more consistent with other commit
39 diff pages. Old diff2way is replaced by new diffs with side-by-side
40 mode, and it also removes mergerly. Cleanup button behaviour on the compare
41 page. Switched file-diffs to use the compare page with file filter.
42 Added collapse/expand commits buttons in compare views. Generally improved UX.
43 - Diffs: added a wide-mode button to expand large diffs.
44
45 - Comments: an overhaul of comments forms. Adjust them for new comment types and
46 resolution comments.
47 - Comments: replaced a ctrl+space commands with slash commands. This becomes
48 more standardized and easier to use.
49
50 - Changelog: added load more anchors into changelog view.
51 Users in changelog can now load comments via ajax and extend the data
52 set to show more than 100 commits. This also re-renders the graph. So it's
53 possible to show 1000s of commits in an efficient way with the DAG graph.
54
55 - User sessions: added interface to show, and cleanup user auth sessions.
56 It's possible to show, and clean obsolete sessions. Also a cleanup of all
57 sessions option were added to completely log-out all users from the system.
58
59 - Integrations: webhook integration have now additional setting to choose if
60 the call should be made with POST or GET.
61
62 - API: get_repos call now allows to filter returned data by specifying a start
63 root location. Additionally, a traverse flag was added to define if returned
64 data should be only from top-level or recursive.
65 - API: comment_type (`note` or `todo`) for comment API.
66 - API: added comment_resolved_id into comments API to resolve TODO notes.
67
68
69 General
70 ^^^^^^^
71
72 - Api: comment_pull_request, added commit_id parameter to validate status
73 changed on particular commit. In case users set status on the commit
74 which is not current valid head this API call won't change the status anymore.
75 - Channelstream: added testing panel for live notifications.
76 - Authentication: disable password change form for accounts that are not
77 managed by RhodeCode, in the case of external accounts such as LDAP/oAuth,
78 password reset doesn't make sense.
79 - Core: let pyramid handle tracebacks for all exceptions.
80 Otherwise, we'll miss exception caused in pure pyramid views.
81 - Vcs server: expose remote tracebacks from HTTP backend using
82 the Pyro4AwareFormatter. This will now in most cases propagate VCSServer
83 exception into Enterprise logs for easier tracking of errors
84 - Ishell: updated code with latest iShell changes.
85 - Svn: generate HTTP downgrade via the auto-generated config. This allows
86 a HTTPs/HTTP configuration with SVN.
87 - Dependencies: bumped various pytest related libraries to latest versions.
88 - Dependencies: bumped gevent to 1.1.2 and greenlet to 0.4.10 versions.
89 - Dependencies: bumped msgpack to version 0.4.8.
90 - Dependencies: bumped supervisor to 3.3.1 version.
91 - Dependencies: bumped Whoosh to version 2.7.4.
92 - Dependencies: bumped Markdown library to 2.6.7
93 - Dependencies: bumped mako templates to 1.0.6
94 - Dependencies: bumped waitress version to 1.0.1
95 - Dependencies: bumped pygments to 2.2.0
96 - dependencies: bumped Mercurial version to 4.0.2
97 - dependencies: bumped git version to 2.9.3
98
99
100 Security
101 ^^^^^^^^
102
103 - Login: Don't display partial password helper hash inside the logs.
104 The information is not-required and will prevent people worrying about this
105 shown in logs.
106 - Auth: use pyramid HTTP exception when detecting CSRF errors. It helps
107 catching this error by our error handler and displaying it nicely to users.
108 - SVN: hide password entries in logs using specially generated configuration
109 for Apache Mod-Dav
110 - Permissions: fixed call to correctly check permissions for admin, before admin
111 users were ban deleting of pull requests in certain conditions.
112
113
114 Performance
115 ^^^^^^^^^^^
116
117 - Markup renderer: use global Markdown object to speed up markdown rendering.
118 We'll skip heavy initialization on each render thanks to this.
119 - Diffs: optimize how lexer is fetched for rich highlight mode.
120 Speeds up initial diff creation significantly since lexer cache is re used
121 and we don't need to fetch lexer many times.
122 - VCS: do an early detection of vcs-type request.
123 In case we're handling a VCS request, we can skip some of the pylons
124 stack initialization, speeding the request processing.
125
126
127 Fixes
128 ^^^^^
129
130 - Code review: render outdated comments that don't fit current context.
131 Comments attached to files that were removed from pull-request now will also
132 properly show up.
133 - Markup renderer: don't render plaintext files as RST. This prevents plain
134 Readme files have been wrongly rendered.
135 - VCS: raise a better exception if file node history cannot be extracted.
136 Helps to trace corrupted repositories.
137 - Exception handling: nicer error catching on repository creation.
138 - Fixed excessive number of session object creation. There should be now a
139 significant reduction in new file or DB entries created for sessions.
140 - Core: remove global timezone hook from tests. This was leaking into main
141 application causing TZ problems (such as UTC log dates).
142 - Pull requests: wait for all dynamic checks before enabling opening a PR.
143 This ensures that all code analysis were run before users are allowed to open
144 a pull request.
145 - i18n: use a consistent way of setting user language.
146 - API: added merge checks into API because it was not validated before and could
147 return an error if the merge wasn't possible for some reason.
148 - VCSServer: fetch proper locale before defaulting to default. Prevents
149 errors on some machines that don't have locales set.
150 - VCSServer: fixed 500 error if the wrong URL on HTTP mode vcsserver was accessed.
151
152
153 Upgrade notes
154 ^^^^^^^^^^^^^
155
156 - Integrations: since new POST/GET option was added to integrations, users
157 are advised to optionally check Webhooks integrations and pick one.
158 (default is still POST) No newline at end of file
@@ -0,0 +1,17 b''
1 # test related requirements
2 pytest==3.0.5
3 py==1.4.31
4 pytest-cov==2.4.0
5 pytest-sugar==0.7.1
6 pytest-runner==2.9.0
7 pytest-catchlog==1.2.2
8 pytest-profiling==1.2.2
9 gprof2dot==2016.10.13
10 pytest-timeout==1.2.0
11
12 mock==1.0.1
13 WebTest==1.4.3
14 cov-core==1.15.0
15 coverage==3.7.1
16 cssselect==0.9.1
17 lxml==3.4.4
@@ -0,0 +1,19 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
@@ -0,0 +1,28 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21
22 class AdminSettingsView(object):
23
24 def __init__(self, context, request):
25 self.request = request
26 self.context = context
27 self.session = request.session
28 self._rhodecode_user = request.user
@@ -0,0 +1,48 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21 import collections
22 import logging
23
24 from pylons import tmpl_context as c
25 from pyramid.view import view_config
26
27 from rhodecode.admin.views.base import AdminSettingsView
28 from rhodecode.admin.navigation import navigation_list
29 from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator)
30 from rhodecode.lib.utils import read_opensource_licenses
31
32 log = logging.getLogger(__name__)
33
34
35 class OpenSourceLicensesAdminSettingsView(AdminSettingsView):
36
37 @LoginRequired()
38 @HasPermissionAllDecorator('hg.admin')
39 @view_config(
40 route_name='admin_settings_open_source', request_method='GET',
41 renderer='rhodecode:templates/admin/settings/settings.mako')
42 def open_source_licenses(self):
43 c.active = 'open_source'
44 c.navlist = navigation_list(self.request)
45 c.opensource_licenses = collections.OrderedDict(
46 sorted(read_opensource_licenses().items(), key=lambda t: t[0]))
47
48 return {}
@@ -0,0 +1,100 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21 import logging
22
23 from pylons import tmpl_context as c
24 from pyramid.view import view_config
25 from pyramid.httpexceptions import HTTPFound
26
27 from rhodecode.translation import _
28
29 from rhodecode.admin.views.base import AdminSettingsView
30 from rhodecode.lib.auth import (
31 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
32 from rhodecode.lib.utils2 import safe_int
33 from rhodecode.lib import system_info
34 from rhodecode.lib import user_sessions
35
36
37 from rhodecode.admin.navigation import navigation_list
38
39
40 log = logging.getLogger(__name__)
41
42
43 class AdminSessionSettingsView(AdminSettingsView):
44
45 @LoginRequired()
46 @HasPermissionAllDecorator('hg.admin')
47 @view_config(
48 route_name='admin_settings_sessions', request_method='GET',
49 renderer='rhodecode:templates/admin/settings/settings.mako')
50 def settings_sessions(self):
51 c.active = 'sessions'
52 c.navlist = navigation_list(self.request)
53
54 c.cleanup_older_days = 60
55 older_than_seconds = 60 * 60 * 24 * c.cleanup_older_days
56
57 config = system_info.rhodecode_config().get_value()['value']['config']
58 c.session_model = user_sessions.get_session_handler(
59 config.get('beaker.session.type', 'memory'))(config)
60
61 c.session_conf = c.session_model.config
62 c.session_count = c.session_model.get_count()
63 c.session_expired_count = c.session_model.get_expired_count(
64 older_than_seconds)
65
66 return {}
67
68 @LoginRequired()
69 @CSRFRequired()
70 @HasPermissionAllDecorator('hg.admin')
71 @view_config(
72 route_name='admin_settings_sessions_cleanup', request_method='POST')
73 def settings_sessions_cleanup(self):
74 _ = self.request.translate
75 expire_days = safe_int(self.request.params.get('expire_days'))
76
77 if expire_days is None:
78 expire_days = 60
79
80 older_than_seconds = 60 * 60 * 24 * expire_days
81
82 config = system_info.rhodecode_config().get_value()['value']['config']
83 session_model = user_sessions.get_session_handler(
84 config.get('beaker.session.type', 'memory'))(config)
85
86 try:
87 session_model.clean_sessions(
88 older_than_seconds=older_than_seconds)
89 self.request.session.flash(
90 _('Cleaned up old sessions'), queue='success')
91 except user_sessions.CleanupCommand as msg:
92 self.request.session.flash(msg.message, queue='warning')
93 except Exception as e:
94 log.exception('Failed session cleanup')
95 self.request.session.flash(
96 _('Failed to cleanup up old sessions'), queue='error')
97
98 redirect_to = self.request.resource_path(
99 self.context, route_name='admin_settings_sessions')
100 return HTTPFound(redirect_to)
@@ -0,0 +1,60 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21 import logging
22
23 from pyramid.view import view_config
24
25 from rhodecode.svn_support.utils import generate_mod_dav_svn_config
26
27 from rhodecode.admin.views.base import AdminSettingsView
28 from rhodecode.lib.auth import (
29 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
30
31 log = logging.getLogger(__name__)
32
33
34 class SvnConfigAdminSettingsView(AdminSettingsView):
35
36 @LoginRequired()
37 @CSRFRequired()
38 @HasPermissionAllDecorator('hg.admin')
39 @view_config(
40 route_name='admin_settings_vcs_svn_generate_cfg',
41 request_method='POST', renderer='json')
42 def vcs_svn_generate_config(self):
43 _ = self.request.translate
44 try:
45 generate_mod_dav_svn_config(self.request.registry)
46 msg = {
47 'message': _('Apache configuration for Subversion generated.'),
48 'level': 'success',
49 }
50 except Exception:
51 log.exception(
52 'Exception while generating the Apache '
53 'configuration for Subversion.')
54 msg = {
55 'message': _('Failed to generate the Apache configuration for Subversion.'),
56 'level': 'error',
57 }
58
59 data = {'message': msg}
60 return data
@@ -0,0 +1,202 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21 import logging
22 import urllib2
23 import packaging.version
24
25 from pylons import tmpl_context as c
26 from pyramid.view import view_config
27
28 import rhodecode
29 from rhodecode.lib import helpers as h
30 from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator)
31 from rhodecode.lib.utils2 import str2bool
32 from rhodecode.lib import system_info
33 from rhodecode.lib.ext_json import json
34
35 from rhodecode.admin.views.base import AdminSettingsView
36 from rhodecode.admin.navigation import navigation_list
37 from rhodecode.model.settings import SettingsModel
38
39 log = logging.getLogger(__name__)
40
41
42 class AdminSystemInfoSettingsView(AdminSettingsView):
43
44 @staticmethod
45 def get_update_data(update_url):
46 """Return the JSON update data."""
47 ver = rhodecode.__version__
48 log.debug('Checking for upgrade on `%s` server', update_url)
49 opener = urllib2.build_opener()
50 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
51 response = opener.open(update_url)
52 response_data = response.read()
53 data = json.loads(response_data)
54
55 return data
56
57 def get_update_url(self):
58 settings = SettingsModel().get_all_settings()
59 return settings.get('rhodecode_update_url')
60
61 @LoginRequired()
62 @HasPermissionAllDecorator('hg.admin')
63 @view_config(
64 route_name='admin_settings_system', request_method='GET',
65 renderer='rhodecode:templates/admin/settings/settings.mako')
66 def settings_system_info(self):
67 _ = self.request.translate
68
69 c.active = 'system'
70 c.navlist = navigation_list(self.request)
71
72 # TODO(marcink), figure out how to allow only selected users to do this
73 c.allowed_to_snapshot = self._rhodecode_user.admin
74
75 snapshot = str2bool(self.request.params.get('snapshot'))
76
77 c.rhodecode_update_url = self.get_update_url()
78 server_info = system_info.get_system_info(self.request.environ)
79
80 for key, val in server_info.items():
81 setattr(c, key, val)
82
83 def val(name, subkey='human_value'):
84 return server_info[name][subkey]
85
86 def state(name):
87 return server_info[name]['state']
88
89 def val2(name):
90 val = server_info[name]['human_value']
91 state = server_info[name]['state']
92 return val, state
93
94 update_info_msg = _('Note: please make sure this server can '
95 'access `${url}` for the update link to work',
96 mapping=dict(url=c.rhodecode_update_url))
97 c.data_items = [
98 # update info
99 (_('Update info'), h.literal(
100 '<span class="link" id="check_for_update" >%s.</span>' % (
101 _('Check for updates')) +
102 '<br/> <span >%s.</span>' % (update_info_msg)
103 ), ''),
104
105 # RhodeCode specific
106 (_('RhodeCode Version'), val('rhodecode_app')['text'], state('rhodecode_app')),
107 (_('RhodeCode Server IP'), val('server')['server_ip'], state('server')),
108 (_('RhodeCode Server ID'), val('server')['server_id'], state('server')),
109 (_('RhodeCode Configuration'), val('rhodecode_config')['path'], state('rhodecode_config')),
110 ('', '', ''), # spacer
111
112 # Database
113 (_('Database'), val('database')['url'], state('database')),
114 (_('Database version'), val('database')['version'], state('database')),
115 ('', '', ''), # spacer
116
117 # Platform/Python
118 (_('Platform'), val('platform')['name'], state('platform')),
119 (_('Platform UUID'), val('platform')['uuid'], state('platform')),
120 (_('Python version'), val('python')['version'], state('python')),
121 (_('Python path'), val('python')['executable'], state('python')),
122 ('', '', ''), # spacer
123
124 # Systems stats
125 (_('CPU'), val('cpu'), state('cpu')),
126 (_('Load'), val('load')['text'], state('load')),
127 (_('Memory'), val('memory')['text'], state('memory')),
128 (_('Uptime'), val('uptime')['text'], state('uptime')),
129 ('', '', ''), # spacer
130
131 # Repo storage
132 (_('Storage location'), val('storage')['path'], state('storage')),
133 (_('Storage info'), val('storage')['text'], state('storage')),
134 (_('Storage inodes'), val('storage_inodes')['text'], state('storage_inodes')),
135
136 (_('Gist storage location'), val('storage_gist')['path'], state('storage_gist')),
137 (_('Gist storage info'), val('storage_gist')['text'], state('storage_gist')),
138
139 (_('Archive cache storage location'), val('storage_archive')['path'], state('storage_archive')),
140 (_('Archive cache info'), val('storage_archive')['text'], state('storage_archive')),
141
142 (_('Temp storage location'), val('storage_temp')['path'], state('storage_temp')),
143 (_('Temp storage info'), val('storage_temp')['text'], state('storage_temp')),
144
145 (_('Search info'), val('search')['text'], state('search')),
146 (_('Search location'), val('search')['location'], state('search')),
147 ('', '', ''), # spacer
148
149 # VCS specific
150 (_('VCS Backends'), val('vcs_backends'), state('vcs_backends')),
151 (_('VCS Server'), val('vcs_server')['text'], state('vcs_server')),
152 (_('GIT'), val('git'), state('git')),
153 (_('HG'), val('hg'), state('hg')),
154 (_('SVN'), val('svn'), state('svn')),
155
156 ]
157
158 if snapshot:
159 if c.allowed_to_snapshot:
160 c.data_items.pop(0) # remove server info
161 self.request.override_renderer = 'admin/settings/settings_system_snapshot.mako'
162 else:
163 self.request.session.flash(
164 'You are not allowed to do this', queue='warning')
165 return {}
166
167 @LoginRequired()
168 @HasPermissionAllDecorator('hg.admin')
169 @view_config(
170 route_name='admin_settings_system_update', request_method='GET',
171 renderer='rhodecode:templates/admin/settings/settings_system_update.mako')
172 def settings_system_info_check_update(self):
173 _ = self.request.translate
174
175 update_url = self.get_update_url()
176
177 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">{}</div>'.format(s)
178 try:
179 data = self.get_update_data(update_url)
180 except urllib2.URLError as e:
181 log.exception("Exception contacting upgrade server")
182 self.request.override_renderer = 'string'
183 return _err('Failed to contact upgrade server: %r' % e)
184 except ValueError as e:
185 log.exception("Bad data sent from update server")
186 self.request.override_renderer = 'string'
187 return _err('Bad data sent from update server')
188
189 latest = data['versions'][0]
190
191 c.update_url = update_url
192 c.latest_data = latest
193 c.latest_ver = latest['version']
194 c.cur_ver = rhodecode.__version__
195 c.should_upgrade = False
196
197 if (packaging.version.Version(c.latest_ver) >
198 packaging.version.Version(c.cur_ver)):
199 c.should_upgrade = True
200 c.important_notices = latest['general']
201
202 return {}
@@ -0,0 +1,44 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2017-2017 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21 import mock
22 import pytest
23
24 from rhodecode.lib.user_sessions import FileAuthSessions
25 from rhodecode.api.tests.utils import (
26 build_data, api_call, assert_ok, assert_error, crash)
27
28
29 @pytest.mark.usefixtures("testuser_api", "app")
30 class TestCleanupSessions(object):
31 def test_api_cleanup_sessions(self):
32 id_, params = build_data(self.apikey, 'cleanup_sessions')
33 response = api_call(self.app, params)
34
35 expected = {'backend': 'file sessions', 'sessions_removed': 0}
36 assert_ok(id_, expected, given=response.body)
37
38 @mock.patch.object(FileAuthSessions, 'clean_sessions', crash)
39 def test_api_cleanup_error(self):
40 id_, params = build_data(self.apikey, 'cleanup_sessions', )
41 response = api_call(self.app, params)
42
43 expected = 'Error occurred during session cleanup'
44 assert_error(id_, expected, given=response.body)
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,5 +1,5 b''
1 1 [bumpversion]
2 current_version = 4.5.2
2 current_version = 4.6.0
3 3 message = release: Bump version {current_version} to {new_version}
4 4
5 5 [bumpversion:file:rhodecode/VERSION]
@@ -4,26 +4,21 b' done = false'
4 4 [task:bump_version]
5 5 done = true
6 6
7 [task:rc_tools_pinned]
8 done = true
9
10 7 [task:fixes_on_stable]
11 done = true
12 8
13 9 [task:pip2nix_generated]
14 done = true
15 10
16 11 [task:changelog_updated]
17 done = true
18 12
19 13 [task:generate_api_docs]
20 done = true
14
15 [task:updated_translation]
21 16
22 17 [release]
23 state = prepared
24 version = 4.5.2
18 state = in_progress
19 version = 4.6.0
25 20
26 [task:updated_translation]
21 [task:rc_tools_pinned]
27 22
28 23 [task:generate_js_routes]
29 24
@@ -29,8 +29,6 b' recursive-include rhodecode *.mako'
29 29 # 502 page
30 30 include rhodecode/public/502.html
31 31
32 # 502 page
33 include rhodecode/public/502.html
34 32
35 33 # images, css
36 34 include rhodecode/public/css/*.css
@@ -1,11 +1,25 b''
1
2 .PHONY: clean docs docs-clean docs-cleanup test test-clean test-only web-build
1 3
2 4 WEBPACK=./node_modules/webpack/bin/webpack.js
3 5 GRUNT=grunt
4 6 NODE_PATH=./node_modules
5 CI_PREFIX=enterprise
7
8
9 clean:
10 make test-clean
11 find . -type f \( -iname '*.c' -o -iname '*.pyc' -o -iname '*.so' \) -exec rm '{}' ';'
6 12
7 .PHONY: docs docs-clean ci-docs clean test test-clean test-lint test-only
13 test:
14 make test-clean
15 make test-only
8 16
17 test-clean:
18 rm -rf coverage.xml htmlcov junit.xml pylint.log result
19 find . -type d -name "__pycache__" -prune -exec rm -rf '{}' ';'
20
21 test-only:
22 PYTHONHASHSEED=random py.test -vv -r xw --cov=rhodecode --cov-report=term-missing --cov-report=html rhodecode
9 23
10 24 docs:
11 25 (cd docs; nix-build default.nix -o result; make clean html)
@@ -13,27 +27,9 b' docs:'
13 27 docs-clean:
14 28 (cd docs; make clean)
15 29
16 ci-docs: docs;
17
18
19 clean: test-clean
20 find . -type f \( -iname '*.c' -o -iname '*.pyc' -o -iname '*.so' \) -exec rm '{}' ';'
21
22 test: test-clean test-only
23
24 test-clean:
25 rm -rf coverage.xml htmlcov junit.xml pylint.log result
26
27 test-only:
28 PYTHONHASHSEED=random py.test -vv -r xw --cov=rhodecode --cov-report=term-missing --cov-report=html rhodecode/tests/
30 docs-cleanup:
31 (cd docs; make cleanup)
29 32
30 33 web-build:
31 34 NODE_PATH=$(NODE_PATH) $(GRUNT)
32 35
33 web-test:
34 @echo "no test for our javascript, yet!"
35
36 docs-bootstrap:
37 (cd docs; nix-build default.nix -o result)
38 @echo "Please go to docs folder and run make html"
39
@@ -415,19 +415,23 b' search.location = %(here)s/data/index'
415 415 ########################################
416 416 ## channelstream enables persistent connections and live notification
417 417 ## in the system. It's also used by the chat system
418 channelstream.enabled = false
418 419
419 channelstream.enabled = false
420 ## location of channelstream server on the backend
420 ## server address for channelstream server on the backend
421 421 channelstream.server = 127.0.0.1:9800
422
422 423 ## location of the channelstream server from outside world
423 ## most likely this would be an http server special backend URL, that handles
424 ## websocket connections see nginx example for config
425 # channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
426 ## proxy path that can be used by http daemons for exposing channelstream
427 # channelstream.proxy_path = /_channelstream
424 ## use ws:// for http or wss:// for https. This address needs to be handled
425 ## by external HTTP server such as Nginx or Apache
426 ## see nginx/apache configuration examples in our docs
427 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
428 428 channelstream.secret = secret
429 429 channelstream.history.location = %(here)s/channelstream_history
430 430
431 ## Internal application path that Javascript uses to connect into.
432 ## If you use proxy-prefix the prefix should be added before /_channelstream
433 channelstream.proxy_path = /_channelstream
434
431 435
432 436 ###################################
433 437 ## APPENLIGHT CONFIG ##
@@ -501,9 +505,9 b' appenlight.log_namespace_blacklist ='
501 505 ##############
502 506 debug_style = true
503 507
504 #########################################################
505 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
506 #########################################################
508 ###########################################
509 ### MAIN RHODECODE DATABASE CONFIG ###
510 ###########################################
507 511 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
508 512 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
509 513 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
@@ -586,12 +590,16 b' svn.proxy.location_root = /'
586 590 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
587 591 #svn.proxy.reload_timeout = 10
588 592
593 ## Dummy marker to add new entries after.
594 ## Add any custom entries below. Please don't remove.
595 custom.conf = 1
596
589 597
590 598 ################################
591 599 ### LOGGING CONFIGURATION ####
592 600 ################################
593 601 [loggers]
594 keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates
602 keys = root, routes, rhodecode, sqlalchemy, beaker, templates
595 603
596 604 [handlers]
597 605 keys = console, console_sql
@@ -619,12 +627,6 b' handlers ='
619 627 qualname = beaker.container
620 628 propagate = 1
621 629
622 [logger_pyro4]
623 level = DEBUG
624 handlers =
625 qualname = Pyro4
626 propagate = 1
627
628 630 [logger_templates]
629 631 level = INFO
630 632 handlers =
@@ -649,13 +651,13 b' propagate = 0'
649 651
650 652 [handler_console]
651 653 class = StreamHandler
652 args = (sys.stderr,)
654 args = (sys.stderr, )
653 655 level = DEBUG
654 656 formatter = color_formatter
655 657
656 658 [handler_console_sql]
657 659 class = StreamHandler
658 args = (sys.stderr,)
660 args = (sys.stderr, )
659 661 level = DEBUG
660 662 formatter = color_formatter_sql
661 663
@@ -1,4 +1,17 b''
1 """gunicorn config hooks"""
1 """
2 gunicorn config extension and hooks. Sets additional configuration that is
3 available post the .ini config.
4
5 - workers = ${cpu_number}
6 - threads = 1
7 - proc_name = ${gunicorn_proc_name}
8 - worker_class = sync
9 - worker_connections = 10
10 - max_requests = 1000
11 - max_requests_jitter = 30
12 - timeout = 21600
13
14 """
2 15
3 16 import multiprocessing
4 17 import sys
@@ -6,50 +19,31 b' import threading'
6 19 import traceback
7 20
8 21
9 # GLOBAL #
22 # GLOBAL
10 23 errorlog = '-'
11 24 accesslog = '-'
12 25 loglevel = 'debug'
13 26
14 # SECURITY #
27 # SECURITY
15 28 limit_request_line = 4094
16 29 limit_request_fields = 100
17 30 limit_request_field_size = 8190
18 31
19 # SERVER MECHANICS #
20 # None == system temp dir #
32 # SERVER MECHANICS
33 # None == system temp dir
21 34 worker_tmp_dir = None
22 35 tmp_upload_dir = None
23 #proc_name =
24
25 # self adjust workers based on CPU #
26 #workers = multiprocessing.cpu_count() * 2 + 1
27
28 access_log_format = '[%(p)s] %(h)15s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" request_time:%(L)s'
29
30 # For the gevent worker classes #
31 # this limits the maximum number of simultaneous clients that #
32 # a single process can handle. #
33 #worker_connections = 10
34 36
35 # Max requests to handle by each worker before restarting it, #
36 # could prevent memory leaks #
37 #max_requests = 1000
38 #max_requests_jitter = 30
39
37 # Custom log format
38 access_log_format = (
39 '%(t)s GNCRN %(p)-8s %(h)-15s rqt:%(L)s %(s)s %(b)s "%(m)s:%(U)s %(q)s" usr:%(u)s "%(f)s" "%(a)s"')
40 40
41 # If a worker does not notify the master process in this #
42 # number of seconds it is killed and a new worker is spawned #
43 # to replace it. #
44 #timeout = 3600
45
46 access_log_format = (
47 '[%(p)-10s] %(h)s time:%(L)s %(l)s %(u)s '
48 '%(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"')
41 # self adjust workers based on CPU count
42 # workers = multiprocessing.cpu_count() * 2 + 1
49 43
50 44
51 45 def post_fork(server, worker):
52 server.log.info("[<%s>] worker spawned", worker.pid)
46 server.log.info("[<%-10s>] WORKER spawned", worker.pid)
53 47
54 48
55 49 def pre_fork(server, worker):
@@ -67,7 +61,7 b' def when_ready(server):'
67 61 def worker_int(worker):
68 62 worker.log.info("[<%-10s>] worker received INT or QUIT signal", worker.pid)
69 63
70 # get traceback info
64 # get traceback info, on worker crash
71 65 id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
72 66 code = []
73 67 for thread_id, stack in sys._current_frames().items():
@@ -389,19 +389,23 b' search.location = %(here)s/data/index'
389 389 ########################################
390 390 ## channelstream enables persistent connections and live notification
391 391 ## in the system. It's also used by the chat system
392 channelstream.enabled = false
392 393
393 channelstream.enabled = false
394 ## location of channelstream server on the backend
394 ## server address for channelstream server on the backend
395 395 channelstream.server = 127.0.0.1:9800
396
396 397 ## location of the channelstream server from outside world
397 ## most likely this would be an http server special backend URL, that handles
398 ## websocket connections see nginx example for config
399 # channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
400 ## proxy path that can be used by http daemons for exposing channelstream
401 # channelstream.proxy_path = /_channelstream
398 ## use ws:// for http or wss:// for https. This address needs to be handled
399 ## by external HTTP server such as Nginx or Apache
400 ## see nginx/apache configuration examples in our docs
401 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
402 402 channelstream.secret = secret
403 403 channelstream.history.location = %(here)s/channelstream_history
404 404
405 ## Internal application path that Javascript uses to connect into.
406 ## If you use proxy-prefix the prefix should be added before /_channelstream
407 channelstream.proxy_path = /_channelstream
408
405 409
406 410 ###################################
407 411 ## APPENLIGHT CONFIG ##
@@ -470,9 +474,9 b' appenlight.log_namespace_blacklist ='
470 474 set debug = false
471 475
472 476
473 #########################################################
474 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
475 #########################################################
477 ###########################################
478 ### MAIN RHODECODE DATABASE CONFIG ###
479 ###########################################
476 480 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
477 481 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
478 482 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
@@ -555,12 +559,16 b' svn.proxy.location_root = /'
555 559 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
556 560 #svn.proxy.reload_timeout = 10
557 561
562 ## Dummy marker to add new entries after.
563 ## Add any custom entries below. Please don't remove.
564 custom.conf = 1
565
558 566
559 567 ################################
560 568 ### LOGGING CONFIGURATION ####
561 569 ################################
562 570 [loggers]
563 keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates
571 keys = root, routes, rhodecode, sqlalchemy, beaker, templates
564 572
565 573 [handlers]
566 574 keys = console, console_sql
@@ -588,12 +596,6 b' handlers ='
588 596 qualname = beaker.container
589 597 propagate = 1
590 598
591 [logger_pyro4]
592 level = DEBUG
593 handlers =
594 qualname = Pyro4
595 propagate = 1
596
597 599 [logger_templates]
598 600 level = INFO
599 601 handlers =
@@ -618,13 +620,13 b' propagate = 0'
618 620
619 621 [handler_console]
620 622 class = StreamHandler
621 args = (sys.stderr,)
623 args = (sys.stderr, )
622 624 level = INFO
623 625 formatter = generic
624 626
625 627 [handler_console_sql]
626 628 class = StreamHandler
627 args = (sys.stderr,)
629 args = (sys.stderr, )
628 630 level = WARN
629 631 formatter = generic
630 632
@@ -135,6 +135,8 b' let'
135 135 rhodecode-testdata
136 136 ]);
137 137
138 #TODO: either move this into overrides, OR use the new machanics from
139 # pip2nix and requiremtn.txt file
138 140 propagatedBuildInputs = attrs.propagatedBuildInputs ++ (with self; [
139 141 rhodecode-tools
140 142 ]);
@@ -49,6 +49,12 b' help:'
49 49 clean:
50 50 rm -rf $(BUILDDIR)/*
51 51
52 cleanup:
53 @echo "cleaning build dir"
54 rm -rf $(BUILDDIR)/*
55 @echo "cleaning result symlink"
56 rm -v result
57
52 58 html:
53 59 $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
54 60 @echo
@@ -1,32 +1,68 b''
1 1 .. _apache-conf-eg:
2 2
3 Apache Configuration Examples
4 -----------------------------
3 Apache Configuration Example
4 ----------------------------
5
6 Use the following example to configure Apache as a your web server.
7 Below config if for an Apache Reverse Proxy configuration.
8
9 .. note::
10
11 Apache requires the following modules to be enabled. Below is an example
12 how to enable them on Ubuntu Server
13
5 14
6 Use the following example to securely configure your Apache HTTP virtual hosts
7 file.
15 .. code-block:: bash
16
17 $ sudo a2enmod proxy
18 $ sudo a2enmod proxy_http
19 $ sudo a2enmod proxy_balancer
20 $ sudo a2enmod headers
21 $ sudo a2enmod ssl
22 $ sudo a2enmod rewrite
23
24 # requires Apache 2.4+, required to handle websockets/channelstream
25 $ sudo a2enmod proxy_wstunnel
26
8 27
9 28 .. code-block:: apache
10 29
30 ## HTTP to HTTPS rewrite
11 31 <VirtualHost *:80>
12 ServerName hg.myserver.com
13 ServerAlias hg.myserver.com
32 ServerName rhodecode.myserver.com
33 DocumentRoot /var/www/html
34 Redirect permanent / https://rhodecode.myserver.com/
35 </VirtualHost>
36
37 ## MAIN SSL enabled server
38 <VirtualHost *:443>
39
40 ServerName rhodecode.myserver.com
41 ServerAlias rhodecode.myserver.com
42
43 ## serve static files by Apache, recommended for performance
44 #Alias /_static /home/ubuntu/.rccontrol/community-1/static
45
46 RequestHeader set X-Forwarded-Proto "https"
47
48 ## channelstream websocket handling
49 ProxyPass /_channelstream ws://localhost:9800
50 ProxyPassReverse /_channelstream ws://localhost:9800
14 51
15 52 <Proxy *>
16 53 Order allow,deny
17 54 Allow from all
18 55 </Proxy>
19 56
20 # important !
21 # Directive to properly generate url (clone url) for pylons
22
57 # Directive to properly generate url (clone url) for RhodeCode
23 58 ProxyPreserveHost On
24 59
25 #rhodecode instance
26 ProxyPass / http://127.0.0.1:5000/
27 ProxyPassReverse / http://127.0.0.1:5000/
60 # Url to running RhodeCode instance. This is shown as `- URL:` when
61 # running rccontrol status.
62 ProxyPass / http://127.0.0.1:10002/
63 ProxyPassReverse / http://127.0.0.1:10002/
28 64
29 # Set strict HTTPS
65 # strict http prevents from https -> http downgrade
30 66 Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"
31 67
32 68 # Set x-frame options
@@ -35,80 +71,17 b' file.'
35 71 # To enable https use line below
36 72 # SetEnvIf X-Url-Scheme https HTTPS=1
37 73
38 # Secure your Diffie-hellmann deployment
74 # SSL setup
75 SSLEngine On
76 SSLCertificateFile /etc/apache2/ssl/rhodecode.myserver.pem
77 SSLCertificateKeyFile /etc/apache2/ssl/rhodecode.myserver.key
78
39 79 SSLProtocol all -SSLv2 -SSLv3
40 80 SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
41 81 SSLHonorCipherOrder on
42 SSLOpenSSLConfCmd DHParameters "{path to dhparams.pem}"
82
83 # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
84 #SSLOpenSSLConfCmd DHParameters "/etc/apache2/dhparam.pem"
43 85
44 86 </VirtualHost>
45 87
46 Use the following example to configure Apache for a multi-node setup. The
47 timeout setting should be increased if you experience timeouts when working
48 with large |repos|.
49
50 .. code-block:: apache
51
52 #
53 # Timeout: The number of seconds before receives and sends time out.
54 #
55 Timeout 600
56
57 <VirtualHost *:80>
58
59 ProxyRequests off
60
61 #important !
62 #Directive to properly generate url (clone url) for pylons
63 ProxyPreserveHost On
64
65 ServerName your.rce.com
66 ServerAlias your.rce.com
67
68 <Proxy balancer://mycluster>
69 # WebHead1
70 BalancerMember http://10.58.1.171:10002 route=1
71 # WebHead2
72 BalancerMember http://10.58.1.172:10001 route=2
73
74 # Security "technically we aren't blocking
75 # anyone but this the place to make those
76 # chages
77 Order Deny,Allow
78 Deny from none
79 Allow from all
80
81 # Load Balancer Settings
82 # We will be configuring a simple Round
83 # Robin style load balancer. This means
84 # that all webheads take an equal share of
85 # of the load.
86 ProxySet stickysession=ROUTEID
87
88 </Proxy>
89
90 # balancer-manager
91 # This tool is built into the mod_proxy_balancer
92 # module and will allow you to do some simple
93 # modifications to the balanced group via a gui
94 # web interface.
95 <Location /balancer-manager>
96 SetHandler balancer-manager
97
98 # recommend locking this one down to your
99 # your office
100 Order deny,allow
101 Allow from all
102 </Location>
103
104 # Point of Balance
105 # This setting will allow to explicitly name the
106 # the location in the site that we want to be
107 # balanced, in this example we will balance "/"
108 # or everything in the site.
109 ProxyPass /balancer-manager !
110 ProxyPass / balancer://mycluster/
111
112 ProxyPassReverse / balancer://mycluster/
113
114 </VirtualHost>
@@ -9,7 +9,6 b' the information in the following section'
9 9 .. toctree::
10 10
11 11 apache-diffie-hellman
12 apache-conf-examples
12 apache-conf-example
13 13 apache-subdirectory
14 apache-reverse-proxy
15 14 apache-wsgi-coding
@@ -7,7 +7,8 b' Use the following example to configure A'
7 7
8 8 .. code-block:: apache
9 9
10 <Location /<someprefix>/ # Change <someprefix> into your chosen prefix
10 # Change someprefix into your chosen prefix
11 <Location /someprefix >
11 12 ProxyPreserveHost On
12 13 ProxyPass "http://127.0.0.1:5000/"
13 14 ProxyPassReverse "http://127.0.0.1:5000/"
@@ -3,6 +3,7 b' Nginx Configuration Example'
3 3
4 4 Use the following example to configure Nginx as a your web server.
5 5
6
6 7 .. code-block:: nginx
7 8
8 9 log_format log_custom '$remote_addr - $remote_user [$time_local] '
@@ -10,8 +11,10 b' Use the following example to configure N'
10 11 '"$http_referer" "$http_user_agent" '
11 12 '$request_time $upstream_response_time $pipe';
12 13
14 ## define upstream (local RhodeCode instance) to connect to
13 15 upstream rc {
14
16 # Url to running RhodeCode instance.
17 # This is shown as `- URL:` in output from rccontrol status.
15 18 server 127.0.0.1:10002;
16 19
17 20 # add more instances for load balancing
@@ -19,8 +22,17 b' Use the following example to configure N'
19 22 # server 127.0.0.1:10004;
20 23 }
21 24
22 ## gist alias server, for serving nicer GIST urls
25 ## HTTP to HTTPS rewrite
26 server {
27 listen 80;
28 server_name rhodecode.myserver.com;
23 29
30 if ($http_host = rhodecode.myserver.com) {
31 rewrite (.*) https://rhodecode.myserver.com$1 permanent;
32 }
33 }
34
35 ## Optional gist alias server, for serving nicer GIST urls.
24 36 server {
25 37 listen 443;
26 38 server_name gist.myserver.com;
@@ -37,6 +49,7 b' Use the following example to configure N'
37 49 ssl_prefer_server_ciphers on;
38 50 ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
39 51
52 # strict http prevents from https -> http downgrade
40 53 add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";
41 54
42 55 # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
@@ -46,15 +59,6 b' Use the following example to configure N'
46 59 rewrite (.*) https://rhodecode.myserver.com/_admin/gists;
47 60 }
48 61
49 ## HTTP to HTTPS rewrite
50 server {
51 listen 80;
52 server_name rhodecode.myserver.com;
53
54 if ($http_host = rhodecode.myserver.com) {
55 rewrite (.*) https://rhodecode.myserver.com$1 permanent;
56 }
57 }
58 62
59 63 ## MAIN SSL enabled server
60 64 server {
@@ -79,14 +83,15 b' Use the following example to configure N'
79 83
80 84 include /etc/nginx/proxy.conf;
81 85
82 ## serve static files by nginx, recommended
86 ## serve static files by Nginx, recommended for performance
83 87 # location /_static/rhodecode {
84 88 # alias /path/to/.rccontrol/enterprise-1/static;
85 89 # }
86 90
87 ## channel stream live components
91 ## channelstream websocket handling
88 92 location /_channelstream {
89 93 rewrite /_channelstream/(.*) /$1 break;
94
90 95 proxy_pass http://127.0.0.1:9800;
91 96
92 97 proxy_connect_timeout 10;
@@ -1,7 +1,7 b''
1 1 .. _nginx-ws-ref:
2 2
3 Nginx Configuration
4 ===================
3 Nginx HTTP Server Configuration
4 -------------------------------
5 5
6 6 To set up your Nginx Web Server for optimal performance and security, use
7 7 the information in the following sections.
@@ -12,6 +12,7 b' it somehow becomes unavailable you can u'
12 12 Logging into the |RCE| database with ``iShell`` should only be done by an
13 13 experienced and knowledgeable database administrator.
14 14
15
15 16 Reset Admin Account Privileges
16 17 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17 18
@@ -22,8 +23,7 b' account permissions.'
22 23 .. code-block:: bash
23 24
24 25 # Open iShell from the terminal
25 $ .rccontrol/enterprise-1/profile/bin/paster \
26 ishell .rccontrol/enterprise-1/rhodecode.ini
26 $ rccontrol ishell enterprise-1
27 27
28 28 .. code-block:: mysql
29 29
@@ -33,6 +33,7 b' account permissions.'
33 33 In [3]: Session().add(adminuser);Session().commit()
34 34 In [4]: exit()
35 35
36
36 37 Set to read global ``.hgrc`` file
37 38 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
38 39
@@ -46,8 +47,7 b' following example to make changes to thi'
46 47 .. code-block:: bash
47 48
48 49 # Open iShell from the terminal
49 $ .rccontrol/enterprise-5/profile/bin/paster \
50 ishell.rccontrol/enterprise-5/rhodecode.ini
50 $ rccontrol ishell enterprise-1
51 51
52 52 .. code-block:: mysql
53 53
@@ -59,6 +59,7 b' following example to make changes to thi'
59 59 In [5]: Session().add(new_option);Session().commit()
60 60 In [6]: exit()
61 61
62
62 63 Manually Reset Password
63 64 ^^^^^^^^^^^^^^^^^^^^^^^
64 65
@@ -73,8 +74,7 b' Use the following code example to carry '
73 74 .. code-block:: bash
74 75
75 76 # starts the ishell interactive prompt
76 $ .rccontrol/enterprise-1/profile/bin/paster \
77 ishell .rccontrol/enterprise-1/rhodecode.ini
77 $ rccontrol ishell enterprise-1
78 78
79 79 .. code-block:: mysql
80 80
@@ -91,7 +91,6 b' Use the following code example to carry '
91 91 In [8]: exit()
92 92
93 93
94
95 94 Change user details
96 95 ^^^^^^^^^^^^^^^^^^^
97 96
@@ -106,8 +105,7 b' Use the following code example to carry '
106 105 .. code-block:: bash
107 106
108 107 # starts the ishell interactive prompt
109 $ .rccontrol/enterprise-1/profile/bin/paster \
110 ishell .rccontrol/enterprise-1/rhodecode.ini
108 $ rccontrol ishell enterprise-1
111 109
112 110 .. code-block:: mysql
113 111
@@ -117,3 +115,37 b' Use the following code example to carry '
117 115 In [3]: my_user.username = 'SomeUser'
118 116 In [4]: Session().add(my_user);Session().commit()
119 117 In [5]: exit()
118
119
120 Change user login type
121 ^^^^^^^^^^^^^^^^^^^^^^
122
123 Sometimes it's required to change account type from RhodeCode to LDAP or
124 other external authentication type.
125 If you need to manually change the method of login, use the following steps.
126
127 1. Navigate to your |RCE| install location.
128 2. Run the interactive ``ishell`` prompt.
129 3. Set a new arguments for users.
130
131 Use the following code example to carry out these steps.
132 Available values for new_extern_type can be found when browsing available
133 authentication types in RhodeCode admin interface for authentication.
134 Use the text which is shown after '#' sign, eg.
135 ` LDAP (egg:rhodecode-enterprise-ce#ldap)` it's type is 'ldap'
136
137 .. code-block:: bash
138
139 # starts the ishell interactive prompt
140 $ rccontrol ishell enterprise-1
141
142 .. code-block:: mysql
143
144 # Use this example to change users from authentication
145 # using rhodecode internal to ldap
146 In [1]: new_extern_type = 'ldap'
147 In [2]: my_user = User.get_by_username('some_username')
148 In [3]: my_user.extern_type = new_extern_type
149 In [4]: my_user.extern_name = new_extern_type
150 In [5]: Session().add(my_user);Session().commit()
151 In [6]: exit()
@@ -27,6 +27,7 b' Once installed you need to enable ``dav_'
27 27
28 28 $ sudo a2enmod dav_svn
29 29 $ sudo a2enmod headers
30 $ sudo a2enmod authn_anon
30 31
31 32
32 33 Configuring Apache Setup
@@ -55,7 +56,7 b' permission issues could occur. To do thi'
55 56 export APACHE_RUN_GROUP=rhodecode
56 57
57 58 1. To configure Apache, create and edit a virtual hosts file, for example
58 :file:`/etc/apache2/sites-available/default.conf`. Below is an example
59 :file:`/etc/apache2/sites-enabled/default.conf`. Below is an example
59 60 how to use one with auto-generated config ```mod_dav_svn.conf```
60 61 from configured |RCE| instance.
61 62
@@ -13,7 +13,7 b' 1. Open ishell from the terminal and use'
13 13 .. code-block:: bash
14 14
15 15 # Open iShell from the terminal and set ini file
16 $ .rccontrol/enterprise-1/profile/bin/paster ishell .rccontrol/enterprise-1/rhodecode.ini
16 $ rccontrol ishell enterprise-1
17 17
18 18 2. Run the following commands, and ensure that |RCE| has write access to the
19 19 new directory:
@@ -3,21 +3,6 b''
3 3 Increase Database Performance
4 4 -----------------------------
5 5
6 To increase database performance switch to database-based user sessions.
7 File-based sessions are only suitable for smaller setups. The most common
8 issue being file limit errors which occur if there are lots of session files.
9 Therefore, in a large scale deployment, to give better performance,
10 scalability, and maintainability we recommend switching from file-based
11 sessions to database-based user sessions.
6 For tuning PostgreSQL we recommend reading: http://www.revsys.com/writings/postgresql-performance.html
12 7
13 To switch to database-based user sessions uncomment the following section in
14 your :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file.
15
16 .. code-block:: ini
17
18 # db session
19 beaker.session.type = ext:database
20
21 # adjust this property to include your database credentials
22 beaker.session.sa.url = postgresql://postgres:<pass>@localhost/rhodecode
23 beaker.session.table_name = db_session
8 For tuning MySQL we recommend reading: http://www.tecmint.com/mysql-mariadb-performance-tuning-and-optimization/ No newline at end of file
@@ -34,8 +34,8 b' performance boost.'
34 34
35 35 .. code-block:: bash
36 36
37 # mount tmp to memory with 2GB limit and 755 write permissions
38 mount -t tmpfs -o size=2G,mode=0755 tmpfs /tmp
37 # mount tmp to memory with 2GB limit and 1777 write permissions
38 mount -t tmpfs -o size=2G,mode=1777 tmpfs /tmp
39 39
40 40 For more information about TMPFS, see the documentation `here`_.
41 41
@@ -10,6 +10,7 b' may find some of the following methods u'
10 10
11 11 tuning-gunicorn
12 12 tuning-vcs-memory-cache
13 tuning-user-sessions-performance
13 14 tuning-increase-db-performance
14 15 tuning-scale-horizontally
15 16 tuning-increase-cache-size
@@ -36,7 +36,7 b' close_pull_request'
36 36 comment_pull_request
37 37 --------------------
38 38
39 .. py:function:: comment_pull_request(apiuser, repoid, pullrequestid, message=<Optional:None>, status=<Optional:None>, userid=<Optional:<OptionalAttr:apiuser>>)
39 .. py:function:: comment_pull_request(apiuser, repoid, pullrequestid, message=<Optional:None>, commit_id=<Optional:None>, status=<Optional:None>, comment_type=<Optional:u'note'>, resolves_comment_id=<Optional:None>, userid=<Optional:<OptionalAttr:apiuser>>)
40 40
41 41 Comment on the pull request specified with the `pullrequestid`,
42 42 in the |repo| specified by the `repoid`, and optionally change the
@@ -48,15 +48,18 b' comment_pull_request'
48 48 :type repoid: str or int
49 49 :param pullrequestid: The pull request ID.
50 50 :type pullrequestid: int
51 :param commit_id: Specify the commit_id for which to set a comment. If
52 given commit_id is different than latest in the PR status
53 change won't be performed.
54 :type commit_id: str
51 55 :param message: The text content of the comment.
52 56 :type message: str
53 57 :param status: (**Optional**) Set the approval status of the pull
54 request. Valid options are:
55 * not_reviewed
56 * approved
57 * rejected
58 * under_review
58 request. One of: 'not_reviewed', 'approved', 'rejected',
59 'under_review'
59 60 :type status: str
61 :param comment_type: Comment type, one of: 'note', 'todo'
62 :type comment_type: Optional(str), default: 'note'
60 63 :param userid: Comment on the pull request as this user
61 64 :type userid: Optional(str or int)
62 65
@@ -68,7 +71,9 b' comment_pull_request'
68 71 result :
69 72 {
70 73 "pull_request_id": "<Integer>",
71 "comment_id": "<Integer>"
74 "comment_id": "<Integer>",
75 "status": {"given": <given_status>,
76 "was_changed": <bool status_was_actually_changed> },
72 77 }
73 78 error : null
74 79
@@ -28,7 +28,7 b' add_field_to_repo'
28 28 comment_commit
29 29 --------------
30 30
31 .. py:function:: comment_commit(apiuser, repoid, commit_id, message, userid=<Optional:<OptionalAttr:apiuser>>, status=<Optional:None>)
31 .. py:function:: comment_commit(apiuser, repoid, commit_id, message, status=<Optional:None>, comment_type=<Optional:u'note'>, resolves_comment_id=<Optional:None>, userid=<Optional:<OptionalAttr:apiuser>>)
32 32
33 33 Set a commit comment, and optionally change the status of the commit.
34 34
@@ -40,15 +40,17 b' comment_commit'
40 40 :type commit_id: str
41 41 :param message: The comment text.
42 42 :type message: str
43 :param status: (**Optional**) status of commit, one of: 'not_reviewed',
44 'approved', 'rejected', 'under_review'
45 :type status: str
46 :param comment_type: Comment type, one of: 'note', 'todo'
47 :type comment_type: Optional(str), default: 'note'
43 48 :param userid: Set the user name of the comment creator.
44 49 :type userid: Optional(str or int)
45 :param status: status, one of 'not_reviewed', 'approved', 'rejected',
46 'under_review'
47 :type status: str
48 50
49 51 Example error output:
50 52
51 .. code-block:: json
53 .. code-block:: bash
52 54
53 55 {
54 56 "id" : <id_given_in_input>,
@@ -539,7 +541,7 b' get_repo_settings'
539 541 get_repos
540 542 ---------
541 543
542 .. py:function:: get_repos(apiuser)
544 .. py:function:: get_repos(apiuser, root=<Optional:None>, traverse=<Optional:True>)
543 545
544 546 Lists all existing repositories.
545 547
@@ -548,6 +550,14 b' get_repos'
548 550
549 551 :param apiuser: This is filled automatically from the |authtoken|.
550 552 :type apiuser: AuthUser
553 :param root: specify root repository group to fetch repositories.
554 filters the returned repositories to be members of given root group.
555 :type root: Optional(None)
556 :param traverse: traverse given root into subrepositories. With this flag
557 set to False, it will only return top-level repositories from `root`.
558 if root is empty it will return just top-level repositories.
559 :type traverse: Optional(True)
560
551 561
552 562 Example output:
553 563
@@ -3,6 +3,49 b''
3 3 server methods
4 4 ==============
5 5
6 cleanup_sessions
7 ----------------
8
9 .. py:function:: cleanup_sessions(apiuser, older_then=<Optional:60>)
10
11 Triggers a session cleanup action.
12
13 If the ``older_then`` option is set, only sessions that hasn't been
14 accessed in the given number of days will be removed.
15
16 This command can only be run using an |authtoken| with admin rights to
17 the specified repository.
18
19 This command takes the following options:
20
21 :param apiuser: This is filled automatically from the |authtoken|.
22 :type apiuser: AuthUser
23 :param older_then: Deletes session that hasn't been accessed
24 in given number of days.
25 :type older_then: Optional(int)
26
27 Example output:
28
29 .. code-block:: bash
30
31 id : <id_given_in_input>
32 result: {
33 "backend": "<type of backend>",
34 "sessions_removed": <number_of_removed_sessions>
35 }
36 error : null
37
38 Example error output:
39
40 .. code-block:: bash
41
42 id : <id_given_in_input>
43 result : null
44 error : {
45 'Error occurred during session cleanup'
46 }
47
48
6 49 get_ip
7 50 ------
8 51
@@ -47,6 +47,17 b' Followed by::'
47 47 nix-channel --update
48 48
49 49
50 Install required binaries
51 -------------------------
52
53 We need some handy tools first.
54
55 run::
56
57 nix-env -i nix-prefetch-hg
58 nix-env -i nix-prefetch-git
59
60
50 61 Clone the required repositories
51 62 -------------------------------
52 63
@@ -64,6 +75,21 b' To do this, use the following example::'
64 75 via support@rhodecode.com
65 76
66 77
78 Install some required libraries
79 -------------------------------
80
81 There are some required drivers that we need to install to test RhodeCode
82 under different types of databases. For example in Ubuntu we need to install
83 the following.
84
85 required libraries::
86
87 sudo apt-get install libapr1-dev libaprutil1-dev
88 sudo apt-get install libsvn-dev
89 sudo apt-get install mysql-server libmysqlclient-dev
90 sudo apt-get install postgresql postgresql-contrib libpq-dev
91 sudo apt-get install libcurl4-openssl-dev
92
67 93
68 94 Enter the Development Shell
69 95 ---------------------------
@@ -9,6 +9,7 b' Release Notes'
9 9 .. toctree::
10 10 :maxdepth: 1
11 11
12 release-notes-4.6.0.rst
12 13 release-notes-4.5.2.rst
13 14 release-notes-4.5.1.rst
14 15 release-notes-4.5.0.rst
@@ -68,6 +68,7 b''
68 68 "<%= dirs.js.src %>/rhodecode/utils/os.js",
69 69 "<%= dirs.js.src %>/rhodecode/utils/topics.js",
70 70 "<%= dirs.js.src %>/rhodecode/init.js",
71 "<%= dirs.js.src %>/rhodecode/changelog.js",
71 72 "<%= dirs.js.src %>/rhodecode/codemirror.js",
72 73 "<%= dirs.js.src %>/rhodecode/comments.js",
73 74 "<%= dirs.js.src %>/rhodecode/constants.js",
@@ -100,11 +100,7 b' self: super: {'
100 100 });
101 101
102 102 py-gfm = super.py-gfm.override {
103 src = pkgs.fetchgit {
104 url = "https://code.rhodecode.com/upstream/py-gfm";
105 rev = "0d66a19bc16e3d49de273c0f797d4e4781e8c0f2";
106 sha256 = "0ryp74jyihd3ckszq31bml5jr3bciimhfp7va7kw6ld92930ksv3";
107 };
103 name = "py-gfm-0.1.3.rhodecode-upstream1";
108 104 };
109 105
110 106 pycurl = super.pycurl.override (attrs: {
@@ -123,12 +119,7 b' self: super: {'
123 119 });
124 120
125 121 Pylons = super.Pylons.override (attrs: {
126 name = "Pylons-1.0.1-patch1";
127 src = pkgs.fetchgit {
128 url = "https://code.rhodecode.com/upstream/pylons";
129 rev = "707354ee4261b9c10450404fc9852ccea4fd667d";
130 sha256 = "b2763274c2780523a335f83a1df65be22ebe4ff413a7bc9e9288d23c1f62032e";
131 };
122 name = "Pylons-1.0.2.rhodecode-patch1";
132 123 });
133 124
134 125 pyramid = super.pyramid.override (attrs: {
@@ -149,16 +140,6 b' self: super: {'
149 140 };
150 141 });
151 142
152 Pyro4 = super.Pyro4.override (attrs: {
153 # TODO: Was not able to generate this version, needs further
154 # investigation.
155 name = "Pyro4-4.35";
156 src = pkgs.fetchurl {
157 url = "https://pypi.python.org/packages/source/P/Pyro4/Pyro4-4.35.src.tar.gz";
158 md5 = "cbe6cb855f086a0f092ca075005855f3";
159 };
160 });
161
162 143 pysqlite = super.pysqlite.override (attrs: {
163 144 propagatedBuildInputs = [
164 145 pkgs.sqlite
@@ -202,12 +183,6 b' self: super: {'
202 183 '';
203 184 });
204 185
205 rhodecode-tools = super.rhodecode-tools.override (attrs: {
206 patches = [
207 ./patch-rhodecode-tools-setup.diff
208 ];
209 });
210
211 186 URLObject = super.URLObject.override (attrs: {
212 187 meta = {
213 188 license = {
@@ -81,26 +81,26 b''
81 81 };
82 82 };
83 83 Mako = super.buildPythonPackage {
84 name = "Mako-1.0.1";
84 name = "Mako-1.0.6";
85 85 buildInputs = with self; [];
86 86 doCheck = false;
87 87 propagatedBuildInputs = with self; [MarkupSafe];
88 88 src = fetchurl {
89 url = "https://pypi.python.org/packages/8e/a4/aa56533ecaa5f22ca92428f74e074d0c9337282933c722391902c8f9e0f8/Mako-1.0.1.tar.gz";
90 md5 = "9f0aafd177b039ef67b90ea350497a54";
89 url = "https://pypi.python.org/packages/56/4b/cb75836863a6382199aefb3d3809937e21fa4cb0db15a4f4ba0ecc2e7e8e/Mako-1.0.6.tar.gz";
90 md5 = "a28e22a339080316b2acc352b9ee631c";
91 91 };
92 92 meta = {
93 93 license = [ pkgs.lib.licenses.mit ];
94 94 };
95 95 };
96 96 Markdown = super.buildPythonPackage {
97 name = "Markdown-2.6.2";
97 name = "Markdown-2.6.7";
98 98 buildInputs = with self; [];
99 99 doCheck = false;
100 100 propagatedBuildInputs = with self; [];
101 101 src = fetchurl {
102 url = "https://pypi.python.org/packages/62/8b/83658b5f6c220d5fcde9f9852d46ea54765d734cfbc5a9f4c05bfc36db4d/Markdown-2.6.2.tar.gz";
103 md5 = "256d19afcc564dc4ce4c229bb762f7ae";
102 url = "https://pypi.python.org/packages/48/a4/fc6b002789c2239ac620ca963694c95b8f74e4747769cdf6021276939e74/Markdown-2.6.7.zip";
103 md5 = "632710a7474bbb74a82084392251061f";
104 104 };
105 105 meta = {
106 106 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -133,13 +133,13 b''
133 133 };
134 134 };
135 135 Paste = super.buildPythonPackage {
136 name = "Paste-2.0.2";
136 name = "Paste-2.0.3";
137 137 buildInputs = with self; [];
138 138 doCheck = false;
139 139 propagatedBuildInputs = with self; [six];
140 140 src = fetchurl {
141 url = "https://pypi.python.org/packages/d5/8d/0f8ac40687b97ff3e07ebd1369be20bdb3f93864d2dc3c2ff542edb4ce50/Paste-2.0.2.tar.gz";
142 md5 = "4bfc8a7eaf858f6309d2ac0f40fc951c";
141 url = "https://pypi.python.org/packages/30/c3/5c2f7c7a02e4f58d4454353fa1c32c94f79fa4e36d07a67c0ac295ea369e/Paste-2.0.3.tar.gz";
142 md5 = "1231e14eae62fa7ed76e9130b04bc61e";
143 143 };
144 144 meta = {
145 145 license = [ pkgs.lib.licenses.mit ];
@@ -172,26 +172,26 b''
172 172 };
173 173 };
174 174 Pygments = super.buildPythonPackage {
175 name = "Pygments-2.1.3";
175 name = "Pygments-2.2.0";
176 176 buildInputs = with self; [];
177 177 doCheck = false;
178 178 propagatedBuildInputs = with self; [];
179 179 src = fetchurl {
180 url = "https://pypi.python.org/packages/b8/67/ab177979be1c81bc99c8d0592ef22d547e70bb4c6815c383286ed5dec504/Pygments-2.1.3.tar.gz";
181 md5 = "ed3fba2467c8afcda4d317e4ef2c6150";
180 url = "https://pypi.python.org/packages/71/2a/2e4e77803a8bd6408a2903340ac498cb0a2181811af7c9ec92cb70b0308a/Pygments-2.2.0.tar.gz";
181 md5 = "13037baca42f16917cbd5ad2fab50844";
182 182 };
183 183 meta = {
184 184 license = [ pkgs.lib.licenses.bsdOriginal ];
185 185 };
186 186 };
187 187 Pylons = super.buildPythonPackage {
188 name = "Pylons-1.0.1";
188 name = "Pylons-1.0.2.dev20161213";
189 189 buildInputs = with self; [];
190 190 doCheck = false;
191 191 propagatedBuildInputs = with self; [Routes WebHelpers Beaker Paste PasteDeploy PasteScript FormEncode simplejson decorator nose Mako WebError WebTest Tempita MarkupSafe WebOb];
192 192 src = fetchurl {
193 url = "https://pypi.python.org/packages/a2/69/b835a6bad00acbfeed3f33c6e44fa3f936efc998c795bfb15c61a79ecf62/Pylons-1.0.1.tar.gz";
194 md5 = "6cb880d75fa81213192142b07a6e4915";
193 url = "https://code.rhodecode.com/upstream/pylons/archive/707354ee4261b9c10450404fc9852ccea4fd667d.tar.gz?md5=f26633726fa2cd3a340316ee6a5d218f";
194 md5 = "f26633726fa2cd3a340316ee6a5d218f";
195 195 };
196 196 meta = {
197 197 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -341,13 +341,13 b''
341 341 };
342 342 };
343 343 Whoosh = super.buildPythonPackage {
344 name = "Whoosh-2.7.0";
344 name = "Whoosh-2.7.4";
345 345 buildInputs = with self; [];
346 346 doCheck = false;
347 347 propagatedBuildInputs = with self; [];
348 348 src = fetchurl {
349 url = "https://pypi.python.org/packages/1c/dc/2f0231ff3875ded36df8c1ab851451e51a237dc0e5a86d3d96036158da94/Whoosh-2.7.0.zip";
350 md5 = "7abfd970f16fadc7311960f3fa0bc7a9";
349 url = "https://pypi.python.org/packages/25/2b/6beed2107b148edc1321da0d489afc4617b9ed317ef7b72d4993cad9b684/Whoosh-2.7.4.tar.gz";
350 md5 = "c2710105f20b3e29936bd2357383c325";
351 351 };
352 352 meta = {
353 353 license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.bsd2 ];
@@ -639,19 +639,6 b''
639 639 license = [ pkgs.lib.licenses.bsdOriginal ];
640 640 };
641 641 };
642 dulwich = super.buildPythonPackage {
643 name = "dulwich-0.12.0";
644 buildInputs = with self; [];
645 doCheck = false;
646 propagatedBuildInputs = with self; [];
647 src = fetchurl {
648 url = "https://pypi.python.org/packages/6f/04/fbe561b6d45c0ec758330d5b7f5ba4b6cb4f1ca1ab49859d2fc16320da75/dulwich-0.12.0.tar.gz";
649 md5 = "f3a8a12bd9f9dd8c233e18f3d49436fa";
650 };
651 meta = {
652 license = [ pkgs.lib.licenses.gpl2Plus ];
653 };
654 };
655 642 ecdsa = super.buildPythonPackage {
656 643 name = "ecdsa-0.11";
657 644 buildInputs = with self; [];
@@ -679,13 +666,13 b''
679 666 };
680 667 };
681 668 elasticsearch-dsl = super.buildPythonPackage {
682 name = "elasticsearch-dsl-2.0.0";
669 name = "elasticsearch-dsl-2.2.0";
683 670 buildInputs = with self; [];
684 671 doCheck = false;
685 672 propagatedBuildInputs = with self; [six python-dateutil elasticsearch];
686 673 src = fetchurl {
687 url = "https://pypi.python.org/packages/4e/5d/e788ae8dbe2ff4d13426db0a027533386a5c276c77a2654dc0e2007ce04a/elasticsearch-dsl-2.0.0.tar.gz";
688 md5 = "4cdfec81bb35383dd3b7d02d7dc5ee68";
674 url = "https://pypi.python.org/packages/66/2f/52a086968788e58461641570f45c3207a52d46ebbe9b77dc22b6a8ffda66/elasticsearch-dsl-2.2.0.tar.gz";
675 md5 = "fa6bd3c87ea3caa8f0f051bc37c53221";
689 676 };
690 677 meta = {
691 678 license = [ pkgs.lib.licenses.asl20 ];
@@ -731,13 +718,13 b''
731 718 };
732 719 };
733 720 gevent = super.buildPythonPackage {
734 name = "gevent-1.1.1";
721 name = "gevent-1.1.2";
735 722 buildInputs = with self; [];
736 723 doCheck = false;
737 724 propagatedBuildInputs = with self; [greenlet];
738 725 src = fetchurl {
739 url = "https://pypi.python.org/packages/12/dc/0b2e57823225de86f6e111a65d212c9e3b64847dddaa19691a6cb94b0b2e/gevent-1.1.1.tar.gz";
740 md5 = "1532f5396ab4d07a231f1935483be7c3";
726 url = "https://pypi.python.org/packages/43/8f/cb3224a0e6ab663547f45c10d0651cfd52633fde4283bf68d627084df8cc/gevent-1.1.2.tar.gz";
727 md5 = "bb32a2f852a4997138014d5007215c6e";
741 728 };
742 729 meta = {
743 730 license = [ pkgs.lib.licenses.mit ];
@@ -757,26 +744,26 b''
757 744 };
758 745 };
759 746 gprof2dot = super.buildPythonPackage {
760 name = "gprof2dot-2015.12.1";
747 name = "gprof2dot-2016.10.13";
761 748 buildInputs = with self; [];
762 749 doCheck = false;
763 750 propagatedBuildInputs = with self; [];
764 751 src = fetchurl {
765 url = "https://pypi.python.org/packages/b9/34/7bf93c1952d40fa5c95ad963f4d8344b61ef58558632402eca18e6c14127/gprof2dot-2015.12.1.tar.gz";
766 md5 = "e23bf4e2f94db032750c193384b4165b";
752 url = "https://pypi.python.org/packages/a0/e0/73c71baed306f0402a00a94ffc7b2be94ad1296dfcb8b46912655b93154c/gprof2dot-2016.10.13.tar.gz";
753 md5 = "0125401f15fd2afe1df686a76c64a4fd";
767 754 };
768 755 meta = {
769 756 license = [ { fullName = "LGPL"; } ];
770 757 };
771 758 };
772 759 greenlet = super.buildPythonPackage {
773 name = "greenlet-0.4.9";
760 name = "greenlet-0.4.10";
774 761 buildInputs = with self; [];
775 762 doCheck = false;
776 763 propagatedBuildInputs = with self; [];
777 764 src = fetchurl {
778 url = "https://pypi.python.org/packages/4e/3d/9d421539b74e33608b245092870156b2e171fb49f2b51390aa4641eecb4a/greenlet-0.4.9.zip";
779 md5 = "c6659cdb2a5e591723e629d2eef22e82";
765 url = "https://pypi.python.org/packages/67/62/ca2a95648666eaa2ffeb6a9b3964f21d419ae27f82f2e66b53da5b943fc4/greenlet-0.4.10.zip";
766 md5 = "bed0c4b3b896702131f4d5c72f87c41d";
780 767 };
781 768 meta = {
782 769 license = [ pkgs.lib.licenses.mit ];
@@ -939,13 +926,13 b''
939 926 };
940 927 };
941 928 msgpack-python = super.buildPythonPackage {
942 name = "msgpack-python-0.4.6";
929 name = "msgpack-python-0.4.8";
943 930 buildInputs = with self; [];
944 931 doCheck = false;
945 932 propagatedBuildInputs = with self; [];
946 933 src = fetchurl {
947 url = "https://pypi.python.org/packages/15/ce/ff2840885789ef8035f66cd506ea05bdb228340307d5e71a7b1e3f82224c/msgpack-python-0.4.6.tar.gz";
948 md5 = "8b317669314cf1bc881716cccdaccb30";
934 url = "https://pypi.python.org/packages/21/27/8a1d82041c7a2a51fcc73675875a5f9ea06c2663e02fcfeb708be1d081a0/msgpack-python-0.4.8.tar.gz";
935 md5 = "dcd854fb41ee7584ebbf35e049e6be98";
949 936 };
950 937 meta = {
951 938 license = [ pkgs.lib.licenses.asl20 ];
@@ -1108,13 +1095,13 b''
1108 1095 };
1109 1096 };
1110 1097 py = super.buildPythonPackage {
1111 name = "py-1.4.29";
1098 name = "py-1.4.31";
1112 1099 buildInputs = with self; [];
1113 1100 doCheck = false;
1114 1101 propagatedBuildInputs = with self; [];
1115 1102 src = fetchurl {
1116 url = "https://pypi.python.org/packages/2a/bc/a1a4a332ac10069b8e5e25136a35e08a03f01fd6ab03d819889d79a1fd65/py-1.4.29.tar.gz";
1117 md5 = "c28e0accba523a29b35a48bb703fb96c";
1103 url = "https://pypi.python.org/packages/f4/9a/8dfda23f36600dd701c6722316ba8a3ab4b990261f83e7d3ffc6dfedf7ef/py-1.4.31.tar.gz";
1104 md5 = "5d2c63c56dc3f2115ec35c066ecd582b";
1118 1105 };
1119 1106 meta = {
1120 1107 license = [ pkgs.lib.licenses.mit ];
@@ -1139,8 +1126,8 b''
1139 1126 doCheck = false;
1140 1127 propagatedBuildInputs = with self; [setuptools Markdown];
1141 1128 src = fetchurl {
1142 url = "https://pypi.python.org/packages/12/e4/6b3d8678da04f97d7490d8264d8de51c2dc9fb91209ccee9c515c95e14c5/py-gfm-0.1.3.tar.gz";
1143 md5 = "e588d9e69640a241b97e2c59c22527a6";
1129 url = "https://code.rhodecode.com/upstream/py-gfm/archive/0d66a19bc16e3d49de273c0f797d4e4781e8c0f2.tar.gz?md5=0d0d5385bfb629eea636a80b9c2bfd16";
1130 md5 = "0d0d5385bfb629eea636a80b9c2bfd16";
1144 1131 };
1145 1132 meta = {
1146 1133 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -1290,13 +1277,13 b''
1290 1277 };
1291 1278 };
1292 1279 pytest = super.buildPythonPackage {
1293 name = "pytest-2.8.5";
1280 name = "pytest-3.0.5";
1294 1281 buildInputs = with self; [];
1295 1282 doCheck = false;
1296 1283 propagatedBuildInputs = with self; [py];
1297 1284 src = fetchurl {
1298 url = "https://pypi.python.org/packages/b1/3d/d7ea9b0c51e0cacded856e49859f0a13452747491e842c236bbab3714afe/pytest-2.8.5.zip";
1299 md5 = "8493b06f700862f1294298d6c1b715a9";
1285 url = "https://pypi.python.org/packages/a8/87/b7ca49efe52d2b4169f2bfc49aa5e384173c4619ea8e635f123a0dac5b75/pytest-3.0.5.tar.gz";
1286 md5 = "cefd527b59332688bf5db4a10aa8a7cb";
1300 1287 };
1301 1288 meta = {
1302 1289 license = [ pkgs.lib.licenses.mit ];
@@ -1316,52 +1303,65 b''
1316 1303 };
1317 1304 };
1318 1305 pytest-cov = super.buildPythonPackage {
1319 name = "pytest-cov-1.8.1";
1306 name = "pytest-cov-2.4.0";
1320 1307 buildInputs = with self; [];
1321 1308 doCheck = false;
1322 propagatedBuildInputs = with self; [py pytest coverage cov-core];
1309 propagatedBuildInputs = with self; [pytest coverage];
1323 1310 src = fetchurl {
1324 url = "https://pypi.python.org/packages/11/4b/b04646e97f1721878eb21e9f779102d84dd044d324382263b1770a3e4838/pytest-cov-1.8.1.tar.gz";
1325 md5 = "76c778afa2494088270348be42d759fc";
1311 url = "https://pypi.python.org/packages/00/c0/2bfd1fcdb9d407b8ac8185b1cb5ff458105c6b207a9a7f0e13032de9828f/pytest-cov-2.4.0.tar.gz";
1312 md5 = "2fda09677d232acc99ec1b3c5831e33f";
1326 1313 };
1327 1314 meta = {
1328 license = [ pkgs.lib.licenses.mit ];
1315 license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.mit ];
1329 1316 };
1330 1317 };
1331 1318 pytest-profiling = super.buildPythonPackage {
1332 name = "pytest-profiling-1.0.1";
1319 name = "pytest-profiling-1.2.2";
1333 1320 buildInputs = with self; [];
1334 1321 doCheck = false;
1335 1322 propagatedBuildInputs = with self; [six pytest gprof2dot];
1336 1323 src = fetchurl {
1337 url = "https://pypi.python.org/packages/d8/67/8ffab73406e22870e07fa4dc8dce1d7689b26dba8efd00161c9b6fc01ec0/pytest-profiling-1.0.1.tar.gz";
1338 md5 = "354404eb5b3fd4dc5eb7fffbb3d9b68b";
1324 url = "https://pypi.python.org/packages/73/e8/804681323bac0bc45c520ec34185ba8469008942266d0074699b204835c1/pytest-profiling-1.2.2.tar.gz";
1325 md5 = "0a16d7dda2d23b91e9730fa4558cf728";
1339 1326 };
1340 1327 meta = {
1341 1328 license = [ pkgs.lib.licenses.mit ];
1342 1329 };
1343 1330 };
1344 1331 pytest-runner = super.buildPythonPackage {
1345 name = "pytest-runner-2.7.1";
1332 name = "pytest-runner-2.9";
1346 1333 buildInputs = with self; [];
1347 1334 doCheck = false;
1348 1335 propagatedBuildInputs = with self; [];
1349 1336 src = fetchurl {
1350 url = "https://pypi.python.org/packages/99/6b/c4ff4418d3424d4475b7af60724fd4a5cdd91ed8e489dc9443281f0052bc/pytest-runner-2.7.1.tar.gz";
1351 md5 = "e56f0bc8d79a6bd91772b44ef4215c7e";
1337 url = "https://pypi.python.org/packages/11/d4/c335ddf94463e451109e3494e909765c3e5205787b772e3b25ee8601b86a/pytest-runner-2.9.tar.gz";
1338 md5 = "2212a2e34404b0960b2fdc2c469247b2";
1352 1339 };
1353 1340 meta = {
1354 1341 license = [ pkgs.lib.licenses.mit ];
1355 1342 };
1356 1343 };
1344 pytest-sugar = super.buildPythonPackage {
1345 name = "pytest-sugar-0.7.1";
1346 buildInputs = with self; [];
1347 doCheck = false;
1348 propagatedBuildInputs = with self; [pytest termcolor];
1349 src = fetchurl {
1350 url = "https://pypi.python.org/packages/03/97/05d988b4fa870e7373e8ee4582408543b9ca2bd35c3c67b569369c6f9c49/pytest-sugar-0.7.1.tar.gz";
1351 md5 = "7400f7c11f3d572b2c2a3b60352d35fe";
1352 };
1353 meta = {
1354 license = [ pkgs.lib.licenses.bsdOriginal ];
1355 };
1356 };
1357 1357 pytest-timeout = super.buildPythonPackage {
1358 name = "pytest-timeout-0.4";
1358 name = "pytest-timeout-1.2.0";
1359 1359 buildInputs = with self; [];
1360 1360 doCheck = false;
1361 1361 propagatedBuildInputs = with self; [pytest];
1362 1362 src = fetchurl {
1363 url = "https://pypi.python.org/packages/24/48/5f6bd4b8026a26e1dd427243d560a29a0f1b24a5c7cffca4bf049a7bb65b/pytest-timeout-0.4.tar.gz";
1364 md5 = "03b28aff69cbbfb959ed35ade5fde262";
1363 url = "https://pypi.python.org/packages/cc/b7/b2a61365ea6b6d2e8881360ae7ed8dad0327ad2df89f2f0be4a02304deb2/pytest-timeout-1.2.0.tar.gz";
1364 md5 = "83607d91aa163562c7ee835da57d061d";
1365 1365 };
1366 1366 meta = {
1367 1367 license = [ pkgs.lib.licenses.mit { fullName = "DFSG approved"; } ];
@@ -1498,36 +1498,36 b''
1498 1498 };
1499 1499 };
1500 1500 rhodecode-enterprise-ce = super.buildPythonPackage {
1501 name = "rhodecode-enterprise-ce-4.5.2";
1502 buildInputs = with self; [WebTest configobj cssselect lxml mock pytest pytest-cov pytest-runner pytest-sugar];
1501 name = "rhodecode-enterprise-ce-4.6.0";
1502 buildInputs = with self; [pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage cssselect lxml configobj];
1503 1503 doCheck = true;
1504 1504 propagatedBuildInputs = with self; [Babel Beaker FormEncode Mako Markdown MarkupSafe MySQL-python Paste PasteDeploy PasteScript Pygments pygments-markdown-lexer Pylons Pyro4 Routes SQLAlchemy Tempita URLObject WebError WebHelpers WebHelpers2 WebOb WebTest Whoosh alembic amqplib anyjson appenlight-client authomatic backport-ipaddress celery channelstream colander decorator deform docutils gevent gunicorn infrae.cache ipython iso8601 kombu msgpack-python packaging psycopg2 py-gfm pycrypto pycurl pyparsing pyramid pyramid-debugtoolbar pyramid-mako pyramid-beaker pysqlite python-dateutil python-ldap python-memcached python-pam recaptcha-client repoze.lru requests simplejson subprocess32 waitress zope.cachedescriptors dogpile.cache dogpile.core psutil py-bcrypt];
1505 1505 src = ./.;
1506 1506 meta = {
1507 license = [ { fullName = "AGPLv3, and Commercial License"; } ];
1507 license = [ { fullName = "Affero GNU General Public License v3 or later (AGPLv3+)"; } { fullName = "AGPLv3, and Commercial License"; } ];
1508 1508 };
1509 1509 };
1510 1510 rhodecode-tools = super.buildPythonPackage {
1511 name = "rhodecode-tools-0.10.2";
1511 name = "rhodecode-tools-0.11.0";
1512 1512 buildInputs = with self; [];
1513 1513 doCheck = false;
1514 propagatedBuildInputs = with self; [click future six Mako MarkupSafe requests Whoosh elasticsearch elasticsearch-dsl urllib3];
1514 propagatedBuildInputs = with self; [click future six Mako MarkupSafe requests elasticsearch elasticsearch-dsl urllib3 Whoosh];
1515 1515 src = fetchurl {
1516 url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.10.2.zip";
1517 md5 = "d2af3985a1a32a678944d4d48870cb04";
1516 url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.11.0.tar.gz?md5=e5fd0a8363af08a0ced71b50ca9cce15";
1517 md5 = "e5fd0a8363af08a0ced71b50ca9cce15";
1518 1518 };
1519 1519 meta = {
1520 1520 license = [ { fullName = "AGPLv3 and Proprietary"; } ];
1521 1521 };
1522 1522 };
1523 1523 serpent = super.buildPythonPackage {
1524 name = "serpent-1.12";
1524 name = "serpent-1.15";
1525 1525 buildInputs = with self; [];
1526 1526 doCheck = false;
1527 1527 propagatedBuildInputs = with self; [];
1528 1528 src = fetchurl {
1529 url = "https://pypi.python.org/packages/3b/19/1e0e83b47c09edaef8398655088036e7e67386b5c48770218ebb339fbbd5/serpent-1.12.tar.gz";
1530 md5 = "05869ac7b062828b34f8f927f0457b65";
1529 url = "https://pypi.python.org/packages/7b/38/b2b27673a882ff2ea5871bb3e3e6b496ebbaafd1612e51990ffb158b9254/serpent-1.15.tar.gz";
1530 md5 = "e27b1aad5c218e16442f52abb7c7053a";
1531 1531 };
1532 1532 meta = {
1533 1533 license = [ pkgs.lib.licenses.mit ];
@@ -1547,26 +1547,26 b''
1547 1547 };
1548 1548 };
1549 1549 setuptools = super.buildPythonPackage {
1550 name = "setuptools-20.8.1";
1550 name = "setuptools-30.1.0";
1551 1551 buildInputs = with self; [];
1552 1552 doCheck = false;
1553 1553 propagatedBuildInputs = with self; [];
1554 1554 src = fetchurl {
1555 url = "https://pypi.python.org/packages/c4/19/c1bdc88b53da654df43770f941079dbab4e4788c2dcb5658fb86259894c7/setuptools-20.8.1.zip";
1556 md5 = "fe58a5cac0df20bb83942b252a4b0543";
1555 url = "https://pypi.python.org/packages/1e/43/002c8616db9a3e7be23c2556e39b90a32bb40ba0dc652de1999d5334d372/setuptools-30.1.0.tar.gz";
1556 md5 = "cac497f42e5096ac8df29e38d3f81c3e";
1557 1557 };
1558 1558 meta = {
1559 1559 license = [ pkgs.lib.licenses.mit ];
1560 1560 };
1561 1561 };
1562 1562 setuptools-scm = super.buildPythonPackage {
1563 name = "setuptools-scm-1.11.0";
1563 name = "setuptools-scm-1.15.0";
1564 1564 buildInputs = with self; [];
1565 1565 doCheck = false;
1566 1566 propagatedBuildInputs = with self; [];
1567 1567 src = fetchurl {
1568 url = "https://pypi.python.org/packages/cd/5f/e3a038292358058d83d764a47d09114aa5a8003ed4529518f9e580f1a94f/setuptools_scm-1.11.0.tar.gz";
1569 md5 = "4c5c896ba52e134bbc3507bac6400087";
1568 url = "https://pypi.python.org/packages/80/b7/31b6ae5fcb188e37f7e31abe75f9be90490a5456a72860fa6e643f8a3cbc/setuptools_scm-1.15.0.tar.gz";
1569 md5 = "b6916c78ed6253d6602444fad4279c5b";
1570 1570 };
1571 1571 meta = {
1572 1572 license = [ pkgs.lib.licenses.mit ];
@@ -1625,18 +1625,31 b''
1625 1625 };
1626 1626 };
1627 1627 supervisor = super.buildPythonPackage {
1628 name = "supervisor-3.3.0";
1628 name = "supervisor-3.3.1";
1629 1629 buildInputs = with self; [];
1630 1630 doCheck = false;
1631 1631 propagatedBuildInputs = with self; [meld3];
1632 1632 src = fetchurl {
1633 url = "https://pypi.python.org/packages/44/80/d28047d120bfcc8158b4e41127706731ee6a3419c661e0a858fb0e7c4b2d/supervisor-3.3.0.tar.gz";
1634 md5 = "46bac00378d1eddb616752b990c67416";
1633 url = "https://pypi.python.org/packages/80/37/964c0d53cbd328796b1aeb7abea4c0f7b0e8c7197ea9b0b9967b7d004def/supervisor-3.3.1.tar.gz";
1634 md5 = "202f760f9bf4930ec06557bac73e5cf2";
1635 1635 };
1636 1636 meta = {
1637 1637 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1638 1638 };
1639 1639 };
1640 termcolor = super.buildPythonPackage {
1641 name = "termcolor-1.1.0";
1642 buildInputs = with self; [];
1643 doCheck = false;
1644 propagatedBuildInputs = with self; [];
1645 src = fetchurl {
1646 url = "https://pypi.python.org/packages/8a/48/a76be51647d0eb9f10e2a4511bf3ffb8cc1e6b14e9e4fab46173aa79f981/termcolor-1.1.0.tar.gz";
1647 md5 = "043e89644f8909d462fbbfa511c768df";
1648 };
1649 meta = {
1650 license = [ pkgs.lib.licenses.mit ];
1651 };
1652 };
1640 1653 traitlets = super.buildPythonPackage {
1641 1654 name = "traitlets-4.3.1";
1642 1655 buildInputs = with self; [];
@@ -1729,13 +1742,13 b''
1729 1742 };
1730 1743 };
1731 1744 waitress = super.buildPythonPackage {
1732 name = "waitress-0.8.9";
1745 name = "waitress-1.0.1";
1733 1746 buildInputs = with self; [];
1734 1747 doCheck = false;
1735 propagatedBuildInputs = with self; [setuptools];
1748 propagatedBuildInputs = with self; [];
1736 1749 src = fetchurl {
1737 url = "https://pypi.python.org/packages/ee/65/fc9dee74a909a1187ca51e4f15ad9c4d35476e4ab5813f73421505c48053/waitress-0.8.9.tar.gz";
1738 md5 = "da3f2e62b3676be5dd630703a68e2a04";
1750 url = "https://pypi.python.org/packages/78/7d/84d11b96c3f60164dec3bef4a859a03aeae0231aa93f57fbe0d05fa4ff36/waitress-1.0.1.tar.gz";
1751 md5 = "dda92358a7569669086155923a46e57c";
1739 1752 };
1740 1753 meta = {
1741 1754 license = [ pkgs.lib.licenses.zpt21 ];
@@ -1835,30 +1848,5 b''
1835 1848
1836 1849 ### Test requirements
1837 1850
1838 pytest-sugar = super.buildPythonPackage {
1839 name = "pytest-sugar-0.7.1";
1840 buildInputs = with self; [];
1841 doCheck = false;
1842 propagatedBuildInputs = with self; [pytest termcolor];
1843 src = fetchurl {
1844 url = "https://pypi.python.org/packages/03/97/05d988b4fa870e7373e8ee4582408543b9ca2bd35c3c67b569369c6f9c49/pytest-sugar-0.7.1.tar.gz";
1845 md5 = "7400f7c11f3d572b2c2a3b60352d35fe";
1846 };
1847 meta = {
1848 license = [ pkgs.lib.licenses.bsdOriginal ];
1849 };
1850 };
1851 termcolor = super.buildPythonPackage {
1852 name = "termcolor-1.1.0";
1853 buildInputs = with self; [];
1854 doCheck = false;
1855 propagatedBuildInputs = with self; [];
1856 src = fetchurl {
1857 url = "https://pypi.python.org/packages/8a/48/a76be51647d0eb9f10e2a4511bf3ffb8cc1e6b14e9e4fab46173aa79f981/termcolor-1.1.0.tar.gz";
1858 md5 = "043e89644f8909d462fbbfa511c768df";
1859 };
1860 meta = {
1861 license = [ pkgs.lib.licenses.mit ];
1862 };
1863 };
1851
1864 1852 }
@@ -1,150 +1,131 b''
1 Babel==1.3
2 Beaker==1.7.0
3 Chameleon==2.24
4 CProfileV==1.0.6
5 FormEncode==1.2.4
6 Jinja2==2.7.3
7 Mako==1.0.1
8 Markdown==2.6.2
9 MarkupSafe==0.23
10 MySQL-python==1.2.5
11 Paste==2.0.2
12 PasteDeploy==1.5.2
13 PasteScript==1.7.5
14 Pygments==2.1.3
15 pygments-markdown-lexer==0.1.0.dev39
16
17 # TODO: This version is not available on PyPI
18 # Pylons==1.0.2.dev20160108
19 Pylons==1.0.1
1 ## core
2 setuptools==30.1.0
3 setuptools-scm==1.15.0
20 4
21 # TODO: This version is not available, but newer ones are
22 # Pyro4==4.35
23 Pyro4==4.41
24
25 # TODO: This should probably not be in here
26 # -e hg+https://johbo@code.rhodecode.com/johbo/rhodecode-fork@3a454bd1f17c0b2b2a951cf2b111e0320d7942a9#egg=RhodeCodeEnterprise-dev
27
28 Routes==1.13
29 SQLAlchemy==0.9.9
30 Sphinx==1.2.2
31 Tempita==0.5.2
32 URLObject==2.4.0
33 WebError==0.10.3
34
35 # TODO: This is modified by us, needs a better integration. For now
36 # using the latest version before.
37 # WebHelpers==1.3.dev20150807
38 WebHelpers==1.3
39
40 WebHelpers2==2.0
41 WebOb==1.3.1
42 WebTest==1.4.3
43 Whoosh==2.7.0
44 alembic==0.8.4
45 5 amqplib==1.0.2
46 6 anyjson==0.3.3
47 appenlight-client==0.6.14
48 authomatic==0.1.0.post1;
7 authomatic==0.1.0.post1
8 Babel==1.3
49 9 backport-ipaddress==0.1
50 bottle==0.12.8
51 bumpversion==0.5.3
10 Beaker==1.7.0
52 11 celery==2.2.10
12 Chameleon==2.24
53 13 channelstream==0.5.2
54 14 click==5.1
55 15 colander==1.2
56 16 configobj==5.0.6
57 cov-core==1.15.0
58 coverage==3.7.1
59 cssselect==0.9.1
60 17 decorator==3.4.2
61 18 deform==2.0a2
62 19 docutils==0.12
63 20 dogpile.cache==0.6.1
64 21 dogpile.core==0.4.1
65 dulwich==0.12.0
66 22 ecdsa==0.11
23 FormEncode==1.2.4
67 24 future==0.14.3
68 25 futures==3.0.2
69 gevent==1.1.1
70 gprof2dot==2015.12.1
71 greenlet==0.4.9
72 gunicorn==19.6.0
73
74 # TODO: Needs subvertpy and blows up without Subversion headers,
75 # actually we should not need this for Enterprise at all.
76 # hgsubversion==1.8.2
77
78 26 gnureadline==6.3.3
79 27 infrae.cache==1.0.1
80 invoke==0.13.0
81 ipdb==0.10.1
82 ipython==5.1.0
83 28 iso8601==0.1.11
84 29 itsdangerous==0.24
30 Jinja2==2.7.3
85 31 kombu==1.5.1
86 lxml==3.4.4
32 Mako==1.0.6
33 Markdown==2.6.7
34 MarkupSafe==0.23
87 35 meld3==1.0.2
88 mock==1.0.1
89 msgpack-python==0.4.6
36 msgpack-python==0.4.8
37 MySQL-python==1.2.5
90 38 nose==1.3.6
91 39 objgraph==2.0.0
92 40 packaging==15.2
93 41 paramiko==1.15.1
42 Paste==2.0.3
43 PasteDeploy==1.5.2
44 PasteScript==1.7.5
94 45 psutil==4.3.1
95 46 psycopg2==2.6.1
96 py==1.4.29
97 47 py-bcrypt==0.4
98 py-gfm==0.1.3
99 48 pycrypto==2.6.1
100 49 pycurl==7.19.5
101 50 pyflakes==0.8.1
51 pygments-markdown-lexer==0.1.0.dev39
52 Pygments==2.2.0
102 53 pyparsing==1.5.7
103 pyramid==1.6.1
104 54 pyramid-beaker==0.8
105 55 pyramid-debugtoolbar==2.4.2
106 56 pyramid-jinja2==2.5
107 57 pyramid-mako==1.0.2
58 pyramid==1.6.1
108 59 pysqlite==2.6.3
109 pytest==2.8.5
110 pytest-runner==2.7.1
111 pytest-catchlog==1.2.2
112 pytest-cov==1.8.1
113 pytest-profiling==1.0.1
114 pytest-timeout==0.4
115 60 python-dateutil==1.5
116 61 python-ldap==2.4.19
117 62 python-memcached==1.57
118 63 python-pam==1.8.2
119 64 pytz==2015.4
120 65 pyzmq==14.6.0
121
122 # TODO: This is not available in public
123 # rc-testdata==0.2.0
124
125 https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.10.2.zip#md5=d2af3985a1a32a678944d4d48870cb04
126
127
128 66 recaptcha-client==1.0.6
129 67 repoze.lru==0.6
130 68 requests==2.9.1
131 serpent==1.12
69 Routes==1.13
132 70 setproctitle==1.1.8
133 setuptools==20.8.1
134 setuptools-scm==1.11.0
135 71 simplejson==3.7.2
136 72 six==1.9.0
73 Sphinx==1.2.2
74 SQLAlchemy==0.9.9
137 75 subprocess32==3.2.6
138 supervisor==3.3.0
139 transifex-client==0.10
76 supervisor==3.3.1
77 Tempita==0.5.2
140 78 translationstring==1.3
141 79 trollius==1.0.4
142 uWSGI==2.0.11.2
143 80 urllib3==1.16
81 URLObject==2.4.0
144 82 venusian==1.0
145 waitress==0.8.9
83 WebError==0.10.3
84 WebHelpers2==2.0
85 WebHelpers==1.3
86 WebOb==1.3.1
87 Whoosh==2.7.4
146 88 wsgiref==0.1.2
147 89 zope.cachedescriptors==4.0.0
148 90 zope.deprecation==4.1.2
149 91 zope.event==4.0.3
150 92 zope.interface==4.1.3
93
94 ## customized/patched libs
95 # our patched version of Pylons==1.0.2
96 https://code.rhodecode.com/upstream/pylons/archive/707354ee4261b9c10450404fc9852ccea4fd667d.tar.gz?md5=f26633726fa2cd3a340316ee6a5d218f#egg=Pylons==1.0.2.rhodecode-patch-1
97 # not released py-gfm==0.1.3
98 https://code.rhodecode.com/upstream/py-gfm/archive/0d66a19bc16e3d49de273c0f797d4e4781e8c0f2.tar.gz?md5=0d0d5385bfb629eea636a80b9c2bfd16#egg=py-gfm==0.1.3.rhodecode-upstream1
99
100
101 ## cli tools
102 alembic==0.8.4
103 invoke==0.13.0
104 bumpversion==0.5.3
105 transifex-client==0.10
106
107 ## http servers
108 gevent==1.1.2
109 greenlet==0.4.10
110 gunicorn==19.6.0
111 waitress==1.0.1
112 uWSGI==2.0.11.2
113
114 ## debug
115 ipdb==0.10.1
116 ipython==5.1.0
117 CProfileV==1.0.6
118 bottle==0.12.8
119
120 ## rhodecode-tools, special case
121 https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.11.0.tar.gz?md5=e5fd0a8363af08a0ced71b50ca9cce15#egg=rhodecode-tools==0.11.0
122
123 ## appenlight
124 appenlight-client==0.6.14
125
126 # Pyro/Deprecated TODO(Marcink): remove in 4.7 release.
127 Pyro4==4.41
128 serpent==1.15
129
130 ## test related requirements
131 -r requirements_test.txt
@@ -1,1 +1,1 b''
1 4.5.2 No newline at end of file
1 4.6.0 No newline at end of file
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -51,11 +51,11 b' PYRAMID_SETTINGS = {}'
51 51 EXTENSIONS = {}
52 52
53 53 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
54 __dbversion__ = 63 # defines current db version for migrations
54 __dbversion__ = 64 # defines current db version for migrations
55 55 __platform__ = platform.system()
56 56 __license__ = 'AGPLv3, and Commercial License'
57 57 __author__ = 'RhodeCode GmbH'
58 __url__ = 'http://rhodecode.com'
58 __url__ = 'https://code.rhodecode.com'
59 59
60 60 is_windows = __platform__ in ['Windows']
61 61 is_unix = not is_windows
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2016 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -39,5 +39,19 b' def includeme(config):'
39 39 name='admin_settings_vcs_svn_generate_cfg',
40 40 pattern=ADMIN_PREFIX + '/settings/vcs/svn_generate_cfg')
41 41
42 config.add_route(
43 name='admin_settings_system',
44 pattern=ADMIN_PREFIX + '/settings/system')
45 config.add_route(
46 name='admin_settings_system_update',
47 pattern=ADMIN_PREFIX + '/settings/system/updates')
48
49 config.add_route(
50 name='admin_settings_sessions',
51 pattern=ADMIN_PREFIX + '/settings/sessions')
52 config.add_route(
53 name='admin_settings_sessions_cleanup',
54 pattern=ADMIN_PREFIX + '/settings/sessions/cleanup')
55
42 56 # Scan module for configuration decorators.
43 57 config.scan()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2016 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2016 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -66,6 +66,15 b' class NavEntry(object):'
66 66 else:
67 67 return url(self.view_name)
68 68
69 def get_localized_name(self, request):
70 if hasattr(request, 'translate'):
71 return request.translate(self.name)
72 else:
73 # TODO(marcink): Remove this after migrating to pyramid
74 from pyramid.threadlocal import get_current_request
75 pyramid_request = get_current_request()
76 return pyramid_request.translate(self.name)
77
69 78
70 79 @implementer(IAdminNavigationRegistry)
71 80 class NavigationRegistry(object):
@@ -80,18 +89,22 b' class NavigationRegistry(object):'
80 89 NavEntry('email', _('Email'), 'admin_settings_email'),
81 90 NavEntry('hooks', _('Hooks'), 'admin_settings_hooks'),
82 91 NavEntry('search', _('Full Text Search'), 'admin_settings_search'),
92
83 93 NavEntry('integrations', _('Integrations'),
84 94 'global_integrations_home', pyramid=True),
85 NavEntry('system', _('System Info'), 'admin_settings_system'),
95 NavEntry('system', _('System Info'),
96 'admin_settings_system', pyramid=True),
97 NavEntry('sessions', _('User Sessions'),
98 'admin_settings_sessions', pyramid=True),
86 99 NavEntry('open_source', _('Open Source Licenses'),
87 100 'admin_settings_open_source', pyramid=True),
101
88 102 # TODO: marcink: we disable supervisor now until the supervisor stats
89 103 # page is fixed in the nix configuration
90 104 # NavEntry('supervisor', _('Supervisor'), 'admin_settings_supervisor'),
91 105 ]
92 106
93 _labs_entry = NavEntry('labs', _('Labs'),
94 'admin_settings_labs')
107 _labs_entry = NavEntry('labs', _('Labs'), 'admin_settings_labs')
95 108
96 109 def __init__(self, labs_active=False):
97 110 self._registered_entries = collections.OrderedDict([
@@ -105,7 +118,8 b' class NavigationRegistry(object):'
105 118 self._registered_entries[entry.key] = entry
106 119
107 120 def get_navlist(self, request):
108 navlist = [NavListEntry(i.key, i.name, i.generate_url(request))
121 navlist = [NavListEntry(i.key, i.get_localized_name(request),
122 i.generate_url(request))
109 123 for i in self._registered_entries.values()]
110 124 return navlist
111 125
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2016 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -132,7 +132,7 b' def exception_view(exc, request):'
132 132 log.debug('json-rpc error rpc_id:%s "%s"', rpc_id, fault_message)
133 133 elif isinstance(exc, JSONRPCValidationError):
134 134 colander_exc = exc.colander_exception
135 #TODO: think maybe of nicer way to serialize errors ?
135 # TODO(marcink): think maybe of nicer way to serialize errors ?
136 136 fault_message = colander_exc.asdict()
137 137 log.debug('json-rpc error rpc_id:%s "%s"', rpc_id, fault_message)
138 138 elif isinstance(exc, JSONRPCForbidden):
@@ -240,7 +240,7 b' def request_view(request):'
240 240 message=('Missing non optional `%s` arg in JSON DATA' % arg)
241 241 )
242 242
243 # sanitze extra passed arguments
243 # sanitize extra passed arguments
244 244 for k in request.rpc_params.keys()[:]:
245 245 if k not in func_kwargs:
246 246 del request.rpc_params[k]
@@ -256,7 +256,7 b' def request_view(request):'
256 256 except JSONRPCBaseError:
257 257 raise
258 258 except Exception:
259 log.exception('Unhandled exception occured on api call: %s', func)
259 log.exception('Unhandled exception occurred on api call: %s', func)
260 260 return jsonrpc_error(request, retid=request.rpc_id,
261 261 message='Internal server error')
262 262
@@ -269,9 +269,10 b' def setup_request(request):'
269 269 We need to raise JSONRPCError here if we want to return some errors back to
270 270 user.
271 271 """
272
272 273 log.debug('Executing setup request: %r', request)
273 274 request.rpc_ip_addr = get_ip_addr(request.environ)
274 # TODO: marcink, deprecate GET at some point
275 # TODO(marcink): deprecate GET at some point
275 276 if request.method not in ['POST', 'GET']:
276 277 log.debug('unsupported request method "%s"', request.method)
277 278 raise JSONRPCError(
@@ -308,6 +309,8 b' def setup_request(request):'
308 309 if not api_key:
309 310 raise KeyError('api_key or auth_token')
310 311
312 # TODO(marcink): support passing in token in request header
313
311 314 request.rpc_api_key = api_key
312 315 request.rpc_id = json_body['id']
313 316 request.rpc_method = json_body['method']
@@ -485,8 +488,7 b' def includeme(config):'
485 488 config.registry.jsonrpc_methods = OrderedDict()
486 489
487 490 # match filter by given method only
488 config.add_view_predicate(
489 'jsonrpc_method', MethodPredicate)
491 config.add_view_predicate('jsonrpc_method', MethodPredicate)
490 492
491 493 config.add_renderer(DEFAULT_RENDERER, ExtJsonRenderer(
492 494 serializer=json.dumps, indent=4))
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2016 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -20,7 +20,7 b''
20 20
21 21 import pytest
22 22
23 from rhodecode.model.comment import ChangesetCommentsModel
23 from rhodecode.model.comment import CommentsModel
24 24 from rhodecode.model.db import UserLog
25 25 from rhodecode.model.pull_request import PullRequestModel
26 26 from rhodecode.tests import TEST_USER_ADMIN_LOGIN
@@ -52,13 +52,13 b' class TestCommentPullRequest(object):'
52 52 response = api_call(self.app, params)
53 53 pull_request = PullRequestModel().get(pull_request.pull_request_id)
54 54
55 comments = ChangesetCommentsModel().get_comments(
55 comments = CommentsModel().get_comments(
56 56 pull_request.target_repo.repo_id, pull_request=pull_request)
57 57
58 58 expected = {
59 59 'pull_request_id': pull_request.pull_request_id,
60 60 'comment_id': comments[-1].comment_id,
61 'status': None
61 'status': {'given': None, 'was_changed': None}
62 62 }
63 63 assert_ok(id_, expected, response.body)
64 64
@@ -83,12 +83,61 b' class TestCommentPullRequest(object):'
83 83 response = api_call(self.app, params)
84 84 pull_request = PullRequestModel().get(pull_request_id)
85 85
86 comments = ChangesetCommentsModel().get_comments(
86 comments = CommentsModel().get_comments(
87 87 pull_request.target_repo.repo_id, pull_request=pull_request)
88 88 expected = {
89 89 'pull_request_id': pull_request.pull_request_id,
90 90 'comment_id': comments[-1].comment_id,
91 'status': 'rejected'
91 'status': {'given': 'rejected', 'was_changed': True}
92 }
93 assert_ok(id_, expected, response.body)
94
95 @pytest.mark.backends("git", "hg")
96 def test_api_comment_pull_request_change_status_with_specific_commit_id(
97 self, pr_util, no_notifications):
98 pull_request = pr_util.create_pull_request()
99 pull_request_id = pull_request.pull_request_id
100 latest_commit_id = 'test_commit'
101 # inject additional revision, to fail test the status change on
102 # non-latest commit
103 pull_request.revisions = pull_request.revisions + ['test_commit']
104
105 id_, params = build_data(
106 self.apikey, 'comment_pull_request',
107 repoid=pull_request.target_repo.repo_name,
108 pullrequestid=pull_request.pull_request_id,
109 status='approved', commit_id=latest_commit_id)
110 response = api_call(self.app, params)
111 pull_request = PullRequestModel().get(pull_request_id)
112
113 expected = {
114 'pull_request_id': pull_request.pull_request_id,
115 'comment_id': None,
116 'status': {'given': 'approved', 'was_changed': False}
117 }
118 assert_ok(id_, expected, response.body)
119
120 @pytest.mark.backends("git", "hg")
121 def test_api_comment_pull_request_change_status_with_specific_commit_id(
122 self, pr_util, no_notifications):
123 pull_request = pr_util.create_pull_request()
124 pull_request_id = pull_request.pull_request_id
125 latest_commit_id = pull_request.revisions[0]
126
127 id_, params = build_data(
128 self.apikey, 'comment_pull_request',
129 repoid=pull_request.target_repo.repo_name,
130 pullrequestid=pull_request.pull_request_id,
131 status='approved', commit_id=latest_commit_id)
132 response = api_call(self.app, params)
133 pull_request = PullRequestModel().get(pull_request_id)
134
135 comments = CommentsModel().get_comments(
136 pull_request.target_repo.repo_id, pull_request=pull_request)
137 expected = {
138 'pull_request_id': pull_request.pull_request_id,
139 'comment_id': comments[-1].comment_id,
140 'status': {'given': 'approved', 'was_changed': True}
92 141 }
93 142 assert_ok(id_, expected, response.body)
94 143
@@ -103,7 +152,7 b' class TestCommentPullRequest(object):'
103 152 pullrequestid=pull_request_id)
104 153 response = api_call(self.app, params)
105 154
106 expected = 'message and status parameter missing'
155 expected = 'Both message and status parameters are missing. At least one is required.'
107 156 assert_error(id_, expected, given=response.body)
108 157
109 158 @pytest.mark.backends("git", "hg")
@@ -118,7 +167,7 b' class TestCommentPullRequest(object):'
118 167 status='42')
119 168 response = api_call(self.app, params)
120 169
121 expected = 'unknown comment status`42`'
170 expected = 'Unknown comment status: `42`'
122 171 assert_error(id_, expected, given=response.body)
123 172
124 173 @pytest.mark.backends("git", "hg")
@@ -144,3 +193,17 b' class TestCommentPullRequest(object):'
144 193
145 194 expected = 'userid is not the same as your user'
146 195 assert_error(id_, expected, given=response.body)
196
197 @pytest.mark.backends("git", "hg")
198 def test_api_comment_pull_request_wrong_commit_id_error(self, pr_util):
199 pull_request = pr_util.create_pull_request()
200 id_, params = build_data(
201 self.apikey_regular, 'comment_pull_request',
202 repoid=pull_request.target_repo.repo_name,
203 status='approved',
204 pullrequestid=pull_request.pull_request_id,
205 commit_id='XXX')
206 response = api_call(self.app, params)
207
208 expected = 'Invalid commit_id `XXX` for this pull request.'
209 assert_error(id_, expected, given=response.body)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -22,7 +22,8 b''
22 22 import pytest
23 23
24 24 from rhodecode.model.repo import RepoModel
25 from rhodecode.api.tests.utils import build_data, api_call, assert_ok, jsonify
25 from rhodecode.api.tests.utils import (
26 build_data, api_call, assert_ok, assert_error, jsonify)
26 27 from rhodecode.model.db import User
27 28
28 29
@@ -40,6 +41,76 b' class TestGetRepos(object):'
40 41 expected = ret
41 42 assert_ok(id_, expected, given=response.body)
42 43
44 def test_api_get_repos_only_toplevel(self, user_util):
45 repo_group = user_util.create_repo_group(auto_cleanup=True)
46 user_util.create_repo(parent=repo_group)
47
48 id_, params = build_data(self.apikey, 'get_repos', traverse=0)
49 response = api_call(self.app, params)
50
51 result = []
52 for repo in RepoModel().get_repos_for_root(root=None):
53 result.append(repo.get_api_data(include_secrets=True))
54 expected = jsonify(result)
55
56 assert_ok(id_, expected, given=response.body)
57
58 def test_api_get_repos_with_wrong_root(self):
59 id_, params = build_data(self.apikey, 'get_repos', root='abracadabra')
60 response = api_call(self.app, params)
61
62 expected = 'Root repository group `abracadabra` does not exist'
63 assert_error(id_, expected, given=response.body)
64
65 def test_api_get_repos_with_root(self, user_util):
66 repo_group = user_util.create_repo_group(auto_cleanup=True)
67 repo_group_name = repo_group.group_name
68
69 user_util.create_repo(parent=repo_group)
70 user_util.create_repo(parent=repo_group)
71
72 # nested, should not show up
73 user_util._test_name = '{}/'.format(repo_group_name)
74 sub_repo_group = user_util.create_repo_group(auto_cleanup=True)
75 user_util.create_repo(parent=sub_repo_group)
76
77 id_, params = build_data(self.apikey, 'get_repos',
78 root=repo_group_name, traverse=0)
79 response = api_call(self.app, params)
80
81 result = []
82 for repo in RepoModel().get_repos_for_root(repo_group):
83 result.append(repo.get_api_data(include_secrets=True))
84
85 assert len(result) == 2
86 expected = jsonify(result)
87 assert_ok(id_, expected, given=response.body)
88
89 def test_api_get_repos_with_root_and_traverse(self, user_util):
90 repo_group = user_util.create_repo_group(auto_cleanup=True)
91 repo_group_name = repo_group.group_name
92
93 user_util.create_repo(parent=repo_group)
94 user_util.create_repo(parent=repo_group)
95
96 # nested, should not show up
97 user_util._test_name = '{}/'.format(repo_group_name)
98 sub_repo_group = user_util.create_repo_group(auto_cleanup=True)
99 user_util.create_repo(parent=sub_repo_group)
100
101 id_, params = build_data(self.apikey, 'get_repos',
102 root=repo_group_name, traverse=1)
103 response = api_call(self.app, params)
104
105 result = []
106 for repo in RepoModel().get_repos_for_root(
107 repo_group_name, traverse=True):
108 result.append(repo.get_api_data(include_secrets=True))
109
110 assert len(result) == 3
111 expected = jsonify(result)
112 assert_ok(id_, expected, given=response.body)
113
43 114 def test_api_get_repos_non_admin(self):
44 115 id_, params = build_data(self.apikey_regular, 'get_repos')
45 116 response = api_call(self.app, params)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -20,18 +20,17 b''
20 20
21 21 import pytest
22 22
23 from rhodecode.model.db import UserLog
23 from rhodecode.model.db import UserLog, PullRequest
24 24 from rhodecode.model.meta import Session
25 from rhodecode.model.pull_request import PullRequestModel
26 25 from rhodecode.tests import TEST_USER_ADMIN_LOGIN
27 26 from rhodecode.api.tests.utils import (
28 build_data, api_call, assert_error)
27 build_data, api_call, assert_error, assert_ok)
29 28
30 29
31 30 @pytest.mark.usefixtures("testuser_api", "app")
32 31 class TestMergePullRequest(object):
33 32 @pytest.mark.backends("git", "hg")
34 def test_api_merge_pull_request(self, pr_util, no_notifications):
33 def test_api_merge_pull_request_merge_failed(self, pr_util, no_notifications):
35 34 pull_request = pr_util.create_pull_request(mergeable=True)
36 35 author = pull_request.user_id
37 36 repo = pull_request.target_repo.repo_id
@@ -51,6 +50,41 b' class TestMergePullRequest(object):'
51 50 # it.
52 51 Session().add(pull_request)
53 52
53 expected = 'merge not possible for following reasons: ' \
54 'Pull request reviewer approval is pending.'
55 assert_error(id_, expected, given=response.body)
56
57 @pytest.mark.backends("git", "hg")
58 def test_api_merge_pull_request(self, pr_util, no_notifications):
59 pull_request = pr_util.create_pull_request(mergeable=True, approved=True)
60 author = pull_request.user_id
61 repo = pull_request.target_repo.repo_id
62 pull_request_id = pull_request.pull_request_id
63 pull_request_repo = pull_request.target_repo.repo_name
64
65 id_, params = build_data(
66 self.apikey, 'comment_pull_request',
67 repoid=pull_request_repo,
68 pullrequestid=pull_request_id,
69 status='approved')
70
71 response = api_call(self.app, params)
72 expected = {
73 'comment_id': response.json.get('result', {}).get('comment_id'),
74 'pull_request_id': pull_request_id,
75 'status': {'given': 'approved', 'was_changed': True}
76 }
77 assert_ok(id_, expected, given=response.body)
78
79 id_, params = build_data(
80 self.apikey, 'merge_pull_request',
81 repoid=pull_request_repo,
82 pullrequestid=pull_request_id)
83
84 response = api_call(self.app, params)
85
86 pull_request = PullRequest.get(pull_request_id)
87
54 88 expected = {
55 89 'executed': True,
56 90 'failure_reason': 0,
@@ -59,8 +93,7 b' class TestMergePullRequest(object):'
59 93 'merge_ref': pull_request.shadow_merge_ref._asdict()
60 94 }
61 95
62 response_json = response.json['result']
63 assert response_json == expected
96 assert_ok(id_, expected, response.body)
64 97
65 98 action = 'user_merged_pull_request:%d' % (pull_request_id, )
66 99 journal = UserLog.query()\
@@ -75,8 +108,7 b' class TestMergePullRequest(object):'
75 108 repoid=pull_request_repo, pullrequestid=pull_request_id)
76 109 response = api_call(self.app, params)
77 110
78 expected = 'pull request `%s` merge failed, pull request is closed' % (
79 pull_request_id)
111 expected = 'merge not possible for following reasons: This pull request is closed.'
80 112 assert_error(id_, expected, given=response.body)
81 113
82 114 @pytest.mark.backends("git", "hg")
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -24,7 +24,8 b' from rhodecode.lib.vcs.nodes import File'
24 24 from rhodecode.model.db import User
25 25 from rhodecode.model.pull_request import PullRequestModel
26 26 from rhodecode.tests import TEST_USER_ADMIN_LOGIN
27 from rhodecode.api.tests.utils import (build_data, api_call)
27 from rhodecode.api.tests.utils import (
28 build_data, api_call, assert_ok, assert_error)
28 29
29 30
30 31 @pytest.mark.usefixtures("testuser_api", "app")
@@ -74,8 +75,7 b' class TestUpdatePullRequest(object):'
74 75 expected = 'pull request `{}` update failed, pull request ' \
75 76 'is closed'.format(pull_request.pull_request_id)
76 77
77 response_json = response.json['error']
78 assert response_json == expected
78 assert_error(id_, expected, response.body)
79 79
80 80 @pytest.mark.backends("git", "hg")
81 81 def test_api_update_update_commits(
@@ -90,9 +90,11 b' class TestUpdatePullRequest(object):'
90 90 pr_util.update_source_repository(head='c')
91 91 repo = pull_request.source_repo.scm_instance()
92 92 commits = [x for x in repo.get_commits()]
93 print commits
93 94
94 95 added_commit_id = commits[-1].raw_id # c commit
95 common_commits = commits[1].raw_id # b commit is common ancestor
96 common_commit_id = commits[1].raw_id # b commit is common ancestor
97 total_commits = [added_commit_id, common_commit_id]
96 98
97 99 id_, params = build_data(
98 100 self.apikey, 'update_pull_request',
@@ -107,12 +109,13 b' class TestUpdatePullRequest(object):'
107 109 pull_request.pull_request_id),
108 110 "pull_request": response.json['result']['pull_request'],
109 111 "updated_commits": {"added": [added_commit_id],
110 "common": [common_commits], "removed": []},
112 "common": [common_commit_id],
113 "total": total_commits,
114 "removed": []},
111 115 "updated_reviewers": {"added": [], "removed": []},
112 116 }
113 117
114 response_json = response.json['result']
115 assert response_json == expected
118 assert_ok(id_, expected, response.body)
116 119
117 120 @pytest.mark.backends("git", "hg")
118 121 def test_api_update_change_reviewers(
@@ -139,8 +142,7 b' class TestUpdatePullRequest(object):'
139 142 "updated_reviewers": {"added": added, "removed": removed},
140 143 }
141 144
142 response_json = response.json['result']
143 assert response_json == expected
145 assert_ok(id_, expected, response.body)
144 146
145 147 @pytest.mark.backends("git", "hg")
146 148 def test_api_update_bad_user_in_reviewers(self, pr_util):
@@ -155,8 +157,7 b' class TestUpdatePullRequest(object):'
155 157
156 158 expected = 'user `bad_name` does not exist'
157 159
158 response_json = response.json['error']
159 assert response_json == expected
160 assert_error(id_, expected, response.body)
160 161
161 162 @pytest.mark.backends("git", "hg")
162 163 def test_api_update_repo_error(self, pr_util):
@@ -184,9 +185,7 b' class TestUpdatePullRequest(object):'
184 185 response = api_call(self.app, params)
185 186
186 187 expected = 'pull request `999999` does not exist'
187
188 response_json = response.json['error']
189 assert response_json == expected
188 assert_error(id_, expected, response.body)
190 189
191 190 @pytest.mark.backends("git", "hg")
192 191 def test_api_update_pull_request_no_perms_to_update(
@@ -203,5 +202,4 b' class TestUpdatePullRequest(object):'
203 202 expected = ('pull request `%s` update failed, '
204 203 'no permission to update.') % pull_request.pull_request_id
205 204
206 response_json = response.json['error']
207 assert response_json == expected
205 assert_error(id_, expected, response.body)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2014-2016 RhodeCode GmbH
3 # Copyright (C) 2014-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -26,11 +26,12 b' import collections'
26 26 import logging
27 27
28 28 from rhodecode.api.exc import JSONRPCError
29 from rhodecode.lib.auth import HasPermissionAnyApi, HasRepoPermissionAnyApi, \
30 HasRepoGroupPermissionAnyApi
29 from rhodecode.lib.auth import (
30 HasPermissionAnyApi, HasRepoPermissionAnyApi, HasRepoGroupPermissionAnyApi)
31 31 from rhodecode.lib.utils import safe_unicode
32 from rhodecode.lib.vcs.exceptions import RepositoryError
32 33 from rhodecode.controllers.utils import get_commit_from_ref_name
33 from rhodecode.lib.vcs.exceptions import RepositoryError
34 from rhodecode.lib.utils2 import str2bool
34 35
35 36 log = logging.getLogger(__name__)
36 37
@@ -92,7 +93,7 b' class Optional(object):'
92 93 return self.type_
93 94
94 95 @classmethod
95 def extract(cls, val, evaluate_locals=None):
96 def extract(cls, val, evaluate_locals=None, binary=None):
96 97 """
97 98 Extracts value from Optional() instance
98 99
@@ -101,7 +102,11 b' class Optional(object):'
101 102 value of instance
102 103 """
103 104 if isinstance(val, cls):
104 return val.getval(evaluate_locals)
105 val = val.getval(evaluate_locals)
106
107 if binary:
108 val = str2bool(val)
109
105 110 return val
106 111
107 112
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2015-2016 RhodeCode GmbH
3 # Copyright (C) 2015-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2016 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2016 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2016 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -30,9 +30,9 b' from rhodecode.lib.auth import (HasRepoP'
30 30 from rhodecode.lib.base import vcs_operation_context
31 31 from rhodecode.lib.utils2 import str2bool
32 32 from rhodecode.model.changeset_status import ChangesetStatusModel
33 from rhodecode.model.comment import ChangesetCommentsModel
34 from rhodecode.model.db import Session, ChangesetStatus
35 from rhodecode.model.pull_request import PullRequestModel
33 from rhodecode.model.comment import CommentsModel
34 from rhodecode.model.db import Session, ChangesetStatus, ChangesetComment
35 from rhodecode.model.pull_request import PullRequestModel, MergeCheck
36 36 from rhodecode.model.settings import SettingsModel
37 37
38 38 log = logging.getLogger(__name__)
@@ -270,13 +270,14 b' def merge_pull_request(request, apiuser,'
270 270 raise JSONRPCError('userid is not the same as your user')
271 271
272 272 pull_request = get_pull_request_or_error(pullrequestid)
273 if not PullRequestModel().check_user_merge(
274 pull_request, apiuser, api=True):
275 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
276 if pull_request.is_closed():
273
274 check = MergeCheck.validate(pull_request, user=apiuser)
275 merge_possible = not check.failed
276
277 if not merge_possible:
278 reasons = ','.join([msg for _e, msg in check.errors])
277 279 raise JSONRPCError(
278 'pull request `%s` merge failed, pull request is closed' % (
279 pullrequestid,))
280 'merge not possible for following reasons: {}'.format(reasons))
280 281
281 282 target_repo = pull_request.target_repo
282 283 extras = vcs_operation_context(
@@ -359,9 +360,12 b' def close_pull_request(request, apiuser,'
359 360
360 361
361 362 @jsonrpc_method()
362 def comment_pull_request(request, apiuser, repoid, pullrequestid,
363 message=Optional(None), status=Optional(None),
364 userid=Optional(OAttr('apiuser'))):
363 def comment_pull_request(
364 request, apiuser, repoid, pullrequestid, message=Optional(None),
365 commit_id=Optional(None), status=Optional(None),
366 comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE),
367 resolves_comment_id=Optional(None),
368 userid=Optional(OAttr('apiuser'))):
365 369 """
366 370 Comment on the pull request specified with the `pullrequestid`,
367 371 in the |repo| specified by the `repoid`, and optionally change the
@@ -373,15 +377,18 b' def comment_pull_request(request, apiuse'
373 377 :type repoid: str or int
374 378 :param pullrequestid: The pull request ID.
375 379 :type pullrequestid: int
380 :param commit_id: Specify the commit_id for which to set a comment. If
381 given commit_id is different than latest in the PR status
382 change won't be performed.
383 :type commit_id: str
376 384 :param message: The text content of the comment.
377 385 :type message: str
378 386 :param status: (**Optional**) Set the approval status of the pull
379 request. Valid options are:
380 * not_reviewed
381 * approved
382 * rejected
383 * under_review
387 request. One of: 'not_reviewed', 'approved', 'rejected',
388 'under_review'
384 389 :type status: str
390 :param comment_type: Comment type, one of: 'note', 'todo'
391 :type comment_type: Optional(str), default: 'note'
385 392 :param userid: Comment on the pull request as this user
386 393 :type userid: Optional(str or int)
387 394
@@ -393,7 +400,9 b' def comment_pull_request(request, apiuse'
393 400 result :
394 401 {
395 402 "pull_request_id": "<Integer>",
396 "comment_id": "<Integer>"
403 "comment_id": "<Integer>",
404 "status": {"given": <given_status>,
405 "was_changed": <bool status_was_actually_changed> },
397 406 }
398 407 error : null
399 408 """
@@ -412,37 +421,68 b' def comment_pull_request(request, apiuse'
412 421 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
413 422 message = Optional.extract(message)
414 423 status = Optional.extract(status)
424 commit_id = Optional.extract(commit_id)
425 comment_type = Optional.extract(comment_type)
426 resolves_comment_id = Optional.extract(resolves_comment_id)
427
415 428 if not message and not status:
416 raise JSONRPCError('message and status parameter missing')
429 raise JSONRPCError(
430 'Both message and status parameters are missing. '
431 'At least one is required.')
417 432
418 433 if (status not in (st[0] for st in ChangesetStatus.STATUSES) and
419 434 status is not None):
420 raise JSONRPCError('unknown comment status`%s`' % status)
435 raise JSONRPCError('Unknown comment status: `%s`' % status)
436
437 if commit_id and commit_id not in pull_request.revisions:
438 raise JSONRPCError(
439 'Invalid commit_id `%s` for this pull request.' % commit_id)
421 440
422 441 allowed_to_change_status = PullRequestModel().check_user_change_status(
423 442 pull_request, apiuser)
443
444 # if commit_id is passed re-validated if user is allowed to change status
445 # based on latest commit_id from the PR
446 if commit_id:
447 commit_idx = pull_request.revisions.index(commit_id)
448 if commit_idx != 0:
449 allowed_to_change_status = False
450
451 if resolves_comment_id:
452 comment = ChangesetComment.get(resolves_comment_id)
453 if not comment:
454 raise JSONRPCError(
455 'Invalid resolves_comment_id `%s` for this pull request.'
456 % resolves_comment_id)
457 if comment.comment_type != ChangesetComment.COMMENT_TYPE_TODO:
458 raise JSONRPCError(
459 'Comment `%s` is wrong type for setting status to resolved.'
460 % resolves_comment_id)
461
424 462 text = message
463 status_label = ChangesetStatus.get_status_lbl(status)
425 464 if status and allowed_to_change_status:
426 st_message = (('Status change %(transition_icon)s %(status)s')
427 % {'transition_icon': '>',
428 'status': ChangesetStatus.get_status_lbl(status)})
465 st_message = ('Status change %(transition_icon)s %(status)s'
466 % {'transition_icon': '>', 'status': status_label})
429 467 text = message or st_message
430 468
431 469 rc_config = SettingsModel().get_all_settings()
432 470 renderer = rc_config.get('rhodecode_markup_renderer', 'rst')
433 comment = ChangesetCommentsModel().create(
471
472 status_change = status and allowed_to_change_status
473 comment = CommentsModel().create(
434 474 text=text,
435 475 repo=pull_request.target_repo.repo_id,
436 476 user=apiuser.user_id,
437 477 pull_request=pull_request.pull_request_id,
438 478 f_path=None,
439 479 line_no=None,
440 status_change=(ChangesetStatus.get_status_lbl(status)
441 if status and allowed_to_change_status else None),
442 status_change_type=(status
443 if status and allowed_to_change_status else None),
480 status_change=(status_label if status_change else None),
481 status_change_type=(status if status_change else None),
444 482 closing_pr=False,
445 renderer=renderer
483 renderer=renderer,
484 comment_type=comment_type,
485 resolves_comment_id=resolves_comment_id
446 486 )
447 487
448 488 if allowed_to_change_status and status:
@@ -458,8 +498,8 b' def comment_pull_request(request, apiuse'
458 498 Session().commit()
459 499 data = {
460 500 'pull_request_id': pull_request.pull_request_id,
461 'comment_id': comment.comment_id,
462 'status': status
501 'comment_id': comment.comment_id if comment else None,
502 'status': {'given': status, 'was_changed': status_change},
463 503 }
464 504 return data
465 505
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2016 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -34,9 +34,10 b' from rhodecode.lib.exceptions import Sta'
34 34 from rhodecode.lib.utils2 import str2bool, time_to_datetime
35 35 from rhodecode.lib.ext_json import json
36 36 from rhodecode.model.changeset_status import ChangesetStatusModel
37 from rhodecode.model.comment import ChangesetCommentsModel
37 from rhodecode.model.comment import CommentsModel
38 38 from rhodecode.model.db import (
39 Session, ChangesetStatus, RepositoryField, Repository)
39 Session, ChangesetStatus, RepositoryField, Repository, RepoGroup,
40 ChangesetComment)
40 41 from rhodecode.model.repo import RepoModel
41 42 from rhodecode.model.scm import ScmModel, RepoList
42 43 from rhodecode.model.settings import SettingsModel, VcsSettingsModel
@@ -217,7 +218,7 b' def get_repo(request, apiuser, repoid, c'
217 218
218 219
219 220 @jsonrpc_method()
220 def get_repos(request, apiuser):
221 def get_repos(request, apiuser, root=Optional(None), traverse=Optional(True)):
221 222 """
222 223 Lists all existing repositories.
223 224
@@ -226,6 +227,14 b' def get_repos(request, apiuser):'
226 227
227 228 :param apiuser: This is filled automatically from the |authtoken|.
228 229 :type apiuser: AuthUser
230 :param root: specify root repository group to fetch repositories.
231 filters the returned repositories to be members of given root group.
232 :type root: Optional(None)
233 :param traverse: traverse given root into subrepositories. With this flag
234 set to False, it will only return top-level repositories from `root`.
235 if root is empty it will return just top-level repositories.
236 :type traverse: Optional(True)
237
229 238
230 239 Example output:
231 240
@@ -257,8 +266,28 b' def get_repos(request, apiuser):'
257 266 _perms = ('repository.read', 'repository.write', 'repository.admin',)
258 267 extras = {'user': apiuser}
259 268
260 repo_list = RepoList(
261 RepoModel().get_all(), perm_set=_perms, extra_kwargs=extras)
269 root = Optional.extract(root)
270 traverse = Optional.extract(traverse, binary=True)
271
272 if root:
273 # verify parent existance, if it's empty return an error
274 parent = RepoGroup.get_by_group_name(root)
275 if not parent:
276 raise JSONRPCError(
277 'Root repository group `{}` does not exist'.format(root))
278
279 if traverse:
280 repos = RepoModel().get_repos_for_root(root=root, traverse=traverse)
281 else:
282 repos = RepoModel().get_repos_for_root(root=parent)
283 else:
284 if traverse:
285 repos = RepoModel().get_all()
286 else:
287 # return just top-level
288 repos = RepoModel().get_repos_for_root(root=None)
289
290 repo_list = RepoList(repos, perm_set=_perms, extra_kwargs=extras)
262 291 return [repo.get_api_data(include_secrets=include_secrets)
263 292 for repo in repo_list]
264 293
@@ -1354,8 +1383,10 b' def lock(request, apiuser, repoid, locke'
1354 1383
1355 1384 @jsonrpc_method()
1356 1385 def comment_commit(
1357 request, apiuser, repoid, commit_id, message,
1358 userid=Optional(OAttr('apiuser')), status=Optional(None)):
1386 request, apiuser, repoid, commit_id, message, status=Optional(None),
1387 comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE),
1388 resolves_comment_id=Optional(None),
1389 userid=Optional(OAttr('apiuser'))):
1359 1390 """
1360 1391 Set a commit comment, and optionally change the status of the commit.
1361 1392
@@ -1367,15 +1398,17 b' def comment_commit('
1367 1398 :type commit_id: str
1368 1399 :param message: The comment text.
1369 1400 :type message: str
1401 :param status: (**Optional**) status of commit, one of: 'not_reviewed',
1402 'approved', 'rejected', 'under_review'
1403 :type status: str
1404 :param comment_type: Comment type, one of: 'note', 'todo'
1405 :type comment_type: Optional(str), default: 'note'
1370 1406 :param userid: Set the user name of the comment creator.
1371 1407 :type userid: Optional(str or int)
1372 :param status: status, one of 'not_reviewed', 'approved', 'rejected',
1373 'under_review'
1374 :type status: str
1375 1408
1376 1409 Example error output:
1377 1410
1378 .. code-block:: json
1411 .. code-block:: bash
1379 1412
1380 1413 {
1381 1414 "id" : <id_given_in_input>,
@@ -1398,21 +1431,37 b' def comment_commit('
1398 1431
1399 1432 user = get_user_or_error(userid)
1400 1433 status = Optional.extract(status)
1434 comment_type = Optional.extract(comment_type)
1435 resolves_comment_id = Optional.extract(resolves_comment_id)
1401 1436
1402 1437 allowed_statuses = [x[0] for x in ChangesetStatus.STATUSES]
1403 1438 if status and status not in allowed_statuses:
1404 1439 raise JSONRPCError('Bad status, must be on '
1405 1440 'of %s got %s' % (allowed_statuses, status,))
1406 1441
1442 if resolves_comment_id:
1443 comment = ChangesetComment.get(resolves_comment_id)
1444 if not comment:
1445 raise JSONRPCError(
1446 'Invalid resolves_comment_id `%s` for this commit.'
1447 % resolves_comment_id)
1448 if comment.comment_type != ChangesetComment.COMMENT_TYPE_TODO:
1449 raise JSONRPCError(
1450 'Comment `%s` is wrong type for setting status to resolved.'
1451 % resolves_comment_id)
1452
1407 1453 try:
1408 1454 rc_config = SettingsModel().get_all_settings()
1409 1455 renderer = rc_config.get('rhodecode_markup_renderer', 'rst')
1410 1456 status_change_label = ChangesetStatus.get_status_lbl(status)
1411 comm = ChangesetCommentsModel().create(
1412 message, repo, user, revision=commit_id,
1457 comm = CommentsModel().create(
1458 message, repo, user, commit_id=commit_id,
1413 1459 status_change=status_change_label,
1414 1460 status_change_type=status,
1415 renderer=renderer)
1461 renderer=renderer,
1462 comment_type=comment_type,
1463 resolves_comment_id=resolves_comment_id
1464 )
1416 1465 if status:
1417 1466 # also do a status change
1418 1467 try:
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2016 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2016 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -26,6 +26,8 b' from rhodecode.api import jsonrpc_method'
26 26 from rhodecode.api.utils import (
27 27 Optional, OAttr, has_superadmin_permission, get_user_or_error)
28 28 from rhodecode.lib.utils import repo2db_mapper
29 from rhodecode.lib import system_info
30 from rhodecode.lib import user_sessions
29 31 from rhodecode.model.db import UserIpMap
30 32 from rhodecode.model.scm import ScmModel
31 33
@@ -176,3 +178,67 b' def rescan_repos(request, apiuser, remov'
176 178 'Error occurred during rescan repositories action'
177 179 )
178 180
181
182 @jsonrpc_method()
183 def cleanup_sessions(request, apiuser, older_then=Optional(60)):
184 """
185 Triggers a session cleanup action.
186
187 If the ``older_then`` option is set, only sessions that hasn't been
188 accessed in the given number of days will be removed.
189
190 This command can only be run using an |authtoken| with admin rights to
191 the specified repository.
192
193 This command takes the following options:
194
195 :param apiuser: This is filled automatically from the |authtoken|.
196 :type apiuser: AuthUser
197 :param older_then: Deletes session that hasn't been accessed
198 in given number of days.
199 :type older_then: Optional(int)
200
201 Example output:
202
203 .. code-block:: bash
204
205 id : <id_given_in_input>
206 result: {
207 "backend": "<type of backend>",
208 "sessions_removed": <number_of_removed_sessions>
209 }
210 error : null
211
212 Example error output:
213
214 .. code-block:: bash
215
216 id : <id_given_in_input>
217 result : null
218 error : {
219 'Error occurred during session cleanup'
220 }
221
222 """
223 if not has_superadmin_permission(apiuser):
224 raise JSONRPCForbidden()
225
226 older_then = Optional.extract(older_then)
227 older_than_seconds = 60 * 60 * 24 * older_then
228
229 config = system_info.rhodecode_config().get_value()['value']['config']
230 session_model = user_sessions.get_session_handler(
231 config.get('beaker.session.type', 'memory'))(config)
232
233 backend = session_model.SESSION_TYPE
234 try:
235 cleaned = session_model.clean_sessions(
236 older_than_seconds=older_than_seconds)
237 return {'sessions_removed': cleaned, 'backend': backend}
238 except user_sessions.CleanupCommand as msg:
239 return {'cleanup_command': msg.message, 'backend': backend}
240 except Exception as e:
241 log.exception('Failed session cleanup')
242 raise JSONRPCError(
243 'Error occurred during session cleanup'
244 )
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2016 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2016 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2016 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2016 RhodeCode GmbH
3 # Copyright (C) 2012-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2016 RhodeCode GmbH
3 # Copyright (C) 2012-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2016 RhodeCode GmbH
3 # Copyright (C) 2012-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -197,14 +197,14 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
197 197 config.add_view(
198 198 'rhodecode.authentication.views.AuthnPluginViewBase',
199 199 attr='settings_get',
200 renderer='rhodecode:templates/admin/auth/plugin_settings.html',
200 renderer='rhodecode:templates/admin/auth/plugin_settings.mako',
201 201 request_method='GET',
202 202 route_name='auth_home',
203 203 context=CrowdAuthnResource)
204 204 config.add_view(
205 205 'rhodecode.authentication.views.AuthnPluginViewBase',
206 206 attr='settings_post',
207 renderer='rhodecode:templates/admin/auth/plugin_settings.html',
207 renderer='rhodecode:templates/admin/auth/plugin_settings.mako',
208 208 request_method='POST',
209 209 route_name='auth_home',
210 210 context=CrowdAuthnResource)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2016 RhodeCode GmbH
3 # Copyright (C) 2012-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -83,14 +83,14 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
83 83 config.add_view(
84 84 'rhodecode.authentication.views.AuthnPluginViewBase',
85 85 attr='settings_get',
86 renderer='rhodecode:templates/admin/auth/plugin_settings.html',
86 renderer='rhodecode:templates/admin/auth/plugin_settings.mako',
87 87 request_method='GET',
88 88 route_name='auth_home',
89 89 context=HeadersAuthnResource)
90 90 config.add_view(
91 91 'rhodecode.authentication.views.AuthnPluginViewBase',
92 92 attr='settings_post',
93 renderer='rhodecode:templates/admin/auth/plugin_settings.html',
93 renderer='rhodecode:templates/admin/auth/plugin_settings.mako',
94 94 request_method='POST',
95 95 route_name='auth_home',
96 96 context=HeadersAuthnResource)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2016 RhodeCode GmbH
3 # Copyright (C) 2012-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -74,14 +74,14 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
74 74 config.add_view(
75 75 'rhodecode.authentication.views.AuthnPluginViewBase',
76 76 attr='settings_get',
77 renderer='rhodecode:templates/admin/auth/plugin_settings.html',
77 renderer='rhodecode:templates/admin/auth/plugin_settings.mako',
78 78 request_method='GET',
79 79 route_name='auth_home',
80 80 context=JasigCasAuthnResource)
81 81 config.add_view(
82 82 'rhodecode.authentication.views.AuthnPluginViewBase',
83 83 attr='settings_post',
84 renderer='rhodecode:templates/admin/auth/plugin_settings.html',
84 renderer='rhodecode:templates/admin/auth/plugin_settings.mako',
85 85 request_method='POST',
86 86 route_name='auth_home',
87 87 context=JasigCasAuthnResource)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -332,14 +332,14 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
332 332 config.add_view(
333 333 'rhodecode.authentication.views.AuthnPluginViewBase',
334 334 attr='settings_get',
335 renderer='rhodecode:templates/admin/auth/plugin_settings.html',
335 renderer='rhodecode:templates/admin/auth/plugin_settings.mako',
336 336 request_method='GET',
337 337 route_name='auth_home',
338 338 context=LdapAuthnResource)
339 339 config.add_view(
340 340 'rhodecode.authentication.views.AuthnPluginViewBase',
341 341 attr='settings_post',
342 renderer='rhodecode:templates/admin/auth/plugin_settings.html',
342 renderer='rhodecode:templates/admin/auth/plugin_settings.mako',
343 343 request_method='POST',
344 344 route_name='auth_home',
345 345 context=LdapAuthnResource)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2016 RhodeCode GmbH
3 # Copyright (C) 2012-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -82,14 +82,14 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
82 82 config.add_view(
83 83 'rhodecode.authentication.views.AuthnPluginViewBase',
84 84 attr='settings_get',
85 renderer='rhodecode:templates/admin/auth/plugin_settings.html',
85 renderer='rhodecode:templates/admin/auth/plugin_settings.mako',
86 86 request_method='GET',
87 87 route_name='auth_home',
88 88 context=PamAuthnResource)
89 89 config.add_view(
90 90 'rhodecode.authentication.views.AuthnPluginViewBase',
91 91 attr='settings_post',
92 renderer='rhodecode:templates/admin/auth/plugin_settings.html',
92 renderer='rhodecode:templates/admin/auth/plugin_settings.mako',
93 93 request_method='POST',
94 94 route_name='auth_home',
95 95 context=PamAuthnResource)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2016 RhodeCode GmbH
3 # Copyright (C) 2012-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -52,14 +52,14 b' class RhodeCodeAuthPlugin(RhodeCodeAuthP'
52 52 config.add_view(
53 53 'rhodecode.authentication.views.AuthnPluginViewBase',
54 54 attr='settings_get',
55 renderer='rhodecode:templates/admin/auth/plugin_settings.html',
55 renderer='rhodecode:templates/admin/auth/plugin_settings.mako',
56 56 request_method='GET',
57 57 route_name='auth_home',
58 58 context=RhodecodeAuthnResource)
59 59 config.add_view(
60 60 'rhodecode.authentication.views.AuthnPluginViewBase',
61 61 attr='settings_post',
62 renderer='rhodecode:templates/admin/auth/plugin_settings.html',
62 renderer='rhodecode:templates/admin/auth/plugin_settings.mako',
63 63 request_method='POST',
64 64 route_name='auth_home',
65 65 context=RhodecodeAuthnResource)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2016 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -55,14 +55,14 b' class RhodeCodeAuthPlugin(RhodeCodeAuthP'
55 55 config.add_view(
56 56 'rhodecode.authentication.views.AuthnPluginViewBase',
57 57 attr='settings_get',
58 renderer='rhodecode:templates/admin/auth/plugin_settings.html',
58 renderer='rhodecode:templates/admin/auth/plugin_settings.mako',
59 59 request_method='GET',
60 60 route_name='auth_home',
61 61 context=RhodecodeAuthnResource)
62 62 config.add_view(
63 63 'rhodecode.authentication.views.AuthnPluginViewBase',
64 64 attr='settings_post',
65 renderer='rhodecode:templates/admin/auth/plugin_settings.html',
65 renderer='rhodecode:templates/admin/auth/plugin_settings.mako',
66 66 request_method='POST',
67 67 route_name='auth_home',
68 68 context=RhodecodeAuthnResource)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2016 RhodeCode GmbH
3 # Copyright (C) 2012-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2016 RhodeCode GmbH
3 # Copyright (C) 2012-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2016 RhodeCode GmbH
3 # Copyright (C) 2012-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2016 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2016 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,4 +1,4 b''
1 # Copyright (C) 2016 RhodeCode GmbH
1 # Copyright (C) 2017 RhodeCode GmbH
2 2 #
3 3 # This program is free software: you can redistribute it and/or modify
4 4 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2016 RhodeCode GmbH
3 # Copyright (C) 2012-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -134,7 +134,7 b' class AuthSettingsView(object):'
134 134 'available_plugins': authn_registry.get_plugins(),
135 135 'enabled_plugins': enabled_plugins,
136 136 }
137 html = render('rhodecode:templates/admin/auth/auth_settings.html',
137 html = render('rhodecode:templates/admin/auth/auth_settings.mako',
138 138 template_context,
139 139 request=self.request)
140 140
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -46,7 +46,7 b' PLUGIN_DEFINITION = {'
46 46 'javascript': [],
47 47 'css': [],
48 48 'template_hooks': {
49 'plugin_init_template': 'rhodecode:templates/channelstream/plugin_init.html'
49 'plugin_init_template': 'rhodecode:templates/channelstream/plugin_init.mako'
50 50 },
51 51 'url_gen': url_gen,
52 52 'static': None,
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -62,7 +62,7 b' class ChannelstreamView(object):'
62 62 registry = request.registry
63 63 self.channelstream_config = registry.rhodecode_plugins['channelstream']
64 64 if not self.channelstream_config.get('enabled'):
65 log.exception('Channelstream plugin is disabled')
65 log.error('Channelstream plugin is disabled')
66 66 raise HTTPBadRequest()
67 67
68 68 @NotAnonymous()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2013-2016 RhodeCode GmbH
3 # Copyright (C) 2013-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -52,7 +52,8 b' from rhodecode.lib.middleware.https_fixu'
52 52 from rhodecode.lib.middleware.vcs import VCSMiddleware
53 53 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
54 54 from rhodecode.lib.utils2 import aslist as rhodecode_aslist
55 from rhodecode.subscribers import scan_repositories_if_enabled
55 from rhodecode.subscribers import (
56 scan_repositories_if_enabled, write_metadata_if_needed)
56 57
57 58
58 59 log = logging.getLogger(__name__)
@@ -232,6 +233,14 b' def error_handler(exception, request):'
232 233 if isinstance(exception, HTTPError):
233 234 base_response = exception
234 235
236 def is_http_error(response):
237 # error which should have traceback
238 return response.status_code > 499
239
240 if is_http_error(base_response):
241 log.exception(
242 'error occurred handling this request for path: %s', request.path)
243
235 244 c = AttributeDict()
236 245 c.error_message = base_response.status
237 246 c.error_explanation = base_response.explanation or str(base_response)
@@ -251,7 +260,7 b' def error_handler(exception, request):'
251 260 c.causes = base_response.causes
252 261
253 262 response = render_to_response(
254 '/errors/error_document.html', {'c': c}, request=request,
263 '/errors/error_document.mako', {'c': c}, request=request,
255 264 response=base_response)
256 265
257 266 return response
@@ -283,8 +292,12 b' def includeme(config):'
283 292 config.add_route(
284 293 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
285 294
295 config.add_translation_dirs('rhodecode:i18n/')
296 settings['default_locale_name'] = settings.get('lang', 'en')
297
286 298 # Add subscribers.
287 299 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
300 config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
288 301
289 302 # Set the authorization policy.
290 303 authz_policy = ACLAuthorizationPolicy()
@@ -320,6 +333,13 b' def includeme_first(config):'
320 333 config.add_view(favicon_redirect, route_name='favicon')
321 334 config.add_route('favicon', '/favicon.ico')
322 335
336 def robots_redirect(context, request):
337 return HTTPFound(
338 request.static_path('rhodecode:public/robots.txt'))
339
340 config.add_view(robots_redirect, route_name='robots')
341 config.add_route('robots', '/robots.txt')
342
323 343 config.add_static_view(
324 344 '_static/deform', 'deform:static')
325 345 config.add_static_view(
@@ -351,7 +371,6 b' def wrap_app_in_wsgi_middlewares(pyramid'
351 371 pyramid_app = make_gzip_middleware(
352 372 pyramid_app, settings, compress_level=1)
353 373
354
355 374 # this should be the outer most middleware in the wsgi stack since
356 375 # middleware like Routes make database calls
357 376 def pyramid_app_with_cleanup(environ, start_response):
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2016-2016 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -503,12 +503,6 b' def make_map(config):'
503 503 m.connect('admin_settings_search', '/settings/search',
504 504 action='settings_search', conditions={'method': ['GET']})
505 505
506 m.connect('admin_settings_system', '/settings/system',
507 action='settings_system', conditions={'method': ['GET']})
508
509 m.connect('admin_settings_system_update', '/settings/system/updates',
510 action='settings_system_update', conditions={'method': ['GET']})
511
512 506 m.connect('admin_settings_supervisor', '/settings/supervisor',
513 507 action='settings_supervisor', conditions={'method': ['GET']})
514 508 m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log',
@@ -566,6 +560,10 b' def make_map(config):'
566 560 '/my_account/toggle_visibility',
567 561 action='my_notifications_toggle_visibility',
568 562 conditions={'method': ['POST']})
563 m.connect('my_account_notifications_test_channelstream',
564 '/my_account/test_channelstream',
565 action='my_account_notifications_test_channelstream',
566 conditions={'method': ['POST']})
569 567
570 568 # NOTIFICATION REST ROUTES
571 569 with rmap.submapper(path_prefix=ADMIN_PREFIX,
@@ -624,9 +622,11 b' def make_map(config):'
624 622 'pull_requests_global_0', '/pull_requests/{pull_request_id:[0-9]+}',
625 623 action='pull_requests')
626 624 m.connect(
627 'pull_requests_global', '/pull-requests/{pull_request_id:[0-9]+}',
625 'pull_requests_global_1', '/pull-requests/{pull_request_id:[0-9]+}',
628 626 action='pull_requests')
629
627 m.connect(
628 'pull_requests_global', '/pull-request/{pull_request_id:[0-9]+}',
629 action='pull_requests')
630 630
631 631 # USER JOURNAL
632 632 rmap.connect('journal', '%s/journal' % (ADMIN_PREFIX,),
@@ -694,8 +694,8 b' def make_map(config):'
694 694 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
695 695
696 696 rmap.connect('repo_refs_data', '/{repo_name}/refs-data',
697 controller='summary', action='repo_refs_data', jsroute=True,
698 requirements=URL_NAME_REQUIREMENTS)
697 controller='summary', action='repo_refs_data',
698 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
699 699 rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog',
700 700 controller='summary', action='repo_refs_changelog_data',
701 701 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
@@ -704,9 +704,9 b' def make_map(config):'
704 704 jsroute=True, requirements=URL_NAME_REQUIREMENTS)
705 705
706 706 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
707 controller='changeset', revision='tip', jsroute=True,
707 controller='changeset', revision='tip',
708 708 conditions={'function': check_repo},
709 requirements=URL_NAME_REQUIREMENTS)
709 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
710 710 rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}',
711 711 controller='changeset', revision='tip', action='changeset_children',
712 712 conditions={'function': check_repo},
@@ -923,7 +923,7 b' def make_map(config):'
923 923 controller='pullrequests',
924 924 action='show', conditions={'function': check_repo,
925 925 'method': ['GET']},
926 requirements=URL_NAME_REQUIREMENTS)
926 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
927 927
928 928 rmap.connect('pullrequest_update',
929 929 '/{repo_name}/pull-request/{pull_request_id}',
@@ -997,10 +997,10 b' def make_map(config):'
997 997 conditions={'function': check_repo},
998 998 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
999 999
1000 rmap.connect('changelog_details', '/{repo_name}/changelog_details/{cs}',
1001 controller='changelog', action='changelog_details',
1000 rmap.connect('changelog_elements', '/{repo_name}/changelog_details',
1001 controller='changelog', action='changelog_elements',
1002 1002 conditions={'function': check_repo},
1003 requirements=URL_NAME_REQUIREMENTS)
1003 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1004 1004
1005 1005 rmap.connect('files_home', '/{repo_name}/files/{revision}/{f_path}',
1006 1006 controller='files', revision='tip', f_path='',
@@ -1064,7 +1064,7 b' def make_map(config):'
1064 1064 '/{repo_name}/annotate/{revision}/{f_path}',
1065 1065 controller='files', action='index', revision='tip',
1066 1066 f_path='', annotate=True, conditions={'function': check_repo},
1067 requirements=URL_NAME_REQUIREMENTS)
1067 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1068 1068
1069 1069 rmap.connect('files_edit',
1070 1070 '/{repo_name}/edit/{revision}/{f_path}',
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -153,11 +153,11 b' class AdminController(BaseController):'
153 153
154 154 c.users_log = Page(users_log, page=p, items_per_page=10,
155 155 url=url_generator)
156 c.log_data = render('admin/admin_log.html')
156 c.log_data = render('admin/admin_log.mako')
157 157
158 158 if request.is_xhr:
159 159 return c.log_data
160 return render('admin/admin.html')
160 return render('admin/admin.mako')
161 161
162 162 # global redirect doesn't need permissions
163 163 def pull_requests(self, pull_request_id):
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -57,7 +57,7 b' class DefaultsController(BaseController)'
57 57 defaults = SettingsModel().get_default_repo_settings()
58 58
59 59 return htmlfill.render(
60 render('admin/defaults/defaults.html'),
60 render('admin/defaults/defaults.mako'),
61 61 defaults=defaults,
62 62 encoding="UTF-8",
63 63 force_defaults=False
@@ -88,7 +88,7 b' class DefaultsController(BaseController)'
88 88 defaults = errors.value
89 89
90 90 return htmlfill.render(
91 render('admin/defaults/defaults.html'),
91 render('admin/defaults/defaults.mako'),
92 92 defaults=defaults,
93 93 errors=errors.error_dict or {},
94 94 prefix_error=False,
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2013-2016 RhodeCode GmbH
3 # Copyright (C) 2013-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -114,7 +114,7 b' class GistsController(BaseController):'
114 114 c.active = 'public'
115 115
116 116 from rhodecode.lib.utils import PartialRenderer
117 _render = PartialRenderer('data_table/_dt_elements.html')
117 _render = PartialRenderer('data_table/_dt_elements.mako')
118 118
119 119 data = []
120 120
@@ -130,7 +130,7 b' class GistsController(BaseController):'
130 130 'description': _render('gist_description', gist.gist_description)
131 131 })
132 132 c.data = json.dumps(data)
133 return render('admin/gists/index.html')
133 return render('admin/gists/index.mako')
134 134
135 135 @LoginRequired()
136 136 @NotAnonymous()
@@ -186,7 +186,7 b' class GistsController(BaseController):'
186 186 del errors['nodes.0.filename']
187 187
188 188 return formencode.htmlfill.render(
189 render('admin/gists/new.html'),
189 render('admin/gists/new.mako'),
190 190 defaults=defaults,
191 191 errors=errors,
192 192 prefix_error=False,
@@ -202,11 +202,11 b' class GistsController(BaseController):'
202 202
203 203 @LoginRequired()
204 204 @NotAnonymous()
205 def new(self, format='html'):
205 def new(self):
206 206 """GET /admin/gists/new: Form to create a new item"""
207 207 # url('new_gist')
208 208 self.__load_defaults()
209 return render('admin/gists/new.html')
209 return render('admin/gists/new.mako')
210 210
211 211 @LoginRequired()
212 212 @NotAnonymous()
@@ -266,7 +266,7 b' class GistsController(BaseController):'
266 266 if (f_path is None or f.path == f_path)])
267 267 response.content_type = 'text/plain'
268 268 return content
269 return render('admin/gists/show.html')
269 return render('admin/gists/show.mako')
270 270
271 271 @LoginRequired()
272 272 @NotAnonymous()
@@ -322,7 +322,9 b' class GistsController(BaseController):'
322 322
323 323 @LoginRequired()
324 324 @NotAnonymous()
325 def edit_form(self, gist_id, format='html'):
325 def edit_form(self, gist_id):
326 translate = _ = c.pyramid_request.translate
327
326 328 """GET /admin/gists/gist_id/edit: Form to edit an existing item"""
327 329 # url('edit_gist', gist_id=ID)
328 330 self._add_gist_to_context(gist_id)
@@ -342,9 +344,11 b' class GistsController(BaseController):'
342 344 else:
343 345 # this cannot use timeago, since it's used in select2 as a value
344 346 expiry = h.age(h.time_to_datetime(c.gist.gist_expires))
347
348 expiry = translate(expiry)
345 349 self.__load_defaults(
346 350 extra_values=(0, _('%(expiry)s - current value') % {'expiry': expiry}))
347 return render('admin/gists/edit.html')
351 return render('admin/gists/edit.mako')
348 352
349 353 @LoginRequired()
350 354 @NotAnonymous()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2013-2016 RhodeCode GmbH
3 # Copyright (C) 2013-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -24,13 +24,16 b' my account controller for RhodeCode admi'
24 24 """
25 25
26 26 import logging
27 import datetime
27 28
28 29 import formencode
29 30 from formencode import htmlfill
31 from pyramid.threadlocal import get_current_registry
30 32 from pylons import request, tmpl_context as c, url, session
31 33 from pylons.controllers.util import redirect
32 34 from pylons.i18n.translation import _
33 35 from sqlalchemy.orm import joinedload
36 from webob.exc import HTTPBadGateway
34 37
35 38 from rhodecode import forms
36 39 from rhodecode.lib import helpers as h
@@ -41,6 +44,8 b' from rhodecode.lib.base import BaseContr'
41 44 from rhodecode.lib.utils import jsonify
42 45 from rhodecode.lib.utils2 import safe_int, md5, str2bool
43 46 from rhodecode.lib.ext_json import json
47 from rhodecode.lib.channelstream import channelstream_request, \
48 ChannelstreamException
44 49
45 50 from rhodecode.model.validation_schema.schemas import user_schema
46 51 from rhodecode.model.db import (
@@ -52,7 +57,7 b' from rhodecode.model.repo import RepoMod'
52 57 from rhodecode.model.auth_token import AuthTokenModel
53 58 from rhodecode.model.meta import Session
54 59 from rhodecode.model.pull_request import PullRequestModel
55 from rhodecode.model.comment import ChangesetCommentsModel
60 from rhodecode.model.comment import CommentsModel
56 61
57 62 log = logging.getLogger(__name__)
58 63
@@ -76,6 +81,9 b' class MyAccountController(BaseController'
76 81 " crucial for entire application"), category='warning')
77 82 return redirect(url('users'))
78 83
84 c.auth_user = AuthUser(
85 user_id=c.rhodecode_user.user_id, ip_addr=self.ip_addr)
86
79 87 def _load_my_repos_data(self, watched=False):
80 88 if watched:
81 89 admin = False
@@ -104,8 +112,7 b' class MyAccountController(BaseController'
104 112 # url('my_account')
105 113 c.active = 'profile_edit'
106 114 self.__load_data()
107 c.perm_user = AuthUser(user_id=c.rhodecode_user.user_id,
108 ip_addr=self.ip_addr)
115 c.perm_user = c.auth_user
109 116 c.extern_type = c.user.extern_type
110 117 c.extern_name = c.user.extern_name
111 118
@@ -137,7 +144,7 b' class MyAccountController(BaseController'
137 144
138 145 except formencode.Invalid as errors:
139 146 return htmlfill.render(
140 render('admin/my_account/my_account.html'),
147 render('admin/my_account/my_account.mako'),
141 148 defaults=errors.value,
142 149 errors=errors.error_dict or {},
143 150 prefix_error=False,
@@ -152,7 +159,7 b' class MyAccountController(BaseController'
152 159 return redirect('my_account')
153 160
154 161 return htmlfill.render(
155 render('admin/my_account/my_account.html'),
162 render('admin/my_account/my_account.mako'),
156 163 defaults=defaults,
157 164 encoding="UTF-8",
158 165 force_defaults=False
@@ -168,7 +175,7 b' class MyAccountController(BaseController'
168 175
169 176 defaults = c.user.get_dict()
170 177 return htmlfill.render(
171 render('admin/my_account/my_account.html'),
178 render('admin/my_account/my_account.mako'),
172 179 defaults=defaults, encoding="UTF-8", force_defaults=False)
173 180
174 181 def my_account_edit(self):
@@ -177,14 +184,13 b' class MyAccountController(BaseController'
177 184 """
178 185 c.active = 'profile_edit'
179 186 self.__load_data()
180 c.perm_user = AuthUser(user_id=c.rhodecode_user.user_id,
181 ip_addr=self.ip_addr)
187 c.perm_user = c.auth_user
182 188 c.extern_type = c.user.extern_type
183 189 c.extern_name = c.user.extern_name
184 190
185 191 defaults = c.user.get_dict()
186 192 return htmlfill.render(
187 render('admin/my_account/my_account.html'),
193 render('admin/my_account/my_account.mako'),
188 194 defaults=defaults,
189 195 encoding="UTF-8",
190 196 force_defaults=False
@@ -194,6 +200,7 b' class MyAccountController(BaseController'
194 200 def my_account_password(self):
195 201 c.active = 'password'
196 202 self.__load_data()
203 c.extern_type = c.user.extern_type
197 204
198 205 schema = user_schema.ChangePasswordSchema().bind(
199 206 username=c.rhodecode_user.username)
@@ -201,7 +208,7 b' class MyAccountController(BaseController'
201 208 form = forms.Form(schema,
202 209 buttons=(forms.buttons.save, forms.buttons.reset))
203 210
204 if request.method == 'POST':
211 if request.method == 'POST' and c.extern_type == 'rhodecode':
205 212 controls = request.POST.items()
206 213 try:
207 214 valid_data = form.validate(controls)
@@ -228,7 +235,7 b' class MyAccountController(BaseController'
228 235 return redirect(url('my_account_password'))
229 236
230 237 c.form = form
231 return render('admin/my_account/my_account.html')
238 return render('admin/my_account/my_account.mako')
232 239
233 240 def my_account_repos(self):
234 241 c.active = 'repos'
@@ -236,7 +243,7 b' class MyAccountController(BaseController'
236 243
237 244 # json used to render the grid
238 245 c.data = self._load_my_repos_data()
239 return render('admin/my_account/my_account.html')
246 return render('admin/my_account/my_account.mako')
240 247
241 248 def my_account_watched(self):
242 249 c.active = 'watched'
@@ -244,15 +251,14 b' class MyAccountController(BaseController'
244 251
245 252 # json used to render the grid
246 253 c.data = self._load_my_repos_data(watched=True)
247 return render('admin/my_account/my_account.html')
254 return render('admin/my_account/my_account.mako')
248 255
249 256 def my_account_perms(self):
250 257 c.active = 'perms'
251 258 self.__load_data()
252 c.perm_user = AuthUser(user_id=c.rhodecode_user.user_id,
253 ip_addr=self.ip_addr)
259 c.perm_user = c.auth_user
254 260
255 return render('admin/my_account/my_account.html')
261 return render('admin/my_account/my_account.mako')
256 262
257 263 def my_account_emails(self):
258 264 c.active = 'emails'
@@ -260,7 +266,7 b' class MyAccountController(BaseController'
260 266
261 267 c.user_email_map = UserEmailMap.query()\
262 268 .filter(UserEmailMap.user == c.user).all()
263 return render('admin/my_account/my_account.html')
269 return render('admin/my_account/my_account.mako')
264 270
265 271 @auth.CSRFRequired()
266 272 def my_account_emails_add(self):
@@ -312,11 +318,11 b' class MyAccountController(BaseController'
312 318 user_id=c.rhodecode_user.user_id, statuses=statuses)
313 319
314 320 from rhodecode.lib.utils import PartialRenderer
315 _render = PartialRenderer('data_table/_dt_elements.html')
321 _render = PartialRenderer('data_table/_dt_elements.mako')
316 322 data = []
317 323 for pr in pull_requests:
318 324 repo_id = pr.target_repo_id
319 comments = ChangesetCommentsModel().get_all_comments(
325 comments = CommentsModel().get_all_comments(
320 326 repo_id, pull_request=pr)
321 327 owned = pr.user_id == c.rhodecode_user.user_id
322 328 status = pr.calculated_review_status()
@@ -366,7 +372,7 b' class MyAccountController(BaseController'
366 372 if not request.is_xhr:
367 373 c.data_participate = json.dumps(data['data'])
368 374 c.records_total_participate = data['recordsTotal']
369 return render('admin/my_account/my_account.html')
375 return render('admin/my_account/my_account.mako')
370 376 else:
371 377 return json.dumps(data)
372 378
@@ -387,7 +393,7 b' class MyAccountController(BaseController'
387 393 c.role_options = [(c.role_values, _("Role"))]
388 394 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
389 395 c.rhodecode_user.user_id, show_expired=show_expired)
390 return render('admin/my_account/my_account.html')
396 return render('admin/my_account/my_account.mako')
391 397
392 398 @auth.CSRFRequired()
393 399 def my_account_auth_tokens_add(self):
@@ -420,7 +426,7 b' class MyAccountController(BaseController'
420 426
421 427 def my_notifications(self):
422 428 c.active = 'notifications'
423 return render('admin/my_account/my_account.html')
429 return render('admin/my_account/my_account.mako')
424 430
425 431 @auth.CSRFRequired()
426 432 @jsonify
@@ -430,3 +436,33 b' class MyAccountController(BaseController'
430 436 user.update_userdata(notification_status=new_status)
431 437 Session().commit()
432 438 return user.user_data['notification_status']
439
440 @auth.CSRFRequired()
441 @jsonify
442 def my_account_notifications_test_channelstream(self):
443 message = 'Test message sent via Channelstream by user: {}, on {}'.format(
444 c.rhodecode_user.username, datetime.datetime.now())
445 payload = {
446 'type': 'message',
447 'timestamp': datetime.datetime.utcnow(),
448 'user': 'system',
449 #'channel': 'broadcast',
450 'pm_users': [c.rhodecode_user.username],
451 'message': {
452 'message': message,
453 'level': 'info',
454 'topic': '/notifications'
455 }
456 }
457
458 registry = get_current_registry()
459 rhodecode_plugins = getattr(registry, 'rhodecode_plugins', {})
460 channelstream_config = rhodecode_plugins.get('channelstream', {})
461
462 try:
463 channelstream_request(channelstream_config, [payload], '/message')
464 except ChannelstreamException as e:
465 log.exception('Failed to send channelstream data')
466 return {"response": 'ERROR: {}'.format(e.__class__.__name__)}
467 return {"response": 'Channelstream data sent. '
468 'You should see a new live message now.'}
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -82,9 +82,9 b' class NotificationsController(BaseContro'
82 82 c.current_filter = 'comment'
83 83
84 84 if request.is_xhr:
85 return render('admin/notifications/notifications_data.html')
85 return render('admin/notifications/notifications_data.mako')
86 86
87 return render('admin/notifications/notifications.html')
87 return render('admin/notifications/notifications.mako')
88 88
89 89
90 90 @auth.CSRFRequired()
@@ -102,7 +102,7 b' class NotificationsController(BaseContro'
102 102 url('notifications'), request.GET)
103 103 c.notifications = Page(notif, page=1, items_per_page=10,
104 104 url=notifications_url)
105 return render('admin/notifications/notifications_data.html')
105 return render('admin/notifications/notifications_data.mako')
106 106
107 107 def _has_permissions(self, notification):
108 108 def is_owner():
@@ -173,6 +173,6 b' class NotificationsController(BaseContro'
173 173 Session().commit()
174 174 c.notification = no
175 175
176 return render('admin/notifications/show_notification.html')
176 return render('admin/notifications/show_notification.mako')
177 177
178 178 return abort(403)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -80,7 +80,7 b' class PermissionsController(BaseControll'
80 80 defaults.update(c.user.get_default_perms())
81 81
82 82 return htmlfill.render(
83 render('admin/permissions/permissions.html'),
83 render('admin/permissions/permissions.mako'),
84 84 defaults=defaults,
85 85 encoding="UTF-8",
86 86 force_defaults=False)
@@ -116,7 +116,7 b' class PermissionsController(BaseControll'
116 116 defaults = errors.value
117 117
118 118 return htmlfill.render(
119 render('admin/permissions/permissions.html'),
119 render('admin/permissions/permissions.mako'),
120 120 defaults=defaults,
121 121 errors=errors.error_dict or {},
122 122 prefix_error=False,
@@ -137,7 +137,7 b' class PermissionsController(BaseControll'
137 137 defaults = {}
138 138 defaults.update(c.user.get_default_perms())
139 139 return htmlfill.render(
140 render('admin/permissions/permissions.html'),
140 render('admin/permissions/permissions.mako'),
141 141 defaults=defaults,
142 142 encoding="UTF-8",
143 143 force_defaults=False)
@@ -165,7 +165,7 b' class PermissionsController(BaseControll'
165 165 defaults = errors.value
166 166
167 167 return htmlfill.render(
168 render('admin/permissions/permissions.html'),
168 render('admin/permissions/permissions.mako'),
169 169 defaults=defaults,
170 170 errors=errors.error_dict or {},
171 171 prefix_error=False,
@@ -188,7 +188,7 b' class PermissionsController(BaseControll'
188 188 defaults.update(c.user.get_default_perms())
189 189
190 190 return htmlfill.render(
191 render('admin/permissions/permissions.html'),
191 render('admin/permissions/permissions.mako'),
192 192 defaults=defaults,
193 193 encoding="UTF-8",
194 194 force_defaults=False)
@@ -219,7 +219,7 b' class PermissionsController(BaseControll'
219 219 defaults = errors.value
220 220
221 221 return htmlfill.render(
222 render('admin/permissions/permissions.html'),
222 render('admin/permissions/permissions.mako'),
223 223 defaults=defaults,
224 224 errors=errors.error_dict or {},
225 225 prefix_error=False,
@@ -239,11 +239,11 b' class PermissionsController(BaseControll'
239 239 c.user_ip_map = (
240 240 UserIpMap.query().filter(UserIpMap.user == c.user).all())
241 241
242 return render('admin/permissions/permissions.html')
242 return render('admin/permissions/permissions.mako')
243 243
244 244 @HasPermissionAllDecorator('hg.admin')
245 245 def permission_perms(self):
246 246 c.active = 'perms'
247 247 c.user = User.get_default_user()
248 248 c.perm_user = c.user.AuthUser
249 return render('admin/permissions/permissions.html')
249 return render('admin/permissions/permissions.mako')
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -162,7 +162,7 b' class RepoGroupsController(BaseControlle'
162 162 repo_group_data = RepoGroupModel().get_repo_groups_as_dict(
163 163 repo_group_list=repo_group_list_acl, admin=True)
164 164 c.data = json.dumps(repo_group_data)
165 return render('admin/repo_groups/repo_groups.html')
165 return render('admin/repo_groups/repo_groups.mako')
166 166
167 167 # perm checks inside
168 168 @NotAnonymous()
@@ -199,7 +199,7 b' class RepoGroupsController(BaseControlle'
199 199 # TODO: in futureaction_logger(, '', '', '', self.sa)
200 200 except formencode.Invalid as errors:
201 201 return htmlfill.render(
202 render('admin/repo_groups/repo_group_add.html'),
202 render('admin/repo_groups/repo_group_add.mako'),
203 203 defaults=errors.value,
204 204 errors=errors.error_dict or {},
205 205 prefix_error=False,
@@ -224,7 +224,7 b' class RepoGroupsController(BaseControlle'
224 224 return abort(403)
225 225
226 226 self.__load_defaults()
227 return render('admin/repo_groups/repo_group_add.html')
227 return render('admin/repo_groups/repo_group_add.mako')
228 228
229 229 @HasRepoGroupPermissionAnyDecorator('group.admin')
230 230 @auth.CSRFRequired()
@@ -263,7 +263,7 b' class RepoGroupsController(BaseControlle'
263 263 except formencode.Invalid as errors:
264 264 c.active = 'settings'
265 265 return htmlfill.render(
266 render('admin/repo_groups/repo_group_edit.html'),
266 render('admin/repo_groups/repo_group_edit.mako'),
267 267 defaults=errors.value,
268 268 errors=errors.error_dict or {},
269 269 prefix_error=False,
@@ -338,7 +338,7 b' class RepoGroupsController(BaseControlle'
338 338 defaults = self.__load_data(c.repo_group.group_id)
339 339
340 340 return htmlfill.render(
341 render('admin/repo_groups/repo_group_edit.html'),
341 render('admin/repo_groups/repo_group_edit.mako'),
342 342 defaults=defaults,
343 343 encoding="UTF-8",
344 344 force_defaults=False
@@ -351,7 +351,7 b' class RepoGroupsController(BaseControlle'
351 351 c.active = 'advanced'
352 352 c.repo_group = RepoGroupModel()._get_repo_group(group_name)
353 353
354 return render('admin/repo_groups/repo_group_edit.html')
354 return render('admin/repo_groups/repo_group_edit.mako')
355 355
356 356 @HasRepoGroupPermissionAnyDecorator('group.admin')
357 357 def edit_repo_group_perms(self, group_name):
@@ -363,7 +363,7 b' class RepoGroupsController(BaseControlle'
363 363 defaults = self.__load_data(c.repo_group.group_id)
364 364
365 365 return htmlfill.render(
366 render('admin/repo_groups/repo_group_edit.html'),
366 render('admin/repo_groups/repo_group_edit.mako'),
367 367 defaults=defaults,
368 368 encoding="UTF-8",
369 369 force_defaults=False
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2013-2016 RhodeCode GmbH
3 # Copyright (C) 2013-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -147,7 +147,7 b' class ReposController(BaseRepoController'
147 147 # json used to render the grid
148 148 c.data = json.dumps(repos_data)
149 149
150 return render('admin/repos/repos.html')
150 return render('admin/repos/repos.mako')
151 151
152 152 # perms check inside
153 153 @NotAnonymous()
@@ -175,7 +175,7 b' class ReposController(BaseRepoController'
175 175 task_id = task.task_id
176 176 except formencode.Invalid as errors:
177 177 return htmlfill.render(
178 render('admin/repos/repo_add.html'),
178 render('admin/repos/repo_add.mako'),
179 179 defaults=errors.value,
180 180 errors=errors.error_dict or {},
181 181 prefix_error=False,
@@ -235,7 +235,7 b' class ReposController(BaseRepoController'
235 235 defaults.update({'repo_group': parent_group_choice})
236 236
237 237 return htmlfill.render(
238 render('admin/repos/repo_add.html'),
238 render('admin/repos/repo_add.mako'),
239 239 defaults=defaults,
240 240 errors={},
241 241 prefix_error=False,
@@ -249,7 +249,7 b' class ReposController(BaseRepoController'
249 249 c.task_id = request.GET.get('task_id')
250 250 if not c.repo:
251 251 raise HTTPNotFound()
252 return render('admin/repos/repo_creating.html')
252 return render('admin/repos/repo_creating.mako')
253 253
254 254 @NotAnonymous()
255 255 @jsonify
@@ -334,7 +334,7 b' class ReposController(BaseRepoController'
334 334 defaults = self.__load_data(repo_name)
335 335 defaults.update(errors.value)
336 336 return htmlfill.render(
337 render('admin/repos/repo_edit.html'),
337 render('admin/repos/repo_edit.mako'),
338 338 defaults=defaults,
339 339 errors=errors.error_dict or {},
340 340 prefix_error=False,
@@ -410,7 +410,7 b' class ReposController(BaseRepoController'
410 410 c.personal_repo_group = c.rhodecode_user.personal_repo_group
411 411 c.active = 'settings'
412 412 return htmlfill.render(
413 render('admin/repos/repo_edit.html'),
413 render('admin/repos/repo_edit.mako'),
414 414 defaults=defaults,
415 415 encoding="UTF-8",
416 416 force_defaults=False)
@@ -424,7 +424,7 b' class ReposController(BaseRepoController'
424 424 defaults = RepoModel()._get_defaults(repo_name)
425 425
426 426 return htmlfill.render(
427 render('admin/repos/repo_edit.html'),
427 render('admin/repos/repo_edit.mako'),
428 428 defaults=defaults,
429 429 encoding="UTF-8",
430 430 force_defaults=False)
@@ -454,7 +454,7 b' class ReposController(BaseRepoController'
454 454 if request.POST:
455 455
456 456 return redirect(url('repo_edit_fields'))
457 return render('admin/repos/repo_edit.html')
457 return render('admin/repos/repo_edit.mako')
458 458
459 459 @HasRepoPermissionAllDecorator('repository.admin')
460 460 @auth.CSRFRequired()
@@ -509,7 +509,7 b' class ReposController(BaseRepoController'
509 509
510 510 if request.POST:
511 511 return redirect(url('repo_edit_advanced'))
512 return render('admin/repos/repo_edit.html')
512 return render('admin/repos/repo_edit.mako')
513 513
514 514 @HasRepoPermissionAllDecorator('repository.admin')
515 515 @auth.CSRFRequired()
@@ -642,7 +642,7 b' class ReposController(BaseRepoController'
642 642 c.repo_info = self._load_repo(repo_name)
643 643 c.active = 'caches'
644 644
645 return render('admin/repos/repo_edit.html')
645 return render('admin/repos/repo_edit.mako')
646 646
647 647 @HasRepoPermissionAllDecorator('repository.admin')
648 648 @auth.CSRFRequired()
@@ -664,7 +664,7 b' class ReposController(BaseRepoController'
664 664 c.repo_info = self._load_repo(repo_name)
665 665 c.active = 'remote'
666 666
667 return render('admin/repos/repo_edit.html')
667 return render('admin/repos/repo_edit.mako')
668 668
669 669 @HasRepoPermissionAllDecorator('repository.admin')
670 670 @auth.CSRFRequired()
@@ -702,7 +702,7 b' class ReposController(BaseRepoController'
702 702
703 703 c.active = 'statistics'
704 704
705 return render('admin/repos/repo_edit.html')
705 return render('admin/repos/repo_edit.mako')
706 706
707 707 @HasRepoPermissionAllDecorator('repository.admin')
708 708 @auth.CSRFRequired()
@@ -771,7 +771,7 b' class ReposController(BaseRepoController'
771 771 c.global_patterns = c.settings_model.get_global_settings()
772 772 c.repo_patterns = c.settings_model.get_repo_settings()
773 773
774 return render('admin/repos/repo_edit.html')
774 return render('admin/repos/repo_edit.mako')
775 775
776 776 @HasRepoPermissionAllDecorator('repository.admin')
777 777 def repo_settings_vcs(self, repo_name):
@@ -791,7 +791,7 b' class ReposController(BaseRepoController'
791 791 rhodecode.CONFIG.get('labs_settings_active', 'true'))
792 792
793 793 return htmlfill.render(
794 render('admin/repos/repo_edit.html'),
794 render('admin/repos/repo_edit.mako'),
795 795 defaults=defaults,
796 796 encoding="UTF-8",
797 797 force_defaults=False)
@@ -819,7 +819,7 b' class ReposController(BaseRepoController'
819 819 _("Some form inputs contain invalid data."),
820 820 category='error')
821 821 return htmlfill.render(
822 render('admin/repos/repo_edit.html'),
822 render('admin/repos/repo_edit.mako'),
823 823 defaults=errors.value,
824 824 errors=errors.error_dict or {},
825 825 prefix_error=False,
@@ -842,7 +842,7 b' class ReposController(BaseRepoController'
842 842 return redirect(url('repo_vcs_settings', repo_name=repo_name))
843 843
844 844 return htmlfill.render(
845 render('admin/repos/repo_edit.html'),
845 render('admin/repos/repo_edit.mako'),
846 846 defaults=self._vcs_form_defaults(repo_name),
847 847 encoding="UTF-8",
848 848 force_defaults=False)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -25,15 +25,13 b' settings controller for rhodecode admin'
25 25
26 26 import collections
27 27 import logging
28 import urllib2
29 28
30 29 import datetime
31 30 import formencode
32 31 from formencode import htmlfill
33 import packaging.version
34 32 from pylons import request, tmpl_context as c, url, config
35 33 from pylons.controllers.util import redirect
36 from pylons.i18n.translation import _, lazy_ugettext
34 from pylons.i18n.translation import _
37 35 from pyramid.threadlocal import get_current_registry
38 36 from webob.exc import HTTPBadRequest
39 37
@@ -48,7 +46,6 b' from rhodecode.lib.utils import repo2db_'
48 46 from rhodecode.lib.utils2 import (
49 47 str2bool, safe_unicode, AttributeDict, safe_int)
50 48 from rhodecode.lib.compat import OrderedDict
51 from rhodecode.lib.ext_json import json
52 49 from rhodecode.lib.utils import jsonify
53 50
54 51 from rhodecode.model.db import RhodeCodeUi, Repository
@@ -150,7 +147,7 b' class SettingsController(BaseController)'
150 147 _("Some form inputs contain invalid data."),
151 148 category='error')
152 149 return htmlfill.render(
153 render('admin/settings/settings.html'),
150 render('admin/settings/settings.mako'),
154 151 defaults=errors.value,
155 152 errors=errors.error_dict or {},
156 153 prefix_error=False,
@@ -179,7 +176,7 b' class SettingsController(BaseController)'
179 176 return redirect(url('admin_settings_vcs'))
180 177
181 178 return htmlfill.render(
182 render('admin/settings/settings.html'),
179 render('admin/settings/settings.mako'),
183 180 defaults=self._form_defaults(),
184 181 encoding="UTF-8",
185 182 force_defaults=False)
@@ -198,7 +195,7 b' class SettingsController(BaseController)'
198 195 c.svn_proxy_generate_config = pyramid_settings[generate_config]
199 196
200 197 return htmlfill.render(
201 render('admin/settings/settings.html'),
198 render('admin/settings/settings.mako'),
202 199 defaults=self._form_defaults(),
203 200 encoding="UTF-8",
204 201 force_defaults=False)
@@ -235,7 +232,7 b' class SettingsController(BaseController)'
235 232 c.active = 'mapping'
236 233
237 234 return htmlfill.render(
238 render('admin/settings/settings.html'),
235 render('admin/settings/settings.mako'),
239 236 defaults=self._form_defaults(),
240 237 encoding="UTF-8",
241 238 force_defaults=False)
@@ -253,7 +250,7 b' class SettingsController(BaseController)'
253 250 form_result = application_form.to_python(dict(request.POST))
254 251 except formencode.Invalid as errors:
255 252 return htmlfill.render(
256 render('admin/settings/settings.html'),
253 render('admin/settings/settings.mako'),
257 254 defaults=errors.value,
258 255 errors=errors.error_dict or {},
259 256 prefix_error=False,
@@ -296,7 +293,7 b' class SettingsController(BaseController)'
296 293 .get_personal_group_name_pattern()
297 294
298 295 return htmlfill.render(
299 render('admin/settings/settings.html'),
296 render('admin/settings/settings.mako'),
300 297 defaults=self._form_defaults(),
301 298 encoding="UTF-8",
302 299 force_defaults=False)
@@ -312,7 +309,7 b' class SettingsController(BaseController)'
312 309 form_result = application_form.to_python(dict(request.POST))
313 310 except formencode.Invalid as errors:
314 311 return htmlfill.render(
315 render('admin/settings/settings.html'),
312 render('admin/settings/settings.mako'),
316 313 defaults=errors.value,
317 314 errors=errors.error_dict or {},
318 315 prefix_error=False,
@@ -360,7 +357,7 b' class SettingsController(BaseController)'
360 357 c.active = 'visual'
361 358
362 359 return htmlfill.render(
363 render('admin/settings/settings.html'),
360 render('admin/settings/settings.mako'),
364 361 defaults=self._form_defaults(),
365 362 encoding="UTF-8",
366 363 force_defaults=False)
@@ -406,7 +403,7 b' class SettingsController(BaseController)'
406 403 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
407 404 })
408 405
409 return render('admin/settings/settings.html')
406 return render('admin/settings/settings.mako')
410 407
411 408 @HasPermissionAllDecorator('hg.admin')
412 409 @auth.CSRFRequired()
@@ -469,7 +466,7 b' class SettingsController(BaseController)'
469 466 c.rhodecode_ini = rhodecode.CONFIG
470 467
471 468 return htmlfill.render(
472 render('admin/settings/settings.html'),
469 render('admin/settings/settings.mako'),
473 470 defaults=self._form_defaults(),
474 471 encoding="UTF-8",
475 472 force_defaults=False)
@@ -526,7 +523,7 b' class SettingsController(BaseController)'
526 523 c.custom_hooks = model.get_custom_hooks()
527 524
528 525 return htmlfill.render(
529 render('admin/settings/settings.html'),
526 render('admin/settings/settings.mako'),
530 527 defaults=self._form_defaults(),
531 528 encoding="UTF-8",
532 529 force_defaults=False)
@@ -541,154 +538,7 b' class SettingsController(BaseController)'
541 538 searcher = searcher_from_config(config)
542 539 c.statistics = searcher.statistics()
543 540
544 return render('admin/settings/settings.html')
545
546 @HasPermissionAllDecorator('hg.admin')
547 def settings_system(self):
548 """GET /admin/settings/system: All items in the collection"""
549 # url('admin_settings_system')
550 snapshot = str2bool(request.GET.get('snapshot'))
551 defaults = self._form_defaults()
552
553 c.active = 'system'
554 c.rhodecode_update_url = defaults.get('rhodecode_update_url')
555 server_info = ScmModel().get_server_info(request.environ)
556
557 for key, val in server_info.iteritems():
558 setattr(c, key, val)
559
560 def val(name, subkey='human_value'):
561 return server_info[name][subkey]
562
563 def state(name):
564 return server_info[name]['state']
565
566 def val2(name):
567 val = server_info[name]['human_value']
568 state = server_info[name]['state']
569 return val, state
570
571 c.data_items = [
572 # update info
573 (_('Update info'), h.literal(
574 '<span class="link" id="check_for_update" >%s.</span>' % (
575 _('Check for updates')) +
576 '<br/> <span >%s.</span>' % (_('Note: please make sure this server can access `%s` for the update link to work') % c.rhodecode_update_url)
577 ), ''),
578
579 # RhodeCode specific
580 (_('RhodeCode Version'), val('rhodecode_app')['text'], state('rhodecode_app')),
581 (_('RhodeCode Server IP'), val('server')['server_ip'], state('server')),
582 (_('RhodeCode Server ID'), val('server')['server_id'], state('server')),
583 (_('RhodeCode Configuration'), val('rhodecode_config')['path'], state('rhodecode_config')),
584 ('', '', ''), # spacer
585
586 # Database
587 (_('Database'), val('database')['url'], state('database')),
588 (_('Database version'), val('database')['version'], state('database')),
589 ('', '', ''), # spacer
590
591 # Platform/Python
592 (_('Platform'), val('platform')['name'], state('platform')),
593 (_('Platform UUID'), val('platform')['uuid'], state('platform')),
594 (_('Python version'), val('python')['version'], state('python')),
595 (_('Python path'), val('python')['executable'], state('python')),
596 ('', '', ''), # spacer
597
598 # Systems stats
599 (_('CPU'), val('cpu'), state('cpu')),
600 (_('Load'), val('load')['text'], state('load')),
601 (_('Memory'), val('memory')['text'], state('memory')),
602 (_('Uptime'), val('uptime')['text'], state('uptime')),
603 ('', '', ''), # spacer
604
605 # Repo storage
606 (_('Storage location'), val('storage')['path'], state('storage')),
607 (_('Storage info'), val('storage')['text'], state('storage')),
608 (_('Storage inodes'), val('storage_inodes')['text'], state('storage_inodes')),
609
610 (_('Gist storage location'), val('storage_gist')['path'], state('storage_gist')),
611 (_('Gist storage info'), val('storage_gist')['text'], state('storage_gist')),
612
613 (_('Archive cache storage location'), val('storage_archive')['path'], state('storage_archive')),
614 (_('Archive cache info'), val('storage_archive')['text'], state('storage_archive')),
615
616 (_('Temp storage location'), val('storage_temp')['path'], state('storage_temp')),
617 (_('Temp storage info'), val('storage_temp')['text'], state('storage_temp')),
618
619 (_('Search info'), val('search')['text'], state('search')),
620 (_('Search location'), val('search')['location'], state('search')),
621 ('', '', ''), # spacer
622
623 # VCS specific
624 (_('VCS Backends'), val('vcs_backends'), state('vcs_backends')),
625 (_('VCS Server'), val('vcs_server')['text'], state('vcs_server')),
626 (_('GIT'), val('git'), state('git')),
627 (_('HG'), val('hg'), state('hg')),
628 (_('SVN'), val('svn'), state('svn')),
629
630 ]
631
632 # TODO: marcink, figure out how to allow only selected users to do this
633 c.allowed_to_snapshot = c.rhodecode_user.admin
634
635 if snapshot:
636 if c.allowed_to_snapshot:
637 c.data_items.pop(0) # remove server info
638 return render('admin/settings/settings_system_snapshot.html')
639 else:
640 h.flash('You are not allowed to do this', category='warning')
641
642 return htmlfill.render(
643 render('admin/settings/settings.html'),
644 defaults=defaults,
645 encoding="UTF-8",
646 force_defaults=False)
647
648 @staticmethod
649 def get_update_data(update_url):
650 """Return the JSON update data."""
651 ver = rhodecode.__version__
652 log.debug('Checking for upgrade on `%s` server', update_url)
653 opener = urllib2.build_opener()
654 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
655 response = opener.open(update_url)
656 response_data = response.read()
657 data = json.loads(response_data)
658
659 return data
660
661 @HasPermissionAllDecorator('hg.admin')
662 def settings_system_update(self):
663 """GET /admin/settings/system/updates: All items in the collection"""
664 # url('admin_settings_system_update')
665 defaults = self._form_defaults()
666 update_url = defaults.get('rhodecode_update_url', '')
667
668 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">%s</div>' % (s)
669 try:
670 data = self.get_update_data(update_url)
671 except urllib2.URLError as e:
672 log.exception("Exception contacting upgrade server")
673 return _err('Failed to contact upgrade server: %r' % e)
674 except ValueError as e:
675 log.exception("Bad data sent from update server")
676 return _err('Bad data sent from update server')
677
678 latest = data['versions'][0]
679
680 c.update_url = update_url
681 c.latest_data = latest
682 c.latest_ver = latest['version']
683 c.cur_ver = rhodecode.__version__
684 c.should_upgrade = False
685
686 if (packaging.version.Version(c.latest_ver) >
687 packaging.version.Version(c.cur_ver)):
688 c.should_upgrade = True
689 c.important_notices = latest['general']
690
691 return render('admin/settings/settings_system_update.html')
541 return render('admin/settings/settings.mako')
692 542
693 543 @HasPermissionAllDecorator('hg.admin')
694 544 def settings_supervisor(self):
@@ -710,7 +560,7 b' class SettingsController(BaseController)'
710 560 except Exception as e:
711 561 c.connection_error = str(e)
712 562 log.exception("Exception reading supervisor data")
713 return render('admin/settings/settings.html')
563 return render('admin/settings/settings.mako')
714 564
715 565 groupid = c.rhodecode_ini.get('supervisor.group_id')
716 566
@@ -734,7 +584,7 b' class SettingsController(BaseController)'
734 584 log.exception("Exception reading supervisor data")
735 585 c.supervisor_procs[k] = {'_rhodecode_error': str(e)}
736 586
737 return render('admin/settings/settings.html')
587 return render('admin/settings/settings.mako')
738 588
739 589 @HasPermissionAllDecorator('hg.admin')
740 590 def settings_supervisor_log(self, procid):
@@ -751,7 +601,7 b' class SettingsController(BaseController)'
751 601 offset = abs(safe_int(request.GET.get('offset', c.log_size))) * -1
752 602 c.log = supervisor.read_process_log(_connection, procid, offset, 0)
753 603
754 return render('admin/settings/settings.html')
604 return render('admin/settings/settings.mako')
755 605
756 606 @HasPermissionAllDecorator('hg.admin')
757 607 @auth.CSRFRequired()
@@ -768,7 +618,7 b' class SettingsController(BaseController)'
768 618 _('Some form inputs contain invalid data.'),
769 619 category='error')
770 620 return htmlfill.render(
771 render('admin/settings/settings.html'),
621 render('admin/settings/settings.mako'),
772 622 defaults=errors.value,
773 623 errors=errors.error_dict or {},
774 624 prefix_error=False,
@@ -795,7 +645,7 b' class SettingsController(BaseController)'
795 645 return redirect(url('admin_settings_labs'))
796 646
797 647 return htmlfill.render(
798 render('admin/settings/settings.html'),
648 render('admin/settings/settings.mako'),
799 649 defaults=self._form_defaults(),
800 650 encoding='UTF-8',
801 651 force_defaults=False)
@@ -811,7 +661,7 b' class SettingsController(BaseController)'
811 661 c.lab_settings = _LAB_SETTINGS
812 662
813 663 return htmlfill.render(
814 render('admin/settings/settings.html'),
664 render('admin/settings/settings.mako'),
815 665 defaults=self._form_defaults(),
816 666 encoding='UTF-8',
817 667 force_defaults=False)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2016 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -109,7 +109,7 b' class UserGroupsController(BaseControlle'
109 109 # url('users_groups')
110 110
111 111 from rhodecode.lib.utils import PartialRenderer
112 _render = PartialRenderer('data_table/_dt_elements.html')
112 _render = PartialRenderer('data_table/_dt_elements.mako')
113 113
114 114 def user_group_name(user_group_id, user_group_name):
115 115 return _render("user_group_name", user_group_id, user_group_name)
@@ -136,7 +136,7 b' class UserGroupsController(BaseControlle'
136 136 })
137 137
138 138 c.data = json.dumps(user_groups_data)
139 return render('admin/user_groups/user_groups.html')
139 return render('admin/user_groups/user_groups.mako')
140 140
141 141 @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
142 142 @auth.CSRFRequired()
@@ -167,7 +167,7 b' class UserGroupsController(BaseControlle'
167 167 Session().commit()
168 168 except formencode.Invalid as errors:
169 169 return htmlfill.render(
170 render('admin/user_groups/user_group_add.html'),
170 render('admin/user_groups/user_group_add.mako'),
171 171 defaults=errors.value,
172 172 errors=errors.error_dict or {},
173 173 prefix_error=False,
@@ -185,7 +185,7 b' class UserGroupsController(BaseControlle'
185 185 def new(self):
186 186 """GET /user_groups/new: Form to create a new item"""
187 187 # url('new_users_group')
188 return render('admin/user_groups/user_group_add.html')
188 return render('admin/user_groups/user_group_add.mako')
189 189
190 190 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
191 191 @auth.CSRFRequired()
@@ -224,7 +224,7 b' class UserGroupsController(BaseControlle'
224 224 e = errors.error_dict or {}
225 225
226 226 return htmlfill.render(
227 render('admin/user_groups/user_group_edit.html'),
227 render('admin/user_groups/user_group_edit.mako'),
228 228 defaults=defaults,
229 229 errors=e,
230 230 prefix_error=False,
@@ -276,7 +276,7 b' class UserGroupsController(BaseControlle'
276 276 defaults = self.__load_defaults(user_group_id)
277 277
278 278 return htmlfill.render(
279 render('admin/user_groups/user_group_edit.html'),
279 render('admin/user_groups/user_group_edit.mako'),
280 280 defaults=defaults,
281 281 encoding="UTF-8",
282 282 force_defaults=False
@@ -299,7 +299,7 b' class UserGroupsController(BaseControlle'
299 299 p.permission.permission_name})
300 300
301 301 return htmlfill.render(
302 render('admin/user_groups/user_group_edit.html'),
302 render('admin/user_groups/user_group_edit.mako'),
303 303 defaults=defaults,
304 304 encoding="UTF-8",
305 305 force_defaults=False
@@ -365,7 +365,7 b' class UserGroupsController(BaseControlle'
365 365 permissions['repositories_groups'][gr.group.group_name] \
366 366 = gr.permission.permission_name
367 367 c.permissions = permissions
368 return render('admin/user_groups/user_group_edit.html')
368 return render('admin/user_groups/user_group_edit.mako')
369 369
370 370 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
371 371 def edit_global_perms(self, user_group_id):
@@ -379,7 +379,7 b' class UserGroupsController(BaseControlle'
379 379 defaults.update(c.user_group.get_default_perms())
380 380
381 381 return htmlfill.render(
382 render('admin/user_groups/user_group_edit.html'),
382 render('admin/user_groups/user_group_edit.mako'),
383 383 defaults=defaults,
384 384 encoding="UTF-8",
385 385 force_defaults=False
@@ -425,7 +425,7 b' class UserGroupsController(BaseControlle'
425 425 defaults = errors.value
426 426 c.user_group = user_group
427 427 return htmlfill.render(
428 render('admin/user_groups/user_group_edit.html'),
428 render('admin/user_groups/user_group_edit.mako'),
429 429 defaults=defaults,
430 430 errors=errors.error_dict or {},
431 431 prefix_error=False,
@@ -456,7 +456,7 b' class UserGroupsController(BaseControlle'
456 456 (x.group for x in c.user_group.users_group_repo_group_to_perm),
457 457 key=lambda u: u.group_name.lower())
458 458
459 return render('admin/user_groups/user_group_edit.html')
459 return render('admin/user_groups/user_group_edit.mako')
460 460
461 461 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
462 462 @XHRRequired()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -82,7 +82,7 b' class UsersController(BaseController):'
82 82 # url('users')
83 83
84 84 from rhodecode.lib.utils import PartialRenderer
85 _render = PartialRenderer('data_table/_dt_elements.html')
85 _render = PartialRenderer('data_table/_dt_elements.mako')
86 86
87 87 def username(user_id, username):
88 88 return _render("user_name", user_id, username)
@@ -119,7 +119,7 b' class UsersController(BaseController):'
119 119
120 120
121 121 c.data = json.dumps(users_data)
122 return render('admin/users/users.html')
122 return render('admin/users/users.mako')
123 123
124 124 def _get_personal_repo_group_template_vars(self):
125 125 DummyUser = AttributeDict({
@@ -156,7 +156,7 b' class UsersController(BaseController):'
156 156 except formencode.Invalid as errors:
157 157 self._get_personal_repo_group_template_vars()
158 158 return htmlfill.render(
159 render('admin/users/user_add.html'),
159 render('admin/users/user_add.mako'),
160 160 defaults=errors.value,
161 161 errors=errors.error_dict or {},
162 162 prefix_error=False,
@@ -176,7 +176,7 b' class UsersController(BaseController):'
176 176 # url('new_user')
177 177 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name
178 178 self._get_personal_repo_group_template_vars()
179 return render('admin/users/user_add.html')
179 return render('admin/users/user_add.mako')
180 180
181 181 @HasPermissionAllDecorator('hg.admin')
182 182 @auth.CSRFRequired()
@@ -218,7 +218,7 b' class UsersController(BaseController):'
218 218 e = errors.error_dict or {}
219 219
220 220 return htmlfill.render(
221 render('admin/users/user_edit.html'),
221 render('admin/users/user_edit.mako'),
222 222 defaults=defaults,
223 223 errors=e,
224 224 prefix_error=False,
@@ -414,7 +414,7 b' class UsersController(BaseController):'
414 414 defaults = c.user.get_dict()
415 415 defaults.update({'language': c.user.user_data.get('language')})
416 416 return htmlfill.render(
417 render('admin/users/user_edit.html'),
417 render('admin/users/user_edit.mako'),
418 418 defaults=defaults,
419 419 encoding="UTF-8",
420 420 force_defaults=False)
@@ -446,7 +446,7 b' class UsersController(BaseController):'
446 446 '"inactive" instead of deleting it.') if has_review else ''
447 447
448 448 return htmlfill.render(
449 render('admin/users/user_edit.html'),
449 render('admin/users/user_edit.mako'),
450 450 defaults=defaults,
451 451 encoding="UTF-8",
452 452 force_defaults=False)
@@ -476,7 +476,7 b' class UsersController(BaseController):'
476 476 c.user.user_id, show_expired=show_expired)
477 477 defaults = c.user.get_dict()
478 478 return htmlfill.render(
479 render('admin/users/user_edit.html'),
479 render('admin/users/user_edit.mako'),
480 480 defaults=defaults,
481 481 encoding="UTF-8",
482 482 force_defaults=False)
@@ -539,7 +539,7 b' class UsersController(BaseController):'
539 539 defaults.update(c.user.get_default_perms())
540 540
541 541 return htmlfill.render(
542 render('admin/users/user_edit.html'),
542 render('admin/users/user_edit.mako'),
543 543 defaults=defaults,
544 544 encoding="UTF-8",
545 545 force_defaults=False)
@@ -584,7 +584,7 b' class UsersController(BaseController):'
584 584 defaults = errors.value
585 585 c.user = user
586 586 return htmlfill.render(
587 render('admin/users/user_edit.html'),
587 render('admin/users/user_edit.mako'),
588 588 defaults=defaults,
589 589 errors=errors.error_dict or {},
590 590 prefix_error=False,
@@ -607,7 +607,7 b' class UsersController(BaseController):'
607 607 c.active = 'perms_summary'
608 608 c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr)
609 609
610 return render('admin/users/user_edit.html')
610 return render('admin/users/user_edit.mako')
611 611
612 612 @HasPermissionAllDecorator('hg.admin')
613 613 def edit_emails(self, user_id):
@@ -623,7 +623,7 b' class UsersController(BaseController):'
623 623
624 624 defaults = c.user.get_dict()
625 625 return htmlfill.render(
626 render('admin/users/user_edit.html'),
626 render('admin/users/user_edit.mako'),
627 627 defaults=defaults,
628 628 encoding="UTF-8",
629 629 force_defaults=False)
@@ -685,7 +685,7 b' class UsersController(BaseController):'
685 685
686 686 defaults = c.user.get_dict()
687 687 return htmlfill.render(
688 render('admin/users/user_edit.html'),
688 render('admin/users/user_edit.mako'),
689 689 defaults=defaults,
690 690 encoding="UTF-8",
691 691 force_defaults=False)
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2016 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -34,8 +34,8 b' log = logging.getLogger(__name__)'
34 34
35 35 class BookmarksController(BaseReferencesController):
36 36
37 partials_template = 'bookmarks/bookmarks_data.html'
38 template = 'bookmarks/bookmarks.html'
37 partials_template = 'bookmarks/bookmarks_data.mako'
38 template = 'bookmarks/bookmarks.mako'
39 39
40 40 def __before__(self):
41 41 super(BookmarksController, self).__before__()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -34,8 +34,8 b' log = logging.getLogger(__name__)'
34 34
35 35 class BranchesController(BaseReferencesController):
36 36
37 partials_template = 'branches/branches_data.html'
38 template = 'branches/branches.html'
37 partials_template = 'branches/branches_data.mako'
38 template = 'branches/branches.mako'
39 39
40 40 def __before__(self):
41 41 super(BranchesController, self).__before__()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -30,7 +30,8 b' from pylons.i18n.translation import _'
30 30 from webob.exc import HTTPNotFound, HTTPBadRequest
31 31
32 32 import rhodecode.lib.helpers as h
33 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
33 from rhodecode.lib.auth import (
34 LoginRequired, HasRepoPermissionAnyDecorator, XHRRequired)
34 35 from rhodecode.lib.base import BaseRepoController, render
35 36 from rhodecode.lib.ext_json import json
36 37 from rhodecode.lib.graphmod import _colored, _dagwalker
@@ -98,7 +99,7 b' class ChangelogController(BaseRepoContro'
98 99 redirect(h.url('changelog_home', repo_name=repo.repo_name))
99 100 raise HTTPBadRequest()
100 101
101 def _graph(self, repo, commits):
102 def _graph(self, repo, commits, prev_data=None, next_data=None):
102 103 """
103 104 Generates a DAG graph for repo
104 105
@@ -106,12 +107,30 b' class ChangelogController(BaseRepoContro'
106 107 :param commits: list of commits
107 108 """
108 109 if not commits:
109 c.jsdata = json.dumps([])
110 return
110 return json.dumps([])
111
112 def serialize(commit, parents=True):
113 data = dict(
114 raw_id=commit.raw_id,
115 idx=commit.idx,
116 branch=commit.branch,
117 )
118 if parents:
119 data['parents'] = [
120 serialize(x, parents=False) for x in commit.parents]
121 return data
122
123 prev_data = prev_data or []
124 next_data = next_data or []
125
126 current = [serialize(x) for x in commits]
127 commits = prev_data + current + next_data
111 128
112 129 dag = _dagwalker(repo, commits)
113 data = [['', vtx, edges] for vtx, edges in _colored(dag)]
114 c.jsdata = json.dumps(data)
130
131 data = [[commit_id, vtx, edges, branch]
132 for commit_id, vtx, edges, branch in _colored(dag)]
133 return json.dumps(data), json.dumps(current)
115 134
116 135 def _check_if_valid_branch(self, branch_name, repo_name, f_path):
117 136 if branch_name not in c.rhodecode_repo.branches_all:
@@ -120,26 +139,37 b' class ChangelogController(BaseRepoContro'
120 139 redirect(url('changelog_file_home', repo_name=repo_name,
121 140 revision=branch_name, f_path=f_path or ''))
122 141
142 def _load_changelog_data(self, collection, page, chunk_size, branch_name=None, dynamic=False):
143 c.total_cs = len(collection)
144 c.showing_commits = min(chunk_size, c.total_cs)
145 c.pagination = RepoPage(collection, page=page, item_count=c.total_cs,
146 items_per_page=chunk_size, branch=branch_name)
147
148 c.next_page = c.pagination.next_page
149 c.prev_page = c.pagination.previous_page
150
151 if dynamic:
152 if request.GET.get('chunk') != 'next':
153 c.next_page = None
154 if request.GET.get('chunk') != 'prev':
155 c.prev_page = None
156
157 page_commit_ids = [x.raw_id for x in c.pagination]
158 c.comments = c.rhodecode_db_repo.get_comments(page_commit_ids)
159 c.statuses = c.rhodecode_db_repo.statuses(page_commit_ids)
160
123 161 @LoginRequired()
124 162 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
125 163 'repository.admin')
126 164 def index(self, repo_name, revision=None, f_path=None):
127 165 commit_id = revision
128 limit = 100
166 chunk_size = 20
167
168 c.branch_name = branch_name = request.GET.get('branch', None)
169 c.book_name = book_name = request.GET.get('bookmark', None)
129 170 hist_limit = safe_int(request.GET.get('limit')) or None
130 if request.GET.get('size'):
131 c.size = safe_int(request.GET.get('size'), 1)
132 session['changelog_size'] = c.size
133 session.save()
134 else:
135 c.size = int(session.get('changelog_size', DEFAULT_CHANGELOG_SIZE))
136
137 # min size must be 1 and less than limit
138 c.size = max(c.size, 1) if c.size <= limit else limit
139 171
140 172 p = safe_int(request.GET.get('page', 1), 1)
141 c.branch_name = branch_name = request.GET.get('branch', None)
142 c.book_name = book_name = request.GET.get('bookmark', None)
143 173
144 174 c.selected_name = branch_name or book_name
145 175 if not commit_id and branch_name:
@@ -147,6 +177,8 b' class ChangelogController(BaseRepoContro'
147 177
148 178 c.changelog_for_path = f_path
149 179 pre_load = ['author', 'branch', 'date', 'message', 'parents']
180 commit_ids = []
181
150 182 try:
151 183 if f_path:
152 184 log.debug('generating changelog for path %s', f_path)
@@ -174,13 +206,9 b' class ChangelogController(BaseRepoContro'
174 206 collection = c.rhodecode_repo.get_commits(
175 207 branch_name=branch_name, pre_load=pre_load)
176 208
177 c.total_cs = len(collection)
178 c.showing_commits = min(c.size, c.total_cs)
179 c.pagination = RepoPage(collection, page=p, item_count=c.total_cs,
180 items_per_page=c.size, branch=branch_name)
181 page_commit_ids = [x.raw_id for x in c.pagination]
182 c.comments = c.rhodecode_db_repo.get_comments(page_commit_ids)
183 c.statuses = c.rhodecode_db_repo.statuses(page_commit_ids)
209 self._load_changelog_data(
210 collection, p, chunk_size, c.branch_name, dynamic=f_path)
211
184 212 except EmptyRepositoryError as e:
185 213 h.flash(safe_str(e), category='warning')
186 214 return redirect(url('summary_home', repo_name=repo_name))
@@ -193,24 +221,64 b' class ChangelogController(BaseRepoContro'
193 221 if (request.environ.get('HTTP_X_PARTIAL_XHR')
194 222 or request.environ.get('HTTP_X_PJAX')):
195 223 # loading from ajax, we don't want the first result, it's popped
196 return render('changelog/changelog_file_history.html')
224 return render('changelog/changelog_file_history.mako')
225
226 if not f_path:
227 commit_ids = c.pagination
197 228
198 if f_path:
199 revs = []
200 else:
201 revs = c.pagination
202 self._graph(c.rhodecode_repo, revs)
229 c.graph_data, c.graph_commits = self._graph(
230 c.rhodecode_repo, commit_ids)
203 231
204 return render('changelog/changelog.html')
232 return render('changelog/changelog.mako')
205 233
206 234 @LoginRequired()
207 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
208 'repository.admin')
209 def changelog_details(self, commit_id):
210 if request.environ.get('HTTP_X_PARTIAL_XHR'):
211 c.commit = c.rhodecode_repo.get_commit(commit_id=commit_id)
212 return render('changelog/changelog_details.html')
213 raise HTTPNotFound()
235 @XHRRequired()
236 @HasRepoPermissionAnyDecorator(
237 'repository.read', 'repository.write', 'repository.admin')
238 def changelog_elements(self, repo_name):
239 commit_id = None
240 chunk_size = 20
241
242 def wrap_for_error(err):
243 return '<tr><td colspan="9" class="alert alert-error">ERROR: {}</td></tr>'.format(err)
244
245 c.branch_name = branch_name = request.GET.get('branch', None)
246 c.book_name = book_name = request.GET.get('bookmark', None)
247
248 p = safe_int(request.GET.get('page', 1), 1)
249
250 c.selected_name = branch_name or book_name
251 if not commit_id and branch_name:
252 if branch_name not in c.rhodecode_repo.branches_all:
253 return wrap_for_error(
254 safe_str('Missing branch: {}'.format(branch_name)))
255
256 pre_load = ['author', 'branch', 'date', 'message', 'parents']
257 collection = c.rhodecode_repo.get_commits(
258 branch_name=branch_name, pre_load=pre_load)
259
260 try:
261 self._load_changelog_data(collection, p, chunk_size, dynamic=True)
262 except EmptyRepositoryError as e:
263 return wrap_for_error(safe_str(e))
264 except (RepositoryError, CommitDoesNotExistError, Exception) as e:
265 log.exception('Failed to fetch commits')
266 return wrap_for_error(safe_str(e))
267
268 prev_data = None
269 next_data = None
270
271 prev_graph = json.loads(request.POST.get('graph', ''))
272
273 if request.GET.get('chunk') == 'prev':
274 next_data = prev_graph
275 elif request.GET.get('chunk') == 'next':
276 prev_data = prev_graph
277
278 c.graph_data, c.graph_commits = self._graph(
279 c.rhodecode_repo, c.pagination,
280 prev_data=prev_data, next_data=next_data)
281 return render('changelog/changelog_elements.mako')
214 282
215 283 @LoginRequired()
216 284 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
@@ -218,5 +286,5 b' class ChangelogController(BaseRepoContro'
218 286 def changelog_summary(self, repo_name):
219 287 if request.environ.get('HTTP_X_PJAX'):
220 288 _load_changelog_summary()
221 return render('changelog/changelog_summary_data.html')
289 return render('changelog/changelog_summary_data.mako')
222 290 raise HTTPNotFound()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -46,7 +46,7 b' from rhodecode.lib.vcs.exceptions import'
46 46 RepositoryError, CommitDoesNotExistError, NodeDoesNotExistError)
47 47 from rhodecode.model.db import ChangesetComment, ChangesetStatus
48 48 from rhodecode.model.changeset_status import ChangesetStatusModel
49 from rhodecode.model.comment import ChangesetCommentsModel
49 from rhodecode.model.comment import CommentsModel
50 50 from rhodecode.model.meta import Session
51 51 from rhodecode.model.repo import RepoModel
52 52
@@ -198,15 +198,20 b' class ChangesetController(BaseRepoContro'
198 198 c.lines_added = 0
199 199 c.lines_deleted = 0
200 200
201 # auto collapse if we have more than limit
202 collapse_limit = diffs.DiffProcessor._collapse_commits_over
203 c.collapse_all_commits = len(c.commit_ranges) > collapse_limit
204
201 205 c.commit_statuses = ChangesetStatus.STATUSES
202 206 c.inline_comments = []
203 207 c.files = []
204 208
205 209 c.statuses = []
206 210 c.comments = []
211 c.unresolved_comments = []
207 212 if len(c.commit_ranges) == 1:
208 213 commit = c.commit_ranges[0]
209 c.comments = ChangesetCommentsModel().get_comments(
214 c.comments = CommentsModel().get_comments(
210 215 c.rhodecode_db_repo.repo_id,
211 216 revision=commit.raw_id)
212 217 c.statuses.append(ChangesetStatusModel().get_status(
@@ -222,6 +227,9 b' class ChangesetController(BaseRepoContro'
222 227 for pr in prs:
223 228 c.comments.extend(pr.comments)
224 229
230 c.unresolved_comments = CommentsModel()\
231 .get_commit_unresolved_todos(commit.raw_id)
232
225 233 # Iterate over ranges (default commit view is always one commit)
226 234 for commit in c.commit_ranges:
227 235 c.changes[commit.raw_id] = []
@@ -251,9 +259,9 b' class ChangesetController(BaseRepoContro'
251 259 return None
252 260 return get_node
253 261
254 inline_comments = ChangesetCommentsModel().get_inline_comments(
262 inline_comments = CommentsModel().get_inline_comments(
255 263 c.rhodecode_db_repo.repo_id, revision=commit.raw_id)
256 c.inline_cnt = ChangesetCommentsModel().get_inline_comments_count(
264 c.inline_cnt = CommentsModel().get_inline_comments_count(
257 265 inline_comments)
258 266
259 267 diffset = codeblocks.DiffSet(
@@ -271,7 +279,6 b' class ChangesetController(BaseRepoContro'
271 279 # sort comments by how they were generated
272 280 c.comments = sorted(c.comments, key=lambda x: x.comment_id)
273 281
274
275 282 if len(c.commit_ranges) == 1:
276 283 c.commit = c.commit_ranges[0]
277 284 c.parent_tmpl = ''.join(
@@ -284,17 +291,17 b' class ChangesetController(BaseRepoContro'
284 291 elif method == 'patch':
285 292 response.content_type = 'text/plain'
286 293 c.diff = safe_unicode(diff)
287 return render('changeset/patch_changeset.html')
294 return render('changeset/patch_changeset.mako')
288 295 elif method == 'raw':
289 296 response.content_type = 'text/plain'
290 297 return diff
291 298 elif method == 'show':
292 299 if len(c.commit_ranges) == 1:
293 return render('changeset/changeset.html')
300 return render('changeset/changeset.mako')
294 301 else:
295 302 c.ancestor = None
296 303 c.target_repo = c.rhodecode_db_repo
297 return render('changeset/changeset_range.html')
304 return render('changeset/changeset_range.mako')
298 305
299 306 @LoginRequired()
300 307 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
@@ -330,29 +337,39 b' class ChangesetController(BaseRepoContro'
330 337 commit_id = revision
331 338 status = request.POST.get('changeset_status', None)
332 339 text = request.POST.get('text')
340 comment_type = request.POST.get('comment_type')
341 resolves_comment_id = request.POST.get('resolves_comment_id', None)
342
333 343 if status:
334 344 text = text or (_('Status change %(transition_icon)s %(status)s')
335 345 % {'transition_icon': '>',
336 346 'status': ChangesetStatus.get_status_lbl(status)})
337 347
338 multi_commit_ids = filter(
339 lambda s: s not in ['', None],
340 request.POST.get('commit_ids', '').split(','),)
348 multi_commit_ids = []
349 for _commit_id in request.POST.get('commit_ids', '').split(','):
350 if _commit_id not in ['', None, EmptyCommit.raw_id]:
351 if _commit_id not in multi_commit_ids:
352 multi_commit_ids.append(_commit_id)
341 353
342 354 commit_ids = multi_commit_ids or [commit_id]
355
343 356 comment = None
344 357 for current_id in filter(None, commit_ids):
345 c.co = comment = ChangesetCommentsModel().create(
358 c.co = comment = CommentsModel().create(
346 359 text=text,
347 360 repo=c.rhodecode_db_repo.repo_id,
348 361 user=c.rhodecode_user.user_id,
349 revision=current_id,
362 commit_id=current_id,
350 363 f_path=request.POST.get('f_path'),
351 364 line_no=request.POST.get('line'),
352 365 status_change=(ChangesetStatus.get_status_lbl(status)
353 366 if status else None),
354 status_change_type=status
367 status_change_type=status,
368 comment_type=comment_type,
369 resolves_comment_id=resolves_comment_id
355 370 )
371 c.inline_comment = True if comment.line_no else False
372
356 373 # get status if set !
357 374 if status:
358 375 # if latest status was from pull request and it's closed
@@ -386,7 +403,7 b' class ChangesetController(BaseRepoContro'
386 403 if comment:
387 404 data.update(comment.get_dict())
388 405 data.update({'rendered_text':
389 render('changeset/changeset_comment_block.html')})
406 render('changeset/changeset_comment_block.mako')})
390 407
391 408 return data
392 409
@@ -417,10 +434,15 b' class ChangesetController(BaseRepoContro'
417 434 @jsonify
418 435 def delete_comment(self, repo_name, comment_id):
419 436 comment = ChangesetComment.get(comment_id)
437 if not comment:
438 log.debug('Comment with id:%s not found, skipping', comment_id)
439 # comment already deleted in another call probably
440 return True
441
420 442 owner = (comment.author.user_id == c.rhodecode_user.user_id)
421 443 is_repo_admin = h.HasRepoPermissionAny('repository.admin')(c.repo_name)
422 444 if h.HasPermissionAny('hg.admin')() or is_repo_admin or owner:
423 ChangesetCommentsModel().delete(comment=comment)
445 CommentsModel().delete(comment=comment)
424 446 Session().commit()
425 447 return True
426 448 else:
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2016 RhodeCode GmbH
3 # Copyright (C) 2012-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -79,6 +79,7 b' class CompareController(BaseRepoControll'
79 79 def index(self, repo_name):
80 80 c.compare_home = True
81 81 c.commit_ranges = []
82 c.collapse_all_commits = False
82 83 c.diffset = None
83 84 c.limited_diff = False
84 85 source_repo = c.rhodecode_db_repo.repo_name
@@ -90,7 +91,8 b' class CompareController(BaseRepoControll'
90 91 c.target_ref_type = ""
91 92 c.commit_statuses = ChangesetStatus.STATUSES
92 93 c.preview_mode = False
93 return render('compare/compare_diff.html')
94 c.file_path = None
95 return render('compare/compare_diff.mako')
94 96
95 97 @LoginRequired()
96 98 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
@@ -103,8 +105,10 b' class CompareController(BaseRepoControll'
103 105
104 106 # target_ref will be evaluated in target_repo
105 107 target_repo_name = request.GET.get('target_repo', source_repo_name)
106 target_path, target_id = parse_path_ref(target_ref)
108 target_path, target_id = parse_path_ref(
109 target_ref, default_path=request.GET.get('f_path', ''))
107 110
111 c.file_path = target_path
108 112 c.commit_statuses = ChangesetStatus.STATUSES
109 113
110 114 # if merge is True
@@ -115,7 +119,6 b' class CompareController(BaseRepoControll'
115 119 # if merge is False
116 120 # Show a raw diff of source/target refs even if no ancestor exists
117 121
118
119 122 # c.fulldiff disables cut_off_limit
120 123 c.fulldiff = str2bool(request.GET.get('fulldiff'))
121 124
@@ -131,7 +134,8 b' class CompareController(BaseRepoControll'
131 134 target_repo=source_repo_name,
132 135 target_ref_type=source_ref_type,
133 136 target_ref=source_ref,
134 merge=merge and '1' or '')
137 merge=merge and '1' or '',
138 f_path=target_path)
135 139
136 140 source_repo = Repository.get_by_repo_name(source_repo_name)
137 141 target_repo = Repository.get_by_repo_name(target_repo_name)
@@ -151,8 +155,11 b' class CompareController(BaseRepoControll'
151 155 h.flash(msg, category='error')
152 156 return redirect(url('compare_home', repo_name=c.repo_name))
153 157
154 source_alias = source_repo.scm_instance().alias
155 target_alias = target_repo.scm_instance().alias
158 source_scm = source_repo.scm_instance()
159 target_scm = target_repo.scm_instance()
160
161 source_alias = source_scm.alias
162 target_alias = target_scm.alias
156 163 if source_alias != target_alias:
157 164 msg = _('The comparison of two different kinds of remote repos '
158 165 'is not available')
@@ -175,34 +182,42 b' class CompareController(BaseRepoControll'
175 182 c.source_ref_type = source_ref_type
176 183 c.target_ref_type = target_ref_type
177 184
178 source_scm = source_repo.scm_instance()
179 target_scm = target_repo.scm_instance()
180
181 185 pre_load = ["author", "branch", "date", "message"]
182 186 c.ancestor = None
183 try:
184 c.commit_ranges = source_scm.compare(
185 source_commit.raw_id, target_commit.raw_id,
186 target_scm, merge, pre_load=pre_load)
187 if merge:
188 c.ancestor = source_scm.get_common_ancestor(
189 source_commit.raw_id, target_commit.raw_id, target_scm)
190 except RepositoryRequirementError:
191 msg = _('Could not compare repos with different '
192 'large file settings')
193 log.error(msg)
194 if partial:
195 return msg
196 h.flash(msg, category='error')
197 return redirect(url('compare_home', repo_name=c.repo_name))
187
188 if c.file_path:
189 if source_commit == target_commit:
190 c.commit_ranges = []
191 else:
192 c.commit_ranges = [target_commit]
193 else:
194 try:
195 c.commit_ranges = source_scm.compare(
196 source_commit.raw_id, target_commit.raw_id,
197 target_scm, merge, pre_load=pre_load)
198 if merge:
199 c.ancestor = source_scm.get_common_ancestor(
200 source_commit.raw_id, target_commit.raw_id, target_scm)
201 except RepositoryRequirementError:
202 msg = _('Could not compare repos with different '
203 'large file settings')
204 log.error(msg)
205 if partial:
206 return msg
207 h.flash(msg, category='error')
208 return redirect(url('compare_home', repo_name=c.repo_name))
198 209
199 210 c.statuses = c.rhodecode_db_repo.statuses(
200 211 [x.raw_id for x in c.commit_ranges])
201 212
202 if partial: # for PR ajax commits loader
213 # auto collapse if we have more than limit
214 collapse_limit = diffs.DiffProcessor._collapse_commits_over
215 c.collapse_all_commits = len(c.commit_ranges) > collapse_limit
216
217 if partial: # for PR ajax commits loader
203 218 if not c.ancestor:
204 return '' # cannot merge if there is no ancestor
205 return render('compare/compare_commits.html')
219 return '' # cannot merge if there is no ancestor
220 return render('compare/compare_commits.mako')
206 221
207 222 if c.ancestor:
208 223 # case we want a simple diff without incoming commits,
@@ -238,7 +253,8 b' class CompareController(BaseRepoControll'
238 253
239 254 txtdiff = source_repo.scm_instance().get_diff(
240 255 commit1=source_commit, commit2=target_commit,
241 path1=source_path, path=target_path)
256 path=target_path, path1=source_path)
257
242 258 diff_processor = diffs.DiffProcessor(
243 259 txtdiff, format='newdiff', diff_limit=diff_limit,
244 260 file_limit=file_limit, show_full_diff=c.fulldiff)
@@ -260,5 +276,7 b' class CompareController(BaseRepoControll'
260 276 ).render_patchset(_parsed, source_ref, target_ref)
261 277
262 278 c.preview_mode = merge
279 c.source_commit = source_commit
280 c.target_commit = target_commit
263 281
264 return render('compare/compare_diff.html')
282 return render('compare/compare_diff.mako')
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2014-2016 RhodeCode GmbH
3 # Copyright (C) 2014-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -144,7 +144,7 b' class FilesController(BaseRepoController'
144 144 log.debug('Generating cached file tree for %s, %s, %s',
145 145 repo_name, commit_id, f_path)
146 146 c.full_load = full_load
147 return render('files/files_browser_tree.html')
147 return render('files/files_browser_tree.mako')
148 148
149 149 cache_manager = self.__get_tree_cache_manager(
150 150 repo_name, caches.FILE_TREE)
@@ -255,9 +255,9 b' class FilesController(BaseRepoController'
255 255 raise HTTPNotFound()
256 256
257 257 if request.environ.get('HTTP_X_PJAX'):
258 return render('files/files_pjax.html')
258 return render('files/files_pjax.mako')
259 259
260 return render('files/files.html')
260 return render('files/files.mako')
261 261
262 262 @LoginRequired()
263 263 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
@@ -305,7 +305,7 b' class FilesController(BaseRepoController'
305 305 c.authors.append((
306 306 h.email(author),
307 307 h.person(author, 'username_or_name_or_email')))
308 return render('files/file_authors_box.html')
308 return render('files/file_authors_box.mako')
309 309
310 310 @LoginRequired()
311 311 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
@@ -465,7 +465,7 b' class FilesController(BaseRepoController'
465 465 'Deleted file %s via RhodeCode Enterprise') % (f_path)
466 466 c.f_path = f_path
467 467
468 return render('files/files_delete.html')
468 return render('files/files_delete.mako')
469 469
470 470 @CSRFRequired()
471 471 @LoginRequired()
@@ -574,7 +574,7 b' class FilesController(BaseRepoController'
574 574 'Edited file %s via RhodeCode Enterprise') % (f_path)
575 575 c.f_path = f_path
576 576
577 return render('files/files_edit.html')
577 return render('files/files_edit.mako')
578 578
579 579 def _is_valid_head(self, commit_id, repo):
580 580 # check if commit is a branch identifier- basically we cannot
@@ -700,7 +700,7 b' class FilesController(BaseRepoController'
700 700 c.default_message = (_('Added file via RhodeCode Enterprise'))
701 701 c.f_path = f_path
702 702
703 return render('files/files_add.html')
703 return render('files/files_add.mako')
704 704
705 705 @LoginRequired()
706 706 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
@@ -799,21 +799,15 b' class FilesController(BaseRepoController'
799 799 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
800 800 'repository.admin')
801 801 def diff(self, repo_name, f_path):
802 ignore_whitespace = request.GET.get('ignorews') == '1'
803 line_context = request.GET.get('context', 3)
802
803 c.action = request.GET.get('diff')
804 804 diff1 = request.GET.get('diff1', '')
805 diff2 = request.GET.get('diff2', '')
805 806
806 807 path1, diff1 = parse_path_ref(diff1, default_path=f_path)
807 808
808 diff2 = request.GET.get('diff2', '')
809 c.action = request.GET.get('diff')
810 c.no_changes = diff1 == diff2
811 c.f_path = f_path
812 c.big_diff = False
813 c.ignorews_url = _ignorews_url
814 c.context_url = _context_url
815 c.changes = OrderedDict()
816 c.changes[diff2] = []
809 ignore_whitespace = str2bool(request.GET.get('ignorews'))
810 line_context = request.GET.get('context', 3)
817 811
818 812 if not any((diff1, diff2)):
819 813 h.flash(
@@ -821,18 +815,16 b' class FilesController(BaseRepoController'
821 815 category='error')
822 816 raise HTTPBadRequest()
823 817
824 # special case if we want a show commit_id only, it's impl here
825 # to reduce JS and callbacks
826
827 if request.GET.get('show_rev') and diff1:
828 if str2bool(request.GET.get('annotate', 'False')):
829 _url = url('files_annotate_home', repo_name=c.repo_name,
830 revision=diff1, f_path=path1)
831 else:
832 _url = url('files_home', repo_name=c.repo_name,
833 revision=diff1, f_path=path1)
834
835 return redirect(_url)
818 if c.action not in ['download', 'raw']:
819 # redirect to new view if we render diff
820 return redirect(
821 url('compare_url', repo_name=repo_name,
822 source_ref_type='rev',
823 source_ref=diff1,
824 target_repo=c.repo_name,
825 target_ref_type='rev',
826 target_ref=diff2,
827 f_path=f_path))
836 828
837 829 try:
838 830 node1 = self._get_file_node(diff1, path1)
@@ -877,98 +869,40 b' class FilesController(BaseRepoController'
877 869 return diff.as_raw()
878 870
879 871 else:
880 fid = h.FID(diff2, node2.path)
881 line_context_lcl = get_line_ctx(fid, request.GET)
882 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
883
884 __, commit1, commit2, diff, st, data = diffs.wrapped_diff(
885 filenode_old=node1,
886 filenode_new=node2,
887 diff_limit=self.cut_off_limit_diff,
888 file_limit=self.cut_off_limit_file,
889 show_full_diff=request.GET.get('fulldiff'),
890 ignore_whitespace=ign_whitespace_lcl,
891 line_context=line_context_lcl,)
892
893 c.lines_added = data['stats']['added'] if data else 0
894 c.lines_deleted = data['stats']['deleted'] if data else 0
895 c.files = [data]
896 c.commit_ranges = [c.commit_1, c.commit_2]
897 c.ancestor = None
898 c.statuses = []
899 c.target_repo = c.rhodecode_db_repo
900 c.filename1 = node1.path
901 c.filename = node2.path
902 c.binary_file = node1.is_binary or node2.is_binary
903 operation = data['operation'] if data else ''
904
905 commit_changes = {
906 # TODO: it's passing the old file to the diff to keep the
907 # standard but this is not being used for this template,
908 # but might need both files in the future or a more standard
909 # way to work with that
910 'fid': [commit1, commit2, operation,
911 c.filename, diff, st, data]
912 }
913
914 c.changes = commit_changes
915
916 return render('files/file_diff.html')
872 return redirect(
873 url('compare_url', repo_name=repo_name,
874 source_ref_type='rev',
875 source_ref=diff1,
876 target_repo=c.repo_name,
877 target_ref_type='rev',
878 target_ref=diff2,
879 f_path=f_path))
917 880
918 881 @LoginRequired()
919 882 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
920 883 'repository.admin')
921 884 def diff_2way(self, repo_name, f_path):
885 """
886 Kept only to make OLD links work
887 """
922 888 diff1 = request.GET.get('diff1', '')
923 889 diff2 = request.GET.get('diff2', '')
924 890
925 nodes = []
926 unknown_commits = []
927 for commit in [diff1, diff2]:
928 try:
929 nodes.append(self._get_file_node(commit, f_path))
930 except (RepositoryError, NodeError):
931 log.exception('%(commit)s does not exist' % {'commit': commit})
932 unknown_commits.append(commit)
933 h.flash(h.literal(
934 _('Commit %(commit)s does not exist.') % {'commit': commit}
935 ), category='error')
936
937 if unknown_commits:
938 return redirect(url('files_home', repo_name=c.repo_name,
939 f_path=f_path))
940
941 if all(isinstance(node.commit, EmptyCommit) for node in nodes):
942 raise HTTPNotFound
943
944 node1, node2 = nodes
891 if not any((diff1, diff2)):
892 h.flash(
893 'Need query parameter "diff1" or "diff2" to generate a diff.',
894 category='error')
895 raise HTTPBadRequest()
945 896
946 f_gitdiff = diffs.get_gitdiff(node1, node2, ignore_whitespace=False)
947 diff_processor = diffs.DiffProcessor(f_gitdiff, format='gitdiff')
948 diff_data = diff_processor.prepare()
949
950 if not diff_data or diff_data[0]['raw_diff'] == '':
951 h.flash(h.literal(_('%(file_path)s has not changed '
952 'between %(commit_1)s and %(commit_2)s.') % {
953 'file_path': f_path,
954 'commit_1': node1.commit.id,
955 'commit_2': node2.commit.id
956 }), category='error')
957 return redirect(url('files_home', repo_name=c.repo_name,
958 f_path=f_path))
959
960 c.diff_data = diff_data[0]
961 c.FID = h.FID(diff2, node2.path)
962 # cleanup some unneeded data
963 del c.diff_data['raw_diff']
964 del c.diff_data['chunks']
965
966 c.node1 = node1
967 c.commit_1 = node1.commit
968 c.node2 = node2
969 c.commit_2 = node2.commit
970
971 return render('files/diff_2way.html')
897 return redirect(
898 url('compare_url', repo_name=repo_name,
899 source_ref_type='rev',
900 source_ref=diff1,
901 target_repo=c.repo_name,
902 target_ref_type='rev',
903 target_ref=diff2,
904 f_path=f_path,
905 diffmode='sideside'))
972 906
973 907 def _get_file_node(self, commit_id, f_path):
974 908 if commit_id not in ['', None, 'None', '0' * 12, '0' * 40]:
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2016 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -50,9 +50,9 b' class FollowersController(BaseRepoContro'
50 50 .order_by(UserFollowing.follows_from)
51 51 c.followers_pager = Page(d, page=p, items_per_page=20)
52 52
53 c.followers_data = render('/followers/followers_data.html')
53 c.followers_data = render('/followers/followers_data.mako')
54 54
55 55 if request.environ.get('HTTP_X_PJAX'):
56 56 return c.followers_data
57 57
58 return render('/followers/followers.html')
58 return render('/followers/followers.mako')
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2011-2016 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -122,12 +122,12 b' class ForksController(BaseRepoController'
122 122 d.append(r)
123 123 c.forks_pager = Page(d, page=p, items_per_page=20)
124 124
125 c.forks_data = render('/forks/forks_data.html')
125 c.forks_data = render('/forks/forks_data.mako')
126 126
127 127 if request.environ.get('HTTP_X_PJAX'):
128 128 return c.forks_data
129 129
130 return render('/forks/forks.html')
130 return render('/forks/forks.mako')
131 131
132 132 @LoginRequired()
133 133 @NotAnonymous()
@@ -144,7 +144,7 b' class ForksController(BaseRepoController'
144 144 defaults = self.__load_data(repo_name)
145 145
146 146 return htmlfill.render(
147 render('forks/fork.html'),
147 render('forks/fork.mako'),
148 148 defaults=defaults,
149 149 encoding="UTF-8",
150 150 force_defaults=False
@@ -177,7 +177,7 b' class ForksController(BaseRepoController'
177 177 except formencode.Invalid as errors:
178 178 c.new_repo = errors.value['repo_name']
179 179 return htmlfill.render(
180 render('forks/fork.html'),
180 render('forks/fork.mako'),
181 181 defaults=errors.value,
182 182 errors=errors.error_dict or {},
183 183 prefix_error=False,
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -97,7 +97,7 b' class HomeController(BaseController):'
97 97 c.repos_data = json.dumps(repo_data)
98 98 c.repo_groups_data = json.dumps(repo_group_data)
99 99
100 return render('/index.html')
100 return render('/index.mako')
101 101
102 102 @LoginRequired()
103 103 @HasRepoGroupPermissionAnyDecorator('group.read', 'group.write',
@@ -112,7 +112,7 b' class HomeController(BaseController):'
112 112 c.repos_data = json.dumps(repo_data)
113 113 c.repo_groups_data = json.dumps(repo_group_data)
114 114
115 return render('index_repo_group.html')
115 return render('index_repo_group.mako')
116 116
117 117 def _get_repo_list(self, name_contains=None, repo_type=None, limit=20):
118 118 query = Repository.query()\
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -205,11 +205,11 b' class JournalController(BaseController):'
205 205 c.journal_pager = Page(journal, page=p, items_per_page=20, url=url_generator)
206 206 c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
207 207
208 c.journal_data = render('journal/journal_data.html')
208 c.journal_data = render('journal/journal_data.mako')
209 209 if request.is_xhr:
210 210 return c.journal_data
211 211
212 return render('journal/journal.html')
212 return render('journal/journal.mako')
213 213
214 214 @LoginRequired(auth_token_access=True)
215 215 @NotAnonymous()
@@ -276,10 +276,10 b' class JournalController(BaseController):'
276 276
277 277 c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
278 278
279 c.journal_data = render('journal/journal_data.html')
279 c.journal_data = render('journal/journal_data.mako')
280 280 if request.is_xhr:
281 281 return c.journal_data
282 return render('journal/public_journal.html')
282 return render('journal/public_journal.mako')
283 283
284 284 @LoginRequired(auth_token_access=True)
285 285 def public_journal_atom(self):
This diff has been collapsed as it changes many lines, (530 lines changed) Show them Hide them
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2012-2016 RhodeCode GmbH
3 # Copyright (C) 2012-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -21,10 +21,12 b''
21 21 """
22 22 pull requests controller for rhodecode for initializing pull requests
23 23 """
24 import types
24 25
25 26 import peppercorn
26 27 import formencode
27 28 import logging
29 import collections
28 30
29 31 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPBadRequest
30 32 from pylons import request, tmpl_context as c, url
@@ -43,125 +45,31 b' from rhodecode.lib.auth import ('
43 45 LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous,
44 46 HasAcceptedRepoType, XHRRequired)
45 47 from rhodecode.lib.channelstream import channelstream_request
46 from rhodecode.lib.compat import OrderedDict
47 48 from rhodecode.lib.utils import jsonify
48 from rhodecode.lib.utils2 import safe_int, safe_str, str2bool, safe_unicode
49 from rhodecode.lib.vcs.backends.base import EmptyCommit, UpdateFailureReason
49 from rhodecode.lib.utils2 import (
50 safe_int, safe_str, str2bool, safe_unicode)
51 from rhodecode.lib.vcs.backends.base import (
52 EmptyCommit, UpdateFailureReason, EmptyRepository)
50 53 from rhodecode.lib.vcs.exceptions import (
51 54 EmptyRepositoryError, CommitDoesNotExistError, RepositoryRequirementError,
52 55 NodeDoesNotExistError)
53 from rhodecode.lib.diffs import LimitedDiffContainer
56
54 57 from rhodecode.model.changeset_status import ChangesetStatusModel
55 from rhodecode.model.comment import ChangesetCommentsModel
56 from rhodecode.model.db import PullRequest, ChangesetStatus, ChangesetComment, \
57 Repository
58 from rhodecode.model.comment import CommentsModel
59 from rhodecode.model.db import (PullRequest, ChangesetStatus, ChangesetComment,
60 Repository, PullRequestVersion)
58 61 from rhodecode.model.forms import PullRequestForm
59 62 from rhodecode.model.meta import Session
60 from rhodecode.model.pull_request import PullRequestModel
63 from rhodecode.model.pull_request import PullRequestModel, MergeCheck
61 64
62 65 log = logging.getLogger(__name__)
63 66
64 67
65 68 class PullrequestsController(BaseRepoController):
69
66 70 def __before__(self):
67 71 super(PullrequestsController, self).__before__()
68 72
69 def _load_compare_data(self, pull_request, inline_comments, enable_comments=True):
70 """
71 Load context data needed for generating compare diff
72
73 :param pull_request: object related to the request
74 :param enable_comments: flag to determine if comments are included
75 """
76 source_repo = pull_request.source_repo
77 source_ref_id = pull_request.source_ref_parts.commit_id
78
79 target_repo = pull_request.target_repo
80 target_ref_id = pull_request.target_ref_parts.commit_id
81
82 # despite opening commits for bookmarks/branches/tags, we always
83 # convert this to rev to prevent changes after bookmark or branch change
84 c.source_ref_type = 'rev'
85 c.source_ref = source_ref_id
86
87 c.target_ref_type = 'rev'
88 c.target_ref = target_ref_id
89
90 c.source_repo = source_repo
91 c.target_repo = target_repo
92
93 c.fulldiff = bool(request.GET.get('fulldiff'))
94
95 # diff_limit is the old behavior, will cut off the whole diff
96 # if the limit is applied otherwise will just hide the
97 # big files from the front-end
98 diff_limit = self.cut_off_limit_diff
99 file_limit = self.cut_off_limit_file
100
101 pre_load = ["author", "branch", "date", "message"]
102
103 c.commit_ranges = []
104 source_commit = EmptyCommit()
105 target_commit = EmptyCommit()
106 c.missing_requirements = False
107 try:
108 c.commit_ranges = [
109 source_repo.get_commit(commit_id=rev, pre_load=pre_load)
110 for rev in pull_request.revisions]
111
112 c.statuses = source_repo.statuses(
113 [x.raw_id for x in c.commit_ranges])
114
115 target_commit = source_repo.get_commit(
116 commit_id=safe_str(target_ref_id))
117 source_commit = source_repo.get_commit(
118 commit_id=safe_str(source_ref_id))
119 except RepositoryRequirementError:
120 c.missing_requirements = True
121
122 c.changes = {}
123 c.missing_commits = False
124 if (c.missing_requirements or
125 isinstance(source_commit, EmptyCommit) or
126 source_commit == target_commit):
127 _parsed = []
128 c.missing_commits = True
129 else:
130 vcs_diff = PullRequestModel().get_diff(pull_request)
131 diff_processor = diffs.DiffProcessor(
132 vcs_diff, format='newdiff', diff_limit=diff_limit,
133 file_limit=file_limit, show_full_diff=c.fulldiff)
134 _parsed = diff_processor.prepare()
135
136 commit_changes = OrderedDict()
137 _parsed = diff_processor.prepare()
138 c.limited_diff = isinstance(_parsed, diffs.LimitedDiffContainer)
139
140 _parsed = diff_processor.prepare()
141
142 def _node_getter(commit):
143 def get_node(fname):
144 try:
145 return commit.get_node(fname)
146 except NodeDoesNotExistError:
147 return None
148 return get_node
149
150 c.diffset = codeblocks.DiffSet(
151 repo_name=c.repo_name,
152 source_node_getter=_node_getter(target_commit),
153 target_node_getter=_node_getter(source_commit),
154 comments=inline_comments
155 ).render_patchset(_parsed, target_commit.raw_id, source_commit.raw_id)
156
157 c.included_files = []
158 c.deleted_files = []
159
160 for f in _parsed:
161 st = f['stats']
162 fid = h.FID('', f['filename'])
163 c.included_files.append(f['filename'])
164
165 73 def _extract_ordering(self, request):
166 74 column_index = safe_int(request.GET.get('order[0][column]'))
167 75 order_dir = request.GET.get('order[0][dir]', 'desc')
@@ -205,7 +113,7 b' class PullrequestsController(BaseRepoCon'
205 113 if not request.is_xhr:
206 114 c.data = json.dumps(data['data'])
207 115 c.records_total = data['recordsTotal']
208 return render('/pullrequests/pullrequests.html')
116 return render('/pullrequests/pullrequests.mako')
209 117 else:
210 118 return json.dumps(data)
211 119
@@ -244,10 +152,10 b' class PullrequestsController(BaseRepoCon'
244 152 opened_by=opened_by)
245 153
246 154 from rhodecode.lib.utils import PartialRenderer
247 _render = PartialRenderer('data_table/_dt_elements.html')
155 _render = PartialRenderer('data_table/_dt_elements.mako')
248 156 data = []
249 157 for pr in pull_requests:
250 comments = ChangesetCommentsModel().get_all_comments(
158 comments = CommentsModel().get_all_comments(
251 159 c.rhodecode_db_repo.repo_id, pull_request=pr)
252 160
253 161 data.append({
@@ -336,7 +244,7 b' class PullrequestsController(BaseRepoCon'
336 244 }
337 245 c.default_source_ref = selected_source_ref
338 246
339 return render('/pullrequests/pullrequest.html')
247 return render('/pullrequests/pullrequest.mako')
340 248
341 249 @LoginRequired()
342 250 @NotAnonymous()
@@ -586,14 +494,20 b' class PullrequestsController(BaseRepoCon'
586 494
587 495 Merge will perform a server-side merge of the specified
588 496 pull request, if the pull request is approved and mergeable.
589 After succesfull merging, the pull request is automatically
497 After successful merging, the pull request is automatically
590 498 closed, with a relevant comment.
591 499 """
592 500 pull_request_id = safe_int(pull_request_id)
593 501 pull_request = PullRequest.get_or_404(pull_request_id)
594 502 user = c.rhodecode_user
595 503
596 if self._meets_merge_pre_conditions(pull_request, user):
504 check = MergeCheck.validate(pull_request, user)
505 merge_possible = not check.failed
506
507 for err_type, error_msg in check.errors:
508 h.flash(error_msg, category=err_type)
509
510 if merge_possible:
597 511 log.debug("Pre-conditions checked, trying to merge.")
598 512 extras = vcs_operation_context(
599 513 request.environ, repo_name=pull_request.target_repo.repo_name,
@@ -606,24 +520,6 b' class PullrequestsController(BaseRepoCon'
606 520 repo_name=pull_request.target_repo.repo_name,
607 521 pull_request_id=pull_request.pull_request_id))
608 522
609 def _meets_merge_pre_conditions(self, pull_request, user):
610 if not PullRequestModel().check_user_merge(pull_request, user):
611 raise HTTPForbidden()
612
613 merge_status, msg = PullRequestModel().merge_status(pull_request)
614 if not merge_status:
615 log.debug("Cannot merge, not mergeable.")
616 h.flash(msg, category='error')
617 return False
618
619 if (pull_request.calculated_review_status()
620 is not ChangesetStatus.STATUS_APPROVED):
621 log.debug("Cannot merge, approval is pending.")
622 msg = _('Pull request reviewer approval is pending.')
623 h.flash(msg, category='error')
624 return False
625 return True
626
627 523 def _merge_pull_request(self, pull_request, user, extras):
628 524 merge_resp = PullRequestModel().merge(
629 525 pull_request, user, extras=extras)
@@ -675,82 +571,295 b' class PullrequestsController(BaseRepoCon'
675 571 return redirect(url('my_account_pullrequests'))
676 572 raise HTTPForbidden()
677 573
574 def _get_pr_version(self, pull_request_id, version=None):
575 pull_request_id = safe_int(pull_request_id)
576 at_version = None
577
578 if version and version == 'latest':
579 pull_request_ver = PullRequest.get(pull_request_id)
580 pull_request_obj = pull_request_ver
581 _org_pull_request_obj = pull_request_obj
582 at_version = 'latest'
583 elif version:
584 pull_request_ver = PullRequestVersion.get_or_404(version)
585 pull_request_obj = pull_request_ver
586 _org_pull_request_obj = pull_request_ver.pull_request
587 at_version = pull_request_ver.pull_request_version_id
588 else:
589 _org_pull_request_obj = pull_request_obj = PullRequest.get_or_404(pull_request_id)
590
591 pull_request_display_obj = PullRequest.get_pr_display_object(
592 pull_request_obj, _org_pull_request_obj)
593
594 return _org_pull_request_obj, pull_request_obj, \
595 pull_request_display_obj, at_version
596
597 def _get_diffset(
598 self, source_repo, source_ref_id, target_ref_id, target_commit,
599 source_commit, diff_limit, file_limit, display_inline_comments):
600 vcs_diff = PullRequestModel().get_diff(
601 source_repo, source_ref_id, target_ref_id)
602
603 diff_processor = diffs.DiffProcessor(
604 vcs_diff, format='newdiff', diff_limit=diff_limit,
605 file_limit=file_limit, show_full_diff=c.fulldiff)
606
607 _parsed = diff_processor.prepare()
608
609 def _node_getter(commit):
610 def get_node(fname):
611 try:
612 return commit.get_node(fname)
613 except NodeDoesNotExistError:
614 return None
615
616 return get_node
617
618 diffset = codeblocks.DiffSet(
619 repo_name=c.repo_name,
620 source_repo_name=c.source_repo.repo_name,
621 source_node_getter=_node_getter(target_commit),
622 target_node_getter=_node_getter(source_commit),
623 comments=display_inline_comments
624 )
625 diffset = diffset.render_patchset(
626 _parsed, target_commit.raw_id, source_commit.raw_id)
627
628 return diffset
629
678 630 @LoginRequired()
679 631 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
680 632 'repository.admin')
681 633 def show(self, repo_name, pull_request_id):
682 634 pull_request_id = safe_int(pull_request_id)
683 c.pull_request = PullRequest.get_or_404(pull_request_id)
635 version = request.GET.get('version')
636 from_version = request.GET.get('from_version') or version
637 merge_checks = request.GET.get('merge_checks')
638 c.fulldiff = str2bool(request.GET.get('fulldiff'))
639
640 (pull_request_latest,
641 pull_request_at_ver,
642 pull_request_display_obj,
643 at_version) = self._get_pr_version(
644 pull_request_id, version=version)
645 versions = pull_request_display_obj.versions()
684 646
685 c.template_context['pull_request_data']['pull_request_id'] = \
686 pull_request_id
647 c.at_version = at_version
648 c.at_version_num = (at_version
649 if at_version and at_version != 'latest'
650 else None)
651 c.at_version_pos = ChangesetComment.get_index_from_version(
652 c.at_version_num, versions)
653
654 (prev_pull_request_latest,
655 prev_pull_request_at_ver,
656 prev_pull_request_display_obj,
657 prev_at_version) = self._get_pr_version(
658 pull_request_id, version=from_version)
659
660 c.from_version = prev_at_version
661 c.from_version_num = (prev_at_version
662 if prev_at_version and prev_at_version != 'latest'
663 else None)
664 c.from_version_pos = ChangesetComment.get_index_from_version(
665 c.from_version_num, versions)
666
667 # define if we're in COMPARE mode or VIEW at version mode
668 compare = at_version != prev_at_version
687 669
688 670 # pull_requests repo_name we opened it against
689 671 # ie. target_repo must match
690 if repo_name != c.pull_request.target_repo.repo_name:
672 if repo_name != pull_request_at_ver.target_repo.repo_name:
691 673 raise HTTPNotFound
692 674
693 c.allowed_to_change_status = PullRequestModel(). \
694 check_user_change_status(c.pull_request, c.rhodecode_user)
695 c.allowed_to_update = PullRequestModel().check_user_update(
696 c.pull_request, c.rhodecode_user) and not c.pull_request.is_closed()
697 c.allowed_to_merge = PullRequestModel().check_user_merge(
698 c.pull_request, c.rhodecode_user) and not c.pull_request.is_closed()
699 675 c.shadow_clone_url = PullRequestModel().get_shadow_clone_url(
700 c.pull_request)
701 c.allowed_to_delete = PullRequestModel().check_user_delete(
702 c.pull_request, c.rhodecode_user) and not c.pull_request.is_closed()
676 pull_request_at_ver)
677
678 c.ancestor = None # empty ancestor hidden in display
679 c.pull_request = pull_request_display_obj
680 c.pull_request_latest = pull_request_latest
681
682 pr_closed = pull_request_latest.is_closed()
683 if compare or (at_version and not at_version == 'latest'):
684 c.allowed_to_change_status = False
685 c.allowed_to_update = False
686 c.allowed_to_merge = False
687 c.allowed_to_delete = False
688 c.allowed_to_comment = False
689 else:
690 c.allowed_to_change_status = PullRequestModel(). \
691 check_user_change_status(pull_request_at_ver, c.rhodecode_user)
692 c.allowed_to_update = PullRequestModel().check_user_update(
693 pull_request_latest, c.rhodecode_user) and not pr_closed
694 c.allowed_to_merge = PullRequestModel().check_user_merge(
695 pull_request_latest, c.rhodecode_user) and not pr_closed
696 c.allowed_to_delete = PullRequestModel().check_user_delete(
697 pull_request_latest, c.rhodecode_user) and not pr_closed
698 c.allowed_to_comment = not pr_closed
699
700 # check merge capabilities
701 _merge_check = MergeCheck.validate(
702 pull_request_latest, user=c.rhodecode_user)
703 c.pr_merge_errors = _merge_check.error_details
704 c.pr_merge_possible = not _merge_check.failed
705 c.pr_merge_message = _merge_check.merge_msg
706
707 if merge_checks:
708 return render('/pullrequests/pullrequest_merge_checks.mako')
709
710 comments_model = CommentsModel()
711
712 # reviewers and statuses
713 c.pull_request_reviewers = pull_request_at_ver.reviewers_statuses()
714 allowed_reviewers = [x[0].user_id for x in c.pull_request_reviewers]
715 c.pull_request_review_status = pull_request_at_ver.calculated_review_status()
703 716
704 cc_model = ChangesetCommentsModel()
717 # GENERAL COMMENTS with versions #
718 q = comments_model._all_general_comments_of_pull_request(pull_request_latest)
719 q = q.order_by(ChangesetComment.comment_id.asc())
720 general_comments = q.order_by(ChangesetComment.pull_request_version_id.asc())
721
722 # pick comments we want to render at current version
723 c.comment_versions = comments_model.aggregate_comments(
724 general_comments, versions, c.at_version_num)
725 c.comments = c.comment_versions[c.at_version_num]['until']
705 726
706 c.pull_request_reviewers = c.pull_request.reviewers_statuses()
727 # INLINE COMMENTS with versions #
728 q = comments_model._all_inline_comments_of_pull_request(pull_request_latest)
729 q = q.order_by(ChangesetComment.comment_id.asc())
730 inline_comments = q.order_by(ChangesetComment.pull_request_version_id.asc())
731 c.inline_versions = comments_model.aggregate_comments(
732 inline_comments, versions, c.at_version_num, inline=True)
733
734 # inject latest version
735 latest_ver = PullRequest.get_pr_display_object(
736 pull_request_latest, pull_request_latest)
737
738 c.versions = versions + [latest_ver]
707 739
708 c.pull_request_review_status = c.pull_request.calculated_review_status()
709 c.pr_merge_status, c.pr_merge_msg = PullRequestModel().merge_status(
710 c.pull_request)
711 c.approval_msg = None
712 if c.pull_request_review_status != ChangesetStatus.STATUS_APPROVED:
713 c.approval_msg = _('Reviewer approval is pending.')
714 c.pr_merge_status = False
715 # load compare data into template context
716 enable_comments = not c.pull_request.is_closed()
740 # if we use version, then do not show later comments
741 # than current version
742 display_inline_comments = collections.defaultdict(
743 lambda: collections.defaultdict(list))
744 for co in inline_comments:
745 if c.at_version_num:
746 # pick comments that are at least UPTO given version, so we
747 # don't render comments for higher version
748 should_render = co.pull_request_version_id and \
749 co.pull_request_version_id <= c.at_version_num
750 else:
751 # showing all, for 'latest'
752 should_render = True
753
754 if should_render:
755 display_inline_comments[co.f_path][co.line_no].append(co)
756
757 # load diff data into template context, if we use compare mode then
758 # diff is calculated based on changes between versions of PR
759
760 source_repo = pull_request_at_ver.source_repo
761 source_ref_id = pull_request_at_ver.source_ref_parts.commit_id
762
763 target_repo = pull_request_at_ver.target_repo
764 target_ref_id = pull_request_at_ver.target_ref_parts.commit_id
717 765
766 if compare:
767 # in compare switch the diff base to latest commit from prev version
768 target_ref_id = prev_pull_request_display_obj.revisions[0]
718 769
719 # inline comments
720 c.inline_comments = cc_model.get_inline_comments(
721 c.rhodecode_db_repo.repo_id,
722 pull_request=pull_request_id)
770 # despite opening commits for bookmarks/branches/tags, we always
771 # convert this to rev to prevent changes after bookmark or branch change
772 c.source_ref_type = 'rev'
773 c.source_ref = source_ref_id
774
775 c.target_ref_type = 'rev'
776 c.target_ref = target_ref_id
777
778 c.source_repo = source_repo
779 c.target_repo = target_repo
780
781 # diff_limit is the old behavior, will cut off the whole diff
782 # if the limit is applied otherwise will just hide the
783 # big files from the front-end
784 diff_limit = self.cut_off_limit_diff
785 file_limit = self.cut_off_limit_file
723 786
724 c.inline_cnt = cc_model.get_inline_comments_count(c.inline_comments)
787 c.commit_ranges = []
788 source_commit = EmptyCommit()
789 target_commit = EmptyCommit()
790 c.missing_requirements = False
725 791
726 self._load_compare_data(
727 c.pull_request, c.inline_comments, enable_comments=enable_comments)
792 # try first shadow repo, fallback to regular repo
793 try:
794 commits_source_repo = pull_request_latest.get_shadow_repo()
795 except Exception:
796 log.debug('Failed to get shadow repo', exc_info=True)
797 commits_source_repo = source_repo.scm_instance()
798
799 c.commits_source_repo = commits_source_repo
800 commit_cache = {}
801 try:
802 pre_load = ["author", "branch", "date", "message"]
803 show_revs = pull_request_at_ver.revisions
804 for rev in show_revs:
805 comm = commits_source_repo.get_commit(
806 commit_id=rev, pre_load=pre_load)
807 c.commit_ranges.append(comm)
808 commit_cache[comm.raw_id] = comm
728 809
729 # outdated comments
730 c.outdated_comments = {}
731 c.outdated_cnt = 0
732 if ChangesetCommentsModel.use_outdated_comments(c.pull_request):
733 c.outdated_comments = cc_model.get_outdated_comments(
734 c.rhodecode_db_repo.repo_id,
735 pull_request=c.pull_request)
736 # Count outdated comments and check for deleted files
737 for file_name, lines in c.outdated_comments.iteritems():
738 for comments in lines.values():
739 c.outdated_cnt += len(comments)
740 if file_name not in c.included_files:
741 c.deleted_files.append(file_name)
810 target_commit = commits_source_repo.get_commit(
811 commit_id=safe_str(target_ref_id))
812 source_commit = commits_source_repo.get_commit(
813 commit_id=safe_str(source_ref_id))
814 except CommitDoesNotExistError:
815 pass
816 except RepositoryRequirementError:
817 log.warning(
818 'Failed to get all required data from repo', exc_info=True)
819 c.missing_requirements = True
820
821 c.statuses = source_repo.statuses(
822 [x.raw_id for x in c.commit_ranges])
823
824 # auto collapse if we have more than limit
825 collapse_limit = diffs.DiffProcessor._collapse_commits_over
826 c.collapse_all_commits = len(c.commit_ranges) > collapse_limit
827 c.compare_mode = compare
828
829 c.missing_commits = False
830 if (c.missing_requirements or isinstance(source_commit, EmptyCommit)
831 or source_commit == target_commit):
742 832
833 c.missing_commits = True
834 else:
835
836 c.diffset = self._get_diffset(
837 commits_source_repo, source_ref_id, target_ref_id,
838 target_commit, source_commit,
839 diff_limit, file_limit, display_inline_comments)
840
841 c.limited_diff = c.diffset.limited_diff
842
843 # calculate removed files that are bound to comments
844 comment_deleted_files = [
845 fname for fname in display_inline_comments
846 if fname not in c.diffset.file_stats]
847
848 c.deleted_files_comments = collections.defaultdict(dict)
849 for fname, per_line_comments in display_inline_comments.items():
850 if fname in comment_deleted_files:
851 c.deleted_files_comments[fname]['stats'] = 0
852 c.deleted_files_comments[fname]['comments'] = list()
853 for lno, comments in per_line_comments.items():
854 c.deleted_files_comments[fname]['comments'].extend(
855 comments)
743 856
744 857 # this is a hack to properly display links, when creating PR, the
745 858 # compare view and others uses different notation, and
746 # compare_commits.html renders links based on the target_repo.
859 # compare_commits.mako renders links based on the target_repo.
747 860 # We need to swap that here to generate it properly on the html side
748 861 c.target_repo = c.source_repo
749 862
750 # comments
751 c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id,
752 pull_request=pull_request_id)
753
754 863 if c.allowed_to_update:
755 864 force_close = ('forced_closed', _('Close Pull Request'))
756 865 statuses = ChangesetStatus.STATUSES + [force_close]
@@ -758,14 +867,55 b' class PullrequestsController(BaseRepoCon'
758 867 statuses = ChangesetStatus.STATUSES
759 868 c.commit_statuses = statuses
760 869
761 c.ancestor = None # TODO: add ancestor here
870 c.show_version_changes = not pr_closed
871 if c.show_version_changes:
872 cur_obj = pull_request_at_ver
873 prev_obj = prev_pull_request_at_ver
874
875 old_commit_ids = prev_obj.revisions
876 new_commit_ids = cur_obj.revisions
877 commit_changes = PullRequestModel()._calculate_commit_id_changes(
878 old_commit_ids, new_commit_ids)
879 c.commit_changes_summary = commit_changes
880
881 # calculate the diff for commits between versions
882 c.commit_changes = []
883 mark = lambda cs, fw: list(
884 h.itertools.izip_longest([], cs, fillvalue=fw))
885 for c_type, raw_id in mark(commit_changes.added, 'a') \
886 + mark(commit_changes.removed, 'r') \
887 + mark(commit_changes.common, 'c'):
762 888
763 return render('/pullrequests/pullrequest_show.html')
889 if raw_id in commit_cache:
890 commit = commit_cache[raw_id]
891 else:
892 try:
893 commit = commits_source_repo.get_commit(raw_id)
894 except CommitDoesNotExistError:
895 # in case we fail extracting still use "dummy" commit
896 # for display in commit diff
897 commit = h.AttributeDict(
898 {'raw_id': raw_id,
899 'message': 'EMPTY or MISSING COMMIT'})
900 c.commit_changes.append([c_type, commit])
901
902 # current user review statuses for each version
903 c.review_versions = {}
904 if c.rhodecode_user.user_id in allowed_reviewers:
905 for co in general_comments:
906 if co.author.user_id == c.rhodecode_user.user_id:
907 # each comment has a status change
908 status = co.status_change
909 if status:
910 _ver_pr = status[0].comment.pull_request_version_id
911 c.review_versions[_ver_pr] = status[0]
912
913 return render('/pullrequests/pullrequest_show.mako')
764 914
765 915 @LoginRequired()
766 916 @NotAnonymous()
767 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
768 'repository.admin')
917 @HasRepoPermissionAnyDecorator(
918 'repository.read', 'repository.write', 'repository.admin')
769 919 @auth.CSRFRequired()
770 920 @jsonify
771 921 def comment(self, repo_name, pull_request_id):
@@ -778,6 +928,9 b' class PullrequestsController(BaseRepoCon'
778 928 # as a changeset status, still we want to send it in one value.
779 929 status = request.POST.get('changeset_status', None)
780 930 text = request.POST.get('text')
931 comment_type = request.POST.get('comment_type')
932 resolves_comment_id = request.POST.get('resolves_comment_id', None)
933
781 934 if status and '_closed' in status:
782 935 close_pr = True
783 936 status = status.replace('_closed', '')
@@ -798,7 +951,7 b' class PullrequestsController(BaseRepoCon'
798 951 if close_pr:
799 952 message = _('Closing with') + ' ' + message
800 953 text = text or message
801 comm = ChangesetCommentsModel().create(
954 comm = CommentsModel().create(
802 955 text=text,
803 956 repo=c.rhodecode_db_repo.repo_id,
804 957 user=c.rhodecode_user.user_id,
@@ -809,11 +962,11 b' class PullrequestsController(BaseRepoCon'
809 962 if status and allowed_to_change_status else None),
810 963 status_change_type=(status
811 964 if status and allowed_to_change_status else None),
812 closing_pr=close_pr
965 closing_pr=close_pr,
966 comment_type=comment_type,
967 resolves_comment_id=resolves_comment_id
813 968 )
814 969
815
816
817 970 if allowed_to_change_status:
818 971 old_calculated_status = pull_request.calculated_review_status()
819 972 # get status if set !
@@ -863,9 +1016,10 b' class PullrequestsController(BaseRepoCon'
863 1016 }
864 1017 if comm:
865 1018 c.co = comm
1019 c.inline_comment = True if comm.line_no else False
866 1020 data.update(comm.get_dict())
867 1021 data.update({'rendered_text':
868 render('changeset/changeset_comment_block.html')})
1022 render('changeset/changeset_comment_block.mako')})
869 1023
870 1024 return data
871 1025
@@ -889,7 +1043,7 b' class PullrequestsController(BaseRepoCon'
889 1043 is_repo_admin = h.HasRepoPermissionAny('repository.admin')(c.repo_name)
890 1044 if h.HasPermissionAny('hg.admin')() or is_repo_admin or is_owner:
891 1045 old_calculated_status = co.pull_request.calculated_review_status()
892 ChangesetCommentsModel().delete(comment=co)
1046 CommentsModel().delete(comment=co)
893 1047 Session().commit()
894 1048 calculated_status = co.pull_request.calculated_review_status()
895 1049 if old_calculated_status != calculated_status:
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -108,4 +108,4 b' class SearchController(BaseRepoControlle'
108 108 c.cur_query = search_query
109 109 c.search_type = search_type
110 110 # Return a rendered template
111 return render('/search/search.html')
111 return render('/search/search.mako')
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -165,7 +165,7 b' class SummaryController(BaseRepoControll'
165 165 c.repo_name, c.rhodecode_user.user_id)
166 166
167 167 if c.repository_requirements_missing:
168 return render('summary/missing_requirements.html')
168 return render('summary/missing_requirements.mako')
169 169
170 170 c.readme_data, c.readme_file = \
171 171 self.__get_readme_data(c.rhodecode_db_repo)
@@ -173,9 +173,9 b' class SummaryController(BaseRepoControll'
173 173 _load_changelog_summary()
174 174
175 175 if request.is_xhr:
176 return render('changelog/changelog_summary_data.html')
176 return render('changelog/changelog_summary_data.mako')
177 177
178 return render('summary/summary.html')
178 return render('summary/summary.mako')
179 179
180 180 @LoginRequired()
181 181 @XHRRequired()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -31,8 +31,8 b' log = logging.getLogger(__name__)'
31 31
32 32 class TagsController(BaseReferencesController):
33 33
34 partials_template = 'tags/tags_data.html'
35 template = 'tags/tags.html'
34 partials_template = 'tags/tags_data.mako'
35 template = 'tags/tags.mako'
36 36
37 37 def _get_reference_items(self, repo):
38 38 return repo.tags.items()
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -40,4 +40,4 b' class UsersController(BaseController):'
40 40 raise HTTPNotFound()
41 41
42 42 c.active = 'user_profile'
43 return render('users/user.html')
43 return render('users/user.mako')
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -27,6 +27,7 b' Should only contain utilities to be shar'
27 27 from rhodecode.lib import helpers as h
28 28 from rhodecode.lib.vcs.exceptions import RepositoryError
29 29
30
30 31 def parse_path_ref(ref, default_path=None):
31 32 """
32 33 Parse out a path and reference combination and return both parts of it.
@@ -76,8 +77,8 b' def get_commit_from_ref_name(repo, ref_n'
76 77 }
77 78
78 79 commit_id = ref_name
79 if repo_scm.alias != 'svn': # pass svn refs straight to backend until
80 # the branch issue with svn is fixed
80 if repo_scm.alias != 'svn': # pass svn refs straight to backend until
81 # the branch issue with svn is fixed
81 82 if ref_type and ref_type in ref_type_mapping:
82 83 try:
83 84 commit_id = ref_type_mapping[ref_type][ref_name]
@@ -1,4 +1,4 b''
1 # Copyright (C) 2016-2016 RhodeCode GmbH
1 # Copyright (C) 2016-2017 RhodeCode GmbH
2 2 #
3 3 # This program is free software: you can redistribute it and/or modify
4 4 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,4 +1,4 b''
1 # Copyright (C) 2016-2016 RhodeCode GmbH
1 # Copyright (C) 2016-2017 RhodeCode GmbH
2 2 #
3 3 # This program is free software: you can redistribute it and/or modify
4 4 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,4 +1,4 b''
1 # Copyright (C) 2016-2016 RhodeCode GmbH
1 # Copyright (C) 2016-2017 RhodeCode GmbH
2 2 #
3 3 # This program is free software: you can redistribute it and/or modify
4 4 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,4 +1,4 b''
1 # Copyright (C) 2016-2016 RhodeCode GmbH
1 # Copyright (C) 2016-2017 RhodeCode GmbH
2 2 #
3 3 # This program is free software: you can redistribute it and/or modify
4 4 # it under the terms of the GNU Affero General Public License, version 3
@@ -114,7 +114,7 b' class PullRequestCommentEvent(PullReques'
114 114 self.comment = comment
115 115
116 116 def as_dict(self):
117 from rhodecode.model.comment import ChangesetCommentsModel
117 from rhodecode.model.comment import CommentsModel
118 118 data = super(PullRequestCommentEvent, self).as_dict()
119 119
120 120 status = None
@@ -125,7 +125,7 b' class PullRequestCommentEvent(PullReques'
125 125 'comment': {
126 126 'status': status,
127 127 'text': self.comment.text,
128 'url': ChangesetCommentsModel().get_url(self.comment)
128 'url': CommentsModel().get_url(self.comment)
129 129 }
130 130 })
131 131 return data
@@ -1,4 +1,4 b''
1 # Copyright (C) 2016-2016 RhodeCode GmbH
1 # Copyright (C) 2016-2017 RhodeCode GmbH
2 2 #
3 3 # This program is free software: you can redistribute it and/or modify
4 4 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,4 +1,4 b''
1 # Copyright (C) 2016-2016 RhodeCode GmbH
1 # Copyright (C) 2016-2017 RhodeCode GmbH
2 2 #
3 3 # This program is free software: you can redistribute it and/or modify
4 4 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,4 +1,4 b''
1 # Copyright (C) 2016-2016 RhodeCode GmbH
1 # Copyright (C) 2016-2017 RhodeCode GmbH
2 2 #
3 3 # This program is free software: you can redistribute it and/or modify
4 4 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,6 +1,6 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
@@ -1,5 +1,5 b''
1 1 # Translations template for rhodecode-enterprise-ce.
2 # Copyright (C) 2016 RhodeCode GmbH
2 # Copyright (C) 2017 RhodeCode GmbH
3 3 # This file is distributed under the same license as the rhodecode-enterprise-ce project.
4 4 #
5 5 # Translators:
@@ -1,5 +1,5 b''
1 1 # Translations template for rhodecode-enterprise-ce.
2 # Copyright (C) 2016 RhodeCode GmbH
2 # Copyright (C) 2017 RhodeCode GmbH
3 3 # This file is distributed under the same license as the rhodecode-enterprise-ce project.
4 4 #
5 5 # Translators:
@@ -1,5 +1,5 b''
1 1 # Translations template for rhodecode-enterprise-ce.
2 # Copyright (C) 2016 RhodeCode GmbH
2 # Copyright (C) 2017 RhodeCode GmbH
3 3 # This file is distributed under the same license as the rhodecode-enterprise-ce project.
4 4 #
5 5 # Translators:
@@ -1,5 +1,5 b''
1 1 # Translations template for rhodecode-enterprise-ce.
2 # Copyright (C) 2016 RhodeCode GmbH
2 # Copyright (C) 2017 RhodeCode GmbH
3 3 # This file is distributed under the same license as the rhodecode-enterprise-ce project.
4 4 #
5 5 # Translators:
@@ -1,5 +1,5 b''
1 1 # Translations template for rhodecode-enterprise-ce.
2 # Copyright (C) 2016 RhodeCode GmbH
2 # Copyright (C) 2017 RhodeCode GmbH
3 3 # This file is distributed under the same license as the rhodecode-enterprise-ce project.
4 4 #
5 5 # Translators:
@@ -1,9 +1,9 b''
1 1 # Translations template for rhodecode-enterprise-ce.
2 # Copyright (C) 2016 RhodeCode GmbH
2 # Copyright (C) 2017 RhodeCode GmbH
3 3 # This file is distributed under the same license as the rhodecode-enterprise-ce project.
4 4 #
5 5 # Translators:
6 # Alessandro sauzher Ceglie, 2014-2016
6 # Alessandro sauzher Ceglie, 2014-2017
7 7 # FIRST AUTHOR <EMAIL@ADDRESS>, 2014
8 8 msgid ""
9 9 msgstr ""
@@ -1,5 +1,5 b''
1 1 # Translations template for rhodecode-enterprise-ce.
2 # Copyright (C) 2016 RhodeCode GmbH
2 # Copyright (C) 2017 RhodeCode GmbH
3 3 # This file is distributed under the same license as the rhodecode-enterprise-ce project.
4 4 #
5 5 # Translators:
@@ -1,5 +1,5 b''
1 1 # Translations template for rhodecode-enterprise-ce.
2 # Copyright (C) 2016 RhodeCode GmbH
2 # Copyright (C) 2017 RhodeCode GmbH
3 3 # This file is distributed under the same license as the rhodecode-enterprise-ce project.
4 4 #
5 5 # Translators:
@@ -1,5 +1,5 b''
1 1 # Translations template for rhodecode-enterprise-ce.
2 # Copyright (C) 2016 RhodeCode GmbH
2 # Copyright (C) 2017 RhodeCode GmbH
3 3 # This file is distributed under the same license as the rhodecode-enterprise-ce project.
4 4 #
5 5 # Translators:
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/admin.html to rhodecode/templates/admin/admin.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/admin_log.html to rhodecode/templates/admin/admin_log.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/auth/auth_settings.html to rhodecode/templates/admin/auth/auth_settings.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/auth/plugin_settings.html to rhodecode/templates/admin/auth/plugin_settings.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/defaults/defaults.html to rhodecode/templates/admin/defaults/defaults.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/defaults/defaults_repositories.html to rhodecode/templates/admin/defaults/defaults_repositories.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/gists/edit.html to rhodecode/templates/admin/gists/edit.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/gists/index.html to rhodecode/templates/admin/gists/index.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/gists/new.html to rhodecode/templates/admin/gists/new.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/gists/show.html to rhodecode/templates/admin/gists/show.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/integrations/base.html to rhodecode/templates/admin/integrations/base.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/integrations/form.html to rhodecode/templates/admin/integrations/form.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/integrations/list.html to rhodecode/templates/admin/integrations/list.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/integrations/new.html to rhodecode/templates/admin/integrations/new.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/my_account/my_account.html to rhodecode/templates/admin/my_account/my_account.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/my_account/my_account_auth_tokens.html to rhodecode/templates/admin/my_account/my_account_auth_tokens.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/my_account/my_account_emails.html to rhodecode/templates/admin/my_account/my_account_emails.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/my_account/my_account_notifications.html to rhodecode/templates/admin/my_account/my_account_notifications.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/my_account/my_account_password.html to rhodecode/templates/admin/my_account/my_account_password.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/my_account/my_account_perms.html to rhodecode/templates/admin/my_account/my_account_perms.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/my_account/my_account_profile.html to rhodecode/templates/admin/my_account/my_account_profile.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/my_account/my_account_profile_edit.html to rhodecode/templates/admin/my_account/my_account_profile_edit.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/my_account/my_account_pullrequests.html to rhodecode/templates/admin/my_account/my_account_pullrequests.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/my_account/my_account_repos.html to rhodecode/templates/admin/my_account/my_account_repos.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/my_account/my_account_watched.html to rhodecode/templates/admin/my_account/my_account_watched.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/notifications/notifications.html to rhodecode/templates/admin/notifications/notifications.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/notifications/notifications_data.html to rhodecode/templates/admin/notifications/notifications_data.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/notifications/show_notification.html to rhodecode/templates/admin/notifications/show_notification.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/permissions/permissions.html to rhodecode/templates/admin/permissions/permissions.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/permissions/permissions_application.html to rhodecode/templates/admin/permissions/permissions_application.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/permissions/permissions_global.html to rhodecode/templates/admin/permissions/permissions_global.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/permissions/permissions_ips.html to rhodecode/templates/admin/permissions/permissions_ips.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/permissions/permissions_objects.html to rhodecode/templates/admin/permissions/permissions_objects.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/permissions/permissions_perms.html to rhodecode/templates/admin/permissions/permissions_perms.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/repo_groups/repo_group_add.html to rhodecode/templates/admin/repo_groups/repo_group_add.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/repo_groups/repo_group_edit.html to rhodecode/templates/admin/repo_groups/repo_group_edit.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.html to rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/repo_groups/repo_group_edit_perms.html to rhodecode/templates/admin/repo_groups/repo_group_edit_perms.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/repo_groups/repo_group_edit_settings.html to rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/repo_groups/repo_groups.html to rhodecode/templates/admin/repo_groups/repo_groups.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/repos/repo_add.html to rhodecode/templates/admin/repos/repo_add.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/repos/repo_add_base.html to rhodecode/templates/admin/repos/repo_add_base.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/repos/repo_creating.html to rhodecode/templates/admin/repos/repo_creating.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/repos/repo_edit.html to rhodecode/templates/admin/repos/repo_edit.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/repos/repo_edit_advanced.html to rhodecode/templates/admin/repos/repo_edit_advanced.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/repos/repo_edit_caches.html to rhodecode/templates/admin/repos/repo_edit_caches.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/repos/repo_edit_fields.html to rhodecode/templates/admin/repos/repo_edit_fields.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/repos/repo_edit_fork.html to rhodecode/templates/admin/repos/repo_edit_fork.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/repos/repo_edit_issuetracker.html to rhodecode/templates/admin/repos/repo_edit_issuetracker.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/repos/repo_edit_permissions.html to rhodecode/templates/admin/repos/repo_edit_permissions.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/repos/repo_edit_remote.html to rhodecode/templates/admin/repos/repo_edit_remote.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/repos/repo_edit_settings.html to rhodecode/templates/admin/repos/repo_edit_settings.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/repos/repo_edit_statistics.html to rhodecode/templates/admin/repos/repo_edit_statistics.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/repos/repo_edit_vcs.html to rhodecode/templates/admin/repos/repo_edit_vcs.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/repos/repos.html to rhodecode/templates/admin/repos/repos.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/settings/settings.html to rhodecode/templates/admin/settings/settings.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/settings/settings_email.html to rhodecode/templates/admin/settings/settings_email.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/settings/settings_global.html to rhodecode/templates/admin/settings/settings_global.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/settings/settings_hooks.html to rhodecode/templates/admin/settings/settings_hooks.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/settings/settings_issuetracker.html to rhodecode/templates/admin/settings/settings_issuetracker.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/settings/settings_labs.html to rhodecode/templates/admin/settings/settings_labs.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/settings/settings_mapping.html to rhodecode/templates/admin/settings/settings_mapping.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/settings/settings_open_source.html to rhodecode/templates/admin/settings/settings_open_source.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/settings/settings_search.html to rhodecode/templates/admin/settings/settings_search.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/settings/settings_supervisor.html to rhodecode/templates/admin/settings/settings_supervisor.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/settings/settings_supervisor_tail.html to rhodecode/templates/admin/settings/settings_supervisor_tail.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/settings/settings_system.html to rhodecode/templates/admin/settings/settings_system.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/settings/settings_system_snapshot.html to rhodecode/templates/admin/settings/settings_system_snapshot.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/settings/settings_system_update.html to rhodecode/templates/admin/settings/settings_system_update.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/settings/settings_vcs.html to rhodecode/templates/admin/settings/settings_vcs.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/settings/settings_visual.html to rhodecode/templates/admin/settings/settings_visual.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/user_groups/user_group_add.html to rhodecode/templates/admin/user_groups/user_group_add.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/user_groups/user_group_edit.html to rhodecode/templates/admin/user_groups/user_group_edit.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/user_groups/user_group_edit_advanced.html to rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/user_groups/user_group_edit_global_perms.html to rhodecode/templates/admin/user_groups/user_group_edit_global_perms.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/user_groups/user_group_edit_perms.html to rhodecode/templates/admin/user_groups/user_group_edit_perms.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/user_groups/user_group_edit_perms_summary.html to rhodecode/templates/admin/user_groups/user_group_edit_perms_summary.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/user_groups/user_group_edit_settings.html to rhodecode/templates/admin/user_groups/user_group_edit_settings.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/user_groups/user_groups.html to rhodecode/templates/admin/user_groups/user_groups.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/users/user_add.html to rhodecode/templates/admin/users/user_add.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/users/user_edit.html to rhodecode/templates/admin/users/user_edit.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/users/user_edit_advanced.html to rhodecode/templates/admin/users/user_edit_advanced.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/users/user_edit_auth_tokens.html to rhodecode/templates/admin/users/user_edit_auth_tokens.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/users/user_edit_emails.html to rhodecode/templates/admin/users/user_edit_emails.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/users/user_edit_global_perms.html to rhodecode/templates/admin/users/user_edit_global_perms.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/users/user_edit_ips.html to rhodecode/templates/admin/users/user_edit_ips.mako
1 NO CONTENT: file renamed from rhodecode/templates/admin/users/user_edit_perms_summary.html to rhodecode/templates/admin/users/user_edit_perms_summary.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/users/user_edit_profile.html to rhodecode/templates/admin/users/user_edit_profile.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/admin/users/users.html to rhodecode/templates/admin/users/users.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/base/base.html to rhodecode/templates/base/base.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/base/default_perms_box.html to rhodecode/templates/base/default_perms_box.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/base/issue_tracker_settings.html to rhodecode/templates/base/issue_tracker_settings.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/base/perms_summary.html to rhodecode/templates/base/perms_summary.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/base/plugins_base.html to rhodecode/templates/base/plugins_base.mako
1 NO CONTENT: file renamed from rhodecode/templates/base/root.html to rhodecode/templates/base/root.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/base/vcs_settings.html to rhodecode/templates/base/vcs_settings.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/bookmarks/bookmarks.html to rhodecode/templates/bookmarks/bookmarks.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/bookmarks/bookmarks_data.html to rhodecode/templates/bookmarks/bookmarks_data.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/branches/branches.html to rhodecode/templates/branches/branches.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/branches/branches_data.html to rhodecode/templates/branches/branches_data.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/changelog/changelog.html to rhodecode/templates/changelog/changelog.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/changelog/changelog_details.html to rhodecode/templates/changelog/changelog_elements.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/changelog/changelog_file_history.html to rhodecode/templates/changelog/changelog_file_history.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/changelog/changelog_summary_data.html to rhodecode/templates/changelog/changelog_summary_data.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/changeset/changeset.html to rhodecode/templates/changeset/changeset.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/changeset/changeset_comment_block.html to rhodecode/templates/changeset/changeset_comment_block.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/changeset/changeset_file_comment.html to rhodecode/templates/changeset/changeset_file_comment.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/changeset/changeset_range.html to rhodecode/templates/changeset/changeset_range.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/changeset/diff_block.html to rhodecode/templates/changeset/diff_block.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/changeset/patch_changeset.html to rhodecode/templates/changeset/patch_changeset.mako
1 NO CONTENT: file renamed from rhodecode/templates/channelstream/plugin_init.html to rhodecode/templates/channelstream/plugin_init.mako
1 NO CONTENT: file renamed from rhodecode/templates/codeblocks/diffs.html to rhodecode/templates/codeblocks/diffs.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/codeblocks/source.html to rhodecode/templates/codeblocks/source.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/compare/compare_commits.html to rhodecode/templates/compare/compare_commits.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/compare/compare_diff.html to rhodecode/templates/compare/compare_diff.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/data_table/_dt_elements.html to rhodecode/templates/data_table/_dt_elements.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/errors/error_document.html to rhodecode/templates/errors/error_document.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/files/base.html to rhodecode/templates/files/base.mako
1 NO CONTENT: file renamed from rhodecode/templates/files/file_authors_box.html to rhodecode/templates/files/file_authors_box.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/files/file_tree_author_box.html to rhodecode/templates/files/file_tree_author_box.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/files/file_tree_detail.html to rhodecode/templates/files/file_tree_detail.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/files/files.html to rhodecode/templates/files/files.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/files/files_add.html to rhodecode/templates/files/files_add.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/files/files_browser.html to rhodecode/templates/files/files_browser.mako
1 NO CONTENT: file renamed from rhodecode/templates/files/files_browser_tree.html to rhodecode/templates/files/files_browser_tree.mako
1 NO CONTENT: file renamed from rhodecode/templates/files/files_delete.html to rhodecode/templates/files/files_delete.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/files/files_detail.html to rhodecode/templates/files/files_detail.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/files/files_edit.html to rhodecode/templates/files/files_edit.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/files/files_pjax.html to rhodecode/templates/files/files_pjax.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/files/files_source.html to rhodecode/templates/files/files_source.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/followers/followers.html to rhodecode/templates/followers/followers.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/followers/followers_data.html to rhodecode/templates/followers/followers_data.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/forks/fork.html to rhodecode/templates/forks/fork.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/forks/forks.html to rhodecode/templates/forks/forks.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/forks/forks_data.html to rhodecode/templates/forks/forks_data.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/index.html to rhodecode/templates/index.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/index_base.html to rhodecode/templates/index_base.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/index_repo_group.html to rhodecode/templates/index_repo_group.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/journal/journal.html to rhodecode/templates/journal/journal.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/journal/journal_data.html to rhodecode/templates/journal/journal_data.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/journal/public_journal.html to rhodecode/templates/journal/public_journal.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/login.html to rhodecode/templates/login.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/password_reset.html to rhodecode/templates/password_reset.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/pullrequests/pullrequest.html to rhodecode/templates/pullrequests/pullrequest.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/pullrequests/pullrequest_show.html to rhodecode/templates/pullrequests/pullrequest_show.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/pullrequests/pullrequests.html to rhodecode/templates/pullrequests/pullrequests.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/register.html to rhodecode/templates/register.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/search/search.html to rhodecode/templates/search/search.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/search/search_commit.html to rhodecode/templates/search/search_commit.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/search/search_content.html to rhodecode/templates/search/search_content.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/search/search_path.html to rhodecode/templates/search/search_path.mako
1 NO CONTENT: file renamed from rhodecode/templates/search/search_repository.html to rhodecode/templates/search/search_repository.mako
1 NO CONTENT: file renamed from rhodecode/templates/summary/base.html to rhodecode/templates/summary/base.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/summary/components.html to rhodecode/templates/summary/components.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/summary/missing_requirements.html to rhodecode/templates/summary/missing_requirements.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/summary/summary.html to rhodecode/templates/summary/summary.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/tags/tags.html to rhodecode/templates/tags/tags.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/tags/tags_data.html to rhodecode/templates/tags/tags_data.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/users/user.html to rhodecode/templates/users/user.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/users/user_profile.html to rhodecode/templates/users/user_profile.mako
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from rhodecode/templates/widgets.html to rhodecode/templates/widgets.mako
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now