##// END OF EJS Templates
license: update license metadata and generation code
marcink -
r3073:73a2f607 default
parent child Browse files
Show More
@@ -1,52 +1,60 b''
1 1
2 2 ==============================
3 3 Generate the Nix expressions
4 4 ==============================
5 5
6 6 Details can be found in the repository of `RhodeCode Enterprise CE`_ inside of
7 7 the file `docs/contributing/dependencies.rst`.
8 8
9 9 Start the environment as follows:
10 10
11 11 .. code:: shell
12 12
13 13 nix-shell pkgs/shell-generate.nix
14 14
15 15
16 16
17 17 Python dependencies
18 18 ===================
19 19
20 20 .. code:: shell
21 21
22 22 pip2nix generate --licenses
23 23 # or
24 24 nix-shell pkgs/shell-generate.nix --command "pip2nix generate --licenses"
25 25
26 26
27 27 NodeJS dependencies
28 28 ===================
29 29
30 30 .. code:: shell
31 31
32 32 rm -rf node_modules
33 33 nix-shell pkgs/shell-generate.nix --command "
34 34 node2nix --input package.json \
35 35 -o pkgs/node-packages.nix \
36 36 -e pkgs/node-env.nix \
37 37 -c pkgs/node-default.nix \
38 38 -d --flatten --nodejs-6 "
39 39
40 40
41 41
42 42 Bower dependencies
43 43 ==================
44 44
45 45 .. code:: shell
46 46
47 47 nix-shell pkgs/shell-generate.nix --command "bower2nix bower.json pkgs/bower-packages.nix"
48 48
49 49
50 Generate license data
51 =====================
52
53 .. code:: shell
54
55 nix-build pkgs/license-generate.nix -o result-license && cat result-license/licenses.json | python -m json.tool > rhodecode/config/licenses.json
56
57
50 58 .. Links
51 59
52 60 .. _RhodeCode Enterprise CE: https://code.rhodecode.com/rhodecode-enterprise-ce
@@ -1,160 +1,159 b''
1 1 # Utility to generate the license information
2 2 #
3 3 # Usage:
4 4 #
5 # nix-build -I ~/dev license.nix -A result
5 # nix-build license.nix -o result-license
6 6 #
7 # Afterwards ./result will contain the license information as JSON files.
7 # Afterwards ./result-license will contain the license information as JSON files.
8 8 #
9 9 #
10 10 # Overview
11 11 #
12 12 # Uses two steps to get the relevant license information:
13 13 #
14 14 # 1. Walk down the derivations based on "buildInputs" and
15 15 # "propagatedBuildInputs". This results in all dependencies based on the nix
16 16 # declartions.
17 17 #
18 18 # 2. Build Enterprise and query nix-store to get a list of runtime
19 19 # dependencies. The results from step 1 are then limited to the ones which
20 20 # are in this list.
21 21 #
22 # The result is then available in ./result/license.json.
22 # The result is then available in ./result-license/license.json.
23 23 #
24 24
25 25
26 26 let
27 27
28 28 nixpkgs = import <nixpkgs> {};
29 29
30 30 stdenv = nixpkgs.stdenv;
31 31
32 32 # Enterprise as simple as possible, goal here is just to identify the runtime
33 33 # dependencies. Ideally we could avoid building Enterprise at all and somehow
34 34 # figure it out without calling into nix-store.
35 enterprise = import ./default.nix {
35 enterprise = import ../default.nix {
36 36 doCheck = false;
37 37 };
38 38
39 39 # For a given derivation, return the list of all dependencies
40 40 drvToDependencies = drv: nixpkgs.lib.flatten [
41 drv.nativeBuildInputs or []
42 drv.propagatedNativeBuildInputs or []
41 drv.buildInputs or []
42 drv.propagatedBuildInputs or []
43 43 ];
44 44
45 45 # Transform the given derivation into the meta information which we need in
46 46 # the resulting JSON files.
47 47 drvToMeta = drv: {
48 name = drv.name or "UNNAMED";
48 name = drv.name or drv;
49 49 license = if drv ? meta.license then drv.meta.license else "UNKNOWN";
50 50 };
51 51
52 52 # Walk the tree of buildInputs and propagatedBuildInputs and return it as a
53 53 # flat list. Duplicates are avoided.
54 54 listDrvDependencies = drv: let
55 55 addElement = element: seen:
56 56 if (builtins.elem element seen)
57 57 then seen
58 58 else let
59 59 newSeen = seen ++ [ element ];
60 60 newDeps = drvToDependencies element;
61 61 in nixpkgs.lib.fold addElement newSeen newDeps;
62 62 initialElements = drvToDependencies drv;
63 63 in nixpkgs.lib.fold addElement [] initialElements;
64 64
65 65 # Reads in a file with store paths and returns a list of derivation names.
66 66 #
67 67 # Reads the file, splits the lines, then removes the prefix, so that we
68 68 # end up with a list of derivation names in the end.
69 69 storePathsToDrvNames = srcPath: let
70 70 rawStorePaths = nixpkgs.lib.removeSuffix "\n" (
71 71 builtins.readFile srcPath);
72 72 storePaths = nixpkgs.lib.splitString "\n" rawStorePaths;
73 # TODO: johbo: Would be nice to use some sort of utility here to convert
74 # the path to a derivation name.
75 73 storePathPrefix = (
76 builtins.stringLength "/nix/store/zwy7aavnif9ayw30rya1k6xiacafzzl6-");
74 builtins.stringLength "/nix/store/afafafafafafafafafafafafafafafaf-");
77 75 storePathToName = path:
78 76 builtins.substring storePathPrefix (builtins.stringLength path) path;
79 77 in (map storePathToName storePaths);
80 78
81 79 in rec {
82 80
83 81 # Build Enterprise and call nix-store to retrieve the runtime
84 82 # dependencies. The result is available in the nix store.
85 83 runtimeDependencies = stdenv.mkDerivation {
86 84 name = "runtime-dependencies";
87 85 buildInputs = [
88 86 # Needed to query the store
89 87 nixpkgs.nix
90 88 ];
91 89 unpackPhase = ''
92 90 echo "Nothing to unpack"
93 91 '';
94 92 buildPhase = ''
95 93 # Get a list of runtime dependencies
96 94 nix-store -q --references ${enterprise} > nix-store-references
97 95 '';
98 96 installPhase = ''
99 97 mkdir -p $out
100 98 cp -v nix-store-references $out/
101 99 '';
102 100 };
103 101
104 102 # Produce the license overview files.
105 103 result = let
106 104
107 105 # Dependencies according to the nix-store
108 106 runtimeDependencyNames = (
109 107 storePathsToDrvNames "${runtimeDependencies}/nix-store-references");
110 108
111 109 # Dependencies based on buildInputs and propagatedBuildInputs
112 110 enterpriseAllDependencies = listDrvDependencies enterprise;
113 111 enterpriseRuntimeDependencies = let
114 112 elemName = element: element.name or "UNNAMED";
115 113 isRuntime = element: builtins.elem (elemName element) runtimeDependencyNames;
116 114 in builtins.filter isRuntime enterpriseAllDependencies;
117 115
118 116 # Extract relevant meta information
119 117 enterpriseAllLicenses = map drvToMeta enterpriseAllDependencies;
120 118 enterpriseRuntimeLicenses = map drvToMeta enterpriseRuntimeDependencies;
121 119
122 120 in stdenv.mkDerivation {
123 121
124 122 name = "licenses";
125 123
126 124 buildInputs = [];
127 125
128 126 unpackPhase = ''
129 127 echo "Nothing to unpack"
130 128 '';
131 129
132 130 buildPhase = ''
133 131 mkdir build
134 132
135 133 # Copy list of runtime dependencies for the Python processor
136 134 cp "${runtimeDependencies}/nix-store-references" ./build/nix-store-references
137 135
138 136 # All licenses which we found by walking buildInputs and
139 137 # propagatedBuildInputs
140 138 cat > build/all-licenses.json <<EOF
141 139 ${builtins.toJSON enterpriseAllLicenses}
142 140 EOF
143 141
144 142 # License information for our runtime dependencies only. Basically all
145 143 # licenses limited to the items which where also reported by nix-store as
146 144 # a dependency.
147 145 cat > build/licenses.json <<EOF
148 146 ${builtins.toJSON enterpriseRuntimeLicenses}
149 147 EOF
148
150 149 '';
151 150
152 151 installPhase = ''
153 152 mkdir -p $out
154 153
155 154 # Store it all, that helps when things go wrong
156 155 cp -rv ./build/* $out
157 156 '';
158 157 };
159 158
160 159 }
@@ -1,729 +1,744 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2018 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
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import mock
22 22 import pytest
23 23
24 24 import rhodecode
25 25 from rhodecode.apps._base import ADMIN_PREFIX
26 26 from rhodecode.lib.utils2 import md5
27 27 from rhodecode.model.db import RhodeCodeUi
28 28 from rhodecode.model.meta import Session
29 29 from rhodecode.model.settings import SettingsModel, IssueTrackerSettingsModel
30 30 from rhodecode.tests import assert_session_flash
31 31 from rhodecode.tests.utils import AssertResponse
32 32
33 33
34 34 UPDATE_DATA_QUALNAME = 'rhodecode.model.update.UpdateModel.get_update_data'
35 35
36 36
37 37 def route_path(name, params=None, **kwargs):
38 38 import urllib
39 39 from rhodecode.apps._base import ADMIN_PREFIX
40 40
41 41 base_url = {
42 42
43 43 'admin_settings':
44 44 ADMIN_PREFIX +'/settings',
45 45 'admin_settings_update':
46 46 ADMIN_PREFIX + '/settings/update',
47 47 'admin_settings_global':
48 48 ADMIN_PREFIX + '/settings/global',
49 49 'admin_settings_global_update':
50 50 ADMIN_PREFIX + '/settings/global/update',
51 51 'admin_settings_vcs':
52 52 ADMIN_PREFIX + '/settings/vcs',
53 53 'admin_settings_vcs_update':
54 54 ADMIN_PREFIX + '/settings/vcs/update',
55 55 'admin_settings_vcs_svn_pattern_delete':
56 56 ADMIN_PREFIX + '/settings/vcs/svn_pattern_delete',
57 57 'admin_settings_mapping':
58 58 ADMIN_PREFIX + '/settings/mapping',
59 59 'admin_settings_mapping_update':
60 60 ADMIN_PREFIX + '/settings/mapping/update',
61 61 'admin_settings_visual':
62 62 ADMIN_PREFIX + '/settings/visual',
63 63 'admin_settings_visual_update':
64 64 ADMIN_PREFIX + '/settings/visual/update',
65 65 'admin_settings_issuetracker':
66 66 ADMIN_PREFIX + '/settings/issue-tracker',
67 67 'admin_settings_issuetracker_update':
68 68 ADMIN_PREFIX + '/settings/issue-tracker/update',
69 69 'admin_settings_issuetracker_test':
70 70 ADMIN_PREFIX + '/settings/issue-tracker/test',
71 71 'admin_settings_issuetracker_delete':
72 72 ADMIN_PREFIX + '/settings/issue-tracker/delete',
73 73 'admin_settings_email':
74 74 ADMIN_PREFIX + '/settings/email',
75 75 'admin_settings_email_update':
76 76 ADMIN_PREFIX + '/settings/email/update',
77 77 'admin_settings_hooks':
78 78 ADMIN_PREFIX + '/settings/hooks',
79 79 'admin_settings_hooks_update':
80 80 ADMIN_PREFIX + '/settings/hooks/update',
81 81 'admin_settings_hooks_delete':
82 82 ADMIN_PREFIX + '/settings/hooks/delete',
83 83 'admin_settings_search':
84 84 ADMIN_PREFIX + '/settings/search',
85 85 'admin_settings_labs':
86 86 ADMIN_PREFIX + '/settings/labs',
87 87 'admin_settings_labs_update':
88 88 ADMIN_PREFIX + '/settings/labs/update',
89 89
90 90 'admin_settings_sessions':
91 91 ADMIN_PREFIX + '/settings/sessions',
92 92 'admin_settings_sessions_cleanup':
93 93 ADMIN_PREFIX + '/settings/sessions/cleanup',
94 94 'admin_settings_system':
95 95 ADMIN_PREFIX + '/settings/system',
96 96 'admin_settings_system_update':
97 97 ADMIN_PREFIX + '/settings/system/updates',
98 98 'admin_settings_open_source':
99 99 ADMIN_PREFIX + '/settings/open_source',
100 100
101 101
102 102 }[name].format(**kwargs)
103 103
104 104 if params:
105 105 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
106 106 return base_url
107 107
108 108
109 109 @pytest.mark.usefixtures('autologin_user', 'app')
110 110 class TestAdminSettingsController(object):
111 111
112 112 @pytest.mark.parametrize('urlname', [
113 113 'admin_settings_vcs',
114 114 'admin_settings_mapping',
115 115 'admin_settings_global',
116 116 'admin_settings_visual',
117 117 'admin_settings_email',
118 118 'admin_settings_hooks',
119 119 'admin_settings_search',
120 120 ])
121 121 def test_simple_get(self, urlname):
122 122 self.app.get(route_path(urlname))
123 123
124 124 def test_create_custom_hook(self, csrf_token):
125 125 response = self.app.post(
126 126 route_path('admin_settings_hooks_update'),
127 127 params={
128 128 'new_hook_ui_key': 'test_hooks_1',
129 129 'new_hook_ui_value': 'cd /tmp',
130 130 'csrf_token': csrf_token})
131 131
132 132 response = response.follow()
133 133 response.mustcontain('test_hooks_1')
134 134 response.mustcontain('cd /tmp')
135 135
136 136 def test_create_custom_hook_delete(self, csrf_token):
137 137 response = self.app.post(
138 138 route_path('admin_settings_hooks_update'),
139 139 params={
140 140 'new_hook_ui_key': 'test_hooks_2',
141 141 'new_hook_ui_value': 'cd /tmp2',
142 142 'csrf_token': csrf_token})
143 143
144 144 response = response.follow()
145 145 response.mustcontain('test_hooks_2')
146 146 response.mustcontain('cd /tmp2')
147 147
148 148 hook_id = SettingsModel().get_ui_by_key('test_hooks_2').ui_id
149 149
150 150 # delete
151 151 self.app.post(
152 152 route_path('admin_settings_hooks_delete'),
153 153 params={'hook_id': hook_id, 'csrf_token': csrf_token})
154 154 response = self.app.get(route_path('admin_settings_hooks'))
155 155 response.mustcontain(no=['test_hooks_2'])
156 156 response.mustcontain(no=['cd /tmp2'])
157 157
158 158
159 159 @pytest.mark.usefixtures('autologin_user', 'app')
160 160 class TestAdminSettingsGlobal(object):
161 161
162 162 def test_pre_post_code_code_active(self, csrf_token):
163 163 pre_code = 'rc-pre-code-187652122'
164 164 post_code = 'rc-postcode-98165231'
165 165
166 166 response = self.post_and_verify_settings({
167 167 'rhodecode_pre_code': pre_code,
168 168 'rhodecode_post_code': post_code,
169 169 'csrf_token': csrf_token,
170 170 })
171 171
172 172 response = response.follow()
173 173 response.mustcontain(pre_code, post_code)
174 174
175 175 def test_pre_post_code_code_inactive(self, csrf_token):
176 176 pre_code = 'rc-pre-code-187652122'
177 177 post_code = 'rc-postcode-98165231'
178 178 response = self.post_and_verify_settings({
179 179 'rhodecode_pre_code': '',
180 180 'rhodecode_post_code': '',
181 181 'csrf_token': csrf_token,
182 182 })
183 183
184 184 response = response.follow()
185 185 response.mustcontain(no=[pre_code, post_code])
186 186
187 187 def test_captcha_activate(self, csrf_token):
188 188 self.post_and_verify_settings({
189 189 'rhodecode_captcha_private_key': '1234567890',
190 190 'rhodecode_captcha_public_key': '1234567890',
191 191 'csrf_token': csrf_token,
192 192 })
193 193
194 194 response = self.app.get(ADMIN_PREFIX + '/register')
195 195 response.mustcontain('captcha')
196 196
197 197 def test_captcha_deactivate(self, csrf_token):
198 198 self.post_and_verify_settings({
199 199 'rhodecode_captcha_private_key': '',
200 200 'rhodecode_captcha_public_key': '1234567890',
201 201 'csrf_token': csrf_token,
202 202 })
203 203
204 204 response = self.app.get(ADMIN_PREFIX + '/register')
205 205 response.mustcontain(no=['captcha'])
206 206
207 207 def test_title_change(self, csrf_token):
208 208 old_title = 'RhodeCode'
209 209
210 210 for new_title in ['Changed', 'Żółwik', old_title]:
211 211 response = self.post_and_verify_settings({
212 212 'rhodecode_title': new_title,
213 213 'csrf_token': csrf_token,
214 214 })
215 215
216 216 response = response.follow()
217 217 response.mustcontain(
218 218 """<div class="branding">- %s</div>""" % new_title)
219 219
220 220 def post_and_verify_settings(self, settings):
221 221 old_title = 'RhodeCode'
222 222 old_realm = 'RhodeCode authentication'
223 223 params = {
224 224 'rhodecode_title': old_title,
225 225 'rhodecode_realm': old_realm,
226 226 'rhodecode_pre_code': '',
227 227 'rhodecode_post_code': '',
228 228 'rhodecode_captcha_private_key': '',
229 229 'rhodecode_captcha_public_key': '',
230 230 'rhodecode_create_personal_repo_group': False,
231 231 'rhodecode_personal_repo_group_pattern': '${username}',
232 232 }
233 233 params.update(settings)
234 234 response = self.app.post(
235 235 route_path('admin_settings_global_update'), params=params)
236 236
237 237 assert_session_flash(response, 'Updated application settings')
238 238 app_settings = SettingsModel().get_all_settings()
239 239 del settings['csrf_token']
240 240 for key, value in settings.iteritems():
241 241 assert app_settings[key] == value.decode('utf-8')
242 242
243 243 return response
244 244
245 245
246 246 @pytest.mark.usefixtures('autologin_user', 'app')
247 247 class TestAdminSettingsVcs(object):
248 248
249 249 def test_contains_svn_default_patterns(self):
250 250 response = self.app.get(route_path('admin_settings_vcs'))
251 251 expected_patterns = [
252 252 '/trunk',
253 253 '/branches/*',
254 254 '/tags/*',
255 255 ]
256 256 for pattern in expected_patterns:
257 257 response.mustcontain(pattern)
258 258
259 259 def test_add_new_svn_branch_and_tag_pattern(
260 260 self, backend_svn, form_defaults, disable_sql_cache,
261 261 csrf_token):
262 262 form_defaults.update({
263 263 'new_svn_branch': '/exp/branches/*',
264 264 'new_svn_tag': '/important_tags/*',
265 265 'csrf_token': csrf_token,
266 266 })
267 267
268 268 response = self.app.post(
269 269 route_path('admin_settings_vcs_update'),
270 270 params=form_defaults, status=302)
271 271 response = response.follow()
272 272
273 273 # Expect to find the new values on the page
274 274 response.mustcontain('/exp/branches/*')
275 275 response.mustcontain('/important_tags/*')
276 276
277 277 # Expect that those patterns are used to match branches and tags now
278 278 repo = backend_svn['svn-simple-layout'].scm_instance()
279 279 assert 'exp/branches/exp-sphinx-docs' in repo.branches
280 280 assert 'important_tags/v0.5' in repo.tags
281 281
282 282 def test_add_same_svn_value_twice_shows_an_error_message(
283 283 self, form_defaults, csrf_token, settings_util):
284 284 settings_util.create_rhodecode_ui('vcs_svn_branch', '/test')
285 285 settings_util.create_rhodecode_ui('vcs_svn_tag', '/test')
286 286
287 287 response = self.app.post(
288 288 route_path('admin_settings_vcs_update'),
289 289 params={
290 290 'paths_root_path': form_defaults['paths_root_path'],
291 291 'new_svn_branch': '/test',
292 292 'new_svn_tag': '/test',
293 293 'csrf_token': csrf_token,
294 294 },
295 295 status=200)
296 296
297 297 response.mustcontain("Pattern already exists")
298 298 response.mustcontain("Some form inputs contain invalid data.")
299 299
300 300 @pytest.mark.parametrize('section', [
301 301 'vcs_svn_branch',
302 302 'vcs_svn_tag',
303 303 ])
304 304 def test_delete_svn_patterns(
305 305 self, section, csrf_token, settings_util):
306 306 setting = settings_util.create_rhodecode_ui(
307 307 section, '/test_delete', cleanup=False)
308 308
309 309 self.app.post(
310 310 route_path('admin_settings_vcs_svn_pattern_delete'),
311 311 params={
312 312 'delete_svn_pattern': setting.ui_id,
313 313 'csrf_token': csrf_token},
314 314 headers={'X-REQUESTED-WITH': 'XMLHttpRequest'})
315 315
316 316 @pytest.mark.parametrize('section', [
317 317 'vcs_svn_branch',
318 318 'vcs_svn_tag',
319 319 ])
320 320 def test_delete_svn_patterns_raises_404_when_no_xhr(
321 321 self, section, csrf_token, settings_util):
322 322 setting = settings_util.create_rhodecode_ui(section, '/test_delete')
323 323
324 324 self.app.post(
325 325 route_path('admin_settings_vcs_svn_pattern_delete'),
326 326 params={
327 327 'delete_svn_pattern': setting.ui_id,
328 328 'csrf_token': csrf_token},
329 329 status=404)
330 330
331 331 def test_extensions_hgsubversion(self, form_defaults, csrf_token):
332 332 form_defaults.update({
333 333 'csrf_token': csrf_token,
334 334 'extensions_hgsubversion': 'True',
335 335 })
336 336 response = self.app.post(
337 337 route_path('admin_settings_vcs_update'),
338 338 params=form_defaults,
339 339 status=302)
340 340
341 341 response = response.follow()
342 342 extensions_input = (
343 343 '<input id="extensions_hgsubversion" '
344 344 'name="extensions_hgsubversion" type="checkbox" '
345 345 'value="True" checked="checked" />')
346 346 response.mustcontain(extensions_input)
347 347
348 348 def test_extensions_hgevolve(self, form_defaults, csrf_token):
349 349 form_defaults.update({
350 350 'csrf_token': csrf_token,
351 351 'extensions_evolve': 'True',
352 352 })
353 353 response = self.app.post(
354 354 route_path('admin_settings_vcs_update'),
355 355 params=form_defaults,
356 356 status=302)
357 357
358 358 response = response.follow()
359 359 extensions_input = (
360 360 '<input id="extensions_evolve" '
361 361 'name="extensions_evolve" type="checkbox" '
362 362 'value="True" checked="checked" />')
363 363 response.mustcontain(extensions_input)
364 364
365 365 def test_has_a_section_for_pull_request_settings(self):
366 366 response = self.app.get(route_path('admin_settings_vcs'))
367 367 response.mustcontain('Pull Request Settings')
368 368
369 369 def test_has_an_input_for_invalidation_of_inline_comments(self):
370 370 response = self.app.get(route_path('admin_settings_vcs'))
371 371 assert_response = AssertResponse(response)
372 372 assert_response.one_element_exists(
373 373 '[name=rhodecode_use_outdated_comments]')
374 374
375 375 @pytest.mark.parametrize('new_value', [True, False])
376 376 def test_allows_to_change_invalidation_of_inline_comments(
377 377 self, form_defaults, csrf_token, new_value):
378 378 setting_key = 'use_outdated_comments'
379 379 setting = SettingsModel().create_or_update_setting(
380 380 setting_key, not new_value, 'bool')
381 381 Session().add(setting)
382 382 Session().commit()
383 383
384 384 form_defaults.update({
385 385 'csrf_token': csrf_token,
386 386 'rhodecode_use_outdated_comments': str(new_value),
387 387 })
388 388 response = self.app.post(
389 389 route_path('admin_settings_vcs_update'),
390 390 params=form_defaults,
391 391 status=302)
392 392 response = response.follow()
393 393 setting = SettingsModel().get_setting_by_name(setting_key)
394 394 assert setting.app_settings_value is new_value
395 395
396 396 @pytest.mark.parametrize('new_value', [True, False])
397 397 def test_allows_to_change_hg_rebase_merge_strategy(
398 398 self, form_defaults, csrf_token, new_value):
399 399 setting_key = 'hg_use_rebase_for_merging'
400 400
401 401 form_defaults.update({
402 402 'csrf_token': csrf_token,
403 403 'rhodecode_' + setting_key: str(new_value),
404 404 })
405 405
406 406 with mock.patch.dict(
407 407 rhodecode.CONFIG, {'labs_settings_active': 'true'}):
408 408 self.app.post(
409 409 route_path('admin_settings_vcs_update'),
410 410 params=form_defaults,
411 411 status=302)
412 412
413 413 setting = SettingsModel().get_setting_by_name(setting_key)
414 414 assert setting.app_settings_value is new_value
415 415
416 416 @pytest.fixture
417 417 def disable_sql_cache(self, request):
418 418 patcher = mock.patch(
419 419 'rhodecode.lib.caching_query.FromCache.process_query')
420 420 request.addfinalizer(patcher.stop)
421 421 patcher.start()
422 422
423 423 @pytest.fixture
424 424 def form_defaults(self):
425 425 from rhodecode.apps.admin.views.settings import AdminSettingsView
426 426 return AdminSettingsView._form_defaults()
427 427
428 428 # TODO: johbo: What we really want is to checkpoint before a test run and
429 429 # reset the session afterwards.
430 430 @pytest.fixture(scope='class', autouse=True)
431 431 def cleanup_settings(self, request, baseapp):
432 432 ui_id = RhodeCodeUi.ui_id
433 433 original_ids = list(
434 434 r.ui_id for r in RhodeCodeUi.query().values(ui_id))
435 435
436 436 @request.addfinalizer
437 437 def cleanup():
438 438 RhodeCodeUi.query().filter(
439 439 ui_id.notin_(original_ids)).delete(False)
440 440
441 441
442 442 @pytest.mark.usefixtures('autologin_user', 'app')
443 443 class TestLabsSettings(object):
444 444 def test_get_settings_page_disabled(self):
445 445 with mock.patch.dict(
446 446 rhodecode.CONFIG, {'labs_settings_active': 'false'}):
447 447
448 448 response = self.app.get(
449 449 route_path('admin_settings_labs'), status=302)
450 450
451 451 assert response.location.endswith(route_path('admin_settings'))
452 452
453 453 def test_get_settings_page_enabled(self):
454 454 from rhodecode.apps.admin.views import settings
455 455 lab_settings = [
456 456 settings.LabSetting(
457 457 key='rhodecode_bool',
458 458 type='bool',
459 459 group='bool group',
460 460 label='bool label',
461 461 help='bool help'
462 462 ),
463 463 settings.LabSetting(
464 464 key='rhodecode_text',
465 465 type='unicode',
466 466 group='text group',
467 467 label='text label',
468 468 help='text help'
469 469 ),
470 470 ]
471 471 with mock.patch.dict(rhodecode.CONFIG,
472 472 {'labs_settings_active': 'true'}):
473 473 with mock.patch.object(settings, '_LAB_SETTINGS', lab_settings):
474 474 response = self.app.get(route_path('admin_settings_labs'))
475 475
476 476 assert '<label>bool group:</label>' in response
477 477 assert '<label for="rhodecode_bool">bool label</label>' in response
478 478 assert '<p class="help-block">bool help</p>' in response
479 479 assert 'name="rhodecode_bool" type="checkbox"' in response
480 480
481 481 assert '<label>text group:</label>' in response
482 482 assert '<label for="rhodecode_text">text label</label>' in response
483 483 assert '<p class="help-block">text help</p>' in response
484 484 assert 'name="rhodecode_text" size="60" type="text"' in response
485 485
486 486
487 487 @pytest.mark.usefixtures('app')
488 488 class TestOpenSourceLicenses(object):
489 489
490 490 def test_records_are_displayed(self, autologin_user):
491 sample_licenses = {
492 "python2.7-pytest-2.7.1": {
493 "UNKNOWN": None
491 sample_licenses = [
492 {
493 "license": [
494 {
495 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
496 "shortName": "bsdOriginal",
497 "spdxId": "BSD-4-Clause",
498 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
499 }
500 ],
501 "name": "python2.7-coverage-3.7.1"
494 502 },
495 "python2.7-Markdown-2.6.2": {
496 "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause"
497 }
498 }
503 {
504 "license": [
505 {
506 "fullName": "MIT License",
507 "shortName": "mit",
508 "spdxId": "MIT",
509 "url": "http://spdx.org/licenses/MIT.html"
510 }
511 ],
512 "name": "python2.7-bootstrapped-pip-9.0.1"
513 },
514 ]
499 515 read_licenses_patch = mock.patch(
500 516 'rhodecode.apps.admin.views.open_source_licenses.read_opensource_licenses',
501 517 return_value=sample_licenses)
502 518 with read_licenses_patch:
503 519 response = self.app.get(
504 520 route_path('admin_settings_open_source'), status=200)
505 521
506 522 assert_response = AssertResponse(response)
507 523 assert_response.element_contains(
508 524 '.panel-heading', 'Licenses of Third Party Packages')
509 for name in sample_licenses:
510 response.mustcontain(name)
511 for license in sample_licenses[name]:
512 assert_response.element_contains('.panel-body', license)
525 for license_data in sample_licenses:
526 response.mustcontain(license_data["license"][0]["spdxId"])
527 assert_response.element_contains('.panel-body', license_data["name"])
513 528
514 529 def test_records_can_be_read(self, autologin_user):
515 530 response = self.app.get(
516 531 route_path('admin_settings_open_source'), status=200)
517 532 assert_response = AssertResponse(response)
518 533 assert_response.element_contains(
519 534 '.panel-heading', 'Licenses of Third Party Packages')
520 535
521 536 def test_forbidden_when_normal_user(self, autologin_regular_user):
522 537 self.app.get(
523 538 route_path('admin_settings_open_source'), status=404)
524 539
525 540
526 541 @pytest.mark.usefixtures('app')
527 542 class TestUserSessions(object):
528 543
529 544 def test_forbidden_when_normal_user(self, autologin_regular_user):
530 545 self.app.get(route_path('admin_settings_sessions'), status=404)
531 546
532 547 def test_show_sessions_page(self, autologin_user):
533 548 response = self.app.get(route_path('admin_settings_sessions'), status=200)
534 549 response.mustcontain('file')
535 550
536 551 def test_cleanup_old_sessions(self, autologin_user, csrf_token):
537 552
538 553 post_data = {
539 554 'csrf_token': csrf_token,
540 555 'expire_days': '60'
541 556 }
542 557 response = self.app.post(
543 558 route_path('admin_settings_sessions_cleanup'), params=post_data,
544 559 status=302)
545 560 assert_session_flash(response, 'Cleaned up old sessions')
546 561
547 562
548 563 @pytest.mark.usefixtures('app')
549 564 class TestAdminSystemInfo(object):
550 565
551 566 def test_forbidden_when_normal_user(self, autologin_regular_user):
552 567 self.app.get(route_path('admin_settings_system'), status=404)
553 568
554 569 def test_system_info_page(self, autologin_user):
555 570 response = self.app.get(route_path('admin_settings_system'))
556 571 response.mustcontain('RhodeCode Community Edition, version {}'.format(
557 572 rhodecode.__version__))
558 573
559 574 def test_system_update_new_version(self, autologin_user):
560 575 update_data = {
561 576 'versions': [
562 577 {
563 578 'version': '100.3.1415926535',
564 579 'general': 'The latest version we are ever going to ship'
565 580 },
566 581 {
567 582 'version': '0.0.0',
568 583 'general': 'The first version we ever shipped'
569 584 }
570 585 ]
571 586 }
572 587 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
573 588 response = self.app.get(route_path('admin_settings_system_update'))
574 589 response.mustcontain('A <b>new version</b> is available')
575 590
576 591 def test_system_update_nothing_new(self, autologin_user):
577 592 update_data = {
578 593 'versions': [
579 594 {
580 595 'version': '0.0.0',
581 596 'general': 'The first version we ever shipped'
582 597 }
583 598 ]
584 599 }
585 600 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
586 601 response = self.app.get(route_path('admin_settings_system_update'))
587 602 response.mustcontain(
588 603 'This instance is already running the <b>latest</b> stable version')
589 604
590 605 def test_system_update_bad_response(self, autologin_user):
591 606 with mock.patch(UPDATE_DATA_QUALNAME, side_effect=ValueError('foo')):
592 607 response = self.app.get(route_path('admin_settings_system_update'))
593 608 response.mustcontain(
594 609 'Bad data sent from update server')
595 610
596 611
597 612 @pytest.mark.usefixtures("app")
598 613 class TestAdminSettingsIssueTracker(object):
599 614 RC_PREFIX = 'rhodecode_'
600 615 SHORT_PATTERN_KEY = 'issuetracker_pat_'
601 616 PATTERN_KEY = RC_PREFIX + SHORT_PATTERN_KEY
602 617
603 618 def test_issuetracker_index(self, autologin_user):
604 619 response = self.app.get(route_path('admin_settings_issuetracker'))
605 620 assert response.status_code == 200
606 621
607 622 def test_add_empty_issuetracker_pattern(
608 623 self, request, autologin_user, csrf_token):
609 624 post_url = route_path('admin_settings_issuetracker_update')
610 625 post_data = {
611 626 'csrf_token': csrf_token
612 627 }
613 628 self.app.post(post_url, post_data, status=302)
614 629
615 630 def test_add_issuetracker_pattern(
616 631 self, request, autologin_user, csrf_token):
617 632 pattern = 'issuetracker_pat'
618 633 another_pattern = pattern+'1'
619 634 post_url = route_path('admin_settings_issuetracker_update')
620 635 post_data = {
621 636 'new_pattern_pattern_0': pattern,
622 637 'new_pattern_url_0': 'http://url',
623 638 'new_pattern_prefix_0': 'prefix',
624 639 'new_pattern_description_0': 'description',
625 640 'new_pattern_pattern_1': another_pattern,
626 641 'new_pattern_url_1': 'https://url1',
627 642 'new_pattern_prefix_1': 'prefix1',
628 643 'new_pattern_description_1': 'description1',
629 644 'csrf_token': csrf_token
630 645 }
631 646 self.app.post(post_url, post_data, status=302)
632 647 settings = SettingsModel().get_all_settings()
633 648 self.uid = md5(pattern)
634 649 assert settings[self.PATTERN_KEY+self.uid] == pattern
635 650 self.another_uid = md5(another_pattern)
636 651 assert settings[self.PATTERN_KEY+self.another_uid] == another_pattern
637 652
638 653 @request.addfinalizer
639 654 def cleanup():
640 655 defaults = SettingsModel().get_all_settings()
641 656
642 657 entries = [name for name in defaults if (
643 658 (self.uid in name) or (self.another_uid) in name)]
644 659 start = len(self.RC_PREFIX)
645 660 for del_key in entries:
646 661 # TODO: anderson: get_by_name needs name without prefix
647 662 entry = SettingsModel().get_setting_by_name(del_key[start:])
648 663 Session().delete(entry)
649 664
650 665 Session().commit()
651 666
652 667 def test_edit_issuetracker_pattern(
653 668 self, autologin_user, backend, csrf_token, request):
654 669 old_pattern = 'issuetracker_pat'
655 670 old_uid = md5(old_pattern)
656 671 pattern = 'issuetracker_pat_new'
657 672 self.new_uid = md5(pattern)
658 673
659 674 SettingsModel().create_or_update_setting(
660 675 self.SHORT_PATTERN_KEY+old_uid, old_pattern, 'unicode')
661 676
662 677 post_url = route_path('admin_settings_issuetracker_update')
663 678 post_data = {
664 679 'new_pattern_pattern_0': pattern,
665 680 'new_pattern_url_0': 'https://url',
666 681 'new_pattern_prefix_0': 'prefix',
667 682 'new_pattern_description_0': 'description',
668 683 'uid': old_uid,
669 684 'csrf_token': csrf_token
670 685 }
671 686 self.app.post(post_url, post_data, status=302)
672 687 settings = SettingsModel().get_all_settings()
673 688 assert settings[self.PATTERN_KEY+self.new_uid] == pattern
674 689 assert self.PATTERN_KEY+old_uid not in settings
675 690
676 691 @request.addfinalizer
677 692 def cleanup():
678 693 IssueTrackerSettingsModel().delete_entries(self.new_uid)
679 694
680 695 def test_replace_issuetracker_pattern_description(
681 696 self, autologin_user, csrf_token, request, settings_util):
682 697 prefix = 'issuetracker'
683 698 pattern = 'issuetracker_pat'
684 699 self.uid = md5(pattern)
685 700 pattern_key = '_'.join([prefix, 'pat', self.uid])
686 701 rc_pattern_key = '_'.join(['rhodecode', pattern_key])
687 702 desc_key = '_'.join([prefix, 'desc', self.uid])
688 703 rc_desc_key = '_'.join(['rhodecode', desc_key])
689 704 new_description = 'new_description'
690 705
691 706 settings_util.create_rhodecode_setting(
692 707 pattern_key, pattern, 'unicode', cleanup=False)
693 708 settings_util.create_rhodecode_setting(
694 709 desc_key, 'old description', 'unicode', cleanup=False)
695 710
696 711 post_url = route_path('admin_settings_issuetracker_update')
697 712 post_data = {
698 713 'new_pattern_pattern_0': pattern,
699 714 'new_pattern_url_0': 'https://url',
700 715 'new_pattern_prefix_0': 'prefix',
701 716 'new_pattern_description_0': new_description,
702 717 'uid': self.uid,
703 718 'csrf_token': csrf_token
704 719 }
705 720 self.app.post(post_url, post_data, status=302)
706 721 settings = SettingsModel().get_all_settings()
707 722 assert settings[rc_pattern_key] == pattern
708 723 assert settings[rc_desc_key] == new_description
709 724
710 725 @request.addfinalizer
711 726 def cleanup():
712 727 IssueTrackerSettingsModel().delete_entries(self.uid)
713 728
714 729 def test_delete_issuetracker_pattern(
715 730 self, autologin_user, backend, csrf_token, settings_util):
716 731 pattern = 'issuetracker_pat'
717 732 uid = md5(pattern)
718 733 settings_util.create_rhodecode_setting(
719 734 self.SHORT_PATTERN_KEY+uid, pattern, 'unicode', cleanup=False)
720 735
721 736 post_url = route_path('admin_settings_issuetracker_delete')
722 737 post_data = {
723 738 '_method': 'delete',
724 739 'uid': uid,
725 740 'csrf_token': csrf_token
726 741 }
727 742 self.app.post(post_url, post_data, status=302)
728 743 settings = SettingsModel().get_all_settings()
729 744 assert 'rhodecode_%s%s' % (self.SHORT_PATTERN_KEY, uid) not in settings
@@ -1,53 +1,51 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2018 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
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import collections
22 22 import logging
23 23
24 24 from pyramid.view import view_config
25 25
26 26 from rhodecode.apps._base import BaseAppView
27 27 from rhodecode.apps.admin.navigation import navigation_list
28 28 from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator)
29 29 from rhodecode.lib.utils import read_opensource_licenses
30 30
31 31 log = logging.getLogger(__name__)
32 32
33 33
34 34 class OpenSourceLicensesAdminSettingsView(BaseAppView):
35 35
36 36 def load_default_context(self):
37 37 c = self._get_local_tmpl_context()
38
39 38 return c
40 39
41 40 @LoginRequired()
42 41 @HasPermissionAllDecorator('hg.admin')
43 42 @view_config(
44 43 route_name='admin_settings_open_source', request_method='GET',
45 44 renderer='rhodecode:templates/admin/settings/settings.mako')
46 45 def open_source_licenses(self):
47 46 c = self.load_default_context()
48 47 c.active = 'open_source'
49 48 c.navlist = navigation_list(self.request)
50 items = sorted(read_opensource_licenses().items(), key=lambda t: t[0])
51 c.opensource_licenses = collections.OrderedDict(items)
52
49 c.opensource_licenses = sorted(
50 read_opensource_licenses(), key=lambda d: d["name"])
53 51 return self._get_template_context(c)
This diff has been collapsed as it changes many lines, (2281 lines changed) Show them Hide them
@@ -1,369 +1,1912 b''
1 {
2 "libnghttp2-1.7.1": {
3 "MIT License": "http://spdx.org/licenses/MIT"
4 },
5 "nodejs-4.3.1": {
6 "MIT License": "http://spdx.org/licenses/MIT"
7 },
8 "python-2.7.12": {
9 "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0"
10 },
11 "python2.7-Babel-1.3": {
12 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
13 },
14 "python2.7-Beaker-1.7.0": {
15 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
16 },
17 "python2.7-Chameleon-2.24": {
18 "BSD-like": "http://repoze.org/license.html"
19 },
20 "python2.7-FormEncode-1.2.4": {
21 "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0"
22 },
23 "python2.7-Jinja2-2.7.3": {
24 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
25 },
26 "python2.7-Mako-1.0.6": {
27 "MIT License": "http://spdx.org/licenses/MIT"
28 },
29 "python2.7-Markdown-2.6.7": {
30 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
31 },
32 "python2.7-MarkupSafe-0.23": {
33 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
34 },
35 "python2.7-Paste-2.0.3": {
36 "MIT License": "http://spdx.org/licenses/MIT"
37 },
38 "python2.7-PasteDeploy-1.5.2": {
39 "MIT License": "http://spdx.org/licenses/MIT"
40 },
41 "python2.7-PasteScript-1.7.5": {
42 "MIT License": "http://spdx.org/licenses/MIT"
43 },
44 "python2.7-Pygments-2.2.0": {
45 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
46 },
47 "python2.7-Routes-1.13": {
48 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
49 },
50 "python2.7-SQLAlchemy-0.9.9": {
51 "MIT License": "http://spdx.org/licenses/MIT"
52 },
53 "python2.7-Tempita-0.5.2": {
54 "MIT License": "http://spdx.org/licenses/MIT"
55 },
56 "python2.7-URLObject-2.4.0": {
57 "The Unlicense": "http://unlicense.org/"
58 },
59 "python2.7-WebError-0.10.3": {
60 "MIT License": "http://spdx.org/licenses/MIT"
61 },
62 "python2.7-WebHelpers-1.3": {
63 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
64 },
65 "python2.7-WebHelpers2-2.0": {
66 "MIT License": "http://spdx.org/licenses/MIT"
67 },
68 "python2.7-WebOb-1.3.1": {
69 "MIT License": "http://spdx.org/licenses/MIT"
70 },
71 "python2.7-Whoosh-2.7.4": {
72 "BSD 2-clause \"Simplified\" License": "http://spdx.org/licenses/BSD-2-Clause",
73 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
74 },
75 "python2.7-alembic-0.8.4": {
76 "MIT License": "http://spdx.org/licenses/MIT"
77 },
78 "python2.7-appenlight-client-0.6.14": {
79 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
80 },
81 "python2.7-authomatic-0.1.0.post1": {
82 "MIT License": "http://spdx.org/licenses/MIT"
83 },
84 "python2.7-backports.shutil-get-terminal-size-1.0.0": {
85 "MIT License": "http://spdx.org/licenses/MIT"
86 },
87 "python2.7-bleach-1.5.0": {
88 "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0"
89 },
90 "python2.7-celery-2.2.10": {
91 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
92 },
93 "python2.7-channelstream-0.5.2": {
94 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
95 },
96 "python2.7-click-5.1": {
97 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
98 },
99 "python2.7-colander-1.2": {
100 "Repoze License": "http://www.repoze.org/LICENSE.txt"
101 },
102 "python2.7-configobj-5.0.6": {
103 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
104 },
105 "python2.7-configparser-3.5.0": {
106 "MIT License": "http://spdx.org/licenses/MIT"
107 },
108 "python2.7-cssselect-1.0.1": {
109 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
110 },
111 "python2.7-decorator-4.0.11": {
112 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
113 },
114 "python2.7-deform-2.0a2": {
115 "BSD-derived": "http://www.repoze.org/LICENSE.txt"
116 },
117 "python2.7-docutils-0.12": {
118 "BSD 2-clause \"Simplified\" License": "http://spdx.org/licenses/BSD-2-Clause"
119 },
120 "python2.7-dogpile.cache-0.6.1": {
121 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
122 },
123 "python2.7-dogpile.core-0.4.1": {
124 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
125 },
126 "python2.7-elasticsearch-2.3.0": {
127 "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0"
128 },
129 "python2.7-elasticsearch-dsl-2.2.0": {
130 "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0"
131 },
132 "python2.7-entrypoints-0.2.2": {
133 "MIT License": "http://spdx.org/licenses/MIT"
134 },
135 "python2.7-enum34-1.1.6": {
136 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
137 },
138 "python2.7-functools32-3.2.3.post2": {
139 "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0"
140 },
141 "python2.7-future-0.14.3": {
142 "MIT License": "http://spdx.org/licenses/MIT"
143 },
144 "python2.7-futures-3.0.2": {
145 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
146 },
147 "python2.7-gevent-1.1.2": {
148 "MIT License": "http://spdx.org/licenses/MIT"
149 },
150 "python2.7-gnureadline-6.3.3": {
151 "GNU General Public License v1.0 only": "http://spdx.org/licenses/GPL-1.0"
152 },
153 "python2.7-gprof2dot-2016.10.13": {
154 "GNU Lesser General Public License v3.0 or later": "http://spdx.org/licenses/LGPL-3.0+"
155 },
156 "python2.7-greenlet-0.4.10": {
157 "MIT License": "http://spdx.org/licenses/MIT"
158 },
159 "python2.7-gunicorn-19.6.0": {
160 "MIT License": "http://spdx.org/licenses/MIT"
161 },
162 "python2.7-html5lib-0.9999999": {
163 "MIT License": "http://spdx.org/licenses/MIT"
164 },
165 "python2.7-infrae.cache-1.0.1": {
166 "Zope Public License 2.1": "http://spdx.org/licenses/ZPL-2.1"
167 },
168 "python2.7-ipython-5.1.0": {
169 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
170 },
171 "python2.7-ipython-genutils-0.2.0": {
172 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
173 },
174 "python2.7-iso8601-0.1.11": {
175 "MIT License": "http://spdx.org/licenses/MIT"
176 },
177 "python2.7-itsdangerous-0.24": {
178 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
179 },
180 "python2.7-jsonschema-2.6.0": {
181 "MIT License": "http://spdx.org/licenses/MIT"
182 },
183 "python2.7-jupyter-client-5.0.0": {
184 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
185 },
186 "python2.7-jupyter-core-4.3.0": {
187 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
188 },
189 "python2.7-kombu-4.1.0": {
190 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
191 },
192 "python2.7-mistune-0.7.4": {
193 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
194 },
195 "python2.7-msgpack-python-0.4.8": {
196 "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0"
197 },
198 "python2.7-nbconvert-5.1.1": {
199 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
200 },
201 "python2.7-nbformat-4.3.0": {
202 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
203 },
204 "python2.7-packaging-15.2": {
205 "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0"
206 },
207 "python2.7-pandocfilters-1.4.1": {
208 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
209 },
210 "python2.7-pathlib2-2.1.0": {
211 "MIT License": "http://spdx.org/licenses/MIT"
212 },
213 "python2.7-peppercorn-0.5": {
214 "BSD-derived": "http://www.repoze.org/LICENSE.txt"
215 },
216 "python2.7-pexpect-4.2.1": {
217 "ISC License": "http://spdx.org/licenses/ISC"
218 },
219 "python2.7-pickleshare-0.7.4": {
220 "MIT License": "http://spdx.org/licenses/MIT"
221 },
222 "python2.7-prompt-toolkit-1.0.14": {
223 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
224 },
225 "python2.7-psutil-4.3.1": {
226 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
227 },
228 "python2.7-psycopg2-2.6.1": {
229 "GNU Lesser General Public License v3.0 or later": "http://spdx.org/licenses/LGPL-3.0+"
230 },
231 "python2.7-ptyprocess-0.5.1": {
232 "ISC License": "http://opensource.org/licenses/ISC"
233 },
234 "python2.7-py-1.4.31": {
235 "MIT License": "http://spdx.org/licenses/MIT"
236 },
237 "python2.7-py-bcrypt-0.4": {
238 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
239 },
240 "python2.7-py-gfm-0.1.3.rhodecode-upstream1": {
241 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
242 },
243 "python2.7-pycrypto-2.6.1": {
244 "Public Domain": null
245 },
246 "python2.7-pycurl-7.19.5": {
247 "MIT License": "http://spdx.org/licenses/MIT"
248 },
249 "python2.7-pygments-markdown-lexer-0.1.0.dev39": {
250 "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0"
251 },
252 "python2.7-pyparsing-1.5.7": {
253 "MIT License": "http://spdx.org/licenses/MIT"
254 },
255 "python2.7-pyramid-1.7.4": {
256 "Repoze License": "http://www.repoze.org/LICENSE.txt"
257 },
258 "python2.7-pyramid-beaker-0.8": {
259 "Repoze License": "http://www.repoze.org/LICENSE.txt"
260 },
261 "python2.7-pyramid-debugtoolbar-3.0.5": {
262 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause",
263 "Repoze License": "http://www.repoze.org/LICENSE.txt"
264 },
265 "python2.7-pyramid-jinja2-2.5": {
266 "BSD-derived": "http://www.repoze.org/LICENSE.txt"
267 },
268 "python2.7-pyramid-mako-1.0.2": {
269 "Repoze License": "http://www.repoze.org/LICENSE.txt"
270 },
271 "python2.7-pysqlite-2.6.3": {
272 "libpng License": "http://spdx.org/licenses/Libpng",
273 "zlib License": "http://spdx.org/licenses/Zlib"
274 },
275 "python2.7-pytest-3.0.5": {
276 "MIT License": "http://spdx.org/licenses/MIT"
277 },
278 "python2.7-pytest-profiling-1.2.2": {
279 "MIT License": "http://spdx.org/licenses/MIT"
280 },
281 "python2.7-pytest-runner-2.9": {
282 "MIT License": "http://spdx.org/licenses/MIT"
283 },
284 "python2.7-pytest-sugar-0.7.1": {
285 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
286 },
287 "python2.7-pytest-timeout-1.2.0": {
288 "MIT License": "http://spdx.org/licenses/MIT"
289 },
290 "python2.7-python-dateutil-2.1": {
291 "Simplified BSD": null
292 },
293 "python2.7-python-editor-1.0.3": {
294 "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0"
295 },
296 "python2.7-python-ldap-2.4.19": {
297 "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0"
298 },
299 "python2.7-python-memcached-1.57": {
300 "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0"
301 },
302 "python2.7-pytz-2015.4": {
303 "MIT License": "http://spdx.org/licenses/MIT"
304 },
305 "python2.7-pyzmq-14.6.0": {
306 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
307 },
308 "python2.7-repoze.lru-0.6": {
309 "Repoze License": "http://www.repoze.org/LICENSE.txt"
310 },
311 "python2.7-requests-2.9.1": {
312 "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0"
313 },
314 "python2.7-setuptools-scm-1.15.6": {
315 "MIT License": "http://spdx.org/licenses/MIT"
316 },
317 "python2.7-simplegeneric-0.8.1": {
318 "Zope Public License 2.1": "http://spdx.org/licenses/ZPL-2.1"
319 },
320 "python2.7-simplejson-3.7.2": {
321 "MIT License": "http://spdx.org/licenses/MIT"
322 },
323 "python2.7-six-1.9.0": {
324 "MIT License": "http://spdx.org/licenses/MIT"
325 },
326 "python2.7-subprocess32-3.2.6": {
327 "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0"
328 },
329 "python2.7-termcolor-1.1.0": {
330 "MIT License": "http://spdx.org/licenses/MIT"
331 },
332 "python2.7-testpath-0.1": {
333 "MIT License": "http://spdx.org/licenses/MIT"
334 },
335 "python2.7-traitlets-4.3.2": {
336 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
337 },
338 "python2.7-translationstring-1.3": {
339 "Repoze License": "http://www.repoze.org/LICENSE.txt"
340 },
341 "python2.7-urllib3-1.16": {
342 "MIT License": "http://spdx.org/licenses/MIT"
343 },
344 "python2.7-venusian-1.0": {
345 "Repoze License": "http://www.repoze.org/LICENSE.txt"
346 },
347 "python2.7-waitress-1.0.1": {
348 "Zope Public License 2.1": "http://spdx.org/licenses/ZPL-2.1"
349 },
350 "python2.7-wcwidth-0.1.7": {
351 "MIT License": "http://spdx.org/licenses/MIT"
352 },
353 "python2.7-ws4py-0.3.5": {
354 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
355 },
356 "python2.7-zope.cachedescriptors-4.0.0": {
357 "Zope Public License 2.1": "http://spdx.org/licenses/ZPL-2.1"
358 },
359 "python2.7-zope.deprecation-4.1.2": {
360 "Zope Public License 2.1": "http://spdx.org/licenses/ZPL-2.1"
361 },
362 "python2.7-zope.interface-4.1.3": {
363 "Zope Public License 2.1": "http://spdx.org/licenses/ZPL-2.1"
364 },
365 "xz-5.2.2": {
366 "GNU General Public License v2.0 or later": "http://spdx.org/licenses/GPL-2.0+",
367 "GNU Library General Public License v2.1 or later": "http://spdx.org/licenses/LGPL-2.1+"
368 }
369 } No newline at end of file
1 [
2 {
3 "license": [
4 {
5 "fullName": "Python Software Foundation License version 2",
6 "shortName": "psfl",
7 "spdxId": "Python-2.0",
8 "url": "http://spdx.org/licenses/Python-2.0.html"
9 },
10 {
11 "fullName": "Zope Public License 2.0",
12 "shortName": "zpl20",
13 "spdxId": "ZPL-2.0",
14 "url": "http://spdx.org/licenses/ZPL-2.0.html"
15 }
16 ],
17 "name": "python2.7-setuptools-38.4.0"
18 },
19 {
20 "license": {
21 "fullName": "Python Software Foundation License version 2",
22 "shortName": "psfl",
23 "spdxId": "Python-2.0",
24 "url": "http://spdx.org/licenses/Python-2.0.html"
25 },
26 "name": "python-2.7.15"
27 },
28 {
29 "license": [
30 {
31 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
32 "shortName": "bsdOriginal",
33 "spdxId": "BSD-4-Clause",
34 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
35 }
36 ],
37 "name": "python2.7-coverage-3.7.1"
38 },
39 {
40 "license": [
41 {
42 "fullName": "MIT License",
43 "shortName": "mit",
44 "spdxId": "MIT",
45 "url": "http://spdx.org/licenses/MIT.html"
46 }
47 ],
48 "name": "python2.7-bootstrapped-pip-9.0.1"
49 },
50 {
51 "license": [
52 {
53 "fullName": "MIT License",
54 "shortName": "mit",
55 "spdxId": "MIT",
56 "url": "http://spdx.org/licenses/MIT.html"
57 }
58 ],
59 "name": "python2.7-cov-core-1.15.0"
60 },
61 {
62 "license": [
63 {
64 "fullName": "MIT License",
65 "shortName": "mit",
66 "spdxId": "MIT",
67 "url": "http://spdx.org/licenses/MIT.html"
68 }
69 ],
70 "name": "python2.7-webtest-2.0.29"
71 },
72 {
73 "license": [
74 {
75 "fullName": "MIT License",
76 "shortName": "mit",
77 "spdxId": "MIT",
78 "url": "http://spdx.org/licenses/MIT.html"
79 }
80 ],
81 "name": "python2.7-beautifulsoup4-4.6.3"
82 },
83 {
84 "license": [
85 {
86 "fullName": "Zope Public License 2.1",
87 "shortName": "zpl21",
88 "spdxId": "ZPL-2.1",
89 "url": "http://spdx.org/licenses/ZPL-2.1.html"
90 }
91 ],
92 "name": "python2.7-waitress-1.1.0"
93 },
94 {
95 "license": [
96 {
97 "fullName": "MIT License",
98 "shortName": "mit",
99 "spdxId": "MIT",
100 "url": "http://spdx.org/licenses/MIT.html"
101 }
102 ],
103 "name": "python2.7-webob-1.7.4"
104 },
105 {
106 "license": [
107 {
108 "fullName": "MIT License",
109 "shortName": "mit",
110 "spdxId": "MIT",
111 "url": "http://spdx.org/licenses/MIT.html"
112 }
113 ],
114 "name": "python2.7-six-1.11.0"
115 },
116 {
117 "license": [
118 {
119 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
120 "shortName": "bsdOriginal",
121 "spdxId": "BSD-4-Clause",
122 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
123 }
124 ],
125 "name": "python2.7-mock-1.0.1"
126 },
127 {
128 "license": [
129 {
130 "fullName": "MIT License",
131 "shortName": "mit",
132 "spdxId": "MIT",
133 "url": "http://spdx.org/licenses/MIT.html"
134 },
135 {
136 "fullName": "DFSG approved"
137 }
138 ],
139 "name": "python2.7-pytest-timeout-1.2.1"
140 },
141 {
142 "license": [
143 {
144 "fullName": "MIT License",
145 "shortName": "mit",
146 "spdxId": "MIT",
147 "url": "http://spdx.org/licenses/MIT.html"
148 }
149 ],
150 "name": "python2.7-pytest-3.6.0"
151 },
152 {
153 "license": [
154 {
155 "fullName": "ASL"
156 },
157 {
158 "fullName": "Apache License 2.0",
159 "shortName": "asl20",
160 "spdxId": "Apache-2.0",
161 "url": "http://spdx.org/licenses/Apache-2.0.html"
162 }
163 ],
164 "name": "python2.7-funcsigs-1.0.2"
165 },
166 {
167 "license": [
168 {
169 "fullName": "MIT License",
170 "shortName": "mit",
171 "spdxId": "MIT",
172 "url": "http://spdx.org/licenses/MIT.html"
173 }
174 ],
175 "name": "python2.7-pluggy-0.6.0"
176 },
177 {
178 "license": [
179 {
180 "fullName": "MIT License",
181 "shortName": "mit",
182 "spdxId": "MIT",
183 "url": "http://spdx.org/licenses/MIT.html"
184 }
185 ],
186 "name": "python2.7-atomicwrites-1.1.5"
187 },
188 {
189 "license": [
190 {
191 "fullName": "MIT License",
192 "shortName": "mit",
193 "spdxId": "MIT",
194 "url": "http://spdx.org/licenses/MIT.html"
195 }
196 ],
197 "name": "python2.7-more-itertools-4.3.0"
198 },
199 {
200 "license": [
201 {
202 "fullName": "MIT License",
203 "shortName": "mit",
204 "spdxId": "MIT",
205 "url": "http://spdx.org/licenses/MIT.html"
206 }
207 ],
208 "name": "python2.7-attrs-18.1.0"
209 },
210 {
211 "license": [
212 {
213 "fullName": "MIT License",
214 "shortName": "mit",
215 "spdxId": "MIT",
216 "url": "http://spdx.org/licenses/MIT.html"
217 }
218 ],
219 "name": "python2.7-py-1.5.3"
220 },
221 {
222 "license": [
223 {
224 "fullName": "GNU Lesser General Public License v3 or later (LGPLv3+)"
225 },
226 {
227 "fullName": "LGPL"
228 }
229 ],
230 "name": "python2.7-gprof2dot-2017.9.19"
231 },
232 {
233 "license": [
234 {
235 "fullName": "MIT License",
236 "shortName": "mit",
237 "spdxId": "MIT",
238 "url": "http://spdx.org/licenses/MIT.html"
239 }
240 ],
241 "name": "python2.7-pytest-profiling-1.3.0"
242 },
243 {
244 "license": [
245 {
246 "fullName": "MIT License",
247 "shortName": "mit",
248 "spdxId": "MIT",
249 "url": "http://spdx.org/licenses/MIT.html"
250 }
251 ],
252 "name": "python2.7-pytest-runner-4.2"
253 },
254 {
255 "license": [
256 {
257 "fullName": "MIT License",
258 "shortName": "mit",
259 "spdxId": "MIT",
260 "url": "http://spdx.org/licenses/MIT.html"
261 }
262 ],
263 "name": "python2.7-setuptools-scm-2.1.0"
264 },
265 {
266 "license": [
267 {
268 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
269 "shortName": "bsdOriginal",
270 "spdxId": "BSD-4-Clause",
271 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
272 }
273 ],
274 "name": "python2.7-pytest-sugar-0.9.1"
275 },
276 {
277 "license": [
278 {
279 "fullName": "MIT License",
280 "shortName": "mit",
281 "spdxId": "MIT",
282 "url": "http://spdx.org/licenses/MIT.html"
283 }
284 ],
285 "name": "python2.7-termcolor-1.1.0"
286 },
287 {
288 "license": [
289 {
290 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
291 "shortName": "bsdOriginal",
292 "spdxId": "BSD-4-Clause",
293 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
294 },
295 {
296 "fullName": "MIT License",
297 "shortName": "mit",
298 "spdxId": "MIT",
299 "url": "http://spdx.org/licenses/MIT.html"
300 }
301 ],
302 "name": "python2.7-pytest-cov-2.5.1"
303 },
304 {
305 "license": [
306 {
307 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
308 "shortName": "bsdOriginal",
309 "spdxId": "BSD-4-Clause",
310 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
311 }
312 ],
313 "name": "python2.7-appenlight-client-0.6.25"
314 },
315 {
316 "license": [
317 {
318 "fullName": "Apache License 2.0",
319 "shortName": "asl20",
320 "spdxId": "Apache-2.0",
321 "url": "http://spdx.org/licenses/Apache-2.0.html"
322 }
323 ],
324 "name": "python2.7-requests-2.9.1"
325 },
326 {
327 "license": [
328 {
329 "fullName": "AGPLv3 and Proprietary"
330 }
331 ],
332 "name": "python2.7-rhodecode-tools-0.16.0"
333 },
334 {
335 "license": [
336 {
337 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
338 "shortName": "bsdOriginal",
339 "spdxId": "BSD-4-Clause",
340 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
341 },
342 {
343 "fullName": "BSD 2-clause \"Simplified\" License",
344 "shortName": "bsd2",
345 "spdxId": "BSD-2-Clause",
346 "url": "http://spdx.org/licenses/BSD-2-Clause.html"
347 }
348 ],
349 "name": "python2.7-whoosh-2.7.4"
350 },
351 {
352 "license": [
353 {
354 "fullName": "MIT License",
355 "shortName": "mit",
356 "spdxId": "MIT",
357 "url": "http://spdx.org/licenses/MIT.html"
358 }
359 ],
360 "name": "python2.7-urllib3-1.21"
361 },
362 {
363 "license": [
364 {
365 "fullName": "Apache License 2.0",
366 "shortName": "asl20",
367 "spdxId": "Apache-2.0",
368 "url": "http://spdx.org/licenses/Apache-2.0.html"
369 }
370 ],
371 "name": "python2.7-elasticsearch-dsl-2.2.0"
372 },
373 {
374 "license": [
375 {
376 "fullName": "Apache License 2.0",
377 "shortName": "asl20",
378 "spdxId": "Apache-2.0",
379 "url": "http://spdx.org/licenses/Apache-2.0.html"
380 }
381 ],
382 "name": "python2.7-elasticsearch-2.3.0"
383 },
384 {
385 "license": [
386 {
387 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
388 "shortName": "bsdOriginal",
389 "spdxId": "BSD-4-Clause",
390 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
391 },
392 {
393 "fullName": "Apache License 2.0",
394 "shortName": "asl20",
395 "spdxId": "Apache-2.0",
396 "url": "http://spdx.org/licenses/Apache-2.0.html"
397 },
398 {
399 "fullName": "Dual License"
400 }
401 ],
402 "name": "python2.7-python-dateutil-2.7.3"
403 },
404 {
405 "license": [
406 {
407 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
408 "shortName": "bsdOriginal",
409 "spdxId": "BSD-4-Clause",
410 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
411 }
412 ],
413 "name": "python2.7-markupsafe-1.0"
414 },
415 {
416 "license": [
417 {
418 "fullName": "MIT License",
419 "shortName": "mit",
420 "spdxId": "MIT",
421 "url": "http://spdx.org/licenses/MIT.html"
422 }
423 ],
424 "name": "python2.7-mako-1.0.7"
425 },
426 {
427 "license": [
428 {
429 "fullName": "MIT License",
430 "shortName": "mit",
431 "spdxId": "MIT",
432 "url": "http://spdx.org/licenses/MIT.html"
433 }
434 ],
435 "name": "python2.7-future-0.14.3"
436 },
437 {
438 "license": [
439 {
440 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
441 "shortName": "bsdOriginal",
442 "spdxId": "BSD-4-Clause",
443 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
444 }
445 ],
446 "name": "python2.7-click-6.6"
447 },
448 {
449 "license": [
450 {
451 "fullName": "MIT License",
452 "shortName": "mit",
453 "spdxId": "MIT",
454 "url": "http://spdx.org/licenses/MIT.html"
455 }
456 ],
457 "name": "python2.7-bottle-0.12.13"
458 },
459 {
460 "license": [
461 {
462 "fullName": "MIT License",
463 "shortName": "mit",
464 "spdxId": "MIT",
465 "url": "http://spdx.org/licenses/MIT.html"
466 }
467 ],
468 "name": "python2.7-cprofilev-1.0.7"
469 },
470 {
471 "license": [
472 {
473 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
474 "shortName": "bsdOriginal",
475 "spdxId": "BSD-4-Clause",
476 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
477 }
478 ],
479 "name": "python2.7-ipython-5.1.0"
480 },
481 {
482 "license": [
483 {
484 "fullName": "GNU General Public License v3 (GPLv3)"
485 },
486 {
487 "fullName": "GNU General Public License v1.0 only",
488 "shortName": "gpl1",
489 "spdxId": "GPL-1.0",
490 "url": "http://spdx.org/licenses/GPL-1.0.html"
491 }
492 ],
493 "name": "python2.7-gnureadline-6.3.8"
494 },
495 {
496 "license": [
497 {
498 "fullName": "ISC License",
499 "shortName": "isc",
500 "spdxId": "ISC",
501 "url": "http://spdx.org/licenses/ISC.html"
502 },
503 {
504 "fullName": "ISC License (ISCL)"
505 }
506 ],
507 "name": "python2.7-pexpect-4.6.0"
508 },
509 {
510 "license": [],
511 "name": "python2.7-ptyprocess-0.6.0"
512 },
513 {
514 "license": [
515 {
516 "fullName": "MIT License",
517 "shortName": "mit",
518 "spdxId": "MIT",
519 "url": "http://spdx.org/licenses/MIT.html"
520 }
521 ],
522 "name": "python2.7-pathlib2-2.3.0"
523 },
524 {
525 "license": [
526 {
527 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
528 "shortName": "bsdOriginal",
529 "spdxId": "BSD-4-Clause",
530 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
531 },
532 {
533 "fullName": "New BSD License"
534 }
535 ],
536 "name": "python2.7-scandir-1.9.0"
537 },
538 {
539 "license": [
540 {
541 "fullName": "MIT License",
542 "shortName": "mit",
543 "spdxId": "MIT",
544 "url": "http://spdx.org/licenses/MIT.html"
545 }
546 ],
547 "name": "python2.7-backports.shutil-get-terminal-size-1.0.0"
548 },
549 {
550 "license": [
551 {
552 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
553 "shortName": "bsdOriginal",
554 "spdxId": "BSD-4-Clause",
555 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
556 }
557 ],
558 "name": "python2.7-pygments-2.2.0"
559 },
560 {
561 "license": [
562 {
563 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
564 "shortName": "bsdOriginal",
565 "spdxId": "BSD-4-Clause",
566 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
567 }
568 ],
569 "name": "python2.7-prompt-toolkit-1.0.15"
570 },
571 {
572 "license": [
573 {
574 "fullName": "MIT License",
575 "shortName": "mit",
576 "spdxId": "MIT",
577 "url": "http://spdx.org/licenses/MIT.html"
578 }
579 ],
580 "name": "python2.7-wcwidth-0.1.7"
581 },
582 {
583 "license": [
584 {
585 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
586 "shortName": "bsdOriginal",
587 "spdxId": "BSD-4-Clause",
588 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
589 }
590 ],
591 "name": "python2.7-traitlets-4.3.2"
592 },
593 {
594 "license": [
595 {
596 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
597 "shortName": "bsdOriginal",
598 "spdxId": "BSD-4-Clause",
599 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
600 }
601 ],
602 "name": "python2.7-enum34-1.1.6"
603 },
604 {
605 "license": [
606 {
607 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
608 "shortName": "bsdOriginal",
609 "spdxId": "BSD-4-Clause",
610 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
611 },
612 {
613 "fullName": "new BSD License"
614 }
615 ],
616 "name": "python2.7-decorator-4.1.2"
617 },
618 {
619 "license": [
620 {
621 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
622 "shortName": "bsdOriginal",
623 "spdxId": "BSD-4-Clause",
624 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
625 }
626 ],
627 "name": "python2.7-ipython-genutils-0.2.0"
628 },
629 {
630 "license": [
631 {
632 "fullName": "Zope Public License 2.1",
633 "shortName": "zpl21",
634 "spdxId": "ZPL-2.1",
635 "url": "http://spdx.org/licenses/ZPL-2.1.html"
636 }
637 ],
638 "name": "python2.7-simplegeneric-0.8.1"
639 },
640 {
641 "license": [
642 {
643 "fullName": "MIT License",
644 "shortName": "mit",
645 "spdxId": "MIT",
646 "url": "http://spdx.org/licenses/MIT.html"
647 }
648 ],
649 "name": "python2.7-pickleshare-0.7.4"
650 },
651 {
652 "license": [
653 {
654 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
655 "shortName": "bsdOriginal",
656 "spdxId": "BSD-4-Clause",
657 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
658 }
659 ],
660 "name": "python2.7-ipdb-0.11"
661 },
662 {
663 "license": [
664 {
665 "fullName": "MIT License",
666 "shortName": "mit",
667 "spdxId": "MIT",
668 "url": "http://spdx.org/licenses/MIT.html"
669 }
670 ],
671 "name": "python2.7-gunicorn-19.9.0"
672 },
673 {
674 "license": [
675 {
676 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
677 "shortName": "bsdOriginal",
678 "spdxId": "BSD-4-Clause",
679 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
680 }
681 ],
682 "name": "python2.7-futures-3.0.2"
683 },
684 {
685 "license": [
686 {
687 "fullName": "MIT License",
688 "shortName": "mit",
689 "spdxId": "MIT",
690 "url": "http://spdx.org/licenses/MIT.html"
691 }
692 ],
693 "name": "python2.7-greenlet-0.4.13"
694 },
695 {
696 "license": [
697 {
698 "fullName": "MIT License",
699 "shortName": "mit",
700 "spdxId": "MIT",
701 "url": "http://spdx.org/licenses/MIT.html"
702 }
703 ],
704 "name": "python2.7-gevent-1.3.5"
705 },
706 {
707 "license": [
708 {
709 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
710 "shortName": "bsdOriginal",
711 "spdxId": "BSD-4-Clause",
712 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
713 }
714 ],
715 "name": "python2.7-psutil-5.4.6"
716 },
717 {
718 "license": [
719 {
720 "fullName": "MIT License",
721 "shortName": "mit",
722 "spdxId": "MIT",
723 "url": "http://spdx.org/licenses/MIT.html"
724 }
725 ],
726 "name": "python2.7-bumpversion-0.5.3"
727 },
728 {
729 "license": [
730 {
731 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
732 "shortName": "bsdOriginal",
733 "spdxId": "BSD-4-Clause",
734 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
735 }
736 ],
737 "name": "python2.7-invoke-0.13.0"
738 },
739 {
740 "license": [
741 {
742 "fullName": "MIT License",
743 "shortName": "mit",
744 "spdxId": "MIT",
745 "url": "http://spdx.org/licenses/MIT.html"
746 }
747 ],
748 "name": "python2.7-alembic-0.9.9"
749 },
750 {
751 "license": {
752 "fullName": "Apache License 2.0",
753 "shortName": "asl20",
754 "spdxId": "Apache-2.0",
755 "url": "http://spdx.org/licenses/Apache-2.0.html"
756 },
757 "name": "python2.7-python-editor-1.0.3"
758 },
759 {
760 "license": [
761 {
762 "fullName": "MIT License",
763 "shortName": "mit",
764 "spdxId": "MIT",
765 "url": "http://spdx.org/licenses/MIT.html"
766 }
767 ],
768 "name": "python2.7-sqlalchemy-1.1.18"
769 },
770 {
771 "license": [
772 {
773 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
774 "shortName": "bsdOriginal",
775 "spdxId": "BSD-4-Clause",
776 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
777 }
778 ],
779 "name": "python2.7-jupyter-client-5.0.0"
780 },
781 {
782 "license": [
783 {
784 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
785 "shortName": "bsdOriginal",
786 "spdxId": "BSD-4-Clause",
787 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
788 },
789 {
790 "fullName": "LGPL+BSD"
791 },
792 {
793 "fullName": "GNU Library or Lesser General Public License (LGPL)"
794 }
795 ],
796 "name": "python2.7-pyzmq-14.6.0"
797 },
798 {
799 "license": [
800 {
801 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
802 "shortName": "bsdOriginal",
803 "spdxId": "BSD-4-Clause",
804 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
805 }
806 ],
807 "name": "python2.7-jupyter-core-4.4.0"
808 },
809 {
810 "license": [
811 {
812 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
813 "shortName": "bsdOriginal",
814 "spdxId": "BSD-4-Clause",
815 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
816 }
817 ],
818 "name": "python2.7-nbformat-4.4.0"
819 },
820 {
821 "license": [
822 {
823 "fullName": "MIT License",
824 "shortName": "mit",
825 "spdxId": "MIT",
826 "url": "http://spdx.org/licenses/MIT.html"
827 }
828 ],
829 "name": "python2.7-jsonschema-2.6.0"
830 },
831 {
832 "license": [
833 {
834 "fullName": "Python Software Foundation License version 2",
835 "shortName": "psfl",
836 "spdxId": "Python-2.0",
837 "url": "http://spdx.org/licenses/Python-2.0.html"
838 }
839 ],
840 "name": "python2.7-functools32-3.2.3.post2"
841 },
842 {
843 "license": [
844 {
845 "fullName": "Apache License 2.0",
846 "shortName": "asl20",
847 "spdxId": "Apache-2.0",
848 "url": "http://spdx.org/licenses/Apache-2.0.html"
849 }
850 ],
851 "name": "python2.7-bleach-2.1.4"
852 },
853 {
854 "license": [
855 {
856 "fullName": "MIT License",
857 "shortName": "mit",
858 "spdxId": "MIT",
859 "url": "http://spdx.org/licenses/MIT.html"
860 }
861 ],
862 "name": "python2.7-html5lib-1.0.1"
863 },
864 {
865 "license": [
866 {
867 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
868 "shortName": "bsdOriginal",
869 "spdxId": "BSD-4-Clause",
870 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
871 }
872 ],
873 "name": "python2.7-webencodings-0.5.1"
874 },
875 {
876 "license": [
877 {
878 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
879 "shortName": "bsdOriginal",
880 "spdxId": "BSD-4-Clause",
881 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
882 }
883 ],
884 "name": "python2.7-nbconvert-5.3.1"
885 },
886 {
887 "license": [
888 {
889 "fullName": "MIT License",
890 "shortName": "mit",
891 "spdxId": "MIT",
892 "url": "http://spdx.org/licenses/MIT.html"
893 }
894 ],
895 "name": "python2.7-testpath-0.3.1"
896 },
897 {
898 "license": [
899 {
900 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
901 "shortName": "bsdOriginal",
902 "spdxId": "BSD-4-Clause",
903 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
904 }
905 ],
906 "name": "python2.7-pandocfilters-1.4.2"
907 },
908 {
909 "license": [
910 {
911 "fullName": "MIT License",
912 "shortName": "mit",
913 "spdxId": "MIT",
914 "url": "http://spdx.org/licenses/MIT.html"
915 }
916 ],
917 "name": "python2.7-entrypoints-0.2.2"
918 },
919 {
920 "license": [
921 {
922 "fullName": "MIT License",
923 "shortName": "mit",
924 "spdxId": "MIT",
925 "url": "http://spdx.org/licenses/MIT.html"
926 }
927 ],
928 "name": "python2.7-configparser-3.5.0"
929 },
930 {
931 "license": [
932 {
933 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
934 "shortName": "bsdOriginal",
935 "spdxId": "BSD-4-Clause",
936 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
937 }
938 ],
939 "name": "python2.7-jinja2-2.9.6"
940 },
941 {
942 "license": [
943 {
944 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
945 "shortName": "bsdOriginal",
946 "spdxId": "BSD-4-Clause",
947 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
948 }
949 ],
950 "name": "python2.7-mistune-0.8.3"
951 },
952 {
953 "license": [
954 {
955 "fullName": "Zope Public License 2.1",
956 "shortName": "zpl21",
957 "spdxId": "ZPL-2.1",
958 "url": "http://spdx.org/licenses/ZPL-2.1.html"
959 }
960 ],
961 "name": "python2.7-zope.interface-4.5.0"
962 },
963 {
964 "license": [
965 {
966 "fullName": "Zope Public License 2.1",
967 "shortName": "zpl21",
968 "spdxId": "ZPL-2.1",
969 "url": "http://spdx.org/licenses/ZPL-2.1.html"
970 }
971 ],
972 "name": "python2.7-zope.event-4.3.0"
973 },
974 {
975 "license": [
976 {
977 "fullName": "Zope Public License 2.1",
978 "shortName": "zpl21",
979 "spdxId": "ZPL-2.1",
980 "url": "http://spdx.org/licenses/ZPL-2.1.html"
981 }
982 ],
983 "name": "python2.7-zope.deprecation-4.3.0"
984 },
985 {
986 "license": [
987 {
988 "fullName": "Zope Public License 2.1",
989 "shortName": "zpl21",
990 "spdxId": "ZPL-2.1",
991 "url": "http://spdx.org/licenses/ZPL-2.1.html"
992 }
993 ],
994 "name": "python2.7-zope.cachedescriptors-4.3.1"
995 },
996 {
997 "license": [
998 {
999 "fullName": "PSF or ZPL"
1000 }
1001 ],
1002 "name": "python2.7-wsgiref-0.1.2"
1003 },
1004 {
1005 "license": [
1006 {
1007 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1008 "shortName": "bsdOriginal",
1009 "spdxId": "BSD-4-Clause",
1010 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1011 }
1012 ],
1013 "name": "python2.7-webhelpers-1.3"
1014 },
1015 {
1016 "license": [
1017 {
1018 "fullName": "MIT License",
1019 "shortName": "mit",
1020 "spdxId": "MIT",
1021 "url": "http://spdx.org/licenses/MIT.html"
1022 }
1023 ],
1024 "name": "python2.7-webhelpers2-2.0"
1025 },
1026 {
1027 "license": [
1028 {
1029 "fullName": "MIT License",
1030 "shortName": "mit",
1031 "spdxId": "MIT",
1032 "url": "http://spdx.org/licenses/MIT.html"
1033 }
1034 ],
1035 "name": "python2.7-weberror-0.10.3"
1036 },
1037 {
1038 "license": [
1039 {
1040 "fullName": "MIT License",
1041 "shortName": "mit",
1042 "spdxId": "MIT",
1043 "url": "http://spdx.org/licenses/MIT.html"
1044 }
1045 ],
1046 "name": "python2.7-paste-2.0.3"
1047 },
1048 {
1049 "license": [
1050 {
1051 "fullName": "MIT License",
1052 "shortName": "mit",
1053 "spdxId": "MIT",
1054 "url": "http://spdx.org/licenses/MIT.html"
1055 }
1056 ],
1057 "name": "python2.7-tempita-0.5.2"
1058 },
1059 {
1060 "license": {
1061 "fullName": "Repoze License",
1062 "url": "http://www.repoze.org/LICENSE.txt"
1063 },
1064 "name": "python2.7-venusian-1.1.0"
1065 },
1066 {
1067 "license": {
1068 "fullName": "The Unlicense",
1069 "spdxId": "Unlicense",
1070 "url": "http://unlicense.org/"
1071 },
1072 "name": "python2.7-urlobject-2.4.3"
1073 },
1074 {
1075 "license": [
1076 {
1077 "fullName": "Apache License 2.0",
1078 "shortName": "asl20",
1079 "spdxId": "Apache-2.0",
1080 "url": "http://spdx.org/licenses/Apache-2.0.html"
1081 }
1082 ],
1083 "name": "python2.7-trollius-1.0.4"
1084 },
1085 {
1086 "license": {
1087 "fullName": "Repoze License",
1088 "url": "http://www.repoze.org/LICENSE.txt"
1089 },
1090 "name": "python2.7-translationstring-1.3"
1091 },
1092 {
1093 "license": [
1094 {
1095 "fullName": "BSD-derived (http://www.repoze.org/LICENSE.txt)"
1096 }
1097 ],
1098 "name": "python2.7-supervisor-3.3.4"
1099 },
1100 {
1101 "license": [
1102 {
1103 "fullName": "BSD-derived (http://www.repoze.org/LICENSE.txt)"
1104 }
1105 ],
1106 "name": "python2.7-meld3-1.0.2"
1107 },
1108 {
1109 "license": [
1110 {
1111 "fullName": "Python Software Foundation License version 2",
1112 "shortName": "psfl",
1113 "spdxId": "Python-2.0",
1114 "url": "http://spdx.org/licenses/Python-2.0.html"
1115 }
1116 ],
1117 "name": "python2.7-subprocess32-3.5.1"
1118 },
1119 {
1120 "license": [
1121 {
1122 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1123 "shortName": "bsdOriginal",
1124 "spdxId": "BSD-4-Clause",
1125 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1126 }
1127 ],
1128 "name": "python2.7-sshpubkeys-2.2.0"
1129 },
1130 {
1131 "license": [
1132 {
1133 "fullName": "MIT License",
1134 "shortName": "mit",
1135 "spdxId": "MIT",
1136 "url": "http://spdx.org/licenses/MIT.html"
1137 }
1138 ],
1139 "name": "python2.7-ecdsa-0.13"
1140 },
1141 {
1142 "license": [
1143 {
1144 "fullName": "Public Domain",
1145 "shortName": "publicDomain"
1146 }
1147 ],
1148 "name": "python2.7-pycrypto-2.6.1"
1149 },
1150 {
1151 "license": [
1152 {
1153 "fullName": "Academic Free License (AFL)"
1154 },
1155 {
1156 "fullName": "MIT License",
1157 "shortName": "mit",
1158 "spdxId": "MIT",
1159 "url": "http://spdx.org/licenses/MIT.html"
1160 }
1161 ],
1162 "name": "python2.7-simplejson-3.11.1"
1163 },
1164 {
1165 "license": [
1166 {
1167 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1168 "shortName": "bsdOriginal",
1169 "spdxId": "BSD-4-Clause",
1170 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1171 }
1172 ],
1173 "name": "python2.7-setproctitle-1.1.10"
1174 },
1175 {
1176 "license": [
1177 {
1178 "fullName": "MIT License",
1179 "shortName": "mit",
1180 "spdxId": "MIT",
1181 "url": "http://spdx.org/licenses/MIT.html"
1182 }
1183 ],
1184 "name": "python2.7-routes-2.4.1"
1185 },
1186 {
1187 "license": {
1188 "fullName": "Repoze License",
1189 "url": "http://www.repoze.org/LICENSE.txt"
1190 },
1191 "name": "python2.7-repoze.lru-0.7"
1192 },
1193 {
1194 "license": [
1195 {
1196 "fullName": "MIT License",
1197 "shortName": "mit",
1198 "spdxId": "MIT",
1199 "url": "http://spdx.org/licenses/MIT.html"
1200 }
1201 ],
1202 "name": "python2.7-redis-2.10.6"
1203 },
1204 {
1205 "license": [
1206 {
1207 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1208 "shortName": "bsdOriginal",
1209 "spdxId": "BSD-4-Clause",
1210 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1211 }
1212 ],
1213 "name": "python2.7-py-gfm-0.1.3"
1214 },
1215 {
1216 "license": [
1217 {
1218 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1219 "shortName": "bsdOriginal",
1220 "spdxId": "BSD-4-Clause",
1221 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1222 }
1223 ],
1224 "name": "python2.7-markdown-2.6.11"
1225 },
1226 {
1227 "license": [
1228 {
1229 "fullName": "MIT License",
1230 "shortName": "mit",
1231 "spdxId": "MIT",
1232 "url": "http://spdx.org/licenses/MIT.html"
1233 }
1234 ],
1235 "name": "python2.7-tzlocal-1.5.1"
1236 },
1237 {
1238 "license": [
1239 {
1240 "fullName": "MIT License",
1241 "shortName": "mit",
1242 "spdxId": "MIT",
1243 "url": "http://spdx.org/licenses/MIT.html"
1244 }
1245 ],
1246 "name": "python2.7-pytz-2018.4"
1247 },
1248 {
1249 "license": [
1250 {
1251 "fullName": "License :: OSI Approved :: MIT License"
1252 },
1253 {
1254 "fullName": "MIT License",
1255 "shortName": "mit",
1256 "spdxId": "MIT",
1257 "url": "http://spdx.org/licenses/MIT.html"
1258 }
1259 ],
1260 "name": "python2.7-python-pam-1.8.4"
1261 },
1262 {
1263 "license": [
1264 {
1265 "fullName": "GNU General Public License v1.0 only",
1266 "shortName": "gpl1",
1267 "spdxId": "GPL-1.0",
1268 "url": "http://spdx.org/licenses/GPL-1.0.html"
1269 }
1270 ],
1271 "name": "linux-pam-1.3.0"
1272 },
1273 {
1274 "license": [
1275 {
1276 "fullName": "Python Software Foundation License version 2",
1277 "shortName": "psfl",
1278 "spdxId": "Python-2.0",
1279 "url": "http://spdx.org/licenses/Python-2.0.html"
1280 }
1281 ],
1282 "name": "python2.7-python-memcached-1.59"
1283 },
1284 {
1285 "license": [
1286 {
1287 "fullName": "Python Software Foundation License version 2",
1288 "shortName": "psfl",
1289 "spdxId": "Python-2.0",
1290 "url": "http://spdx.org/licenses/Python-2.0.html"
1291 }
1292 ],
1293 "name": "python2.7-python-ldap-3.1.0"
1294 },
1295 {
1296 "license": {
1297 "fullName": "MIT License",
1298 "shortName": "mit",
1299 "spdxId": "MIT",
1300 "url": "http://spdx.org/licenses/MIT.html"
1301 },
1302 "name": "libkrb5-1.15.2"
1303 },
1304 {
1305 "license":{
1306 "fullName": "BSD-derived (https://www.openldap.org/software/release/license.html)"
1307 },
1308 "name": "openldap-2.4.45"
1309 },
1310 {
1311 "license": [
1312 {
1313 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1314 "shortName": "bsdOriginal",
1315 "spdxId": "BSD-4-Clause",
1316 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1317 }
1318 ],
1319 "name": "python2.7-pyasn1-modules-0.2.2"
1320 },
1321 {
1322 "license": [
1323 {
1324 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1325 "shortName": "bsdOriginal",
1326 "spdxId": "BSD-4-Clause",
1327 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1328 }
1329 ],
1330 "name": "python2.7-pyasn1-0.4.4"
1331 },
1332 {
1333 "license": [
1334 {
1335 "fullName": "zlib License",
1336 "shortName": "zlib",
1337 "spdxId": "Zlib",
1338 "url": "http://spdx.org/licenses/Zlib.html"
1339 },
1340 {
1341 "fullName": "libpng License",
1342 "shortName": "libpng",
1343 "spdxId": "Libpng",
1344 "url": "http://spdx.org/licenses/Libpng.html"
1345 }
1346 ],
1347 "name": "python2.7-pysqlite-2.8.3"
1348 },
1349 {
1350 "license": {
1351 "fullName": "Repoze License",
1352 "url": "http://www.repoze.org/LICENSE.txt"
1353 },
1354 "name": "python2.7-pyramid-1.9.2"
1355 },
1356 {
1357 "license": [
1358 {
1359 "fullName": "MIT License",
1360 "shortName": "mit",
1361 "spdxId": "MIT",
1362 "url": "http://spdx.org/licenses/MIT.html"
1363 }
1364 ],
1365 "name": "python2.7-hupper-1.3"
1366 },
1367 {
1368 "license": [
1369 {
1370 "fullName": "MIT License",
1371 "shortName": "mit",
1372 "spdxId": "MIT",
1373 "url": "http://spdx.org/licenses/MIT.html"
1374 }
1375 ],
1376 "name": "python2.7-plaster-pastedeploy-0.6"
1377 },
1378 {
1379 "license": [
1380 {
1381 "fullName": "MIT License",
1382 "shortName": "mit",
1383 "spdxId": "MIT",
1384 "url": "http://spdx.org/licenses/MIT.html"
1385 }
1386 ],
1387 "name": "python2.7-plaster-1.0"
1388 },
1389 {
1390 "license": [
1391 {
1392 "fullName": "MIT License",
1393 "shortName": "mit",
1394 "spdxId": "MIT",
1395 "url": "http://spdx.org/licenses/MIT.html"
1396 }
1397 ],
1398 "name": "python2.7-pastedeploy-1.5.2"
1399 },
1400 {
1401 "license": {
1402 "fullName": "Repoze License",
1403 "url": "http://www.repoze.org/LICENSE.txt"
1404 },
1405 "name": "python2.7-pyramid-mako-1.0.2"
1406 },
1407 {
1408 "license": [
1409 {
1410 "fullName": "Repoze Public License"
1411 },
1412 {
1413 "fullName": "BSD-derived (http://www.repoze.org/LICENSE.txt)"
1414 }
1415 ],
1416 "name": "python2.7-pyramid-jinja2-2.7"
1417 },
1418 {
1419 "license": [
1420 {
1421 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1422 "shortName": "bsdOriginal",
1423 "spdxId": "BSD-4-Clause",
1424 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1425 },
1426 {
1427 "fullName": "Repoze License",
1428 "url": "http://www.repoze.org/LICENSE.txt"
1429 }
1430 ],
1431 "name": "python2.7-pyramid-debugtoolbar-4.4"
1432 },
1433 {
1434 "license": [
1435 {
1436 "fullName": "Python Software Foundation License version 2",
1437 "shortName": "psfl",
1438 "spdxId": "Python-2.0",
1439 "url": "http://spdx.org/licenses/Python-2.0.html"
1440 }
1441 ],
1442 "name": "python2.7-ipaddress-1.0.22"
1443 },
1444 {
1445 "license": {
1446 "fullName": "Repoze License",
1447 "url": "http://www.repoze.org/LICENSE.txt"
1448 },
1449 "name": "python2.7-pyramid-beaker-0.8"
1450 },
1451 {
1452 "license": [
1453 {
1454 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1455 "shortName": "bsdOriginal",
1456 "spdxId": "BSD-4-Clause",
1457 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1458 }
1459 ],
1460 "name": "python2.7-beaker-1.9.1"
1461 },
1462 {
1463 "license": [
1464 {
1465 "fullName": "MIT License",
1466 "shortName": "mit",
1467 "spdxId": "MIT",
1468 "url": "http://spdx.org/licenses/MIT.html"
1469 }
1470 ],
1471 "name": "python2.7-pyparsing-1.5.7"
1472 },
1473 {
1474 "license": [
1475 {
1476 "fullName": "Apache License 2.0",
1477 "shortName": "asl20",
1478 "spdxId": "Apache-2.0",
1479 "url": "http://spdx.org/licenses/Apache-2.0.html"
1480 }
1481 ],
1482 "name": "python2.7-pygments-markdown-lexer-0.1.0.dev39"
1483 },
1484 {
1485 "license": [
1486 {
1487 "fullName": "MIT License",
1488 "shortName": "mit",
1489 "spdxId": "MIT",
1490 "url": "http://spdx.org/licenses/MIT.html"
1491 }
1492 ],
1493 "name": "python2.7-pyflakes-0.8.1"
1494 },
1495 {
1496 "license": {
1497 "fullName": "MIT License",
1498 "shortName": "mit",
1499 "spdxId": "MIT",
1500 "url": "http://spdx.org/licenses/MIT.html"
1501 },
1502 "name": "python2.7-pycurl-7.43.0.2"
1503 },
1504 {
1505 "license": [
1506 {
1507 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1508 "shortName": "bsdOriginal",
1509 "spdxId": "BSD-4-Clause",
1510 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1511 }
1512 ],
1513 "name": "python2.7-py-bcrypt-0.4"
1514 },
1515 {
1516 "license": {
1517 "fullName": "GNU Lesser General Public License v3.0 or later",
1518 "shortName": "lgpl3Plus",
1519 "spdxId": "LGPL-3.0+",
1520 "url": "http://spdx.org/licenses/LGPL-3.0+.html"
1521 },
1522 "name": "python2.7-psycopg2-2.7.4"
1523 },
1524 {
1525 "license": {
1526 "fullName": "PostgreSQL License",
1527 "shortName": "postgresql",
1528 "spdxId": "PostgreSQL",
1529 "url": "http://spdx.org/licenses/PostgreSQL.html"
1530 },
1531 "name": "postgresql-9.6.10"
1532 },
1533 {
1534 "license": [
1535 {
1536 "fullName": "BSD-derived (http://www.repoze.org/LICENSE.txt)"
1537 }
1538 ],
1539 "name": "python2.7-peppercorn-0.5"
1540 },
1541 {
1542 "license": [
1543 {
1544 "fullName": "MIT License",
1545 "shortName": "mit",
1546 "spdxId": "MIT",
1547 "url": "http://spdx.org/licenses/MIT.html"
1548 }
1549 ],
1550 "name": "python2.7-pastescript-2.0.2"
1551 },
1552 {
1553 "license": [
1554 {
1555 "fullName": "Apache License 2.0",
1556 "shortName": "asl20",
1557 "spdxId": "Apache-2.0",
1558 "url": "http://spdx.org/licenses/Apache-2.0.html"
1559 }
1560 ],
1561 "name": "python2.7-packaging-15.2"
1562 },
1563 {
1564 "license": [
1565 {
1566 "fullName": "MIT License",
1567 "shortName": "mit",
1568 "spdxId": "MIT",
1569 "url": "http://spdx.org/licenses/MIT.html"
1570 }
1571 ],
1572 "name": "python2.7-objgraph-3.1.1"
1573 },
1574 {
1575 "license": [
1576 {
1577 "fullName": "MIT License",
1578 "shortName": "mit",
1579 "spdxId": "MIT",
1580 "url": "http://spdx.org/licenses/MIT.html"
1581 }
1582 ],
1583 "name": "python2.7-graphviz-0.9"
1584 },
1585 {
1586 "license": [
1587 {
1588 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1589 "shortName": "bsdOriginal",
1590 "spdxId": "BSD-4-Clause",
1591 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1592 }
1593 ],
1594 "name": "python2.7-pyotp-2.2.6"
1595 },
1596 {
1597 "license": [
1598 {
1599 "fullName": "MIT License",
1600 "shortName": "mit",
1601 "spdxId": "MIT",
1602 "url": "http://spdx.org/licenses/MIT.html"
1603 }
1604 ],
1605 "name": "python2.7-pymysql-0.8.1"
1606 },
1607 {
1608 "license": [
1609 {
1610 "fullName": "GNU General Public License v1.0 only",
1611 "shortName": "gpl1",
1612 "spdxId": "GPL-1.0",
1613 "url": "http://spdx.org/licenses/GPL-1.0.html"
1614 }
1615 ],
1616 "name": "python2.7-mysql-python-1.2.5"
1617 },
1618 {
1619 "license": {
1620 "fullName": "GNU Library General Public License v2.1 only",
1621 "shortName": "lgpl21",
1622 "spdxId": "LGPL-2.1",
1623 "url": "http://spdx.org/licenses/LGPL-2.1.html"
1624 },
1625 "name": "mariadb-connector-c-2.3.4"
1626 },
1627 {
1628 "license": [
1629 {
1630 "fullName": "Apache License 2.0",
1631 "shortName": "asl20",
1632 "spdxId": "Apache-2.0",
1633 "url": "http://spdx.org/licenses/Apache-2.0.html"
1634 }
1635 ],
1636 "name": "python2.7-msgpack-python-0.5.6"
1637 },
1638 {
1639 "license": [
1640 {
1641 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1642 "shortName": "bsdOriginal",
1643 "spdxId": "BSD-4-Clause",
1644 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1645 }
1646 ],
1647 "name": "python2.7-lxml-3.7.3"
1648 },
1649 {
1650 "license": [
1651 {
1652 "fullName": "MIT License",
1653 "shortName": "mit",
1654 "spdxId": "MIT",
1655 "url": "http://spdx.org/licenses/MIT.html"
1656 }
1657 ],
1658 "name": "python2.7-wheel-0.30.0"
1659 },
1660 {
1661 "license": [
1662 {
1663 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1664 "shortName": "bsdOriginal",
1665 "spdxId": "BSD-4-Clause",
1666 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1667 }
1668 ],
1669 "name": "python2.7-kombu-4.2.0"
1670 },
1671 {
1672 "license": [
1673 {
1674 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1675 "shortName": "bsdOriginal",
1676 "spdxId": "BSD-4-Clause",
1677 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1678 }
1679 ],
1680 "name": "python2.7-amqp-2.3.1"
1681 },
1682 {
1683 "license": [
1684 {
1685 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1686 "shortName": "bsdOriginal",
1687 "spdxId": "BSD-4-Clause",
1688 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1689 }
1690 ],
1691 "name": "python2.7-vine-1.1.4"
1692 },
1693 {
1694 "license": [
1695 {
1696 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1697 "shortName": "bsdOriginal",
1698 "spdxId": "BSD-4-Clause",
1699 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1700 }
1701 ],
1702 "name": "python2.7-billiard-3.5.0.3"
1703 },
1704 {
1705 "license": [
1706 {
1707 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1708 "shortName": "bsdOriginal",
1709 "spdxId": "BSD-4-Clause",
1710 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1711 }
1712 ],
1713 "name": "python2.7-itsdangerous-0.24"
1714 },
1715 {
1716 "license": [
1717 {
1718 "fullName": "MIT License",
1719 "shortName": "mit",
1720 "spdxId": "MIT",
1721 "url": "http://spdx.org/licenses/MIT.html"
1722 }
1723 ],
1724 "name": "python2.7-iso8601-0.1.11"
1725 },
1726 {
1727 "license": [
1728 {
1729 "fullName": "Zope Public License 2.1",
1730 "shortName": "zpl21",
1731 "spdxId": "ZPL-2.1",
1732 "url": "http://spdx.org/licenses/ZPL-2.1.html"
1733 }
1734 ],
1735 "name": "python2.7-infrae.cache-1.0.1"
1736 },
1737 {
1738 "license": [
1739 {
1740 "fullName": "Python Software Foundation License version 2",
1741 "shortName": "psfl",
1742 "spdxId": "Python-2.0",
1743 "url": "http://spdx.org/licenses/Python-2.0.html"
1744 }
1745 ],
1746 "name": "python2.7-formencode-1.2.4"
1747 },
1748 {
1749 "license": [
1750 {
1751 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1752 "shortName": "bsdOriginal",
1753 "spdxId": "BSD-4-Clause",
1754 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1755 }
1756 ],
1757 "name": "python2.7-dogpile.core-0.4.1"
1758 },
1759 {
1760 "license": [
1761 {
1762 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1763 "shortName": "bsdOriginal",
1764 "spdxId": "BSD-4-Clause",
1765 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1766 }
1767 ],
1768 "name": "python2.7-dogpile.cache-0.6.6"
1769 },
1770 {
1771 "license": {
1772 "fullName": "BSD 2-clause \"Simplified\" License",
1773 "shortName": "bsd2",
1774 "spdxId": "BSD-2-Clause",
1775 "url": "http://spdx.org/licenses/BSD-2-Clause.html"
1776 },
1777 "name": "python2.7-docutils-0.14"
1778 },
1779 {
1780 "license": [
1781 {
1782 "fullName": "BSD-derived (http://www.repoze.org/LICENSE.txt)"
1783 }
1784 ],
1785 "name": "python2.7-deform-2.0.5"
1786 },
1787 {
1788 "license": {
1789 "fullName": "Repoze License",
1790 "url": "http://www.repoze.org/LICENSE.txt"
1791 },
1792 "name": "python2.7-colander-1.4"
1793 },
1794 {
1795 "license": [
1796 {
1797 "fullName": "BSD-like (http://repoze.org/license.html)"
1798 }
1799 ],
1800 "name": "python2.7-chameleon-2.24"
1801 },
1802 {
1803 "license": [
1804 {
1805 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1806 "shortName": "bsdOriginal",
1807 "spdxId": "BSD-4-Clause",
1808 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1809 }
1810 ],
1811 "name": "python2.7-cssselect-1.0.3"
1812 },
1813 {
1814 "license": [
1815 {
1816 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1817 "shortName": "bsdOriginal",
1818 "spdxId": "BSD-4-Clause",
1819 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1820 }
1821 ],
1822 "name": "python2.7-configobj-5.0.6"
1823 },
1824 {
1825 "license": [
1826 {
1827 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1828 "shortName": "bsdOriginal",
1829 "spdxId": "BSD-4-Clause",
1830 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1831 }
1832 ],
1833 "name": "python2.7-channelstream-0.5.2"
1834 },
1835 {
1836 "license": [
1837 {
1838 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1839 "shortName": "bsdOriginal",
1840 "spdxId": "BSD-4-Clause",
1841 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1842 }
1843 ],
1844 "name": "python2.7-ws4py-0.5.1"
1845 },
1846 {
1847 "license": [
1848 {
1849 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1850 "shortName": "bsdOriginal",
1851 "spdxId": "BSD-4-Clause",
1852 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1853 }
1854 ],
1855 "name": "python2.7-celery-4.1.1"
1856 },
1857 {
1858 "license": [
1859 {
1860 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
1861 "shortName": "bsdOriginal",
1862 "spdxId": "BSD-4-Clause",
1863 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
1864 }
1865 ],
1866 "name": "python2.7-babel-1.3"
1867 },
1868 {
1869 "license": [
1870 {
1871 "fullName": "MIT License",
1872 "shortName": "mit",
1873 "spdxId": "MIT",
1874 "url": "http://spdx.org/licenses/MIT.html"
1875 }
1876 ],
1877 "name": "python2.7-authomatic-0.1.0.post1"
1878 },
1879 {
1880 "license": [
1881 {
1882 "fullName": "MIT License",
1883 "shortName": "mit",
1884 "spdxId": "MIT",
1885 "url": "http://spdx.org/licenses/MIT.html"
1886 }
1887 ],
1888 "name": "node-grunt-cli-1.2.0"
1889 },
1890 {
1891 "license": [
1892 {
1893 "fullName": "MIT License",
1894 "shortName": "mit",
1895 "spdxId": "MIT",
1896 "url": "http://spdx.org/licenses/MIT.html"
1897 }
1898 ],
1899 "name": "node-bower-1.8.4"
1900 },
1901 {
1902 "license": [
1903 {
1904 "fullName": "MIT License",
1905 "shortName": "mit",
1906 "spdxId": "MIT",
1907 "url": "http://spdx.org/licenses/MIT.html"
1908 }
1909 ],
1910 "name": "python2.7-rhodecode-testdata-0.10.0"
1911 }
1912 ]
@@ -1,503 +1,504 b''
1 1
2 2 // tables.less
3 3 // For use in RhodeCode application tables;
4 4 // see style guide documentation for guidelines.
5 5
6 6 // TABLES
7 7
8 8 .rctable,
9 9 table.rctable,
10 10 table.dataTable {
11 11 clear:both;
12 12 width: 100%;
13 13 margin: 0 auto @padding;
14 14 padding: 0;
15 15 vertical-align: baseline;
16 16 line-height:1.5em;
17 17 border: none;
18 18 outline: none;
19 19 border-collapse: collapse;
20 20 border-spacing: 0;
21 21 color: @grey2;
22 22
23 23 b {
24 24 font-weight: normal;
25 25 }
26 26
27 27 em {
28 28 font-weight: bold;
29 29 font-style: normal;
30 30 }
31 31
32 32 th,
33 33 td {
34 34 height: auto;
35 35 max-width: 20%;
36 36 padding: .65em 1em .65em 0;
37 37 vertical-align: middle;
38 38 border-bottom: @border-thickness solid @grey5;
39 39 white-space: normal;
40 40
41 41 &.td-radio,
42 42 &.td-checkbox {
43 43 padding-right: 0;
44 44 text-align: center;
45 45
46 46 input {
47 47 margin: 0 1em;
48 48 }
49 49 }
50 50
51 51 &.truncate-wrap {
52 52 white-space: nowrap !important;
53 53 }
54 54
55 55 pre {
56 56 margin: 0;
57 57 }
58 58
59 59 .show_more {
60 60 height: inherit;
61 61 }
62 62 }
63 63
64 64 .expired td {
65 65 background-color: @grey7;
66 66 }
67 67
68 68 .td-radio + .td-owner {
69 69 padding-left: 1em;
70 70 }
71 71
72 72
73 73 th {
74 74 text-align: left;
75 75 font-family: @text-semibold;
76 76 }
77 77
78 78 .hl {
79 79 td {
80 80 background-color: lighten(@alert4,25%);
81 81 }
82 82 }
83 83
84 84 // Special Data Cell Types
85 85 // See style guide for desciptions and examples.
86 86
87 87 td {
88 88
89 89 &.user {
90 90 padding-left: 1em;
91 91 }
92 92
93 93 &.td-rss {
94 94 width: 20px;
95 95 min-width: 0;
96 96 margin: 0;
97 97 }
98 98
99 99 &.quick_repo_menu {
100 100 width: 15px;
101 101 text-align: center;
102 102
103 103 &:hover {
104 104 background-color: @grey5;
105 105 }
106 106 }
107 107
108 108 &.td-hash {
109 109 min-width: 80px;
110 110 width: 200px;
111 111
112 112 .obsolete {
113 113 text-decoration: line-through;
114 114 color: lighten(@grey2,25%);
115 115 }
116 116 }
117 117
118 118 &.td-time {
119 119 width: 160px;
120 120 white-space: nowrap;
121 121 }
122 122
123 123 &.annotate{
124 124 padding-right: 0;
125 125
126 126 div.annotatediv{
127 127 margin: 0 0.7em;
128 128 }
129 129 }
130 130
131 131 &.tags-col {
132 132 padding-right: 0;
133 133 }
134 134
135 135 &.td-description {
136 136 min-width: 350px;
137 137
138 138 &.truncate, .truncate-wrap {
139 139 white-space: nowrap;
140 140 overflow: hidden;
141 141 text-overflow: ellipsis;
142 142 max-width: 450px;
143 143 }
144 144 }
145 145
146 146 &.td-componentname {
147 147 white-space: nowrap;
148 148 }
149 149
150 150 &.td-name {
151 151
152 152 }
153 153
154 154 &.td-journalaction {
155 155 min-width: 300px;
156 156
157 157 .journal_action_params {
158 158 // waiting for feedback
159 159 }
160 160 }
161 161
162 162 &.td-active {
163 163 padding-left: .65em;
164 164 }
165 165
166 166 &.td-url {
167 167 white-space: nowrap;
168 168 }
169 169
170 170 &.td-comments {
171 171 min-width: 3em;
172 172 }
173 173
174 174 &.td-buttons {
175 175 padding: .3em 0;
176 176 }
177 177
178 178 &.td-action {
179 179 // this is for the remove/delete/edit buttons
180 180 padding-right: 0;
181 181 min-width: 95px;
182 182 text-transform: capitalize;
183 183
184 184 i {
185 185 display: none;
186 186 }
187 187 }
188 188
189 189 // TODO: lisa: this needs to be cleaned up with the buttons
190 190 .grid_edit,
191 191 .grid_delete {
192 192 display: inline-block;
193 193 margin: 0 @padding/3 0 0;
194 194 font-family: @text-light;
195 195
196 196 i {
197 197 display: none;
198 198 }
199 199 }
200 200
201 201 .grid_edit + .grid_delete {
202 202 border-left: @border-thickness solid @grey5;
203 203 padding-left: @padding/2;
204 204 }
205 205
206 206 &.td-compare {
207 207
208 208 input {
209 209 margin-right: 1em;
210 210 }
211 211
212 212 .compare-radio-button {
213 213 margin: 0 1em 0 0;
214 214 }
215 215
216 216
217 217 }
218 218
219 219 &.td-tags {
220 220 padding: .5em 1em .5em 0;
221 221 width: 140px;
222 222
223 223 .tag {
224 224 margin: 1px;
225 225 float: left;
226 226 }
227 227 }
228 228
229 229 .icon-svn, .icon-hg, .icon-git {
230 230 font-size: 1.4em;
231 231 }
232 232
233 233 &.collapse_commit,
234 234 &.expand_commit {
235 235 padding-right: 0;
236 236 padding-left: 1em;
237 237 }
238 238 }
239 239
240 240 .perm_admin_row {
241 241 color: @grey4;
242 242 background-color: @grey6;
243 243 }
244 244
245 245 .noborder {
246 246 border: none;
247 247
248 248 td {
249 249 border: none;
250 250 }
251 251 }
252 252 }
253 253 .rctable.audit-log {
254 254 td {
255 255 vertical-align: top;
256 256 }
257 257 }
258 258
259 259 // TRUNCATING
260 260 // TODO: lisaq: should this possibly be moved out of tables.less?
261 261 // for truncated text
262 262 // used inside of table cells and in code block headers
263 263 .truncate-wrap {
264 264 white-space: nowrap !important;
265 265
266 266 //truncated text
267 267 .truncate {
268 268 max-width: 450px;
269 269 width: 300px;
270 270 overflow: hidden;
271 271 text-overflow: ellipsis;
272 272 -o-text-overflow: ellipsis;
273 273 -ms-text-overflow: ellipsis;
274 274
275 275 &.autoexpand {
276 276 width: 120px;
277 277 margin-right: 200px;
278 278 }
279 279 }
280 280 &:hover .truncate.autoexpand {
281 281 overflow: visible;
282 282 }
283 283
284 284 .tags-truncate {
285 285 width: 150px;
286 286 height: 22px;
287 287 overflow: hidden;
288 288
289 289 .tag {
290 290 display: inline-block;
291 291 }
292 292
293 293 &.truncate {
294 294 height: 22px;
295 295 max-height:2em;
296 296 width: 140px;
297 297 }
298 298 }
299 299 }
300 300
301 301 .apikeys_wrap {
302 302 margin-bottom: @padding;
303 303
304 304 table.rctable td:first-child {
305 305 width: 340px;
306 306 }
307 307 }
308 308
309 309
310 310
311 311 // SPECIAL CASES
312 312
313 313 // Repository Followers
314 314 table.rctable.followers_data {
315 315 width: 75%;
316 316 margin: 0;
317 317 }
318 318
319 319 // Repository List
320 320 // Group Members List
321 321 table.rctable.group_members,
322 322 table#repo_list_table {
323 323 min-width: 600px;
324 324 }
325 325
326 326 // Keyboard mappings
327 327 table.keyboard-mappings {
328 328 th {
329 329 text-align: left;
330 330 font-family: @text-semibold;
331 331 }
332 332 }
333 333
334 334 // Branches, Tags, and Bookmarks
335 335 #obj_list_table.dataTable {
336 336 td.td-time {
337 337 padding-right: 1em;
338 338 }
339 339 }
340 340
341 341 // User Admin
342 342 .rctable.useremails,
343 343 .rctable.account_emails {
344 344 .tag,
345 345 .btn {
346 346 float: right;
347 347 }
348 348 .btn { //to line up with tags
349 349 margin-right: 1.65em;
350 350 }
351 351 }
352 352
353 353 // User List
354 354 #user_list_table {
355 355
356 356 td.td-user {
357 357 min-width: 100px;
358 358 }
359 359 }
360 360
361 361 // Pull Request List Table
362 362 #pull_request_list_table.dataTable {
363 363
364 364 //TODO: lisa: This needs to be removed once the description is adjusted
365 365 // for using an expand_commit button (see issue 765)
366 366 td {
367 367 vertical-align: middle;
368 368 }
369 369 }
370 370
371 371 // Settings (no border)
372 372 table.rctable.dl-settings {
373 373 td {
374 374 border: none;
375 vertical-align: baseline;
375 376 }
376 377 }
377 378
378 379
379 380 // Statistics
380 381 table.trending_language_tbl {
381 382 width: 100%;
382 383 line-height: 1em;
383 384
384 385 td div {
385 386 overflow: visible;
386 387 }
387 388 }
388 389
389 390 .trending_language_tbl, .trending_language_tbl td {
390 391 border: 0;
391 392 margin: 0;
392 393 padding: 0;
393 394 background: transparent;
394 395 }
395 396
396 397 .trending_language_tbl, .trending_language_tbl tr {
397 398 border-spacing: 0 3px;
398 399 }
399 400
400 401 .trending_language {
401 402 position: relative;
402 403 width: 100%;
403 404 height: 19px;
404 405 overflow: hidden;
405 406 background-color: @grey6;
406 407
407 408 span, b{
408 409 position: absolute;
409 410 display: block;
410 411 height: 12px;
411 412 margin-bottom: 0px;
412 413 white-space: pre;
413 414 padding: floor(@basefontsize/4);
414 415 top: 0;
415 416 left: 0;
416 417 }
417 418
418 419 span{
419 420 color: @text-color;
420 421 z-index: 0;
421 422 min-width: 20px;
422 423 }
423 424
424 425 b {
425 426 z-index: 1;
426 427 overflow: hidden;
427 428 background-color: @rcblue;
428 429 color: #FFF;
429 430 text-decoration: none;
430 431 }
431 432
432 433 }
433 434
434 435 // Changesets
435 436 #changesets.rctable {
436 437
437 438 // td must be fixed height for graph
438 439 td {
439 440 height: 32px;
440 441 padding: 0 1em 0 0;
441 442 vertical-align: middle;
442 443 white-space: nowrap;
443 444
444 445 &.td-description {
445 446 white-space: normal;
446 447 }
447 448
448 449 &.expand_commit {
449 450 padding-right: 0;
450 451 }
451 452 }
452 453 }
453 454
454 455 // Compare
455 456 table.compare_view_commits {
456 457 margin-top: @space;
457 458
458 459 td.td-time {
459 460 padding-left: .5em;
460 461 }
461 462
462 463 // special case to not show hover actions on hidden indicator
463 464 tr.compare_select_hidden:hover {
464 465 cursor: inherit;
465 466
466 467 td {
467 468 background-color: inherit;
468 469 }
469 470 }
470 471
471 472 tr:hover {
472 473 cursor: pointer;
473 474
474 475 td {
475 476 background-color: lighten(@alert4,25%);
476 477 }
477 478 }
478 479
479 480
480 481 }
481 482
482 483 .file_history {
483 484 td.td-actions {
484 485 text-align: right;
485 486 }
486 487 }
487 488
488 489
489 490 // Gist List
490 491 #gist_list_table {
491 492 td {
492 493 vertical-align: middle;
493 494
494 495 div{
495 496 display: inline-block;
496 497 vertical-align: middle;
497 498 }
498 499
499 500 img{
500 501 vertical-align: middle;
501 502 }
502 503 }
503 504 }
@@ -1,33 +1,46 b''
1 <%def name="show_license(license_data)">
2 % if isinstance(license_data, dict):
3 <a href="${license_data.get('url', "#noUrl")}">${license_data.get('spdxId') or license_data.get('fullName')}</a>
4 % else:
5 ${license_data}
6 % endif
7 </%def>
8
1 9 <div class="panel panel-default">
2 10 <div class="panel-heading">
3 11 <h3 class="panel-title">${_('Licenses of Third Party Packages')}</h3>
4 12 </div>
5 13 <div class="panel-body">
6 14 <p>
7 15 RhodeCode Enterprise uses various third party packages, many of them
8 16 provided by the open source community.
9 17 </p>
10
11 18 % if c.opensource_licenses:
12 19 <table class="rctable dl-settings">
13 20 <thead>
14 21 <th>Product</th>
15 22 <th>License</th>
16 23 </thead>
17 %for product, licenses in c.opensource_licenses.items():
18 <tr>
19 <td>${product}</td>
20 <td>
21 ${h.literal(', '.join([
22 '<a href="%(link)s" title="%(name)s">%(name)s</a>' % {'link':link, 'name':name}
23 if link else name
24 for name,link in licenses.items()]))}
25 </td>
26 </tr>
27 %endfor
24 % for lib in c.opensource_licenses:
25 <tr>
26 <td>${lib["name"]}</td>
27 <td>
28 <ol>
29 % if isinstance(lib["license"], list):
30 % for license_data in lib["license"]:
31 <li>${show_license(license_data)}</li>
32 % endfor
33 % else:
34 <% license_data = lib["license"] %>
35 <li>${show_license(license_data)}</li>
36 % endif
37 </ol>
38 </td>
39 </tr>
40 % endfor
28 41 </table>
29 42 % endif
30 43 </div>
31 44 </div>
32 45
33 46
@@ -1,445 +1,449 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2018 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
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import json
22 22 import multiprocessing
23 23 import os
24 24
25 25 import mock
26 26 import py
27 27 import pytest
28 28
29 29 from rhodecode.lib import caching_query
30 30 from rhodecode.lib import utils
31 31 from rhodecode.lib.utils2 import md5
32 32 from rhodecode.model import settings
33 33 from rhodecode.model import db
34 34 from rhodecode.model import meta
35 35 from rhodecode.model.repo import RepoModel
36 36 from rhodecode.model.repo_group import RepoGroupModel
37 37 from rhodecode.model.scm import ScmModel
38 38 from rhodecode.model.settings import UiSetting, SettingsModel
39 39 from rhodecode.tests.fixture import Fixture
40 40
41 41
42 42 fixture = Fixture()
43 43
44 44
45 45 def extract_hooks(config):
46 46 """Return a dictionary with the hook entries of the given config."""
47 47 hooks = {}
48 48 config_items = config.serialize()
49 49 for section, name, value in config_items:
50 50 if section != 'hooks':
51 51 continue
52 52 hooks[name] = value
53 53
54 54 return hooks
55 55
56 56
57 57 def disable_hooks(request, hooks):
58 58 """Disables the given hooks from the UI settings."""
59 59 session = meta.Session()
60 60
61 61 model = SettingsModel()
62 62 for hook_key in hooks:
63 63 sett = model.get_ui_by_key(hook_key)
64 64 sett.ui_active = False
65 65 session.add(sett)
66 66
67 67 # Invalidate cache
68 68 ui_settings = session.query(db.RhodeCodeUi).options(
69 69 caching_query.FromCache('sql_cache_short', 'get_hg_ui_settings'))
70 70 ui_settings.invalidate()
71 71
72 72 ui_settings = session.query(db.RhodeCodeUi).options(
73 73 caching_query.FromCache('sql_cache_short', 'get_hook_settings'))
74 74 ui_settings.invalidate()
75 75
76 76 @request.addfinalizer
77 77 def rollback():
78 78 session.rollback()
79 79
80 80
81 81 HOOK_PRE_PUSH = db.RhodeCodeUi.HOOK_PRE_PUSH
82 82 HOOK_PRETX_PUSH = db.RhodeCodeUi.HOOK_PRETX_PUSH
83 83 HOOK_PUSH = db.RhodeCodeUi.HOOK_PUSH
84 84 HOOK_PRE_PULL = db.RhodeCodeUi.HOOK_PRE_PULL
85 85 HOOK_PULL = db.RhodeCodeUi.HOOK_PULL
86 86 HOOK_REPO_SIZE = db.RhodeCodeUi.HOOK_REPO_SIZE
87 87 HOOK_PUSH_KEY = db.RhodeCodeUi.HOOK_PUSH_KEY
88 88
89 89 HG_HOOKS = frozenset(
90 90 (HOOK_PRE_PULL, HOOK_PULL, HOOK_PRE_PUSH, HOOK_PRETX_PUSH, HOOK_PUSH,
91 91 HOOK_REPO_SIZE, HOOK_PUSH_KEY))
92 92
93 93
94 94 @pytest.mark.parametrize('disabled_hooks,expected_hooks', [
95 95 ([], HG_HOOKS),
96 96 (HG_HOOKS, []),
97 97
98 98 ([HOOK_PRE_PUSH, HOOK_PRETX_PUSH, HOOK_REPO_SIZE, HOOK_PUSH_KEY], [HOOK_PRE_PULL, HOOK_PULL, HOOK_PUSH]),
99 99
100 100 # When a pull/push hook is disabled, its pre-pull/push counterpart should
101 101 # be disabled too.
102 102 ([HOOK_PUSH], [HOOK_PRE_PULL, HOOK_PULL, HOOK_REPO_SIZE]),
103 103 ([HOOK_PULL], [HOOK_PRE_PUSH, HOOK_PRETX_PUSH, HOOK_PUSH, HOOK_REPO_SIZE,
104 104 HOOK_PUSH_KEY]),
105 105 ])
106 106 def test_make_db_config_hg_hooks(baseapp, request, disabled_hooks,
107 107 expected_hooks):
108 108 disable_hooks(request, disabled_hooks)
109 109
110 110 config = utils.make_db_config()
111 111 hooks = extract_hooks(config)
112 112
113 113 assert set(hooks.iterkeys()).intersection(HG_HOOKS) == set(expected_hooks)
114 114
115 115
116 116 @pytest.mark.parametrize('disabled_hooks,expected_hooks', [
117 117 ([], ['pull', 'push']),
118 118 ([HOOK_PUSH], ['pull']),
119 119 ([HOOK_PULL], ['push']),
120 120 ([HOOK_PULL, HOOK_PUSH], []),
121 121 ])
122 122 def test_get_enabled_hook_classes(disabled_hooks, expected_hooks):
123 123 hook_keys = (HOOK_PUSH, HOOK_PULL)
124 124 ui_settings = [
125 125 ('hooks', key, 'some value', key not in disabled_hooks)
126 126 for key in hook_keys]
127 127
128 128 result = utils.get_enabled_hook_classes(ui_settings)
129 129 assert sorted(result) == expected_hooks
130 130
131 131
132 132 def test_get_filesystem_repos_finds_repos(tmpdir, baseapp):
133 133 _stub_git_repo(tmpdir.ensure('repo', dir=True))
134 134 repos = list(utils.get_filesystem_repos(str(tmpdir)))
135 135 assert repos == [('repo', ('git', tmpdir.join('repo')))]
136 136
137 137
138 138 def test_get_filesystem_repos_skips_directories(tmpdir, baseapp):
139 139 tmpdir.ensure('not-a-repo', dir=True)
140 140 repos = list(utils.get_filesystem_repos(str(tmpdir)))
141 141 assert repos == []
142 142
143 143
144 144 def test_get_filesystem_repos_skips_directories_with_repos(tmpdir, baseapp):
145 145 _stub_git_repo(tmpdir.ensure('subdir/repo', dir=True))
146 146 repos = list(utils.get_filesystem_repos(str(tmpdir)))
147 147 assert repos == []
148 148
149 149
150 150 def test_get_filesystem_repos_finds_repos_in_subdirectories(tmpdir, baseapp):
151 151 _stub_git_repo(tmpdir.ensure('subdir/repo', dir=True))
152 152 repos = list(utils.get_filesystem_repos(str(tmpdir), recursive=True))
153 153 assert repos == [('subdir/repo', ('git', tmpdir.join('subdir', 'repo')))]
154 154
155 155
156 156 def test_get_filesystem_repos_skips_names_starting_with_dot(tmpdir):
157 157 _stub_git_repo(tmpdir.ensure('.repo', dir=True))
158 158 repos = list(utils.get_filesystem_repos(str(tmpdir)))
159 159 assert repos == []
160 160
161 161
162 162 def test_get_filesystem_repos_skips_files(tmpdir):
163 163 tmpdir.ensure('test-file')
164 164 repos = list(utils.get_filesystem_repos(str(tmpdir)))
165 165 assert repos == []
166 166
167 167
168 168 def test_get_filesystem_repos_skips_removed_repositories(tmpdir):
169 169 removed_repo_name = 'rm__00000000_000000_000000__.stub'
170 170 assert utils.REMOVED_REPO_PAT.match(removed_repo_name)
171 171 _stub_git_repo(tmpdir.ensure(removed_repo_name, dir=True))
172 172 repos = list(utils.get_filesystem_repos(str(tmpdir)))
173 173 assert repos == []
174 174
175 175
176 176 def _stub_git_repo(repo_path):
177 177 """
178 178 Make `repo_path` look like a Git repository.
179 179 """
180 180 repo_path.ensure('.git', dir=True)
181 181
182 182
183 183 @pytest.mark.parametrize('str_class', [str, unicode], ids=['str', 'unicode'])
184 184 def test_get_dirpaths_returns_all_paths(tmpdir, str_class):
185 185 tmpdir.ensure('test-file')
186 186 dirpaths = utils._get_dirpaths(str_class(tmpdir))
187 187 assert dirpaths == ['test-file']
188 188
189 189
190 190 def test_get_dirpaths_returns_all_paths_bytes(
191 191 tmpdir, platform_encodes_filenames):
192 192 if platform_encodes_filenames:
193 193 pytest.skip("This platform seems to encode filenames.")
194 194 tmpdir.ensure('repo-a-umlaut-\xe4')
195 195 dirpaths = utils._get_dirpaths(str(tmpdir))
196 196 assert dirpaths == ['repo-a-umlaut-\xe4']
197 197
198 198
199 199 def test_get_dirpaths_skips_paths_it_cannot_decode(
200 200 tmpdir, platform_encodes_filenames):
201 201 if platform_encodes_filenames:
202 202 pytest.skip("This platform seems to encode filenames.")
203 203 path_with_latin1 = 'repo-a-umlaut-\xe4'
204 204 tmpdir.ensure(path_with_latin1)
205 205 dirpaths = utils._get_dirpaths(unicode(tmpdir))
206 206 assert dirpaths == []
207 207
208 208
209 209 @pytest.fixture(scope='session')
210 210 def platform_encodes_filenames():
211 211 """
212 212 Boolean indicator if the current platform changes filename encodings.
213 213 """
214 214 path_with_latin1 = 'repo-a-umlaut-\xe4'
215 215 tmpdir = py.path.local.mkdtemp()
216 216 tmpdir.ensure(path_with_latin1)
217 217 read_path = tmpdir.listdir()[0].basename
218 218 tmpdir.remove()
219 219 return path_with_latin1 != read_path
220 220
221 221
222 222
223 223
224 224 def test_repo2db_mapper_groups(repo_groups):
225 225 session = meta.Session()
226 226 zombie_group, parent_group, child_group = repo_groups
227 227 zombie_path = os.path.join(
228 228 RepoGroupModel().repos_path, zombie_group.full_path)
229 229 os.rmdir(zombie_path)
230 230
231 231 # Avoid removing test repos when calling repo2db_mapper
232 232 repo_list = {
233 233 repo.repo_name: 'test' for repo in session.query(db.Repository).all()
234 234 }
235 235 utils.repo2db_mapper(repo_list, remove_obsolete=True)
236 236
237 237 groups_in_db = session.query(db.RepoGroup).all()
238 238 assert child_group in groups_in_db
239 239 assert parent_group in groups_in_db
240 240 assert zombie_path not in groups_in_db
241 241
242 242
243 243 def test_repo2db_mapper_enables_largefiles(backend):
244 244 repo = backend.create_repo()
245 245 repo_list = {repo.repo_name: 'test'}
246 246 with mock.patch('rhodecode.model.db.Repository.scm_instance') as scm_mock:
247 247 utils.repo2db_mapper(repo_list, remove_obsolete=False)
248 248 _, kwargs = scm_mock.call_args
249 249 assert kwargs['config'].get('extensions', 'largefiles') == ''
250 250
251 251
252 252 @pytest.mark.backends("git", "svn")
253 253 def test_repo2db_mapper_installs_hooks_for_repos_in_db(backend):
254 254 repo = backend.create_repo()
255 255 repo_list = {repo.repo_name: 'test'}
256 256 utils.repo2db_mapper(repo_list, remove_obsolete=False)
257 257
258 258
259 259 @pytest.mark.backends("git", "svn")
260 260 def test_repo2db_mapper_installs_hooks_for_newly_added_repos(backend):
261 261 repo = backend.create_repo()
262 262 RepoModel().delete(repo, fs_remove=False)
263 263 meta.Session().commit()
264 264 repo_list = {repo.repo_name: repo.scm_instance()}
265 265 utils.repo2db_mapper(repo_list, remove_obsolete=False)
266 266
267 267
268 268 class TestPasswordChanged(object):
269 269 def setup(self):
270 270 self.session = {
271 271 'rhodecode_user': {
272 272 'password': '0cc175b9c0f1b6a831c399e269772661'
273 273 }
274 274 }
275 275 self.auth_user = mock.Mock()
276 276 self.auth_user.userame = 'test'
277 277 self.auth_user.password = 'abc123'
278 278
279 279 def test_returns_false_for_default_user(self):
280 280 self.auth_user.username = db.User.DEFAULT_USER
281 281 result = utils.password_changed(self.auth_user, self.session)
282 282 assert result is False
283 283
284 284 def test_returns_false_if_password_was_not_changed(self):
285 285 self.session['rhodecode_user']['password'] = md5(
286 286 self.auth_user.password)
287 287 result = utils.password_changed(self.auth_user, self.session)
288 288 assert result is False
289 289
290 290 def test_returns_true_if_password_was_changed(self):
291 291 result = utils.password_changed(self.auth_user, self.session)
292 292 assert result is True
293 293
294 294 def test_returns_true_if_auth_user_password_is_empty(self):
295 295 self.auth_user.password = None
296 296 result = utils.password_changed(self.auth_user, self.session)
297 297 assert result is True
298 298
299 299 def test_returns_true_if_session_password_is_empty(self):
300 300 self.session['rhodecode_user'].pop('password')
301 301 result = utils.password_changed(self.auth_user, self.session)
302 302 assert result is True
303 303
304 304
305 class TestReadOpensourceLicenses(object):
305 class TestReadOpenSourceLicenses(object):
306 306 def test_success(self):
307 307 utils._license_cache = None
308 308 json_data = '''
309 309 {
310 310 "python2.7-pytest-2.7.1": {"UNKNOWN": null},
311 311 "python2.7-Markdown-2.6.2": {
312 312 "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause"
313 313 }
314 314 }
315 315 '''
316 316 resource_string_patch = mock.patch.object(
317 317 utils.pkg_resources, 'resource_string', return_value=json_data)
318 318 with resource_string_patch:
319 319 result = utils.read_opensource_licenses()
320 320 assert result == json.loads(json_data)
321 321
322 322 def test_caching(self):
323 323 utils._license_cache = {
324 324 "python2.7-pytest-2.7.1": {
325 325 "UNKNOWN": None
326 326 },
327 327 "python2.7-Markdown-2.6.2": {
328 328 "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause"
329 329 }
330 330 }
331 331 resource_patch = mock.patch.object(
332 332 utils.pkg_resources, 'resource_string', side_effect=Exception)
333 333 json_patch = mock.patch.object(
334 334 utils.json, 'loads', side_effect=Exception)
335 335
336 336 with resource_patch as resource_mock, json_patch as json_mock:
337 337 result = utils.read_opensource_licenses()
338 338
339 339 assert resource_mock.call_count == 0
340 340 assert json_mock.call_count == 0
341 341 assert result == utils._license_cache
342 342
343 343 def test_licenses_file_contains_no_unknown_licenses(self):
344 344 utils._license_cache = None
345 345 result = utils.read_opensource_licenses()
346 license_names = []
347 for licenses in result.values():
348 license_names.extend(licenses.keys())
349 assert 'UNKNOWN' not in license_names
346
347 for license_data in result:
348 if isinstance(license_data["license"], list):
349 for lic_data in license_data["license"]:
350 assert 'UNKNOWN' not in lic_data["fullName"]
351 else:
352 full_name = license_data.get("fullName") or license_data
353 assert 'UNKNOWN' not in full_name
350 354
351 355
352 356 class TestMakeDbConfig(object):
353 357 def test_data_from_config_data_from_db_returned(self):
354 358 test_data = [
355 359 ('section1', 'option1', 'value1'),
356 360 ('section2', 'option2', 'value2'),
357 361 ('section3', 'option3', 'value3'),
358 362 ]
359 363 with mock.patch.object(utils, 'config_data_from_db') as config_mock:
360 364 config_mock.return_value = test_data
361 365 kwargs = {'clear_session': False, 'repo': 'test_repo'}
362 366 result = utils.make_db_config(**kwargs)
363 367 config_mock.assert_called_once_with(**kwargs)
364 368 for section, option, expected_value in test_data:
365 369 value = result.get(section, option)
366 370 assert value == expected_value
367 371
368 372
369 373 class TestConfigDataFromDb(object):
370 374 def test_config_data_from_db_returns_active_settings(self):
371 375 test_data = [
372 376 UiSetting('section1', 'option1', 'value1', True),
373 377 UiSetting('section2', 'option2', 'value2', True),
374 378 UiSetting('section3', 'option3', 'value3', False),
375 379 ]
376 380 repo_name = 'test_repo'
377 381
378 382 model_patch = mock.patch.object(settings, 'VcsSettingsModel')
379 383 hooks_patch = mock.patch.object(
380 384 utils, 'get_enabled_hook_classes',
381 385 return_value=['pull', 'push', 'repo_size'])
382 386 with model_patch as model_mock, hooks_patch:
383 387 instance_mock = mock.Mock()
384 388 model_mock.return_value = instance_mock
385 389 instance_mock.get_ui_settings.return_value = test_data
386 390 result = utils.config_data_from_db(
387 391 clear_session=False, repo=repo_name)
388 392
389 393 self._assert_repo_name_passed(model_mock, repo_name)
390 394
391 395 expected_result = [
392 396 ('section1', 'option1', 'value1'),
393 397 ('section2', 'option2', 'value2'),
394 398 ]
395 399 assert result == expected_result
396 400
397 401 def _assert_repo_name_passed(self, model_mock, repo_name):
398 402 assert model_mock.call_count == 1
399 403 call_args, call_kwargs = model_mock.call_args
400 404 assert call_kwargs['repo'] == repo_name
401 405
402 406
403 407 class TestIsDirWritable(object):
404 408 def test_returns_false_when_not_writable(self):
405 409 with mock.patch('__builtin__.open', side_effect=OSError):
406 410 assert not utils._is_dir_writable('/stub-path')
407 411
408 412 def test_returns_true_when_writable(self, tmpdir):
409 413 assert utils._is_dir_writable(str(tmpdir))
410 414
411 415 def test_is_safe_against_race_conditions(self, tmpdir):
412 416 workers = multiprocessing.Pool()
413 417 directories = [str(tmpdir)] * 10
414 418 workers.map(utils._is_dir_writable, directories)
415 419
416 420
417 421 class TestGetEnabledHooks(object):
418 422 def test_only_active_hooks_are_enabled(self):
419 423 ui_settings = [
420 424 UiSetting('hooks', db.RhodeCodeUi.HOOK_PUSH, 'value', True),
421 425 UiSetting('hooks', db.RhodeCodeUi.HOOK_REPO_SIZE, 'value', True),
422 426 UiSetting('hooks', db.RhodeCodeUi.HOOK_PULL, 'value', False)
423 427 ]
424 428 result = utils.get_enabled_hook_classes(ui_settings)
425 429 assert result == ['push', 'repo_size']
426 430
427 431 def test_all_hooks_are_enabled(self):
428 432 ui_settings = [
429 433 UiSetting('hooks', db.RhodeCodeUi.HOOK_PUSH, 'value', True),
430 434 UiSetting('hooks', db.RhodeCodeUi.HOOK_REPO_SIZE, 'value', True),
431 435 UiSetting('hooks', db.RhodeCodeUi.HOOK_PULL, 'value', True)
432 436 ]
433 437 result = utils.get_enabled_hook_classes(ui_settings)
434 438 assert result == ['push', 'repo_size', 'pull']
435 439
436 440 def test_no_enabled_hooks_when_no_hook_settings_are_found(self):
437 441 ui_settings = []
438 442 result = utils.get_enabled_hook_classes(ui_settings)
439 443 assert result == []
440 444
441 445
442 446 def test_obfuscate_url_pw():
443 447 from rhodecode.lib.utils2 import obfuscate_url_pw
444 448 engine = u'/home/repos/malmö'
445 449 assert obfuscate_url_pw(engine) No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now