##// END OF EJS Templates
api: update pull method with possible specification of the url
marcink -
r2563:6477cf12 default
parent child Browse files
Show More
@@ -1,51 +1,53 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22
22
23 import pytest
23 import pytest
24
24
25 from rhodecode.tests import TESTS_TMP_PATH
25 from rhodecode.tests import TESTS_TMP_PATH
26 from rhodecode.api.tests.utils import (
26 from rhodecode.api.tests.utils import (
27 build_data, api_call, assert_ok, assert_error)
27 build_data, api_call, assert_ok, assert_error)
28
28
29
29
30 @pytest.mark.usefixtures("testuser_api", "app")
30 @pytest.mark.usefixtures("testuser_api", "app")
31 class TestPull(object):
31 class TestPull(object):
32 @pytest.mark.backends("git", "hg")
32 @pytest.mark.backends("git", "hg")
33 def test_api_pull(self, backend):
33 def test_api_pull(self, backend):
34 r = backend.create_repo()
34 r = backend.create_repo()
35 repo_name = r.repo_name
35 repo_name = r.repo_name
36 r.clone_uri = os.path.join(TESTS_TMP_PATH, backend.repo_name)
36 clone_uri = os.path.join(TESTS_TMP_PATH, backend.repo_name)
37 r.clone_uri = clone_uri
37
38
38 id_, params = build_data(self.apikey, 'pull', repoid=repo_name,)
39 id_, params = build_data(self.apikey, 'pull', repoid=repo_name,)
39 response = api_call(self.app, params)
40 response = api_call(self.app, params)
40
41 msg = 'Pulled from url `%s` on repo `%s`' % (
41 expected = {'msg': 'Pulled from `%s`' % (repo_name,),
42 clone_uri, repo_name)
43 expected = {'msg': msg,
42 'repository': repo_name}
44 'repository': repo_name}
43 assert_ok(id_, expected, given=response.body)
45 assert_ok(id_, expected, given=response.body)
44
46
45 def test_api_pull_error(self, backend):
47 def test_api_pull_error(self, backend):
46 id_, params = build_data(
48 id_, params = build_data(
47 self.apikey, 'pull', repoid=backend.repo_name)
49 self.apikey, 'pull', repoid=backend.repo_name)
48 response = api_call(self.app, params)
50 response = api_call(self.app, params)
49
51
50 expected = 'Unable to pull changes from `%s`' % (backend.repo_name,)
52 expected = 'Unable to pull changes from `None`'
51 assert_error(id_, expected, given=response.body)
53 assert_error(id_, expected, given=response.body)
@@ -1,192 +1,195 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import mock
21 import mock
22 import pytest
22 import pytest
23
23
24 from rhodecode.model.repo import RepoModel
24 from rhodecode.model.repo import RepoModel
25 from rhodecode.tests import TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN
25 from rhodecode.tests import TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN
26 from rhodecode.api.tests.utils import (
26 from rhodecode.api.tests.utils import (
27 build_data, api_call, assert_error, assert_ok, crash, jsonify)
27 build_data, api_call, assert_error, assert_ok, crash, jsonify)
28 from rhodecode.tests.fixture import Fixture
28 from rhodecode.tests.fixture import Fixture
29 from rhodecode.tests.plugin import http_host_stub, http_host_only_stub
29 from rhodecode.tests.plugin import http_host_stub, http_host_only_stub
30
30
31 fixture = Fixture()
31 fixture = Fixture()
32
32
33 UPDATE_REPO_NAME = 'api_update_me'
33 UPDATE_REPO_NAME = 'api_update_me'
34
34
35
35
36 class SAME_AS_UPDATES(object):
36 class SAME_AS_UPDATES(object):
37 """ Constant used for tests below """
37 """ Constant used for tests below """
38
38
39
39
40 @pytest.mark.usefixtures("testuser_api", "app")
40 @pytest.mark.usefixtures("testuser_api", "app")
41 class TestApiUpdateRepo(object):
41 class TestApiUpdateRepo(object):
42
42
43 @pytest.mark.parametrize("updates, expected", [
43 @pytest.mark.parametrize("updates, expected", [
44 ({'owner': TEST_USER_REGULAR_LOGIN},
44 ({'owner': TEST_USER_REGULAR_LOGIN},
45 SAME_AS_UPDATES),
45 SAME_AS_UPDATES),
46
46
47 ({'description': 'new description'},
47 ({'description': 'new description'},
48 SAME_AS_UPDATES),
48 SAME_AS_UPDATES),
49
49
50 ({'clone_uri': 'http://foo.com/repo'},
50 ({'clone_uri': 'http://foo.com/repo'},
51 SAME_AS_UPDATES),
51 SAME_AS_UPDATES),
52
52
53 ({'clone_uri': None},
53 ({'clone_uri': None},
54 {'clone_uri': ''}),
54 {'clone_uri': ''}),
55
55
56 ({'clone_uri': ''},
56 ({'clone_uri': ''},
57 {'clone_uri': ''}),
57 {'clone_uri': ''}),
58
58
59 ({'push_uri': ''},
60 {'push_uri': ''}),
61
59 ({'landing_rev': 'rev:tip'},
62 ({'landing_rev': 'rev:tip'},
60 {'landing_rev': ['rev', 'tip']}),
63 {'landing_rev': ['rev', 'tip']}),
61
64
62 ({'enable_statistics': True},
65 ({'enable_statistics': True},
63 SAME_AS_UPDATES),
66 SAME_AS_UPDATES),
64
67
65 ({'enable_locking': True},
68 ({'enable_locking': True},
66 SAME_AS_UPDATES),
69 SAME_AS_UPDATES),
67
70
68 ({'enable_downloads': True},
71 ({'enable_downloads': True},
69 SAME_AS_UPDATES),
72 SAME_AS_UPDATES),
70
73
71 ({'repo_name': 'new_repo_name'},
74 ({'repo_name': 'new_repo_name'},
72 {
75 {
73 'repo_name': 'new_repo_name',
76 'repo_name': 'new_repo_name',
74 'url': 'http://{}/new_repo_name'.format(http_host_only_stub())
77 'url': 'http://{}/new_repo_name'.format(http_host_only_stub())
75 }),
78 }),
76
79
77 ({'repo_name': 'test_group_for_update/{}'.format(UPDATE_REPO_NAME),
80 ({'repo_name': 'test_group_for_update/{}'.format(UPDATE_REPO_NAME),
78 '_group': 'test_group_for_update'},
81 '_group': 'test_group_for_update'},
79 {
82 {
80 'repo_name': 'test_group_for_update/{}'.format(UPDATE_REPO_NAME),
83 'repo_name': 'test_group_for_update/{}'.format(UPDATE_REPO_NAME),
81 'url': 'http://{}/test_group_for_update/{}'.format(
84 'url': 'http://{}/test_group_for_update/{}'.format(
82 http_host_only_stub(), UPDATE_REPO_NAME)
85 http_host_only_stub(), UPDATE_REPO_NAME)
83 }),
86 }),
84 ])
87 ])
85 def test_api_update_repo(self, updates, expected, backend):
88 def test_api_update_repo(self, updates, expected, backend):
86 repo_name = UPDATE_REPO_NAME
89 repo_name = UPDATE_REPO_NAME
87 repo = fixture.create_repo(repo_name, repo_type=backend.alias)
90 repo = fixture.create_repo(repo_name, repo_type=backend.alias)
88 if updates.get('_group'):
91 if updates.get('_group'):
89 fixture.create_repo_group(updates['_group'])
92 fixture.create_repo_group(updates['_group'])
90
93
91 expected_api_data = repo.get_api_data(include_secrets=True)
94 expected_api_data = repo.get_api_data(include_secrets=True)
92 if expected is SAME_AS_UPDATES:
95 if expected is SAME_AS_UPDATES:
93 expected_api_data.update(updates)
96 expected_api_data.update(updates)
94 else:
97 else:
95 expected_api_data.update(expected)
98 expected_api_data.update(expected)
96
99
97 id_, params = build_data(
100 id_, params = build_data(
98 self.apikey, 'update_repo', repoid=repo_name, **updates)
101 self.apikey, 'update_repo', repoid=repo_name, **updates)
99 response = api_call(self.app, params)
102 response = api_call(self.app, params)
100
103
101 if updates.get('repo_name'):
104 if updates.get('repo_name'):
102 repo_name = updates['repo_name']
105 repo_name = updates['repo_name']
103
106
104 try:
107 try:
105 expected = {
108 expected = {
106 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo_name),
109 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo_name),
107 'repository': jsonify(expected_api_data)
110 'repository': jsonify(expected_api_data)
108 }
111 }
109 assert_ok(id_, expected, given=response.body)
112 assert_ok(id_, expected, given=response.body)
110 finally:
113 finally:
111 fixture.destroy_repo(repo_name)
114 fixture.destroy_repo(repo_name)
112 if updates.get('_group'):
115 if updates.get('_group'):
113 fixture.destroy_repo_group(updates['_group'])
116 fixture.destroy_repo_group(updates['_group'])
114
117
115 def test_api_update_repo_fork_of_field(self, backend):
118 def test_api_update_repo_fork_of_field(self, backend):
116 master_repo = backend.create_repo()
119 master_repo = backend.create_repo()
117 repo = backend.create_repo()
120 repo = backend.create_repo()
118 updates = {
121 updates = {
119 'fork_of': master_repo.repo_name,
122 'fork_of': master_repo.repo_name,
120 'fork_of_id': master_repo.repo_id
123 'fork_of_id': master_repo.repo_id
121 }
124 }
122 expected_api_data = repo.get_api_data(include_secrets=True)
125 expected_api_data = repo.get_api_data(include_secrets=True)
123 expected_api_data.update(updates)
126 expected_api_data.update(updates)
124
127
125 id_, params = build_data(
128 id_, params = build_data(
126 self.apikey, 'update_repo', repoid=repo.repo_name, **updates)
129 self.apikey, 'update_repo', repoid=repo.repo_name, **updates)
127 response = api_call(self.app, params)
130 response = api_call(self.app, params)
128 expected = {
131 expected = {
129 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo.repo_name),
132 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo.repo_name),
130 'repository': jsonify(expected_api_data)
133 'repository': jsonify(expected_api_data)
131 }
134 }
132 assert_ok(id_, expected, given=response.body)
135 assert_ok(id_, expected, given=response.body)
133 result = response.json['result']['repository']
136 result = response.json['result']['repository']
134 assert result['fork_of'] == master_repo.repo_name
137 assert result['fork_of'] == master_repo.repo_name
135 assert result['fork_of_id'] == master_repo.repo_id
138 assert result['fork_of_id'] == master_repo.repo_id
136
139
137 def test_api_update_repo_fork_of_not_found(self, backend):
140 def test_api_update_repo_fork_of_not_found(self, backend):
138 master_repo_name = 'fake-parent-repo'
141 master_repo_name = 'fake-parent-repo'
139 repo = backend.create_repo()
142 repo = backend.create_repo()
140 updates = {
143 updates = {
141 'fork_of': master_repo_name
144 'fork_of': master_repo_name
142 }
145 }
143 id_, params = build_data(
146 id_, params = build_data(
144 self.apikey, 'update_repo', repoid=repo.repo_name, **updates)
147 self.apikey, 'update_repo', repoid=repo.repo_name, **updates)
145 response = api_call(self.app, params)
148 response = api_call(self.app, params)
146 expected = {
149 expected = {
147 'repo_fork_of': 'Fork with id `{}` does not exists'.format(
150 'repo_fork_of': 'Fork with id `{}` does not exists'.format(
148 master_repo_name)}
151 master_repo_name)}
149 assert_error(id_, expected, given=response.body)
152 assert_error(id_, expected, given=response.body)
150
153
151 def test_api_update_repo_with_repo_group_not_existing(self):
154 def test_api_update_repo_with_repo_group_not_existing(self):
152 repo_name = 'admin_owned'
155 repo_name = 'admin_owned'
153 fake_repo_group = 'test_group_for_update'
156 fake_repo_group = 'test_group_for_update'
154 fixture.create_repo(repo_name)
157 fixture.create_repo(repo_name)
155 updates = {'repo_name': '{}/{}'.format(fake_repo_group, repo_name)}
158 updates = {'repo_name': '{}/{}'.format(fake_repo_group, repo_name)}
156 id_, params = build_data(
159 id_, params = build_data(
157 self.apikey, 'update_repo', repoid=repo_name, **updates)
160 self.apikey, 'update_repo', repoid=repo_name, **updates)
158 response = api_call(self.app, params)
161 response = api_call(self.app, params)
159 try:
162 try:
160 expected = {
163 expected = {
161 'repo_group': 'Repository group `{}` does not exist'.format(fake_repo_group)
164 'repo_group': 'Repository group `{}` does not exist'.format(fake_repo_group)
162 }
165 }
163 assert_error(id_, expected, given=response.body)
166 assert_error(id_, expected, given=response.body)
164 finally:
167 finally:
165 fixture.destroy_repo(repo_name)
168 fixture.destroy_repo(repo_name)
166
169
167 def test_api_update_repo_regular_user_not_allowed(self):
170 def test_api_update_repo_regular_user_not_allowed(self):
168 repo_name = 'admin_owned'
171 repo_name = 'admin_owned'
169 fixture.create_repo(repo_name)
172 fixture.create_repo(repo_name)
170 updates = {'active': False}
173 updates = {'active': False}
171 id_, params = build_data(
174 id_, params = build_data(
172 self.apikey_regular, 'update_repo', repoid=repo_name, **updates)
175 self.apikey_regular, 'update_repo', repoid=repo_name, **updates)
173 response = api_call(self.app, params)
176 response = api_call(self.app, params)
174 try:
177 try:
175 expected = 'repository `%s` does not exist' % (repo_name,)
178 expected = 'repository `%s` does not exist' % (repo_name,)
176 assert_error(id_, expected, given=response.body)
179 assert_error(id_, expected, given=response.body)
177 finally:
180 finally:
178 fixture.destroy_repo(repo_name)
181 fixture.destroy_repo(repo_name)
179
182
180 @mock.patch.object(RepoModel, 'update', crash)
183 @mock.patch.object(RepoModel, 'update', crash)
181 def test_api_update_repo_exception_occurred(self, backend):
184 def test_api_update_repo_exception_occurred(self, backend):
182 repo_name = UPDATE_REPO_NAME
185 repo_name = UPDATE_REPO_NAME
183 fixture.create_repo(repo_name, repo_type=backend.alias)
186 fixture.create_repo(repo_name, repo_type=backend.alias)
184 id_, params = build_data(
187 id_, params = build_data(
185 self.apikey, 'update_repo', repoid=repo_name,
188 self.apikey, 'update_repo', repoid=repo_name,
186 owner=TEST_USER_ADMIN_LOGIN,)
189 owner=TEST_USER_ADMIN_LOGIN,)
187 response = api_call(self.app, params)
190 response = api_call(self.app, params)
188 try:
191 try:
189 expected = 'failed to update repo `%s`' % (repo_name,)
192 expected = 'failed to update repo `%s`' % (repo_name,)
190 assert_error(id_, expected, given=response.body)
193 assert_error(id_, expected, given=response.body)
191 finally:
194 finally:
192 fixture.destroy_repo(repo_name)
195 fixture.destroy_repo(repo_name)
@@ -1,2050 +1,2060 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2018 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22 import time
22 import time
23
23
24 import rhodecode
24 import rhodecode
25 from rhodecode.api import (
25 from rhodecode.api import (
26 jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError)
26 jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError)
27 from rhodecode.api.utils import (
27 from rhodecode.api.utils import (
28 has_superadmin_permission, Optional, OAttr, get_repo_or_error,
28 has_superadmin_permission, Optional, OAttr, get_repo_or_error,
29 get_user_group_or_error, get_user_or_error, validate_repo_permissions,
29 get_user_group_or_error, get_user_or_error, validate_repo_permissions,
30 get_perm_or_error, parse_args, get_origin, build_commit_data,
30 get_perm_or_error, parse_args, get_origin, build_commit_data,
31 validate_set_owner_permissions)
31 validate_set_owner_permissions)
32 from rhodecode.lib import audit_logger
32 from rhodecode.lib import audit_logger
33 from rhodecode.lib import repo_maintenance
33 from rhodecode.lib import repo_maintenance
34 from rhodecode.lib.auth import HasPermissionAnyApi, HasUserGroupPermissionAnyApi
34 from rhodecode.lib.auth import HasPermissionAnyApi, HasUserGroupPermissionAnyApi
35 from rhodecode.lib.celerylib.utils import get_task_id
35 from rhodecode.lib.celerylib.utils import get_task_id
36 from rhodecode.lib.utils2 import str2bool, time_to_datetime
36 from rhodecode.lib.utils2 import str2bool, time_to_datetime
37 from rhodecode.lib.ext_json import json
37 from rhodecode.lib.ext_json import json
38 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
38 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
39 from rhodecode.model.changeset_status import ChangesetStatusModel
39 from rhodecode.model.changeset_status import ChangesetStatusModel
40 from rhodecode.model.comment import CommentsModel
40 from rhodecode.model.comment import CommentsModel
41 from rhodecode.model.db import (
41 from rhodecode.model.db import (
42 Session, ChangesetStatus, RepositoryField, Repository, RepoGroup,
42 Session, ChangesetStatus, RepositoryField, Repository, RepoGroup,
43 ChangesetComment)
43 ChangesetComment)
44 from rhodecode.model.repo import RepoModel
44 from rhodecode.model.repo import RepoModel
45 from rhodecode.model.scm import ScmModel, RepoList
45 from rhodecode.model.scm import ScmModel, RepoList
46 from rhodecode.model.settings import SettingsModel, VcsSettingsModel
46 from rhodecode.model.settings import SettingsModel, VcsSettingsModel
47 from rhodecode.model import validation_schema
47 from rhodecode.model import validation_schema
48 from rhodecode.model.validation_schema.schemas import repo_schema
48 from rhodecode.model.validation_schema.schemas import repo_schema
49
49
50 log = logging.getLogger(__name__)
50 log = logging.getLogger(__name__)
51
51
52
52
53 @jsonrpc_method()
53 @jsonrpc_method()
54 def get_repo(request, apiuser, repoid, cache=Optional(True)):
54 def get_repo(request, apiuser, repoid, cache=Optional(True)):
55 """
55 """
56 Gets an existing repository by its name or repository_id.
56 Gets an existing repository by its name or repository_id.
57
57
58 The members section so the output returns users groups or users
58 The members section so the output returns users groups or users
59 associated with that repository.
59 associated with that repository.
60
60
61 This command can only be run using an |authtoken| with admin rights,
61 This command can only be run using an |authtoken| with admin rights,
62 or users with at least read rights to the |repo|.
62 or users with at least read rights to the |repo|.
63
63
64 :param apiuser: This is filled automatically from the |authtoken|.
64 :param apiuser: This is filled automatically from the |authtoken|.
65 :type apiuser: AuthUser
65 :type apiuser: AuthUser
66 :param repoid: The repository name or repository id.
66 :param repoid: The repository name or repository id.
67 :type repoid: str or int
67 :type repoid: str or int
68 :param cache: use the cached value for last changeset
68 :param cache: use the cached value for last changeset
69 :type: cache: Optional(bool)
69 :type: cache: Optional(bool)
70
70
71 Example output:
71 Example output:
72
72
73 .. code-block:: bash
73 .. code-block:: bash
74
74
75 {
75 {
76 "error": null,
76 "error": null,
77 "id": <repo_id>,
77 "id": <repo_id>,
78 "result": {
78 "result": {
79 "clone_uri": null,
79 "clone_uri": null,
80 "created_on": "timestamp",
80 "created_on": "timestamp",
81 "description": "repo description",
81 "description": "repo description",
82 "enable_downloads": false,
82 "enable_downloads": false,
83 "enable_locking": false,
83 "enable_locking": false,
84 "enable_statistics": false,
84 "enable_statistics": false,
85 "followers": [
85 "followers": [
86 {
86 {
87 "active": true,
87 "active": true,
88 "admin": false,
88 "admin": false,
89 "api_key": "****************************************",
89 "api_key": "****************************************",
90 "api_keys": [
90 "api_keys": [
91 "****************************************"
91 "****************************************"
92 ],
92 ],
93 "email": "user@example.com",
93 "email": "user@example.com",
94 "emails": [
94 "emails": [
95 "user@example.com"
95 "user@example.com"
96 ],
96 ],
97 "extern_name": "rhodecode",
97 "extern_name": "rhodecode",
98 "extern_type": "rhodecode",
98 "extern_type": "rhodecode",
99 "firstname": "username",
99 "firstname": "username",
100 "ip_addresses": [],
100 "ip_addresses": [],
101 "language": null,
101 "language": null,
102 "last_login": "2015-09-16T17:16:35.854",
102 "last_login": "2015-09-16T17:16:35.854",
103 "lastname": "surname",
103 "lastname": "surname",
104 "user_id": <user_id>,
104 "user_id": <user_id>,
105 "username": "name"
105 "username": "name"
106 }
106 }
107 ],
107 ],
108 "fork_of": "parent-repo",
108 "fork_of": "parent-repo",
109 "landing_rev": [
109 "landing_rev": [
110 "rev",
110 "rev",
111 "tip"
111 "tip"
112 ],
112 ],
113 "last_changeset": {
113 "last_changeset": {
114 "author": "User <user@example.com>",
114 "author": "User <user@example.com>",
115 "branch": "default",
115 "branch": "default",
116 "date": "timestamp",
116 "date": "timestamp",
117 "message": "last commit message",
117 "message": "last commit message",
118 "parents": [
118 "parents": [
119 {
119 {
120 "raw_id": "commit-id"
120 "raw_id": "commit-id"
121 }
121 }
122 ],
122 ],
123 "raw_id": "commit-id",
123 "raw_id": "commit-id",
124 "revision": <revision number>,
124 "revision": <revision number>,
125 "short_id": "short id"
125 "short_id": "short id"
126 },
126 },
127 "lock_reason": null,
127 "lock_reason": null,
128 "locked_by": null,
128 "locked_by": null,
129 "locked_date": null,
129 "locked_date": null,
130 "owner": "owner-name",
130 "owner": "owner-name",
131 "permissions": [
131 "permissions": [
132 {
132 {
133 "name": "super-admin-name",
133 "name": "super-admin-name",
134 "origin": "super-admin",
134 "origin": "super-admin",
135 "permission": "repository.admin",
135 "permission": "repository.admin",
136 "type": "user"
136 "type": "user"
137 },
137 },
138 {
138 {
139 "name": "owner-name",
139 "name": "owner-name",
140 "origin": "owner",
140 "origin": "owner",
141 "permission": "repository.admin",
141 "permission": "repository.admin",
142 "type": "user"
142 "type": "user"
143 },
143 },
144 {
144 {
145 "name": "user-group-name",
145 "name": "user-group-name",
146 "origin": "permission",
146 "origin": "permission",
147 "permission": "repository.write",
147 "permission": "repository.write",
148 "type": "user_group"
148 "type": "user_group"
149 }
149 }
150 ],
150 ],
151 "private": true,
151 "private": true,
152 "repo_id": 676,
152 "repo_id": 676,
153 "repo_name": "user-group/repo-name",
153 "repo_name": "user-group/repo-name",
154 "repo_type": "hg"
154 "repo_type": "hg"
155 }
155 }
156 }
156 }
157 """
157 """
158
158
159 repo = get_repo_or_error(repoid)
159 repo = get_repo_or_error(repoid)
160 cache = Optional.extract(cache)
160 cache = Optional.extract(cache)
161
161
162 include_secrets = False
162 include_secrets = False
163 if has_superadmin_permission(apiuser):
163 if has_superadmin_permission(apiuser):
164 include_secrets = True
164 include_secrets = True
165 else:
165 else:
166 # check if we have at least read permission for this repo !
166 # check if we have at least read permission for this repo !
167 _perms = (
167 _perms = (
168 'repository.admin', 'repository.write', 'repository.read',)
168 'repository.admin', 'repository.write', 'repository.read',)
169 validate_repo_permissions(apiuser, repoid, repo, _perms)
169 validate_repo_permissions(apiuser, repoid, repo, _perms)
170
170
171 permissions = []
171 permissions = []
172 for _user in repo.permissions():
172 for _user in repo.permissions():
173 user_data = {
173 user_data = {
174 'name': _user.username,
174 'name': _user.username,
175 'permission': _user.permission,
175 'permission': _user.permission,
176 'origin': get_origin(_user),
176 'origin': get_origin(_user),
177 'type': "user",
177 'type': "user",
178 }
178 }
179 permissions.append(user_data)
179 permissions.append(user_data)
180
180
181 for _user_group in repo.permission_user_groups():
181 for _user_group in repo.permission_user_groups():
182 user_group_data = {
182 user_group_data = {
183 'name': _user_group.users_group_name,
183 'name': _user_group.users_group_name,
184 'permission': _user_group.permission,
184 'permission': _user_group.permission,
185 'origin': get_origin(_user_group),
185 'origin': get_origin(_user_group),
186 'type': "user_group",
186 'type': "user_group",
187 }
187 }
188 permissions.append(user_group_data)
188 permissions.append(user_group_data)
189
189
190 following_users = [
190 following_users = [
191 user.user.get_api_data(include_secrets=include_secrets)
191 user.user.get_api_data(include_secrets=include_secrets)
192 for user in repo.followers]
192 for user in repo.followers]
193
193
194 if not cache:
194 if not cache:
195 repo.update_commit_cache()
195 repo.update_commit_cache()
196 data = repo.get_api_data(include_secrets=include_secrets)
196 data = repo.get_api_data(include_secrets=include_secrets)
197 data['permissions'] = permissions
197 data['permissions'] = permissions
198 data['followers'] = following_users
198 data['followers'] = following_users
199 return data
199 return data
200
200
201
201
202 @jsonrpc_method()
202 @jsonrpc_method()
203 def get_repos(request, apiuser, root=Optional(None), traverse=Optional(True)):
203 def get_repos(request, apiuser, root=Optional(None), traverse=Optional(True)):
204 """
204 """
205 Lists all existing repositories.
205 Lists all existing repositories.
206
206
207 This command can only be run using an |authtoken| with admin rights,
207 This command can only be run using an |authtoken| with admin rights,
208 or users with at least read rights to |repos|.
208 or users with at least read rights to |repos|.
209
209
210 :param apiuser: This is filled automatically from the |authtoken|.
210 :param apiuser: This is filled automatically from the |authtoken|.
211 :type apiuser: AuthUser
211 :type apiuser: AuthUser
212 :param root: specify root repository group to fetch repositories.
212 :param root: specify root repository group to fetch repositories.
213 filters the returned repositories to be members of given root group.
213 filters the returned repositories to be members of given root group.
214 :type root: Optional(None)
214 :type root: Optional(None)
215 :param traverse: traverse given root into subrepositories. With this flag
215 :param traverse: traverse given root into subrepositories. With this flag
216 set to False, it will only return top-level repositories from `root`.
216 set to False, it will only return top-level repositories from `root`.
217 if root is empty it will return just top-level repositories.
217 if root is empty it will return just top-level repositories.
218 :type traverse: Optional(True)
218 :type traverse: Optional(True)
219
219
220
220
221 Example output:
221 Example output:
222
222
223 .. code-block:: bash
223 .. code-block:: bash
224
224
225 id : <id_given_in_input>
225 id : <id_given_in_input>
226 result: [
226 result: [
227 {
227 {
228 "repo_id" : "<repo_id>",
228 "repo_id" : "<repo_id>",
229 "repo_name" : "<reponame>"
229 "repo_name" : "<reponame>"
230 "repo_type" : "<repo_type>",
230 "repo_type" : "<repo_type>",
231 "clone_uri" : "<clone_uri>",
231 "clone_uri" : "<clone_uri>",
232 "private": : "<bool>",
232 "private": : "<bool>",
233 "created_on" : "<datetimecreated>",
233 "created_on" : "<datetimecreated>",
234 "description" : "<description>",
234 "description" : "<description>",
235 "landing_rev": "<landing_rev>",
235 "landing_rev": "<landing_rev>",
236 "owner": "<repo_owner>",
236 "owner": "<repo_owner>",
237 "fork_of": "<name_of_fork_parent>",
237 "fork_of": "<name_of_fork_parent>",
238 "enable_downloads": "<bool>",
238 "enable_downloads": "<bool>",
239 "enable_locking": "<bool>",
239 "enable_locking": "<bool>",
240 "enable_statistics": "<bool>",
240 "enable_statistics": "<bool>",
241 },
241 },
242 ...
242 ...
243 ]
243 ]
244 error: null
244 error: null
245 """
245 """
246
246
247 include_secrets = has_superadmin_permission(apiuser)
247 include_secrets = has_superadmin_permission(apiuser)
248 _perms = ('repository.read', 'repository.write', 'repository.admin',)
248 _perms = ('repository.read', 'repository.write', 'repository.admin',)
249 extras = {'user': apiuser}
249 extras = {'user': apiuser}
250
250
251 root = Optional.extract(root)
251 root = Optional.extract(root)
252 traverse = Optional.extract(traverse, binary=True)
252 traverse = Optional.extract(traverse, binary=True)
253
253
254 if root:
254 if root:
255 # verify parent existance, if it's empty return an error
255 # verify parent existance, if it's empty return an error
256 parent = RepoGroup.get_by_group_name(root)
256 parent = RepoGroup.get_by_group_name(root)
257 if not parent:
257 if not parent:
258 raise JSONRPCError(
258 raise JSONRPCError(
259 'Root repository group `{}` does not exist'.format(root))
259 'Root repository group `{}` does not exist'.format(root))
260
260
261 if traverse:
261 if traverse:
262 repos = RepoModel().get_repos_for_root(root=root, traverse=traverse)
262 repos = RepoModel().get_repos_for_root(root=root, traverse=traverse)
263 else:
263 else:
264 repos = RepoModel().get_repos_for_root(root=parent)
264 repos = RepoModel().get_repos_for_root(root=parent)
265 else:
265 else:
266 if traverse:
266 if traverse:
267 repos = RepoModel().get_all()
267 repos = RepoModel().get_all()
268 else:
268 else:
269 # return just top-level
269 # return just top-level
270 repos = RepoModel().get_repos_for_root(root=None)
270 repos = RepoModel().get_repos_for_root(root=None)
271
271
272 repo_list = RepoList(repos, perm_set=_perms, extra_kwargs=extras)
272 repo_list = RepoList(repos, perm_set=_perms, extra_kwargs=extras)
273 return [repo.get_api_data(include_secrets=include_secrets)
273 return [repo.get_api_data(include_secrets=include_secrets)
274 for repo in repo_list]
274 for repo in repo_list]
275
275
276
276
277 @jsonrpc_method()
277 @jsonrpc_method()
278 def get_repo_changeset(request, apiuser, repoid, revision,
278 def get_repo_changeset(request, apiuser, repoid, revision,
279 details=Optional('basic')):
279 details=Optional('basic')):
280 """
280 """
281 Returns information about a changeset.
281 Returns information about a changeset.
282
282
283 Additionally parameters define the amount of details returned by
283 Additionally parameters define the amount of details returned by
284 this function.
284 this function.
285
285
286 This command can only be run using an |authtoken| with admin rights,
286 This command can only be run using an |authtoken| with admin rights,
287 or users with at least read rights to the |repo|.
287 or users with at least read rights to the |repo|.
288
288
289 :param apiuser: This is filled automatically from the |authtoken|.
289 :param apiuser: This is filled automatically from the |authtoken|.
290 :type apiuser: AuthUser
290 :type apiuser: AuthUser
291 :param repoid: The repository name or repository id
291 :param repoid: The repository name or repository id
292 :type repoid: str or int
292 :type repoid: str or int
293 :param revision: revision for which listing should be done
293 :param revision: revision for which listing should be done
294 :type revision: str
294 :type revision: str
295 :param details: details can be 'basic|extended|full' full gives diff
295 :param details: details can be 'basic|extended|full' full gives diff
296 info details like the diff itself, and number of changed files etc.
296 info details like the diff itself, and number of changed files etc.
297 :type details: Optional(str)
297 :type details: Optional(str)
298
298
299 """
299 """
300 repo = get_repo_or_error(repoid)
300 repo = get_repo_or_error(repoid)
301 if not has_superadmin_permission(apiuser):
301 if not has_superadmin_permission(apiuser):
302 _perms = (
302 _perms = (
303 'repository.admin', 'repository.write', 'repository.read',)
303 'repository.admin', 'repository.write', 'repository.read',)
304 validate_repo_permissions(apiuser, repoid, repo, _perms)
304 validate_repo_permissions(apiuser, repoid, repo, _perms)
305
305
306 changes_details = Optional.extract(details)
306 changes_details = Optional.extract(details)
307 _changes_details_types = ['basic', 'extended', 'full']
307 _changes_details_types = ['basic', 'extended', 'full']
308 if changes_details not in _changes_details_types:
308 if changes_details not in _changes_details_types:
309 raise JSONRPCError(
309 raise JSONRPCError(
310 'ret_type must be one of %s' % (
310 'ret_type must be one of %s' % (
311 ','.join(_changes_details_types)))
311 ','.join(_changes_details_types)))
312
312
313 pre_load = ['author', 'branch', 'date', 'message', 'parents',
313 pre_load = ['author', 'branch', 'date', 'message', 'parents',
314 'status', '_commit', '_file_paths']
314 'status', '_commit', '_file_paths']
315
315
316 try:
316 try:
317 cs = repo.get_commit(commit_id=revision, pre_load=pre_load)
317 cs = repo.get_commit(commit_id=revision, pre_load=pre_load)
318 except TypeError as e:
318 except TypeError as e:
319 raise JSONRPCError(e.message)
319 raise JSONRPCError(e.message)
320 _cs_json = cs.__json__()
320 _cs_json = cs.__json__()
321 _cs_json['diff'] = build_commit_data(cs, changes_details)
321 _cs_json['diff'] = build_commit_data(cs, changes_details)
322 if changes_details == 'full':
322 if changes_details == 'full':
323 _cs_json['refs'] = cs._get_refs()
323 _cs_json['refs'] = cs._get_refs()
324 return _cs_json
324 return _cs_json
325
325
326
326
327 @jsonrpc_method()
327 @jsonrpc_method()
328 def get_repo_changesets(request, apiuser, repoid, start_rev, limit,
328 def get_repo_changesets(request, apiuser, repoid, start_rev, limit,
329 details=Optional('basic')):
329 details=Optional('basic')):
330 """
330 """
331 Returns a set of commits limited by the number starting
331 Returns a set of commits limited by the number starting
332 from the `start_rev` option.
332 from the `start_rev` option.
333
333
334 Additional parameters define the amount of details returned by this
334 Additional parameters define the amount of details returned by this
335 function.
335 function.
336
336
337 This command can only be run using an |authtoken| with admin rights,
337 This command can only be run using an |authtoken| with admin rights,
338 or users with at least read rights to |repos|.
338 or users with at least read rights to |repos|.
339
339
340 :param apiuser: This is filled automatically from the |authtoken|.
340 :param apiuser: This is filled automatically from the |authtoken|.
341 :type apiuser: AuthUser
341 :type apiuser: AuthUser
342 :param repoid: The repository name or repository ID.
342 :param repoid: The repository name or repository ID.
343 :type repoid: str or int
343 :type repoid: str or int
344 :param start_rev: The starting revision from where to get changesets.
344 :param start_rev: The starting revision from where to get changesets.
345 :type start_rev: str
345 :type start_rev: str
346 :param limit: Limit the number of commits to this amount
346 :param limit: Limit the number of commits to this amount
347 :type limit: str or int
347 :type limit: str or int
348 :param details: Set the level of detail returned. Valid option are:
348 :param details: Set the level of detail returned. Valid option are:
349 ``basic``, ``extended`` and ``full``.
349 ``basic``, ``extended`` and ``full``.
350 :type details: Optional(str)
350 :type details: Optional(str)
351
351
352 .. note::
352 .. note::
353
353
354 Setting the parameter `details` to the value ``full`` is extensive
354 Setting the parameter `details` to the value ``full`` is extensive
355 and returns details like the diff itself, and the number
355 and returns details like the diff itself, and the number
356 of changed files.
356 of changed files.
357
357
358 """
358 """
359 repo = get_repo_or_error(repoid)
359 repo = get_repo_or_error(repoid)
360 if not has_superadmin_permission(apiuser):
360 if not has_superadmin_permission(apiuser):
361 _perms = (
361 _perms = (
362 'repository.admin', 'repository.write', 'repository.read',)
362 'repository.admin', 'repository.write', 'repository.read',)
363 validate_repo_permissions(apiuser, repoid, repo, _perms)
363 validate_repo_permissions(apiuser, repoid, repo, _perms)
364
364
365 changes_details = Optional.extract(details)
365 changes_details = Optional.extract(details)
366 _changes_details_types = ['basic', 'extended', 'full']
366 _changes_details_types = ['basic', 'extended', 'full']
367 if changes_details not in _changes_details_types:
367 if changes_details not in _changes_details_types:
368 raise JSONRPCError(
368 raise JSONRPCError(
369 'ret_type must be one of %s' % (
369 'ret_type must be one of %s' % (
370 ','.join(_changes_details_types)))
370 ','.join(_changes_details_types)))
371
371
372 limit = int(limit)
372 limit = int(limit)
373 pre_load = ['author', 'branch', 'date', 'message', 'parents',
373 pre_load = ['author', 'branch', 'date', 'message', 'parents',
374 'status', '_commit', '_file_paths']
374 'status', '_commit', '_file_paths']
375
375
376 vcs_repo = repo.scm_instance()
376 vcs_repo = repo.scm_instance()
377 # SVN needs a special case to distinguish its index and commit id
377 # SVN needs a special case to distinguish its index and commit id
378 if vcs_repo and vcs_repo.alias == 'svn' and (start_rev == '0'):
378 if vcs_repo and vcs_repo.alias == 'svn' and (start_rev == '0'):
379 start_rev = vcs_repo.commit_ids[0]
379 start_rev = vcs_repo.commit_ids[0]
380
380
381 try:
381 try:
382 commits = vcs_repo.get_commits(
382 commits = vcs_repo.get_commits(
383 start_id=start_rev, pre_load=pre_load)
383 start_id=start_rev, pre_load=pre_load)
384 except TypeError as e:
384 except TypeError as e:
385 raise JSONRPCError(e.message)
385 raise JSONRPCError(e.message)
386 except Exception:
386 except Exception:
387 log.exception('Fetching of commits failed')
387 log.exception('Fetching of commits failed')
388 raise JSONRPCError('Error occurred during commit fetching')
388 raise JSONRPCError('Error occurred during commit fetching')
389
389
390 ret = []
390 ret = []
391 for cnt, commit in enumerate(commits):
391 for cnt, commit in enumerate(commits):
392 if cnt >= limit != -1:
392 if cnt >= limit != -1:
393 break
393 break
394 _cs_json = commit.__json__()
394 _cs_json = commit.__json__()
395 _cs_json['diff'] = build_commit_data(commit, changes_details)
395 _cs_json['diff'] = build_commit_data(commit, changes_details)
396 if changes_details == 'full':
396 if changes_details == 'full':
397 _cs_json['refs'] = {
397 _cs_json['refs'] = {
398 'branches': [commit.branch],
398 'branches': [commit.branch],
399 'bookmarks': getattr(commit, 'bookmarks', []),
399 'bookmarks': getattr(commit, 'bookmarks', []),
400 'tags': commit.tags
400 'tags': commit.tags
401 }
401 }
402 ret.append(_cs_json)
402 ret.append(_cs_json)
403 return ret
403 return ret
404
404
405
405
406 @jsonrpc_method()
406 @jsonrpc_method()
407 def get_repo_nodes(request, apiuser, repoid, revision, root_path,
407 def get_repo_nodes(request, apiuser, repoid, revision, root_path,
408 ret_type=Optional('all'), details=Optional('basic'),
408 ret_type=Optional('all'), details=Optional('basic'),
409 max_file_bytes=Optional(None)):
409 max_file_bytes=Optional(None)):
410 """
410 """
411 Returns a list of nodes and children in a flat list for a given
411 Returns a list of nodes and children in a flat list for a given
412 path at given revision.
412 path at given revision.
413
413
414 It's possible to specify ret_type to show only `files` or `dirs`.
414 It's possible to specify ret_type to show only `files` or `dirs`.
415
415
416 This command can only be run using an |authtoken| with admin rights,
416 This command can only be run using an |authtoken| with admin rights,
417 or users with at least read rights to |repos|.
417 or users with at least read rights to |repos|.
418
418
419 :param apiuser: This is filled automatically from the |authtoken|.
419 :param apiuser: This is filled automatically from the |authtoken|.
420 :type apiuser: AuthUser
420 :type apiuser: AuthUser
421 :param repoid: The repository name or repository ID.
421 :param repoid: The repository name or repository ID.
422 :type repoid: str or int
422 :type repoid: str or int
423 :param revision: The revision for which listing should be done.
423 :param revision: The revision for which listing should be done.
424 :type revision: str
424 :type revision: str
425 :param root_path: The path from which to start displaying.
425 :param root_path: The path from which to start displaying.
426 :type root_path: str
426 :type root_path: str
427 :param ret_type: Set the return type. Valid options are
427 :param ret_type: Set the return type. Valid options are
428 ``all`` (default), ``files`` and ``dirs``.
428 ``all`` (default), ``files`` and ``dirs``.
429 :type ret_type: Optional(str)
429 :type ret_type: Optional(str)
430 :param details: Returns extended information about nodes, such as
430 :param details: Returns extended information about nodes, such as
431 md5, binary, and or content. The valid options are ``basic`` and
431 md5, binary, and or content. The valid options are ``basic`` and
432 ``full``.
432 ``full``.
433 :type details: Optional(str)
433 :type details: Optional(str)
434 :param max_file_bytes: Only return file content under this file size bytes
434 :param max_file_bytes: Only return file content under this file size bytes
435 :type details: Optional(int)
435 :type details: Optional(int)
436
436
437 Example output:
437 Example output:
438
438
439 .. code-block:: bash
439 .. code-block:: bash
440
440
441 id : <id_given_in_input>
441 id : <id_given_in_input>
442 result: [
442 result: [
443 {
443 {
444 "name" : "<name>"
444 "name" : "<name>"
445 "type" : "<type>",
445 "type" : "<type>",
446 "binary": "<true|false>" (only in extended mode)
446 "binary": "<true|false>" (only in extended mode)
447 "md5" : "<md5 of file content>" (only in extended mode)
447 "md5" : "<md5 of file content>" (only in extended mode)
448 },
448 },
449 ...
449 ...
450 ]
450 ]
451 error: null
451 error: null
452 """
452 """
453
453
454 repo = get_repo_or_error(repoid)
454 repo = get_repo_or_error(repoid)
455 if not has_superadmin_permission(apiuser):
455 if not has_superadmin_permission(apiuser):
456 _perms = (
456 _perms = (
457 'repository.admin', 'repository.write', 'repository.read',)
457 'repository.admin', 'repository.write', 'repository.read',)
458 validate_repo_permissions(apiuser, repoid, repo, _perms)
458 validate_repo_permissions(apiuser, repoid, repo, _perms)
459
459
460 ret_type = Optional.extract(ret_type)
460 ret_type = Optional.extract(ret_type)
461 details = Optional.extract(details)
461 details = Optional.extract(details)
462 _extended_types = ['basic', 'full']
462 _extended_types = ['basic', 'full']
463 if details not in _extended_types:
463 if details not in _extended_types:
464 raise JSONRPCError(
464 raise JSONRPCError(
465 'ret_type must be one of %s' % (','.join(_extended_types)))
465 'ret_type must be one of %s' % (','.join(_extended_types)))
466 extended_info = False
466 extended_info = False
467 content = False
467 content = False
468 if details == 'basic':
468 if details == 'basic':
469 extended_info = True
469 extended_info = True
470
470
471 if details == 'full':
471 if details == 'full':
472 extended_info = content = True
472 extended_info = content = True
473
473
474 _map = {}
474 _map = {}
475 try:
475 try:
476 # check if repo is not empty by any chance, skip quicker if it is.
476 # check if repo is not empty by any chance, skip quicker if it is.
477 _scm = repo.scm_instance()
477 _scm = repo.scm_instance()
478 if _scm.is_empty():
478 if _scm.is_empty():
479 return []
479 return []
480
480
481 _d, _f = ScmModel().get_nodes(
481 _d, _f = ScmModel().get_nodes(
482 repo, revision, root_path, flat=False,
482 repo, revision, root_path, flat=False,
483 extended_info=extended_info, content=content,
483 extended_info=extended_info, content=content,
484 max_file_bytes=max_file_bytes)
484 max_file_bytes=max_file_bytes)
485 _map = {
485 _map = {
486 'all': _d + _f,
486 'all': _d + _f,
487 'files': _f,
487 'files': _f,
488 'dirs': _d,
488 'dirs': _d,
489 }
489 }
490 return _map[ret_type]
490 return _map[ret_type]
491 except KeyError:
491 except KeyError:
492 raise JSONRPCError(
492 raise JSONRPCError(
493 'ret_type must be one of %s' % (','.join(sorted(_map.keys()))))
493 'ret_type must be one of %s' % (','.join(sorted(_map.keys()))))
494 except Exception:
494 except Exception:
495 log.exception("Exception occurred while trying to get repo nodes")
495 log.exception("Exception occurred while trying to get repo nodes")
496 raise JSONRPCError(
496 raise JSONRPCError(
497 'failed to get repo: `%s` nodes' % repo.repo_name
497 'failed to get repo: `%s` nodes' % repo.repo_name
498 )
498 )
499
499
500
500
501 @jsonrpc_method()
501 @jsonrpc_method()
502 def get_repo_refs(request, apiuser, repoid):
502 def get_repo_refs(request, apiuser, repoid):
503 """
503 """
504 Returns a dictionary of current references. It returns
504 Returns a dictionary of current references. It returns
505 bookmarks, branches, closed_branches, and tags for given repository
505 bookmarks, branches, closed_branches, and tags for given repository
506
506
507 It's possible to specify ret_type to show only `files` or `dirs`.
507 It's possible to specify ret_type to show only `files` or `dirs`.
508
508
509 This command can only be run using an |authtoken| with admin rights,
509 This command can only be run using an |authtoken| with admin rights,
510 or users with at least read rights to |repos|.
510 or users with at least read rights to |repos|.
511
511
512 :param apiuser: This is filled automatically from the |authtoken|.
512 :param apiuser: This is filled automatically from the |authtoken|.
513 :type apiuser: AuthUser
513 :type apiuser: AuthUser
514 :param repoid: The repository name or repository ID.
514 :param repoid: The repository name or repository ID.
515 :type repoid: str or int
515 :type repoid: str or int
516
516
517 Example output:
517 Example output:
518
518
519 .. code-block:: bash
519 .. code-block:: bash
520
520
521 id : <id_given_in_input>
521 id : <id_given_in_input>
522 "result": {
522 "result": {
523 "bookmarks": {
523 "bookmarks": {
524 "dev": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
524 "dev": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
525 "master": "367f590445081d8ec8c2ea0456e73ae1f1c3d6cf"
525 "master": "367f590445081d8ec8c2ea0456e73ae1f1c3d6cf"
526 },
526 },
527 "branches": {
527 "branches": {
528 "default": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
528 "default": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
529 "stable": "367f590445081d8ec8c2ea0456e73ae1f1c3d6cf"
529 "stable": "367f590445081d8ec8c2ea0456e73ae1f1c3d6cf"
530 },
530 },
531 "branches_closed": {},
531 "branches_closed": {},
532 "tags": {
532 "tags": {
533 "tip": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
533 "tip": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
534 "v4.4.0": "1232313f9e6adac5ce5399c2a891dc1e72b79022",
534 "v4.4.0": "1232313f9e6adac5ce5399c2a891dc1e72b79022",
535 "v4.4.1": "cbb9f1d329ae5768379cdec55a62ebdd546c4e27",
535 "v4.4.1": "cbb9f1d329ae5768379cdec55a62ebdd546c4e27",
536 "v4.4.2": "24ffe44a27fcd1c5b6936144e176b9f6dd2f3a17",
536 "v4.4.2": "24ffe44a27fcd1c5b6936144e176b9f6dd2f3a17",
537 }
537 }
538 }
538 }
539 error: null
539 error: null
540 """
540 """
541
541
542 repo = get_repo_or_error(repoid)
542 repo = get_repo_or_error(repoid)
543 if not has_superadmin_permission(apiuser):
543 if not has_superadmin_permission(apiuser):
544 _perms = ('repository.admin', 'repository.write', 'repository.read',)
544 _perms = ('repository.admin', 'repository.write', 'repository.read',)
545 validate_repo_permissions(apiuser, repoid, repo, _perms)
545 validate_repo_permissions(apiuser, repoid, repo, _perms)
546
546
547 try:
547 try:
548 # check if repo is not empty by any chance, skip quicker if it is.
548 # check if repo is not empty by any chance, skip quicker if it is.
549 vcs_instance = repo.scm_instance()
549 vcs_instance = repo.scm_instance()
550 refs = vcs_instance.refs()
550 refs = vcs_instance.refs()
551 return refs
551 return refs
552 except Exception:
552 except Exception:
553 log.exception("Exception occurred while trying to get repo refs")
553 log.exception("Exception occurred while trying to get repo refs")
554 raise JSONRPCError(
554 raise JSONRPCError(
555 'failed to get repo: `%s` references' % repo.repo_name
555 'failed to get repo: `%s` references' % repo.repo_name
556 )
556 )
557
557
558
558
559 @jsonrpc_method()
559 @jsonrpc_method()
560 def create_repo(
560 def create_repo(
561 request, apiuser, repo_name, repo_type,
561 request, apiuser, repo_name, repo_type,
562 owner=Optional(OAttr('apiuser')),
562 owner=Optional(OAttr('apiuser')),
563 description=Optional(''),
563 description=Optional(''),
564 private=Optional(False),
564 private=Optional(False),
565 clone_uri=Optional(None),
565 clone_uri=Optional(None),
566 push_uri=Optional(None),
566 push_uri=Optional(None),
567 landing_rev=Optional('rev:tip'),
567 landing_rev=Optional('rev:tip'),
568 enable_statistics=Optional(False),
568 enable_statistics=Optional(False),
569 enable_locking=Optional(False),
569 enable_locking=Optional(False),
570 enable_downloads=Optional(False),
570 enable_downloads=Optional(False),
571 copy_permissions=Optional(False)):
571 copy_permissions=Optional(False)):
572 """
572 """
573 Creates a repository.
573 Creates a repository.
574
574
575 * If the repository name contains "/", repository will be created inside
575 * If the repository name contains "/", repository will be created inside
576 a repository group or nested repository groups
576 a repository group or nested repository groups
577
577
578 For example "foo/bar/repo1" will create |repo| called "repo1" inside
578 For example "foo/bar/repo1" will create |repo| called "repo1" inside
579 group "foo/bar". You have to have permissions to access and write to
579 group "foo/bar". You have to have permissions to access and write to
580 the last repository group ("bar" in this example)
580 the last repository group ("bar" in this example)
581
581
582 This command can only be run using an |authtoken| with at least
582 This command can only be run using an |authtoken| with at least
583 permissions to create repositories, or write permissions to
583 permissions to create repositories, or write permissions to
584 parent repository groups.
584 parent repository groups.
585
585
586 :param apiuser: This is filled automatically from the |authtoken|.
586 :param apiuser: This is filled automatically from the |authtoken|.
587 :type apiuser: AuthUser
587 :type apiuser: AuthUser
588 :param repo_name: Set the repository name.
588 :param repo_name: Set the repository name.
589 :type repo_name: str
589 :type repo_name: str
590 :param repo_type: Set the repository type; 'hg','git', or 'svn'.
590 :param repo_type: Set the repository type; 'hg','git', or 'svn'.
591 :type repo_type: str
591 :type repo_type: str
592 :param owner: user_id or username
592 :param owner: user_id or username
593 :type owner: Optional(str)
593 :type owner: Optional(str)
594 :param description: Set the repository description.
594 :param description: Set the repository description.
595 :type description: Optional(str)
595 :type description: Optional(str)
596 :param private: set repository as private
596 :param private: set repository as private
597 :type private: bool
597 :type private: bool
598 :param clone_uri: set clone_uri
598 :param clone_uri: set clone_uri
599 :type clone_uri: str
599 :type clone_uri: str
600 :param push_uri: set push_uri
600 :param push_uri: set push_uri
601 :type push_uri: str
601 :type push_uri: str
602 :param landing_rev: <rev_type>:<rev>
602 :param landing_rev: <rev_type>:<rev>
603 :type landing_rev: str
603 :type landing_rev: str
604 :param enable_locking:
604 :param enable_locking:
605 :type enable_locking: bool
605 :type enable_locking: bool
606 :param enable_downloads:
606 :param enable_downloads:
607 :type enable_downloads: bool
607 :type enable_downloads: bool
608 :param enable_statistics:
608 :param enable_statistics:
609 :type enable_statistics: bool
609 :type enable_statistics: bool
610 :param copy_permissions: Copy permission from group in which the
610 :param copy_permissions: Copy permission from group in which the
611 repository is being created.
611 repository is being created.
612 :type copy_permissions: bool
612 :type copy_permissions: bool
613
613
614
614
615 Example output:
615 Example output:
616
616
617 .. code-block:: bash
617 .. code-block:: bash
618
618
619 id : <id_given_in_input>
619 id : <id_given_in_input>
620 result: {
620 result: {
621 "msg": "Created new repository `<reponame>`",
621 "msg": "Created new repository `<reponame>`",
622 "success": true,
622 "success": true,
623 "task": "<celery task id or None if done sync>"
623 "task": "<celery task id or None if done sync>"
624 }
624 }
625 error: null
625 error: null
626
626
627
627
628 Example error output:
628 Example error output:
629
629
630 .. code-block:: bash
630 .. code-block:: bash
631
631
632 id : <id_given_in_input>
632 id : <id_given_in_input>
633 result : null
633 result : null
634 error : {
634 error : {
635 'failed to create repository `<repo_name>`'
635 'failed to create repository `<repo_name>`'
636 }
636 }
637
637
638 """
638 """
639
639
640 owner = validate_set_owner_permissions(apiuser, owner)
640 owner = validate_set_owner_permissions(apiuser, owner)
641
641
642 description = Optional.extract(description)
642 description = Optional.extract(description)
643 copy_permissions = Optional.extract(copy_permissions)
643 copy_permissions = Optional.extract(copy_permissions)
644 clone_uri = Optional.extract(clone_uri)
644 clone_uri = Optional.extract(clone_uri)
645 push_uri = Optional.extract(push_uri)
645 push_uri = Optional.extract(push_uri)
646 landing_commit_ref = Optional.extract(landing_rev)
646 landing_commit_ref = Optional.extract(landing_rev)
647
647
648 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
648 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
649 if isinstance(private, Optional):
649 if isinstance(private, Optional):
650 private = defs.get('repo_private') or Optional.extract(private)
650 private = defs.get('repo_private') or Optional.extract(private)
651 if isinstance(repo_type, Optional):
651 if isinstance(repo_type, Optional):
652 repo_type = defs.get('repo_type')
652 repo_type = defs.get('repo_type')
653 if isinstance(enable_statistics, Optional):
653 if isinstance(enable_statistics, Optional):
654 enable_statistics = defs.get('repo_enable_statistics')
654 enable_statistics = defs.get('repo_enable_statistics')
655 if isinstance(enable_locking, Optional):
655 if isinstance(enable_locking, Optional):
656 enable_locking = defs.get('repo_enable_locking')
656 enable_locking = defs.get('repo_enable_locking')
657 if isinstance(enable_downloads, Optional):
657 if isinstance(enable_downloads, Optional):
658 enable_downloads = defs.get('repo_enable_downloads')
658 enable_downloads = defs.get('repo_enable_downloads')
659
659
660 schema = repo_schema.RepoSchema().bind(
660 schema = repo_schema.RepoSchema().bind(
661 repo_type_options=rhodecode.BACKENDS.keys(),
661 repo_type_options=rhodecode.BACKENDS.keys(),
662 # user caller
662 # user caller
663 user=apiuser)
663 user=apiuser)
664
664
665 try:
665 try:
666 schema_data = schema.deserialize(dict(
666 schema_data = schema.deserialize(dict(
667 repo_name=repo_name,
667 repo_name=repo_name,
668 repo_type=repo_type,
668 repo_type=repo_type,
669 repo_owner=owner.username,
669 repo_owner=owner.username,
670 repo_description=description,
670 repo_description=description,
671 repo_landing_commit_ref=landing_commit_ref,
671 repo_landing_commit_ref=landing_commit_ref,
672 repo_clone_uri=clone_uri,
672 repo_clone_uri=clone_uri,
673 repo_push_uri=push_uri,
673 repo_push_uri=push_uri,
674 repo_private=private,
674 repo_private=private,
675 repo_copy_permissions=copy_permissions,
675 repo_copy_permissions=copy_permissions,
676 repo_enable_statistics=enable_statistics,
676 repo_enable_statistics=enable_statistics,
677 repo_enable_downloads=enable_downloads,
677 repo_enable_downloads=enable_downloads,
678 repo_enable_locking=enable_locking))
678 repo_enable_locking=enable_locking))
679 except validation_schema.Invalid as err:
679 except validation_schema.Invalid as err:
680 raise JSONRPCValidationError(colander_exc=err)
680 raise JSONRPCValidationError(colander_exc=err)
681
681
682 try:
682 try:
683 data = {
683 data = {
684 'owner': owner,
684 'owner': owner,
685 'repo_name': schema_data['repo_group']['repo_name_without_group'],
685 'repo_name': schema_data['repo_group']['repo_name_without_group'],
686 'repo_name_full': schema_data['repo_name'],
686 'repo_name_full': schema_data['repo_name'],
687 'repo_group': schema_data['repo_group']['repo_group_id'],
687 'repo_group': schema_data['repo_group']['repo_group_id'],
688 'repo_type': schema_data['repo_type'],
688 'repo_type': schema_data['repo_type'],
689 'repo_description': schema_data['repo_description'],
689 'repo_description': schema_data['repo_description'],
690 'repo_private': schema_data['repo_private'],
690 'repo_private': schema_data['repo_private'],
691 'clone_uri': schema_data['repo_clone_uri'],
691 'clone_uri': schema_data['repo_clone_uri'],
692 'push_uri': schema_data['repo_push_uri'],
692 'push_uri': schema_data['repo_push_uri'],
693 'repo_landing_rev': schema_data['repo_landing_commit_ref'],
693 'repo_landing_rev': schema_data['repo_landing_commit_ref'],
694 'enable_statistics': schema_data['repo_enable_statistics'],
694 'enable_statistics': schema_data['repo_enable_statistics'],
695 'enable_locking': schema_data['repo_enable_locking'],
695 'enable_locking': schema_data['repo_enable_locking'],
696 'enable_downloads': schema_data['repo_enable_downloads'],
696 'enable_downloads': schema_data['repo_enable_downloads'],
697 'repo_copy_permissions': schema_data['repo_copy_permissions'],
697 'repo_copy_permissions': schema_data['repo_copy_permissions'],
698 }
698 }
699
699
700 task = RepoModel().create(form_data=data, cur_user=owner)
700 task = RepoModel().create(form_data=data, cur_user=owner)
701 task_id = get_task_id(task)
701 task_id = get_task_id(task)
702 # no commit, it's done in RepoModel, or async via celery
702 # no commit, it's done in RepoModel, or async via celery
703 return {
703 return {
704 'msg': "Created new repository `%s`" % (schema_data['repo_name'],),
704 'msg': "Created new repository `%s`" % (schema_data['repo_name'],),
705 'success': True, # cannot return the repo data here since fork
705 'success': True, # cannot return the repo data here since fork
706 # can be done async
706 # can be done async
707 'task': task_id
707 'task': task_id
708 }
708 }
709 except Exception:
709 except Exception:
710 log.exception(
710 log.exception(
711 u"Exception while trying to create the repository %s",
711 u"Exception while trying to create the repository %s",
712 schema_data['repo_name'])
712 schema_data['repo_name'])
713 raise JSONRPCError(
713 raise JSONRPCError(
714 'failed to create repository `%s`' % (schema_data['repo_name'],))
714 'failed to create repository `%s`' % (schema_data['repo_name'],))
715
715
716
716
717 @jsonrpc_method()
717 @jsonrpc_method()
718 def add_field_to_repo(request, apiuser, repoid, key, label=Optional(''),
718 def add_field_to_repo(request, apiuser, repoid, key, label=Optional(''),
719 description=Optional('')):
719 description=Optional('')):
720 """
720 """
721 Adds an extra field to a repository.
721 Adds an extra field to a repository.
722
722
723 This command can only be run using an |authtoken| with at least
723 This command can only be run using an |authtoken| with at least
724 write permissions to the |repo|.
724 write permissions to the |repo|.
725
725
726 :param apiuser: This is filled automatically from the |authtoken|.
726 :param apiuser: This is filled automatically from the |authtoken|.
727 :type apiuser: AuthUser
727 :type apiuser: AuthUser
728 :param repoid: Set the repository name or repository id.
728 :param repoid: Set the repository name or repository id.
729 :type repoid: str or int
729 :type repoid: str or int
730 :param key: Create a unique field key for this repository.
730 :param key: Create a unique field key for this repository.
731 :type key: str
731 :type key: str
732 :param label:
732 :param label:
733 :type label: Optional(str)
733 :type label: Optional(str)
734 :param description:
734 :param description:
735 :type description: Optional(str)
735 :type description: Optional(str)
736 """
736 """
737 repo = get_repo_or_error(repoid)
737 repo = get_repo_or_error(repoid)
738 if not has_superadmin_permission(apiuser):
738 if not has_superadmin_permission(apiuser):
739 _perms = ('repository.admin',)
739 _perms = ('repository.admin',)
740 validate_repo_permissions(apiuser, repoid, repo, _perms)
740 validate_repo_permissions(apiuser, repoid, repo, _perms)
741
741
742 label = Optional.extract(label) or key
742 label = Optional.extract(label) or key
743 description = Optional.extract(description)
743 description = Optional.extract(description)
744
744
745 field = RepositoryField.get_by_key_name(key, repo)
745 field = RepositoryField.get_by_key_name(key, repo)
746 if field:
746 if field:
747 raise JSONRPCError('Field with key '
747 raise JSONRPCError('Field with key '
748 '`%s` exists for repo `%s`' % (key, repoid))
748 '`%s` exists for repo `%s`' % (key, repoid))
749
749
750 try:
750 try:
751 RepoModel().add_repo_field(repo, key, field_label=label,
751 RepoModel().add_repo_field(repo, key, field_label=label,
752 field_desc=description)
752 field_desc=description)
753 Session().commit()
753 Session().commit()
754 return {
754 return {
755 'msg': "Added new repository field `%s`" % (key,),
755 'msg': "Added new repository field `%s`" % (key,),
756 'success': True,
756 'success': True,
757 }
757 }
758 except Exception:
758 except Exception:
759 log.exception("Exception occurred while trying to add field to repo")
759 log.exception("Exception occurred while trying to add field to repo")
760 raise JSONRPCError(
760 raise JSONRPCError(
761 'failed to create new field for repository `%s`' % (repoid,))
761 'failed to create new field for repository `%s`' % (repoid,))
762
762
763
763
764 @jsonrpc_method()
764 @jsonrpc_method()
765 def remove_field_from_repo(request, apiuser, repoid, key):
765 def remove_field_from_repo(request, apiuser, repoid, key):
766 """
766 """
767 Removes an extra field from a repository.
767 Removes an extra field from a repository.
768
768
769 This command can only be run using an |authtoken| with at least
769 This command can only be run using an |authtoken| with at least
770 write permissions to the |repo|.
770 write permissions to the |repo|.
771
771
772 :param apiuser: This is filled automatically from the |authtoken|.
772 :param apiuser: This is filled automatically from the |authtoken|.
773 :type apiuser: AuthUser
773 :type apiuser: AuthUser
774 :param repoid: Set the repository name or repository ID.
774 :param repoid: Set the repository name or repository ID.
775 :type repoid: str or int
775 :type repoid: str or int
776 :param key: Set the unique field key for this repository.
776 :param key: Set the unique field key for this repository.
777 :type key: str
777 :type key: str
778 """
778 """
779
779
780 repo = get_repo_or_error(repoid)
780 repo = get_repo_or_error(repoid)
781 if not has_superadmin_permission(apiuser):
781 if not has_superadmin_permission(apiuser):
782 _perms = ('repository.admin',)
782 _perms = ('repository.admin',)
783 validate_repo_permissions(apiuser, repoid, repo, _perms)
783 validate_repo_permissions(apiuser, repoid, repo, _perms)
784
784
785 field = RepositoryField.get_by_key_name(key, repo)
785 field = RepositoryField.get_by_key_name(key, repo)
786 if not field:
786 if not field:
787 raise JSONRPCError('Field with key `%s` does not '
787 raise JSONRPCError('Field with key `%s` does not '
788 'exists for repo `%s`' % (key, repoid))
788 'exists for repo `%s`' % (key, repoid))
789
789
790 try:
790 try:
791 RepoModel().delete_repo_field(repo, field_key=key)
791 RepoModel().delete_repo_field(repo, field_key=key)
792 Session().commit()
792 Session().commit()
793 return {
793 return {
794 'msg': "Deleted repository field `%s`" % (key,),
794 'msg': "Deleted repository field `%s`" % (key,),
795 'success': True,
795 'success': True,
796 }
796 }
797 except Exception:
797 except Exception:
798 log.exception(
798 log.exception(
799 "Exception occurred while trying to delete field from repo")
799 "Exception occurred while trying to delete field from repo")
800 raise JSONRPCError(
800 raise JSONRPCError(
801 'failed to delete field for repository `%s`' % (repoid,))
801 'failed to delete field for repository `%s`' % (repoid,))
802
802
803
803
804 @jsonrpc_method()
804 @jsonrpc_method()
805 def update_repo(
805 def update_repo(
806 request, apiuser, repoid, repo_name=Optional(None),
806 request, apiuser, repoid, repo_name=Optional(None),
807 owner=Optional(OAttr('apiuser')), description=Optional(''),
807 owner=Optional(OAttr('apiuser')), description=Optional(''),
808 private=Optional(False), clone_uri=Optional(None),
808 private=Optional(False),
809 clone_uri=Optional(None), push_uri=Optional(None),
809 landing_rev=Optional('rev:tip'), fork_of=Optional(None),
810 landing_rev=Optional('rev:tip'), fork_of=Optional(None),
810 enable_statistics=Optional(False),
811 enable_statistics=Optional(False),
811 enable_locking=Optional(False),
812 enable_locking=Optional(False),
812 enable_downloads=Optional(False), fields=Optional('')):
813 enable_downloads=Optional(False), fields=Optional('')):
813 """
814 """
814 Updates a repository with the given information.
815 Updates a repository with the given information.
815
816
816 This command can only be run using an |authtoken| with at least
817 This command can only be run using an |authtoken| with at least
817 admin permissions to the |repo|.
818 admin permissions to the |repo|.
818
819
819 * If the repository name contains "/", repository will be updated
820 * If the repository name contains "/", repository will be updated
820 accordingly with a repository group or nested repository groups
821 accordingly with a repository group or nested repository groups
821
822
822 For example repoid=repo-test name="foo/bar/repo-test" will update |repo|
823 For example repoid=repo-test name="foo/bar/repo-test" will update |repo|
823 called "repo-test" and place it inside group "foo/bar".
824 called "repo-test" and place it inside group "foo/bar".
824 You have to have permissions to access and write to the last repository
825 You have to have permissions to access and write to the last repository
825 group ("bar" in this example)
826 group ("bar" in this example)
826
827
827 :param apiuser: This is filled automatically from the |authtoken|.
828 :param apiuser: This is filled automatically from the |authtoken|.
828 :type apiuser: AuthUser
829 :type apiuser: AuthUser
829 :param repoid: repository name or repository ID.
830 :param repoid: repository name or repository ID.
830 :type repoid: str or int
831 :type repoid: str or int
831 :param repo_name: Update the |repo| name, including the
832 :param repo_name: Update the |repo| name, including the
832 repository group it's in.
833 repository group it's in.
833 :type repo_name: str
834 :type repo_name: str
834 :param owner: Set the |repo| owner.
835 :param owner: Set the |repo| owner.
835 :type owner: str
836 :type owner: str
836 :param fork_of: Set the |repo| as fork of another |repo|.
837 :param fork_of: Set the |repo| as fork of another |repo|.
837 :type fork_of: str
838 :type fork_of: str
838 :param description: Update the |repo| description.
839 :param description: Update the |repo| description.
839 :type description: str
840 :type description: str
840 :param private: Set the |repo| as private. (True | False)
841 :param private: Set the |repo| as private. (True | False)
841 :type private: bool
842 :type private: bool
842 :param clone_uri: Update the |repo| clone URI.
843 :param clone_uri: Update the |repo| clone URI.
843 :type clone_uri: str
844 :type clone_uri: str
844 :param landing_rev: Set the |repo| landing revision. Default is ``rev:tip``.
845 :param landing_rev: Set the |repo| landing revision. Default is ``rev:tip``.
845 :type landing_rev: str
846 :type landing_rev: str
846 :param enable_statistics: Enable statistics on the |repo|, (True | False).
847 :param enable_statistics: Enable statistics on the |repo|, (True | False).
847 :type enable_statistics: bool
848 :type enable_statistics: bool
848 :param enable_locking: Enable |repo| locking.
849 :param enable_locking: Enable |repo| locking.
849 :type enable_locking: bool
850 :type enable_locking: bool
850 :param enable_downloads: Enable downloads from the |repo|, (True | False).
851 :param enable_downloads: Enable downloads from the |repo|, (True | False).
851 :type enable_downloads: bool
852 :type enable_downloads: bool
852 :param fields: Add extra fields to the |repo|. Use the following
853 :param fields: Add extra fields to the |repo|. Use the following
853 example format: ``field_key=field_val,field_key2=fieldval2``.
854 example format: ``field_key=field_val,field_key2=fieldval2``.
854 Escape ', ' with \,
855 Escape ', ' with \,
855 :type fields: str
856 :type fields: str
856 """
857 """
857
858
858 repo = get_repo_or_error(repoid)
859 repo = get_repo_or_error(repoid)
859
860
860 include_secrets = False
861 include_secrets = False
861 if not has_superadmin_permission(apiuser):
862 if not has_superadmin_permission(apiuser):
862 validate_repo_permissions(apiuser, repoid, repo, ('repository.admin',))
863 validate_repo_permissions(apiuser, repoid, repo, ('repository.admin',))
863 else:
864 else:
864 include_secrets = True
865 include_secrets = True
865
866
866 updates = dict(
867 updates = dict(
867 repo_name=repo_name
868 repo_name=repo_name
868 if not isinstance(repo_name, Optional) else repo.repo_name,
869 if not isinstance(repo_name, Optional) else repo.repo_name,
869
870
870 fork_id=fork_of
871 fork_id=fork_of
871 if not isinstance(fork_of, Optional) else repo.fork.repo_name if repo.fork else None,
872 if not isinstance(fork_of, Optional) else repo.fork.repo_name if repo.fork else None,
872
873
873 user=owner
874 user=owner
874 if not isinstance(owner, Optional) else repo.user.username,
875 if not isinstance(owner, Optional) else repo.user.username,
875
876
876 repo_description=description
877 repo_description=description
877 if not isinstance(description, Optional) else repo.description,
878 if not isinstance(description, Optional) else repo.description,
878
879
879 repo_private=private
880 repo_private=private
880 if not isinstance(private, Optional) else repo.private,
881 if not isinstance(private, Optional) else repo.private,
881
882
882 clone_uri=clone_uri
883 clone_uri=clone_uri
883 if not isinstance(clone_uri, Optional) else repo.clone_uri,
884 if not isinstance(clone_uri, Optional) else repo.clone_uri,
884
885
886 push_uri=push_uri
887 if not isinstance(push_uri, Optional) else repo.push_uri,
888
885 repo_landing_rev=landing_rev
889 repo_landing_rev=landing_rev
886 if not isinstance(landing_rev, Optional) else repo._landing_revision,
890 if not isinstance(landing_rev, Optional) else repo._landing_revision,
887
891
888 repo_enable_statistics=enable_statistics
892 repo_enable_statistics=enable_statistics
889 if not isinstance(enable_statistics, Optional) else repo.enable_statistics,
893 if not isinstance(enable_statistics, Optional) else repo.enable_statistics,
890
894
891 repo_enable_locking=enable_locking
895 repo_enable_locking=enable_locking
892 if not isinstance(enable_locking, Optional) else repo.enable_locking,
896 if not isinstance(enable_locking, Optional) else repo.enable_locking,
893
897
894 repo_enable_downloads=enable_downloads
898 repo_enable_downloads=enable_downloads
895 if not isinstance(enable_downloads, Optional) else repo.enable_downloads)
899 if not isinstance(enable_downloads, Optional) else repo.enable_downloads)
896
900
897 ref_choices, _labels = ScmModel().get_repo_landing_revs(
901 ref_choices, _labels = ScmModel().get_repo_landing_revs(
898 request.translate, repo=repo)
902 request.translate, repo=repo)
899
903
900 old_values = repo.get_api_data()
904 old_values = repo.get_api_data()
901 schema = repo_schema.RepoSchema().bind(
905 schema = repo_schema.RepoSchema().bind(
902 repo_type_options=rhodecode.BACKENDS.keys(),
906 repo_type_options=rhodecode.BACKENDS.keys(),
903 repo_ref_options=ref_choices,
907 repo_ref_options=ref_choices,
904 # user caller
908 # user caller
905 user=apiuser,
909 user=apiuser,
906 old_values=old_values)
910 old_values=old_values)
907 try:
911 try:
908 schema_data = schema.deserialize(dict(
912 schema_data = schema.deserialize(dict(
909 # we save old value, users cannot change type
913 # we save old value, users cannot change type
910 repo_type=repo.repo_type,
914 repo_type=repo.repo_type,
911
915
912 repo_name=updates['repo_name'],
916 repo_name=updates['repo_name'],
913 repo_owner=updates['user'],
917 repo_owner=updates['user'],
914 repo_description=updates['repo_description'],
918 repo_description=updates['repo_description'],
915 repo_clone_uri=updates['clone_uri'],
919 repo_clone_uri=updates['clone_uri'],
916 repo_push_uri=updates['push_uri'],
920 repo_push_uri=updates['push_uri'],
917 repo_fork_of=updates['fork_id'],
921 repo_fork_of=updates['fork_id'],
918 repo_private=updates['repo_private'],
922 repo_private=updates['repo_private'],
919 repo_landing_commit_ref=updates['repo_landing_rev'],
923 repo_landing_commit_ref=updates['repo_landing_rev'],
920 repo_enable_statistics=updates['repo_enable_statistics'],
924 repo_enable_statistics=updates['repo_enable_statistics'],
921 repo_enable_downloads=updates['repo_enable_downloads'],
925 repo_enable_downloads=updates['repo_enable_downloads'],
922 repo_enable_locking=updates['repo_enable_locking']))
926 repo_enable_locking=updates['repo_enable_locking']))
923 except validation_schema.Invalid as err:
927 except validation_schema.Invalid as err:
924 raise JSONRPCValidationError(colander_exc=err)
928 raise JSONRPCValidationError(colander_exc=err)
925
929
926 # save validated data back into the updates dict
930 # save validated data back into the updates dict
927 validated_updates = dict(
931 validated_updates = dict(
928 repo_name=schema_data['repo_group']['repo_name_without_group'],
932 repo_name=schema_data['repo_group']['repo_name_without_group'],
929 repo_group=schema_data['repo_group']['repo_group_id'],
933 repo_group=schema_data['repo_group']['repo_group_id'],
930
934
931 user=schema_data['repo_owner'],
935 user=schema_data['repo_owner'],
932 repo_description=schema_data['repo_description'],
936 repo_description=schema_data['repo_description'],
933 repo_private=schema_data['repo_private'],
937 repo_private=schema_data['repo_private'],
934 clone_uri=schema_data['repo_clone_uri'],
938 clone_uri=schema_data['repo_clone_uri'],
935 push_uri=schema_data['repo_push_uri'],
939 push_uri=schema_data['repo_push_uri'],
936 repo_landing_rev=schema_data['repo_landing_commit_ref'],
940 repo_landing_rev=schema_data['repo_landing_commit_ref'],
937 repo_enable_statistics=schema_data['repo_enable_statistics'],
941 repo_enable_statistics=schema_data['repo_enable_statistics'],
938 repo_enable_locking=schema_data['repo_enable_locking'],
942 repo_enable_locking=schema_data['repo_enable_locking'],
939 repo_enable_downloads=schema_data['repo_enable_downloads'],
943 repo_enable_downloads=schema_data['repo_enable_downloads'],
940 )
944 )
941
945
942 if schema_data['repo_fork_of']:
946 if schema_data['repo_fork_of']:
943 fork_repo = get_repo_or_error(schema_data['repo_fork_of'])
947 fork_repo = get_repo_or_error(schema_data['repo_fork_of'])
944 validated_updates['fork_id'] = fork_repo.repo_id
948 validated_updates['fork_id'] = fork_repo.repo_id
945
949
946 # extra fields
950 # extra fields
947 fields = parse_args(Optional.extract(fields), key_prefix='ex_')
951 fields = parse_args(Optional.extract(fields), key_prefix='ex_')
948 if fields:
952 if fields:
949 validated_updates.update(fields)
953 validated_updates.update(fields)
950
954
951 try:
955 try:
952 RepoModel().update(repo, **validated_updates)
956 RepoModel().update(repo, **validated_updates)
953 audit_logger.store_api(
957 audit_logger.store_api(
954 'repo.edit', action_data={'old_data': old_values},
958 'repo.edit', action_data={'old_data': old_values},
955 user=apiuser, repo=repo)
959 user=apiuser, repo=repo)
956 Session().commit()
960 Session().commit()
957 return {
961 return {
958 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo.repo_name),
962 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo.repo_name),
959 'repository': repo.get_api_data(include_secrets=include_secrets)
963 'repository': repo.get_api_data(include_secrets=include_secrets)
960 }
964 }
961 except Exception:
965 except Exception:
962 log.exception(
966 log.exception(
963 u"Exception while trying to update the repository %s",
967 u"Exception while trying to update the repository %s",
964 repoid)
968 repoid)
965 raise JSONRPCError('failed to update repo `%s`' % repoid)
969 raise JSONRPCError('failed to update repo `%s`' % repoid)
966
970
967
971
968 @jsonrpc_method()
972 @jsonrpc_method()
969 def fork_repo(request, apiuser, repoid, fork_name,
973 def fork_repo(request, apiuser, repoid, fork_name,
970 owner=Optional(OAttr('apiuser')),
974 owner=Optional(OAttr('apiuser')),
971 description=Optional(''),
975 description=Optional(''),
972 private=Optional(False),
976 private=Optional(False),
973 clone_uri=Optional(None),
977 clone_uri=Optional(None),
974 landing_rev=Optional('rev:tip'),
978 landing_rev=Optional('rev:tip'),
975 copy_permissions=Optional(False)):
979 copy_permissions=Optional(False)):
976 """
980 """
977 Creates a fork of the specified |repo|.
981 Creates a fork of the specified |repo|.
978
982
979 * If the fork_name contains "/", fork will be created inside
983 * If the fork_name contains "/", fork will be created inside
980 a repository group or nested repository groups
984 a repository group or nested repository groups
981
985
982 For example "foo/bar/fork-repo" will create fork called "fork-repo"
986 For example "foo/bar/fork-repo" will create fork called "fork-repo"
983 inside group "foo/bar". You have to have permissions to access and
987 inside group "foo/bar". You have to have permissions to access and
984 write to the last repository group ("bar" in this example)
988 write to the last repository group ("bar" in this example)
985
989
986 This command can only be run using an |authtoken| with minimum
990 This command can only be run using an |authtoken| with minimum
987 read permissions of the forked repo, create fork permissions for an user.
991 read permissions of the forked repo, create fork permissions for an user.
988
992
989 :param apiuser: This is filled automatically from the |authtoken|.
993 :param apiuser: This is filled automatically from the |authtoken|.
990 :type apiuser: AuthUser
994 :type apiuser: AuthUser
991 :param repoid: Set repository name or repository ID.
995 :param repoid: Set repository name or repository ID.
992 :type repoid: str or int
996 :type repoid: str or int
993 :param fork_name: Set the fork name, including it's repository group membership.
997 :param fork_name: Set the fork name, including it's repository group membership.
994 :type fork_name: str
998 :type fork_name: str
995 :param owner: Set the fork owner.
999 :param owner: Set the fork owner.
996 :type owner: str
1000 :type owner: str
997 :param description: Set the fork description.
1001 :param description: Set the fork description.
998 :type description: str
1002 :type description: str
999 :param copy_permissions: Copy permissions from parent |repo|. The
1003 :param copy_permissions: Copy permissions from parent |repo|. The
1000 default is False.
1004 default is False.
1001 :type copy_permissions: bool
1005 :type copy_permissions: bool
1002 :param private: Make the fork private. The default is False.
1006 :param private: Make the fork private. The default is False.
1003 :type private: bool
1007 :type private: bool
1004 :param landing_rev: Set the landing revision. The default is tip.
1008 :param landing_rev: Set the landing revision. The default is tip.
1005
1009
1006 Example output:
1010 Example output:
1007
1011
1008 .. code-block:: bash
1012 .. code-block:: bash
1009
1013
1010 id : <id_for_response>
1014 id : <id_for_response>
1011 api_key : "<api_key>"
1015 api_key : "<api_key>"
1012 args: {
1016 args: {
1013 "repoid" : "<reponame or repo_id>",
1017 "repoid" : "<reponame or repo_id>",
1014 "fork_name": "<forkname>",
1018 "fork_name": "<forkname>",
1015 "owner": "<username or user_id = Optional(=apiuser)>",
1019 "owner": "<username or user_id = Optional(=apiuser)>",
1016 "description": "<description>",
1020 "description": "<description>",
1017 "copy_permissions": "<bool>",
1021 "copy_permissions": "<bool>",
1018 "private": "<bool>",
1022 "private": "<bool>",
1019 "landing_rev": "<landing_rev>"
1023 "landing_rev": "<landing_rev>"
1020 }
1024 }
1021
1025
1022 Example error output:
1026 Example error output:
1023
1027
1024 .. code-block:: bash
1028 .. code-block:: bash
1025
1029
1026 id : <id_given_in_input>
1030 id : <id_given_in_input>
1027 result: {
1031 result: {
1028 "msg": "Created fork of `<reponame>` as `<forkname>`",
1032 "msg": "Created fork of `<reponame>` as `<forkname>`",
1029 "success": true,
1033 "success": true,
1030 "task": "<celery task id or None if done sync>"
1034 "task": "<celery task id or None if done sync>"
1031 }
1035 }
1032 error: null
1036 error: null
1033
1037
1034 """
1038 """
1035
1039
1036 repo = get_repo_or_error(repoid)
1040 repo = get_repo_or_error(repoid)
1037 repo_name = repo.repo_name
1041 repo_name = repo.repo_name
1038
1042
1039 if not has_superadmin_permission(apiuser):
1043 if not has_superadmin_permission(apiuser):
1040 # check if we have at least read permission for
1044 # check if we have at least read permission for
1041 # this repo that we fork !
1045 # this repo that we fork !
1042 _perms = (
1046 _perms = (
1043 'repository.admin', 'repository.write', 'repository.read')
1047 'repository.admin', 'repository.write', 'repository.read')
1044 validate_repo_permissions(apiuser, repoid, repo, _perms)
1048 validate_repo_permissions(apiuser, repoid, repo, _perms)
1045
1049
1046 # check if the regular user has at least fork permissions as well
1050 # check if the regular user has at least fork permissions as well
1047 if not HasPermissionAnyApi('hg.fork.repository')(user=apiuser):
1051 if not HasPermissionAnyApi('hg.fork.repository')(user=apiuser):
1048 raise JSONRPCForbidden()
1052 raise JSONRPCForbidden()
1049
1053
1050 # check if user can set owner parameter
1054 # check if user can set owner parameter
1051 owner = validate_set_owner_permissions(apiuser, owner)
1055 owner = validate_set_owner_permissions(apiuser, owner)
1052
1056
1053 description = Optional.extract(description)
1057 description = Optional.extract(description)
1054 copy_permissions = Optional.extract(copy_permissions)
1058 copy_permissions = Optional.extract(copy_permissions)
1055 clone_uri = Optional.extract(clone_uri)
1059 clone_uri = Optional.extract(clone_uri)
1056 landing_commit_ref = Optional.extract(landing_rev)
1060 landing_commit_ref = Optional.extract(landing_rev)
1057 private = Optional.extract(private)
1061 private = Optional.extract(private)
1058
1062
1059 schema = repo_schema.RepoSchema().bind(
1063 schema = repo_schema.RepoSchema().bind(
1060 repo_type_options=rhodecode.BACKENDS.keys(),
1064 repo_type_options=rhodecode.BACKENDS.keys(),
1061 # user caller
1065 # user caller
1062 user=apiuser)
1066 user=apiuser)
1063
1067
1064 try:
1068 try:
1065 schema_data = schema.deserialize(dict(
1069 schema_data = schema.deserialize(dict(
1066 repo_name=fork_name,
1070 repo_name=fork_name,
1067 repo_type=repo.repo_type,
1071 repo_type=repo.repo_type,
1068 repo_owner=owner.username,
1072 repo_owner=owner.username,
1069 repo_description=description,
1073 repo_description=description,
1070 repo_landing_commit_ref=landing_commit_ref,
1074 repo_landing_commit_ref=landing_commit_ref,
1071 repo_clone_uri=clone_uri,
1075 repo_clone_uri=clone_uri,
1072 repo_private=private,
1076 repo_private=private,
1073 repo_copy_permissions=copy_permissions))
1077 repo_copy_permissions=copy_permissions))
1074 except validation_schema.Invalid as err:
1078 except validation_schema.Invalid as err:
1075 raise JSONRPCValidationError(colander_exc=err)
1079 raise JSONRPCValidationError(colander_exc=err)
1076
1080
1077 try:
1081 try:
1078 data = {
1082 data = {
1079 'fork_parent_id': repo.repo_id,
1083 'fork_parent_id': repo.repo_id,
1080
1084
1081 'repo_name': schema_data['repo_group']['repo_name_without_group'],
1085 'repo_name': schema_data['repo_group']['repo_name_without_group'],
1082 'repo_name_full': schema_data['repo_name'],
1086 'repo_name_full': schema_data['repo_name'],
1083 'repo_group': schema_data['repo_group']['repo_group_id'],
1087 'repo_group': schema_data['repo_group']['repo_group_id'],
1084 'repo_type': schema_data['repo_type'],
1088 'repo_type': schema_data['repo_type'],
1085 'description': schema_data['repo_description'],
1089 'description': schema_data['repo_description'],
1086 'private': schema_data['repo_private'],
1090 'private': schema_data['repo_private'],
1087 'copy_permissions': schema_data['repo_copy_permissions'],
1091 'copy_permissions': schema_data['repo_copy_permissions'],
1088 'landing_rev': schema_data['repo_landing_commit_ref'],
1092 'landing_rev': schema_data['repo_landing_commit_ref'],
1089 }
1093 }
1090
1094
1091 task = RepoModel().create_fork(data, cur_user=owner)
1095 task = RepoModel().create_fork(data, cur_user=owner)
1092 # no commit, it's done in RepoModel, or async via celery
1096 # no commit, it's done in RepoModel, or async via celery
1093 task_id = get_task_id(task)
1097 task_id = get_task_id(task)
1094
1098
1095 return {
1099 return {
1096 'msg': 'Created fork of `%s` as `%s`' % (
1100 'msg': 'Created fork of `%s` as `%s`' % (
1097 repo.repo_name, schema_data['repo_name']),
1101 repo.repo_name, schema_data['repo_name']),
1098 'success': True, # cannot return the repo data here since fork
1102 'success': True, # cannot return the repo data here since fork
1099 # can be done async
1103 # can be done async
1100 'task': task_id
1104 'task': task_id
1101 }
1105 }
1102 except Exception:
1106 except Exception:
1103 log.exception(
1107 log.exception(
1104 u"Exception while trying to create fork %s",
1108 u"Exception while trying to create fork %s",
1105 schema_data['repo_name'])
1109 schema_data['repo_name'])
1106 raise JSONRPCError(
1110 raise JSONRPCError(
1107 'failed to fork repository `%s` as `%s`' % (
1111 'failed to fork repository `%s` as `%s`' % (
1108 repo_name, schema_data['repo_name']))
1112 repo_name, schema_data['repo_name']))
1109
1113
1110
1114
1111 @jsonrpc_method()
1115 @jsonrpc_method()
1112 def delete_repo(request, apiuser, repoid, forks=Optional('')):
1116 def delete_repo(request, apiuser, repoid, forks=Optional('')):
1113 """
1117 """
1114 Deletes a repository.
1118 Deletes a repository.
1115
1119
1116 * When the `forks` parameter is set it's possible to detach or delete
1120 * When the `forks` parameter is set it's possible to detach or delete
1117 forks of deleted repository.
1121 forks of deleted repository.
1118
1122
1119 This command can only be run using an |authtoken| with admin
1123 This command can only be run using an |authtoken| with admin
1120 permissions on the |repo|.
1124 permissions on the |repo|.
1121
1125
1122 :param apiuser: This is filled automatically from the |authtoken|.
1126 :param apiuser: This is filled automatically from the |authtoken|.
1123 :type apiuser: AuthUser
1127 :type apiuser: AuthUser
1124 :param repoid: Set the repository name or repository ID.
1128 :param repoid: Set the repository name or repository ID.
1125 :type repoid: str or int
1129 :type repoid: str or int
1126 :param forks: Set to `detach` or `delete` forks from the |repo|.
1130 :param forks: Set to `detach` or `delete` forks from the |repo|.
1127 :type forks: Optional(str)
1131 :type forks: Optional(str)
1128
1132
1129 Example error output:
1133 Example error output:
1130
1134
1131 .. code-block:: bash
1135 .. code-block:: bash
1132
1136
1133 id : <id_given_in_input>
1137 id : <id_given_in_input>
1134 result: {
1138 result: {
1135 "msg": "Deleted repository `<reponame>`",
1139 "msg": "Deleted repository `<reponame>`",
1136 "success": true
1140 "success": true
1137 }
1141 }
1138 error: null
1142 error: null
1139 """
1143 """
1140
1144
1141 repo = get_repo_or_error(repoid)
1145 repo = get_repo_or_error(repoid)
1142 repo_name = repo.repo_name
1146 repo_name = repo.repo_name
1143 if not has_superadmin_permission(apiuser):
1147 if not has_superadmin_permission(apiuser):
1144 _perms = ('repository.admin',)
1148 _perms = ('repository.admin',)
1145 validate_repo_permissions(apiuser, repoid, repo, _perms)
1149 validate_repo_permissions(apiuser, repoid, repo, _perms)
1146
1150
1147 try:
1151 try:
1148 handle_forks = Optional.extract(forks)
1152 handle_forks = Optional.extract(forks)
1149 _forks_msg = ''
1153 _forks_msg = ''
1150 _forks = [f for f in repo.forks]
1154 _forks = [f for f in repo.forks]
1151 if handle_forks == 'detach':
1155 if handle_forks == 'detach':
1152 _forks_msg = ' ' + 'Detached %s forks' % len(_forks)
1156 _forks_msg = ' ' + 'Detached %s forks' % len(_forks)
1153 elif handle_forks == 'delete':
1157 elif handle_forks == 'delete':
1154 _forks_msg = ' ' + 'Deleted %s forks' % len(_forks)
1158 _forks_msg = ' ' + 'Deleted %s forks' % len(_forks)
1155 elif _forks:
1159 elif _forks:
1156 raise JSONRPCError(
1160 raise JSONRPCError(
1157 'Cannot delete `%s` it still contains attached forks' %
1161 'Cannot delete `%s` it still contains attached forks' %
1158 (repo.repo_name,)
1162 (repo.repo_name,)
1159 )
1163 )
1160 old_data = repo.get_api_data()
1164 old_data = repo.get_api_data()
1161 RepoModel().delete(repo, forks=forks)
1165 RepoModel().delete(repo, forks=forks)
1162
1166
1163 repo = audit_logger.RepoWrap(repo_id=None,
1167 repo = audit_logger.RepoWrap(repo_id=None,
1164 repo_name=repo.repo_name)
1168 repo_name=repo.repo_name)
1165
1169
1166 audit_logger.store_api(
1170 audit_logger.store_api(
1167 'repo.delete', action_data={'old_data': old_data},
1171 'repo.delete', action_data={'old_data': old_data},
1168 user=apiuser, repo=repo)
1172 user=apiuser, repo=repo)
1169
1173
1170 ScmModel().mark_for_invalidation(repo_name, delete=True)
1174 ScmModel().mark_for_invalidation(repo_name, delete=True)
1171 Session().commit()
1175 Session().commit()
1172 return {
1176 return {
1173 'msg': 'Deleted repository `%s`%s' % (repo_name, _forks_msg),
1177 'msg': 'Deleted repository `%s`%s' % (repo_name, _forks_msg),
1174 'success': True
1178 'success': True
1175 }
1179 }
1176 except Exception:
1180 except Exception:
1177 log.exception("Exception occurred while trying to delete repo")
1181 log.exception("Exception occurred while trying to delete repo")
1178 raise JSONRPCError(
1182 raise JSONRPCError(
1179 'failed to delete repository `%s`' % (repo_name,)
1183 'failed to delete repository `%s`' % (repo_name,)
1180 )
1184 )
1181
1185
1182
1186
1183 #TODO: marcink, change name ?
1187 #TODO: marcink, change name ?
1184 @jsonrpc_method()
1188 @jsonrpc_method()
1185 def invalidate_cache(request, apiuser, repoid, delete_keys=Optional(False)):
1189 def invalidate_cache(request, apiuser, repoid, delete_keys=Optional(False)):
1186 """
1190 """
1187 Invalidates the cache for the specified repository.
1191 Invalidates the cache for the specified repository.
1188
1192
1189 This command can only be run using an |authtoken| with admin rights to
1193 This command can only be run using an |authtoken| with admin rights to
1190 the specified repository.
1194 the specified repository.
1191
1195
1192 This command takes the following options:
1196 This command takes the following options:
1193
1197
1194 :param apiuser: This is filled automatically from |authtoken|.
1198 :param apiuser: This is filled automatically from |authtoken|.
1195 :type apiuser: AuthUser
1199 :type apiuser: AuthUser
1196 :param repoid: Sets the repository name or repository ID.
1200 :param repoid: Sets the repository name or repository ID.
1197 :type repoid: str or int
1201 :type repoid: str or int
1198 :param delete_keys: This deletes the invalidated keys instead of
1202 :param delete_keys: This deletes the invalidated keys instead of
1199 just flagging them.
1203 just flagging them.
1200 :type delete_keys: Optional(``True`` | ``False``)
1204 :type delete_keys: Optional(``True`` | ``False``)
1201
1205
1202 Example output:
1206 Example output:
1203
1207
1204 .. code-block:: bash
1208 .. code-block:: bash
1205
1209
1206 id : <id_given_in_input>
1210 id : <id_given_in_input>
1207 result : {
1211 result : {
1208 'msg': Cache for repository `<repository name>` was invalidated,
1212 'msg': Cache for repository `<repository name>` was invalidated,
1209 'repository': <repository name>
1213 'repository': <repository name>
1210 }
1214 }
1211 error : null
1215 error : null
1212
1216
1213 Example error output:
1217 Example error output:
1214
1218
1215 .. code-block:: bash
1219 .. code-block:: bash
1216
1220
1217 id : <id_given_in_input>
1221 id : <id_given_in_input>
1218 result : null
1222 result : null
1219 error : {
1223 error : {
1220 'Error occurred during cache invalidation action'
1224 'Error occurred during cache invalidation action'
1221 }
1225 }
1222
1226
1223 """
1227 """
1224
1228
1225 repo = get_repo_or_error(repoid)
1229 repo = get_repo_or_error(repoid)
1226 if not has_superadmin_permission(apiuser):
1230 if not has_superadmin_permission(apiuser):
1227 _perms = ('repository.admin', 'repository.write',)
1231 _perms = ('repository.admin', 'repository.write',)
1228 validate_repo_permissions(apiuser, repoid, repo, _perms)
1232 validate_repo_permissions(apiuser, repoid, repo, _perms)
1229
1233
1230 delete = Optional.extract(delete_keys)
1234 delete = Optional.extract(delete_keys)
1231 try:
1235 try:
1232 ScmModel().mark_for_invalidation(repo.repo_name, delete=delete)
1236 ScmModel().mark_for_invalidation(repo.repo_name, delete=delete)
1233 return {
1237 return {
1234 'msg': 'Cache for repository `%s` was invalidated' % (repoid,),
1238 'msg': 'Cache for repository `%s` was invalidated' % (repoid,),
1235 'repository': repo.repo_name
1239 'repository': repo.repo_name
1236 }
1240 }
1237 except Exception:
1241 except Exception:
1238 log.exception(
1242 log.exception(
1239 "Exception occurred while trying to invalidate repo cache")
1243 "Exception occurred while trying to invalidate repo cache")
1240 raise JSONRPCError(
1244 raise JSONRPCError(
1241 'Error occurred during cache invalidation action'
1245 'Error occurred during cache invalidation action'
1242 )
1246 )
1243
1247
1244
1248
1245 #TODO: marcink, change name ?
1249 #TODO: marcink, change name ?
1246 @jsonrpc_method()
1250 @jsonrpc_method()
1247 def lock(request, apiuser, repoid, locked=Optional(None),
1251 def lock(request, apiuser, repoid, locked=Optional(None),
1248 userid=Optional(OAttr('apiuser'))):
1252 userid=Optional(OAttr('apiuser'))):
1249 """
1253 """
1250 Sets the lock state of the specified |repo| by the given user.
1254 Sets the lock state of the specified |repo| by the given user.
1251 From more information, see :ref:`repo-locking`.
1255 From more information, see :ref:`repo-locking`.
1252
1256
1253 * If the ``userid`` option is not set, the repository is locked to the
1257 * If the ``userid`` option is not set, the repository is locked to the
1254 user who called the method.
1258 user who called the method.
1255 * If the ``locked`` parameter is not set, the current lock state of the
1259 * If the ``locked`` parameter is not set, the current lock state of the
1256 repository is displayed.
1260 repository is displayed.
1257
1261
1258 This command can only be run using an |authtoken| with admin rights to
1262 This command can only be run using an |authtoken| with admin rights to
1259 the specified repository.
1263 the specified repository.
1260
1264
1261 This command takes the following options:
1265 This command takes the following options:
1262
1266
1263 :param apiuser: This is filled automatically from the |authtoken|.
1267 :param apiuser: This is filled automatically from the |authtoken|.
1264 :type apiuser: AuthUser
1268 :type apiuser: AuthUser
1265 :param repoid: Sets the repository name or repository ID.
1269 :param repoid: Sets the repository name or repository ID.
1266 :type repoid: str or int
1270 :type repoid: str or int
1267 :param locked: Sets the lock state.
1271 :param locked: Sets the lock state.
1268 :type locked: Optional(``True`` | ``False``)
1272 :type locked: Optional(``True`` | ``False``)
1269 :param userid: Set the repository lock to this user.
1273 :param userid: Set the repository lock to this user.
1270 :type userid: Optional(str or int)
1274 :type userid: Optional(str or int)
1271
1275
1272 Example error output:
1276 Example error output:
1273
1277
1274 .. code-block:: bash
1278 .. code-block:: bash
1275
1279
1276 id : <id_given_in_input>
1280 id : <id_given_in_input>
1277 result : {
1281 result : {
1278 'repo': '<reponame>',
1282 'repo': '<reponame>',
1279 'locked': <bool: lock state>,
1283 'locked': <bool: lock state>,
1280 'locked_since': <int: lock timestamp>,
1284 'locked_since': <int: lock timestamp>,
1281 'locked_by': <username of person who made the lock>,
1285 'locked_by': <username of person who made the lock>,
1282 'lock_reason': <str: reason for locking>,
1286 'lock_reason': <str: reason for locking>,
1283 'lock_state_changed': <bool: True if lock state has been changed in this request>,
1287 'lock_state_changed': <bool: True if lock state has been changed in this request>,
1284 'msg': 'Repo `<reponame>` locked by `<username>` on <timestamp>.'
1288 'msg': 'Repo `<reponame>` locked by `<username>` on <timestamp>.'
1285 or
1289 or
1286 'msg': 'Repo `<repository name>` not locked.'
1290 'msg': 'Repo `<repository name>` not locked.'
1287 or
1291 or
1288 'msg': 'User `<user name>` set lock state for repo `<repository name>` to `<new lock state>`'
1292 'msg': 'User `<user name>` set lock state for repo `<repository name>` to `<new lock state>`'
1289 }
1293 }
1290 error : null
1294 error : null
1291
1295
1292 Example error output:
1296 Example error output:
1293
1297
1294 .. code-block:: bash
1298 .. code-block:: bash
1295
1299
1296 id : <id_given_in_input>
1300 id : <id_given_in_input>
1297 result : null
1301 result : null
1298 error : {
1302 error : {
1299 'Error occurred locking repository `<reponame>`'
1303 'Error occurred locking repository `<reponame>`'
1300 }
1304 }
1301 """
1305 """
1302
1306
1303 repo = get_repo_or_error(repoid)
1307 repo = get_repo_or_error(repoid)
1304 if not has_superadmin_permission(apiuser):
1308 if not has_superadmin_permission(apiuser):
1305 # check if we have at least write permission for this repo !
1309 # check if we have at least write permission for this repo !
1306 _perms = ('repository.admin', 'repository.write',)
1310 _perms = ('repository.admin', 'repository.write',)
1307 validate_repo_permissions(apiuser, repoid, repo, _perms)
1311 validate_repo_permissions(apiuser, repoid, repo, _perms)
1308
1312
1309 # make sure normal user does not pass someone else userid,
1313 # make sure normal user does not pass someone else userid,
1310 # he is not allowed to do that
1314 # he is not allowed to do that
1311 if not isinstance(userid, Optional) and userid != apiuser.user_id:
1315 if not isinstance(userid, Optional) and userid != apiuser.user_id:
1312 raise JSONRPCError('userid is not the same as your user')
1316 raise JSONRPCError('userid is not the same as your user')
1313
1317
1314 if isinstance(userid, Optional):
1318 if isinstance(userid, Optional):
1315 userid = apiuser.user_id
1319 userid = apiuser.user_id
1316
1320
1317 user = get_user_or_error(userid)
1321 user = get_user_or_error(userid)
1318
1322
1319 if isinstance(locked, Optional):
1323 if isinstance(locked, Optional):
1320 lockobj = repo.locked
1324 lockobj = repo.locked
1321
1325
1322 if lockobj[0] is None:
1326 if lockobj[0] is None:
1323 _d = {
1327 _d = {
1324 'repo': repo.repo_name,
1328 'repo': repo.repo_name,
1325 'locked': False,
1329 'locked': False,
1326 'locked_since': None,
1330 'locked_since': None,
1327 'locked_by': None,
1331 'locked_by': None,
1328 'lock_reason': None,
1332 'lock_reason': None,
1329 'lock_state_changed': False,
1333 'lock_state_changed': False,
1330 'msg': 'Repo `%s` not locked.' % repo.repo_name
1334 'msg': 'Repo `%s` not locked.' % repo.repo_name
1331 }
1335 }
1332 return _d
1336 return _d
1333 else:
1337 else:
1334 _user_id, _time, _reason = lockobj
1338 _user_id, _time, _reason = lockobj
1335 lock_user = get_user_or_error(userid)
1339 lock_user = get_user_or_error(userid)
1336 _d = {
1340 _d = {
1337 'repo': repo.repo_name,
1341 'repo': repo.repo_name,
1338 'locked': True,
1342 'locked': True,
1339 'locked_since': _time,
1343 'locked_since': _time,
1340 'locked_by': lock_user.username,
1344 'locked_by': lock_user.username,
1341 'lock_reason': _reason,
1345 'lock_reason': _reason,
1342 'lock_state_changed': False,
1346 'lock_state_changed': False,
1343 'msg': ('Repo `%s` locked by `%s` on `%s`.'
1347 'msg': ('Repo `%s` locked by `%s` on `%s`.'
1344 % (repo.repo_name, lock_user.username,
1348 % (repo.repo_name, lock_user.username,
1345 json.dumps(time_to_datetime(_time))))
1349 json.dumps(time_to_datetime(_time))))
1346 }
1350 }
1347 return _d
1351 return _d
1348
1352
1349 # force locked state through a flag
1353 # force locked state through a flag
1350 else:
1354 else:
1351 locked = str2bool(locked)
1355 locked = str2bool(locked)
1352 lock_reason = Repository.LOCK_API
1356 lock_reason = Repository.LOCK_API
1353 try:
1357 try:
1354 if locked:
1358 if locked:
1355 lock_time = time.time()
1359 lock_time = time.time()
1356 Repository.lock(repo, user.user_id, lock_time, lock_reason)
1360 Repository.lock(repo, user.user_id, lock_time, lock_reason)
1357 else:
1361 else:
1358 lock_time = None
1362 lock_time = None
1359 Repository.unlock(repo)
1363 Repository.unlock(repo)
1360 _d = {
1364 _d = {
1361 'repo': repo.repo_name,
1365 'repo': repo.repo_name,
1362 'locked': locked,
1366 'locked': locked,
1363 'locked_since': lock_time,
1367 'locked_since': lock_time,
1364 'locked_by': user.username,
1368 'locked_by': user.username,
1365 'lock_reason': lock_reason,
1369 'lock_reason': lock_reason,
1366 'lock_state_changed': True,
1370 'lock_state_changed': True,
1367 'msg': ('User `%s` set lock state for repo `%s` to `%s`'
1371 'msg': ('User `%s` set lock state for repo `%s` to `%s`'
1368 % (user.username, repo.repo_name, locked))
1372 % (user.username, repo.repo_name, locked))
1369 }
1373 }
1370 return _d
1374 return _d
1371 except Exception:
1375 except Exception:
1372 log.exception(
1376 log.exception(
1373 "Exception occurred while trying to lock repository")
1377 "Exception occurred while trying to lock repository")
1374 raise JSONRPCError(
1378 raise JSONRPCError(
1375 'Error occurred locking repository `%s`' % repo.repo_name
1379 'Error occurred locking repository `%s`' % repo.repo_name
1376 )
1380 )
1377
1381
1378
1382
1379 @jsonrpc_method()
1383 @jsonrpc_method()
1380 def comment_commit(
1384 def comment_commit(
1381 request, apiuser, repoid, commit_id, message, status=Optional(None),
1385 request, apiuser, repoid, commit_id, message, status=Optional(None),
1382 comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE),
1386 comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE),
1383 resolves_comment_id=Optional(None),
1387 resolves_comment_id=Optional(None),
1384 userid=Optional(OAttr('apiuser'))):
1388 userid=Optional(OAttr('apiuser'))):
1385 """
1389 """
1386 Set a commit comment, and optionally change the status of the commit.
1390 Set a commit comment, and optionally change the status of the commit.
1387
1391
1388 :param apiuser: This is filled automatically from the |authtoken|.
1392 :param apiuser: This is filled automatically from the |authtoken|.
1389 :type apiuser: AuthUser
1393 :type apiuser: AuthUser
1390 :param repoid: Set the repository name or repository ID.
1394 :param repoid: Set the repository name or repository ID.
1391 :type repoid: str or int
1395 :type repoid: str or int
1392 :param commit_id: Specify the commit_id for which to set a comment.
1396 :param commit_id: Specify the commit_id for which to set a comment.
1393 :type commit_id: str
1397 :type commit_id: str
1394 :param message: The comment text.
1398 :param message: The comment text.
1395 :type message: str
1399 :type message: str
1396 :param status: (**Optional**) status of commit, one of: 'not_reviewed',
1400 :param status: (**Optional**) status of commit, one of: 'not_reviewed',
1397 'approved', 'rejected', 'under_review'
1401 'approved', 'rejected', 'under_review'
1398 :type status: str
1402 :type status: str
1399 :param comment_type: Comment type, one of: 'note', 'todo'
1403 :param comment_type: Comment type, one of: 'note', 'todo'
1400 :type comment_type: Optional(str), default: 'note'
1404 :type comment_type: Optional(str), default: 'note'
1401 :param userid: Set the user name of the comment creator.
1405 :param userid: Set the user name of the comment creator.
1402 :type userid: Optional(str or int)
1406 :type userid: Optional(str or int)
1403
1407
1404 Example error output:
1408 Example error output:
1405
1409
1406 .. code-block:: bash
1410 .. code-block:: bash
1407
1411
1408 {
1412 {
1409 "id" : <id_given_in_input>,
1413 "id" : <id_given_in_input>,
1410 "result" : {
1414 "result" : {
1411 "msg": "Commented on commit `<commit_id>` for repository `<repoid>`",
1415 "msg": "Commented on commit `<commit_id>` for repository `<repoid>`",
1412 "status_change": null or <status>,
1416 "status_change": null or <status>,
1413 "success": true
1417 "success": true
1414 },
1418 },
1415 "error" : null
1419 "error" : null
1416 }
1420 }
1417
1421
1418 """
1422 """
1419 repo = get_repo_or_error(repoid)
1423 repo = get_repo_or_error(repoid)
1420 if not has_superadmin_permission(apiuser):
1424 if not has_superadmin_permission(apiuser):
1421 _perms = ('repository.read', 'repository.write', 'repository.admin')
1425 _perms = ('repository.read', 'repository.write', 'repository.admin')
1422 validate_repo_permissions(apiuser, repoid, repo, _perms)
1426 validate_repo_permissions(apiuser, repoid, repo, _perms)
1423
1427
1424 try:
1428 try:
1425 commit_id = repo.scm_instance().get_commit(commit_id=commit_id).raw_id
1429 commit_id = repo.scm_instance().get_commit(commit_id=commit_id).raw_id
1426 except Exception as e:
1430 except Exception as e:
1427 log.exception('Failed to fetch commit')
1431 log.exception('Failed to fetch commit')
1428 raise JSONRPCError(e.message)
1432 raise JSONRPCError(e.message)
1429
1433
1430 if isinstance(userid, Optional):
1434 if isinstance(userid, Optional):
1431 userid = apiuser.user_id
1435 userid = apiuser.user_id
1432
1436
1433 user = get_user_or_error(userid)
1437 user = get_user_or_error(userid)
1434 status = Optional.extract(status)
1438 status = Optional.extract(status)
1435 comment_type = Optional.extract(comment_type)
1439 comment_type = Optional.extract(comment_type)
1436 resolves_comment_id = Optional.extract(resolves_comment_id)
1440 resolves_comment_id = Optional.extract(resolves_comment_id)
1437
1441
1438 allowed_statuses = [x[0] for x in ChangesetStatus.STATUSES]
1442 allowed_statuses = [x[0] for x in ChangesetStatus.STATUSES]
1439 if status and status not in allowed_statuses:
1443 if status and status not in allowed_statuses:
1440 raise JSONRPCError('Bad status, must be on '
1444 raise JSONRPCError('Bad status, must be on '
1441 'of %s got %s' % (allowed_statuses, status,))
1445 'of %s got %s' % (allowed_statuses, status,))
1442
1446
1443 if resolves_comment_id:
1447 if resolves_comment_id:
1444 comment = ChangesetComment.get(resolves_comment_id)
1448 comment = ChangesetComment.get(resolves_comment_id)
1445 if not comment:
1449 if not comment:
1446 raise JSONRPCError(
1450 raise JSONRPCError(
1447 'Invalid resolves_comment_id `%s` for this commit.'
1451 'Invalid resolves_comment_id `%s` for this commit.'
1448 % resolves_comment_id)
1452 % resolves_comment_id)
1449 if comment.comment_type != ChangesetComment.COMMENT_TYPE_TODO:
1453 if comment.comment_type != ChangesetComment.COMMENT_TYPE_TODO:
1450 raise JSONRPCError(
1454 raise JSONRPCError(
1451 'Comment `%s` is wrong type for setting status to resolved.'
1455 'Comment `%s` is wrong type for setting status to resolved.'
1452 % resolves_comment_id)
1456 % resolves_comment_id)
1453
1457
1454 try:
1458 try:
1455 rc_config = SettingsModel().get_all_settings()
1459 rc_config = SettingsModel().get_all_settings()
1456 renderer = rc_config.get('rhodecode_markup_renderer', 'rst')
1460 renderer = rc_config.get('rhodecode_markup_renderer', 'rst')
1457 status_change_label = ChangesetStatus.get_status_lbl(status)
1461 status_change_label = ChangesetStatus.get_status_lbl(status)
1458 comment = CommentsModel().create(
1462 comment = CommentsModel().create(
1459 message, repo, user, commit_id=commit_id,
1463 message, repo, user, commit_id=commit_id,
1460 status_change=status_change_label,
1464 status_change=status_change_label,
1461 status_change_type=status,
1465 status_change_type=status,
1462 renderer=renderer,
1466 renderer=renderer,
1463 comment_type=comment_type,
1467 comment_type=comment_type,
1464 resolves_comment_id=resolves_comment_id
1468 resolves_comment_id=resolves_comment_id
1465 )
1469 )
1466 if status:
1470 if status:
1467 # also do a status change
1471 # also do a status change
1468 try:
1472 try:
1469 ChangesetStatusModel().set_status(
1473 ChangesetStatusModel().set_status(
1470 repo, status, user, comment, revision=commit_id,
1474 repo, status, user, comment, revision=commit_id,
1471 dont_allow_on_closed_pull_request=True
1475 dont_allow_on_closed_pull_request=True
1472 )
1476 )
1473 except StatusChangeOnClosedPullRequestError:
1477 except StatusChangeOnClosedPullRequestError:
1474 log.exception(
1478 log.exception(
1475 "Exception occurred while trying to change repo commit status")
1479 "Exception occurred while trying to change repo commit status")
1476 msg = ('Changing status on a changeset associated with '
1480 msg = ('Changing status on a changeset associated with '
1477 'a closed pull request is not allowed')
1481 'a closed pull request is not allowed')
1478 raise JSONRPCError(msg)
1482 raise JSONRPCError(msg)
1479
1483
1480 Session().commit()
1484 Session().commit()
1481 return {
1485 return {
1482 'msg': (
1486 'msg': (
1483 'Commented on commit `%s` for repository `%s`' % (
1487 'Commented on commit `%s` for repository `%s`' % (
1484 comment.revision, repo.repo_name)),
1488 comment.revision, repo.repo_name)),
1485 'status_change': status,
1489 'status_change': status,
1486 'success': True,
1490 'success': True,
1487 }
1491 }
1488 except JSONRPCError:
1492 except JSONRPCError:
1489 # catch any inside errors, and re-raise them to prevent from
1493 # catch any inside errors, and re-raise them to prevent from
1490 # below global catch to silence them
1494 # below global catch to silence them
1491 raise
1495 raise
1492 except Exception:
1496 except Exception:
1493 log.exception("Exception occurred while trying to comment on commit")
1497 log.exception("Exception occurred while trying to comment on commit")
1494 raise JSONRPCError(
1498 raise JSONRPCError(
1495 'failed to set comment on repository `%s`' % (repo.repo_name,)
1499 'failed to set comment on repository `%s`' % (repo.repo_name,)
1496 )
1500 )
1497
1501
1498
1502
1499 @jsonrpc_method()
1503 @jsonrpc_method()
1500 def grant_user_permission(request, apiuser, repoid, userid, perm):
1504 def grant_user_permission(request, apiuser, repoid, userid, perm):
1501 """
1505 """
1502 Grant permissions for the specified user on the given repository,
1506 Grant permissions for the specified user on the given repository,
1503 or update existing permissions if found.
1507 or update existing permissions if found.
1504
1508
1505 This command can only be run using an |authtoken| with admin
1509 This command can only be run using an |authtoken| with admin
1506 permissions on the |repo|.
1510 permissions on the |repo|.
1507
1511
1508 :param apiuser: This is filled automatically from the |authtoken|.
1512 :param apiuser: This is filled automatically from the |authtoken|.
1509 :type apiuser: AuthUser
1513 :type apiuser: AuthUser
1510 :param repoid: Set the repository name or repository ID.
1514 :param repoid: Set the repository name or repository ID.
1511 :type repoid: str or int
1515 :type repoid: str or int
1512 :param userid: Set the user name.
1516 :param userid: Set the user name.
1513 :type userid: str
1517 :type userid: str
1514 :param perm: Set the user permissions, using the following format
1518 :param perm: Set the user permissions, using the following format
1515 ``(repository.(none|read|write|admin))``
1519 ``(repository.(none|read|write|admin))``
1516 :type perm: str
1520 :type perm: str
1517
1521
1518 Example output:
1522 Example output:
1519
1523
1520 .. code-block:: bash
1524 .. code-block:: bash
1521
1525
1522 id : <id_given_in_input>
1526 id : <id_given_in_input>
1523 result: {
1527 result: {
1524 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
1528 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
1525 "success": true
1529 "success": true
1526 }
1530 }
1527 error: null
1531 error: null
1528 """
1532 """
1529
1533
1530 repo = get_repo_or_error(repoid)
1534 repo = get_repo_or_error(repoid)
1531 user = get_user_or_error(userid)
1535 user = get_user_or_error(userid)
1532 perm = get_perm_or_error(perm)
1536 perm = get_perm_or_error(perm)
1533 if not has_superadmin_permission(apiuser):
1537 if not has_superadmin_permission(apiuser):
1534 _perms = ('repository.admin',)
1538 _perms = ('repository.admin',)
1535 validate_repo_permissions(apiuser, repoid, repo, _perms)
1539 validate_repo_permissions(apiuser, repoid, repo, _perms)
1536
1540
1537 try:
1541 try:
1538
1542
1539 RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
1543 RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
1540
1544
1541 Session().commit()
1545 Session().commit()
1542 return {
1546 return {
1543 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % (
1547 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % (
1544 perm.permission_name, user.username, repo.repo_name
1548 perm.permission_name, user.username, repo.repo_name
1545 ),
1549 ),
1546 'success': True
1550 'success': True
1547 }
1551 }
1548 except Exception:
1552 except Exception:
1549 log.exception(
1553 log.exception(
1550 "Exception occurred while trying edit permissions for repo")
1554 "Exception occurred while trying edit permissions for repo")
1551 raise JSONRPCError(
1555 raise JSONRPCError(
1552 'failed to edit permission for user: `%s` in repo: `%s`' % (
1556 'failed to edit permission for user: `%s` in repo: `%s`' % (
1553 userid, repoid
1557 userid, repoid
1554 )
1558 )
1555 )
1559 )
1556
1560
1557
1561
1558 @jsonrpc_method()
1562 @jsonrpc_method()
1559 def revoke_user_permission(request, apiuser, repoid, userid):
1563 def revoke_user_permission(request, apiuser, repoid, userid):
1560 """
1564 """
1561 Revoke permission for a user on the specified repository.
1565 Revoke permission for a user on the specified repository.
1562
1566
1563 This command can only be run using an |authtoken| with admin
1567 This command can only be run using an |authtoken| with admin
1564 permissions on the |repo|.
1568 permissions on the |repo|.
1565
1569
1566 :param apiuser: This is filled automatically from the |authtoken|.
1570 :param apiuser: This is filled automatically from the |authtoken|.
1567 :type apiuser: AuthUser
1571 :type apiuser: AuthUser
1568 :param repoid: Set the repository name or repository ID.
1572 :param repoid: Set the repository name or repository ID.
1569 :type repoid: str or int
1573 :type repoid: str or int
1570 :param userid: Set the user name of revoked user.
1574 :param userid: Set the user name of revoked user.
1571 :type userid: str or int
1575 :type userid: str or int
1572
1576
1573 Example error output:
1577 Example error output:
1574
1578
1575 .. code-block:: bash
1579 .. code-block:: bash
1576
1580
1577 id : <id_given_in_input>
1581 id : <id_given_in_input>
1578 result: {
1582 result: {
1579 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
1583 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
1580 "success": true
1584 "success": true
1581 }
1585 }
1582 error: null
1586 error: null
1583 """
1587 """
1584
1588
1585 repo = get_repo_or_error(repoid)
1589 repo = get_repo_or_error(repoid)
1586 user = get_user_or_error(userid)
1590 user = get_user_or_error(userid)
1587 if not has_superadmin_permission(apiuser):
1591 if not has_superadmin_permission(apiuser):
1588 _perms = ('repository.admin',)
1592 _perms = ('repository.admin',)
1589 validate_repo_permissions(apiuser, repoid, repo, _perms)
1593 validate_repo_permissions(apiuser, repoid, repo, _perms)
1590
1594
1591 try:
1595 try:
1592 RepoModel().revoke_user_permission(repo=repo, user=user)
1596 RepoModel().revoke_user_permission(repo=repo, user=user)
1593 Session().commit()
1597 Session().commit()
1594 return {
1598 return {
1595 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % (
1599 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % (
1596 user.username, repo.repo_name
1600 user.username, repo.repo_name
1597 ),
1601 ),
1598 'success': True
1602 'success': True
1599 }
1603 }
1600 except Exception:
1604 except Exception:
1601 log.exception(
1605 log.exception(
1602 "Exception occurred while trying revoke permissions to repo")
1606 "Exception occurred while trying revoke permissions to repo")
1603 raise JSONRPCError(
1607 raise JSONRPCError(
1604 'failed to edit permission for user: `%s` in repo: `%s`' % (
1608 'failed to edit permission for user: `%s` in repo: `%s`' % (
1605 userid, repoid
1609 userid, repoid
1606 )
1610 )
1607 )
1611 )
1608
1612
1609
1613
1610 @jsonrpc_method()
1614 @jsonrpc_method()
1611 def grant_user_group_permission(request, apiuser, repoid, usergroupid, perm):
1615 def grant_user_group_permission(request, apiuser, repoid, usergroupid, perm):
1612 """
1616 """
1613 Grant permission for a user group on the specified repository,
1617 Grant permission for a user group on the specified repository,
1614 or update existing permissions.
1618 or update existing permissions.
1615
1619
1616 This command can only be run using an |authtoken| with admin
1620 This command can only be run using an |authtoken| with admin
1617 permissions on the |repo|.
1621 permissions on the |repo|.
1618
1622
1619 :param apiuser: This is filled automatically from the |authtoken|.
1623 :param apiuser: This is filled automatically from the |authtoken|.
1620 :type apiuser: AuthUser
1624 :type apiuser: AuthUser
1621 :param repoid: Set the repository name or repository ID.
1625 :param repoid: Set the repository name or repository ID.
1622 :type repoid: str or int
1626 :type repoid: str or int
1623 :param usergroupid: Specify the ID of the user group.
1627 :param usergroupid: Specify the ID of the user group.
1624 :type usergroupid: str or int
1628 :type usergroupid: str or int
1625 :param perm: Set the user group permissions using the following
1629 :param perm: Set the user group permissions using the following
1626 format: (repository.(none|read|write|admin))
1630 format: (repository.(none|read|write|admin))
1627 :type perm: str
1631 :type perm: str
1628
1632
1629 Example output:
1633 Example output:
1630
1634
1631 .. code-block:: bash
1635 .. code-block:: bash
1632
1636
1633 id : <id_given_in_input>
1637 id : <id_given_in_input>
1634 result : {
1638 result : {
1635 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
1639 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
1636 "success": true
1640 "success": true
1637
1641
1638 }
1642 }
1639 error : null
1643 error : null
1640
1644
1641 Example error output:
1645 Example error output:
1642
1646
1643 .. code-block:: bash
1647 .. code-block:: bash
1644
1648
1645 id : <id_given_in_input>
1649 id : <id_given_in_input>
1646 result : null
1650 result : null
1647 error : {
1651 error : {
1648 "failed to edit permission for user group: `<usergroup>` in repo `<repo>`'
1652 "failed to edit permission for user group: `<usergroup>` in repo `<repo>`'
1649 }
1653 }
1650
1654
1651 """
1655 """
1652
1656
1653 repo = get_repo_or_error(repoid)
1657 repo = get_repo_or_error(repoid)
1654 perm = get_perm_or_error(perm)
1658 perm = get_perm_or_error(perm)
1655 if not has_superadmin_permission(apiuser):
1659 if not has_superadmin_permission(apiuser):
1656 _perms = ('repository.admin',)
1660 _perms = ('repository.admin',)
1657 validate_repo_permissions(apiuser, repoid, repo, _perms)
1661 validate_repo_permissions(apiuser, repoid, repo, _perms)
1658
1662
1659 user_group = get_user_group_or_error(usergroupid)
1663 user_group = get_user_group_or_error(usergroupid)
1660 if not has_superadmin_permission(apiuser):
1664 if not has_superadmin_permission(apiuser):
1661 # check if we have at least read permission for this user group !
1665 # check if we have at least read permission for this user group !
1662 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1666 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1663 if not HasUserGroupPermissionAnyApi(*_perms)(
1667 if not HasUserGroupPermissionAnyApi(*_perms)(
1664 user=apiuser, user_group_name=user_group.users_group_name):
1668 user=apiuser, user_group_name=user_group.users_group_name):
1665 raise JSONRPCError(
1669 raise JSONRPCError(
1666 'user group `%s` does not exist' % (usergroupid,))
1670 'user group `%s` does not exist' % (usergroupid,))
1667
1671
1668 try:
1672 try:
1669 RepoModel().grant_user_group_permission(
1673 RepoModel().grant_user_group_permission(
1670 repo=repo, group_name=user_group, perm=perm)
1674 repo=repo, group_name=user_group, perm=perm)
1671
1675
1672 Session().commit()
1676 Session().commit()
1673 return {
1677 return {
1674 'msg': 'Granted perm: `%s` for user group: `%s` in '
1678 'msg': 'Granted perm: `%s` for user group: `%s` in '
1675 'repo: `%s`' % (
1679 'repo: `%s`' % (
1676 perm.permission_name, user_group.users_group_name,
1680 perm.permission_name, user_group.users_group_name,
1677 repo.repo_name
1681 repo.repo_name
1678 ),
1682 ),
1679 'success': True
1683 'success': True
1680 }
1684 }
1681 except Exception:
1685 except Exception:
1682 log.exception(
1686 log.exception(
1683 "Exception occurred while trying change permission on repo")
1687 "Exception occurred while trying change permission on repo")
1684 raise JSONRPCError(
1688 raise JSONRPCError(
1685 'failed to edit permission for user group: `%s` in '
1689 'failed to edit permission for user group: `%s` in '
1686 'repo: `%s`' % (
1690 'repo: `%s`' % (
1687 usergroupid, repo.repo_name
1691 usergroupid, repo.repo_name
1688 )
1692 )
1689 )
1693 )
1690
1694
1691
1695
1692 @jsonrpc_method()
1696 @jsonrpc_method()
1693 def revoke_user_group_permission(request, apiuser, repoid, usergroupid):
1697 def revoke_user_group_permission(request, apiuser, repoid, usergroupid):
1694 """
1698 """
1695 Revoke the permissions of a user group on a given repository.
1699 Revoke the permissions of a user group on a given repository.
1696
1700
1697 This command can only be run using an |authtoken| with admin
1701 This command can only be run using an |authtoken| with admin
1698 permissions on the |repo|.
1702 permissions on the |repo|.
1699
1703
1700 :param apiuser: This is filled automatically from the |authtoken|.
1704 :param apiuser: This is filled automatically from the |authtoken|.
1701 :type apiuser: AuthUser
1705 :type apiuser: AuthUser
1702 :param repoid: Set the repository name or repository ID.
1706 :param repoid: Set the repository name or repository ID.
1703 :type repoid: str or int
1707 :type repoid: str or int
1704 :param usergroupid: Specify the user group ID.
1708 :param usergroupid: Specify the user group ID.
1705 :type usergroupid: str or int
1709 :type usergroupid: str or int
1706
1710
1707 Example output:
1711 Example output:
1708
1712
1709 .. code-block:: bash
1713 .. code-block:: bash
1710
1714
1711 id : <id_given_in_input>
1715 id : <id_given_in_input>
1712 result: {
1716 result: {
1713 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
1717 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
1714 "success": true
1718 "success": true
1715 }
1719 }
1716 error: null
1720 error: null
1717 """
1721 """
1718
1722
1719 repo = get_repo_or_error(repoid)
1723 repo = get_repo_or_error(repoid)
1720 if not has_superadmin_permission(apiuser):
1724 if not has_superadmin_permission(apiuser):
1721 _perms = ('repository.admin',)
1725 _perms = ('repository.admin',)
1722 validate_repo_permissions(apiuser, repoid, repo, _perms)
1726 validate_repo_permissions(apiuser, repoid, repo, _perms)
1723
1727
1724 user_group = get_user_group_or_error(usergroupid)
1728 user_group = get_user_group_or_error(usergroupid)
1725 if not has_superadmin_permission(apiuser):
1729 if not has_superadmin_permission(apiuser):
1726 # check if we have at least read permission for this user group !
1730 # check if we have at least read permission for this user group !
1727 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1731 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1728 if not HasUserGroupPermissionAnyApi(*_perms)(
1732 if not HasUserGroupPermissionAnyApi(*_perms)(
1729 user=apiuser, user_group_name=user_group.users_group_name):
1733 user=apiuser, user_group_name=user_group.users_group_name):
1730 raise JSONRPCError(
1734 raise JSONRPCError(
1731 'user group `%s` does not exist' % (usergroupid,))
1735 'user group `%s` does not exist' % (usergroupid,))
1732
1736
1733 try:
1737 try:
1734 RepoModel().revoke_user_group_permission(
1738 RepoModel().revoke_user_group_permission(
1735 repo=repo, group_name=user_group)
1739 repo=repo, group_name=user_group)
1736
1740
1737 Session().commit()
1741 Session().commit()
1738 return {
1742 return {
1739 'msg': 'Revoked perm for user group: `%s` in repo: `%s`' % (
1743 'msg': 'Revoked perm for user group: `%s` in repo: `%s`' % (
1740 user_group.users_group_name, repo.repo_name
1744 user_group.users_group_name, repo.repo_name
1741 ),
1745 ),
1742 'success': True
1746 'success': True
1743 }
1747 }
1744 except Exception:
1748 except Exception:
1745 log.exception("Exception occurred while trying revoke "
1749 log.exception("Exception occurred while trying revoke "
1746 "user group permission on repo")
1750 "user group permission on repo")
1747 raise JSONRPCError(
1751 raise JSONRPCError(
1748 'failed to edit permission for user group: `%s` in '
1752 'failed to edit permission for user group: `%s` in '
1749 'repo: `%s`' % (
1753 'repo: `%s`' % (
1750 user_group.users_group_name, repo.repo_name
1754 user_group.users_group_name, repo.repo_name
1751 )
1755 )
1752 )
1756 )
1753
1757
1754
1758
1755 @jsonrpc_method()
1759 @jsonrpc_method()
1756 def pull(request, apiuser, repoid):
1760 def pull(request, apiuser, repoid, remote_uri=Optional(None)):
1757 """
1761 """
1758 Triggers a pull on the given repository from a remote location. You
1762 Triggers a pull on the given repository from a remote location. You
1759 can use this to keep remote repositories up-to-date.
1763 can use this to keep remote repositories up-to-date.
1760
1764
1761 This command can only be run using an |authtoken| with admin
1765 This command can only be run using an |authtoken| with admin
1762 rights to the specified repository. For more information,
1766 rights to the specified repository. For more information,
1763 see :ref:`config-token-ref`.
1767 see :ref:`config-token-ref`.
1764
1768
1765 This command takes the following options:
1769 This command takes the following options:
1766
1770
1767 :param apiuser: This is filled automatically from the |authtoken|.
1771 :param apiuser: This is filled automatically from the |authtoken|.
1768 :type apiuser: AuthUser
1772 :type apiuser: AuthUser
1769 :param repoid: The repository name or repository ID.
1773 :param repoid: The repository name or repository ID.
1770 :type repoid: str or int
1774 :type repoid: str or int
1775 :param remote_uri: Optional remote URI to pass in for pull
1776 :type remote_uri: str
1771
1777
1772 Example output:
1778 Example output:
1773
1779
1774 .. code-block:: bash
1780 .. code-block:: bash
1775
1781
1776 id : <id_given_in_input>
1782 id : <id_given_in_input>
1777 result : {
1783 result : {
1778 "msg": "Pulled from `<repository name>`"
1784 "msg": "Pulled from url `<remote_url>` on repo `<repository name>`"
1779 "repository": "<repository name>"
1785 "repository": "<repository name>"
1780 }
1786 }
1781 error : null
1787 error : null
1782
1788
1783 Example error output:
1789 Example error output:
1784
1790
1785 .. code-block:: bash
1791 .. code-block:: bash
1786
1792
1787 id : <id_given_in_input>
1793 id : <id_given_in_input>
1788 result : null
1794 result : null
1789 error : {
1795 error : {
1790 "Unable to pull changes from `<reponame>`"
1796 "Unable to push changes from `<remote_url>`"
1791 }
1797 }
1792
1798
1793 """
1799 """
1794
1800
1795 repo = get_repo_or_error(repoid)
1801 repo = get_repo_or_error(repoid)
1802 remote_uri = Optional.extract(remote_uri)
1803 remote_uri_display = remote_uri or repo.clone_uri_hidden
1796 if not has_superadmin_permission(apiuser):
1804 if not has_superadmin_permission(apiuser):
1797 _perms = ('repository.admin',)
1805 _perms = ('repository.admin',)
1798 validate_repo_permissions(apiuser, repoid, repo, _perms)
1806 validate_repo_permissions(apiuser, repoid, repo, _perms)
1799
1807
1800 try:
1808 try:
1801 ScmModel().pull_changes(repo.repo_name, apiuser.username)
1809 ScmModel().pull_changes(
1810 repo.repo_name, apiuser.username, remote_uri=remote_uri)
1802 return {
1811 return {
1803 'msg': 'Pulled from `%s`' % repo.repo_name,
1812 'msg': 'Pulled from url `%s` on repo `%s`' % (
1813 remote_uri_display, repo.repo_name),
1804 'repository': repo.repo_name
1814 'repository': repo.repo_name
1805 }
1815 }
1806 except Exception:
1816 except Exception:
1807 log.exception("Exception occurred while trying to "
1817 log.exception("Exception occurred while trying to "
1808 "pull changes from remote location")
1818 "pull changes from remote location")
1809 raise JSONRPCError(
1819 raise JSONRPCError(
1810 'Unable to pull changes from `%s`' % repo.repo_name
1820 'Unable to pull changes from `%s`' % remote_uri_display
1811 )
1821 )
1812
1822
1813
1823
1814 @jsonrpc_method()
1824 @jsonrpc_method()
1815 def strip(request, apiuser, repoid, revision, branch):
1825 def strip(request, apiuser, repoid, revision, branch):
1816 """
1826 """
1817 Strips the given revision from the specified repository.
1827 Strips the given revision from the specified repository.
1818
1828
1819 * This will remove the revision and all of its decendants.
1829 * This will remove the revision and all of its decendants.
1820
1830
1821 This command can only be run using an |authtoken| with admin rights to
1831 This command can only be run using an |authtoken| with admin rights to
1822 the specified repository.
1832 the specified repository.
1823
1833
1824 This command takes the following options:
1834 This command takes the following options:
1825
1835
1826 :param apiuser: This is filled automatically from the |authtoken|.
1836 :param apiuser: This is filled automatically from the |authtoken|.
1827 :type apiuser: AuthUser
1837 :type apiuser: AuthUser
1828 :param repoid: The repository name or repository ID.
1838 :param repoid: The repository name or repository ID.
1829 :type repoid: str or int
1839 :type repoid: str or int
1830 :param revision: The revision you wish to strip.
1840 :param revision: The revision you wish to strip.
1831 :type revision: str
1841 :type revision: str
1832 :param branch: The branch from which to strip the revision.
1842 :param branch: The branch from which to strip the revision.
1833 :type branch: str
1843 :type branch: str
1834
1844
1835 Example output:
1845 Example output:
1836
1846
1837 .. code-block:: bash
1847 .. code-block:: bash
1838
1848
1839 id : <id_given_in_input>
1849 id : <id_given_in_input>
1840 result : {
1850 result : {
1841 "msg": "'Stripped commit <commit_hash> from repo `<repository name>`'"
1851 "msg": "'Stripped commit <commit_hash> from repo `<repository name>`'"
1842 "repository": "<repository name>"
1852 "repository": "<repository name>"
1843 }
1853 }
1844 error : null
1854 error : null
1845
1855
1846 Example error output:
1856 Example error output:
1847
1857
1848 .. code-block:: bash
1858 .. code-block:: bash
1849
1859
1850 id : <id_given_in_input>
1860 id : <id_given_in_input>
1851 result : null
1861 result : null
1852 error : {
1862 error : {
1853 "Unable to strip commit <commit_hash> from repo `<repository name>`"
1863 "Unable to strip commit <commit_hash> from repo `<repository name>`"
1854 }
1864 }
1855
1865
1856 """
1866 """
1857
1867
1858 repo = get_repo_or_error(repoid)
1868 repo = get_repo_or_error(repoid)
1859 if not has_superadmin_permission(apiuser):
1869 if not has_superadmin_permission(apiuser):
1860 _perms = ('repository.admin',)
1870 _perms = ('repository.admin',)
1861 validate_repo_permissions(apiuser, repoid, repo, _perms)
1871 validate_repo_permissions(apiuser, repoid, repo, _perms)
1862
1872
1863 try:
1873 try:
1864 ScmModel().strip(repo, revision, branch)
1874 ScmModel().strip(repo, revision, branch)
1865 audit_logger.store_api(
1875 audit_logger.store_api(
1866 'repo.commit.strip', action_data={'commit_id': revision},
1876 'repo.commit.strip', action_data={'commit_id': revision},
1867 repo=repo,
1877 repo=repo,
1868 user=apiuser, commit=True)
1878 user=apiuser, commit=True)
1869
1879
1870 return {
1880 return {
1871 'msg': 'Stripped commit %s from repo `%s`' % (
1881 'msg': 'Stripped commit %s from repo `%s`' % (
1872 revision, repo.repo_name),
1882 revision, repo.repo_name),
1873 'repository': repo.repo_name
1883 'repository': repo.repo_name
1874 }
1884 }
1875 except Exception:
1885 except Exception:
1876 log.exception("Exception while trying to strip")
1886 log.exception("Exception while trying to strip")
1877 raise JSONRPCError(
1887 raise JSONRPCError(
1878 'Unable to strip commit %s from repo `%s`' % (
1888 'Unable to strip commit %s from repo `%s`' % (
1879 revision, repo.repo_name)
1889 revision, repo.repo_name)
1880 )
1890 )
1881
1891
1882
1892
1883 @jsonrpc_method()
1893 @jsonrpc_method()
1884 def get_repo_settings(request, apiuser, repoid, key=Optional(None)):
1894 def get_repo_settings(request, apiuser, repoid, key=Optional(None)):
1885 """
1895 """
1886 Returns all settings for a repository. If key is given it only returns the
1896 Returns all settings for a repository. If key is given it only returns the
1887 setting identified by the key or null.
1897 setting identified by the key or null.
1888
1898
1889 :param apiuser: This is filled automatically from the |authtoken|.
1899 :param apiuser: This is filled automatically from the |authtoken|.
1890 :type apiuser: AuthUser
1900 :type apiuser: AuthUser
1891 :param repoid: The repository name or repository id.
1901 :param repoid: The repository name or repository id.
1892 :type repoid: str or int
1902 :type repoid: str or int
1893 :param key: Key of the setting to return.
1903 :param key: Key of the setting to return.
1894 :type: key: Optional(str)
1904 :type: key: Optional(str)
1895
1905
1896 Example output:
1906 Example output:
1897
1907
1898 .. code-block:: bash
1908 .. code-block:: bash
1899
1909
1900 {
1910 {
1901 "error": null,
1911 "error": null,
1902 "id": 237,
1912 "id": 237,
1903 "result": {
1913 "result": {
1904 "extensions_largefiles": true,
1914 "extensions_largefiles": true,
1905 "extensions_evolve": true,
1915 "extensions_evolve": true,
1906 "hooks_changegroup_push_logger": true,
1916 "hooks_changegroup_push_logger": true,
1907 "hooks_changegroup_repo_size": false,
1917 "hooks_changegroup_repo_size": false,
1908 "hooks_outgoing_pull_logger": true,
1918 "hooks_outgoing_pull_logger": true,
1909 "phases_publish": "True",
1919 "phases_publish": "True",
1910 "rhodecode_hg_use_rebase_for_merging": true,
1920 "rhodecode_hg_use_rebase_for_merging": true,
1911 "rhodecode_pr_merge_enabled": true,
1921 "rhodecode_pr_merge_enabled": true,
1912 "rhodecode_use_outdated_comments": true
1922 "rhodecode_use_outdated_comments": true
1913 }
1923 }
1914 }
1924 }
1915 """
1925 """
1916
1926
1917 # Restrict access to this api method to admins only.
1927 # Restrict access to this api method to admins only.
1918 if not has_superadmin_permission(apiuser):
1928 if not has_superadmin_permission(apiuser):
1919 raise JSONRPCForbidden()
1929 raise JSONRPCForbidden()
1920
1930
1921 try:
1931 try:
1922 repo = get_repo_or_error(repoid)
1932 repo = get_repo_or_error(repoid)
1923 settings_model = VcsSettingsModel(repo=repo)
1933 settings_model = VcsSettingsModel(repo=repo)
1924 settings = settings_model.get_global_settings()
1934 settings = settings_model.get_global_settings()
1925 settings.update(settings_model.get_repo_settings())
1935 settings.update(settings_model.get_repo_settings())
1926
1936
1927 # If only a single setting is requested fetch it from all settings.
1937 # If only a single setting is requested fetch it from all settings.
1928 key = Optional.extract(key)
1938 key = Optional.extract(key)
1929 if key is not None:
1939 if key is not None:
1930 settings = settings.get(key, None)
1940 settings = settings.get(key, None)
1931 except Exception:
1941 except Exception:
1932 msg = 'Failed to fetch settings for repository `{}`'.format(repoid)
1942 msg = 'Failed to fetch settings for repository `{}`'.format(repoid)
1933 log.exception(msg)
1943 log.exception(msg)
1934 raise JSONRPCError(msg)
1944 raise JSONRPCError(msg)
1935
1945
1936 return settings
1946 return settings
1937
1947
1938
1948
1939 @jsonrpc_method()
1949 @jsonrpc_method()
1940 def set_repo_settings(request, apiuser, repoid, settings):
1950 def set_repo_settings(request, apiuser, repoid, settings):
1941 """
1951 """
1942 Update repository settings. Returns true on success.
1952 Update repository settings. Returns true on success.
1943
1953
1944 :param apiuser: This is filled automatically from the |authtoken|.
1954 :param apiuser: This is filled automatically from the |authtoken|.
1945 :type apiuser: AuthUser
1955 :type apiuser: AuthUser
1946 :param repoid: The repository name or repository id.
1956 :param repoid: The repository name or repository id.
1947 :type repoid: str or int
1957 :type repoid: str or int
1948 :param settings: The new settings for the repository.
1958 :param settings: The new settings for the repository.
1949 :type: settings: dict
1959 :type: settings: dict
1950
1960
1951 Example output:
1961 Example output:
1952
1962
1953 .. code-block:: bash
1963 .. code-block:: bash
1954
1964
1955 {
1965 {
1956 "error": null,
1966 "error": null,
1957 "id": 237,
1967 "id": 237,
1958 "result": true
1968 "result": true
1959 }
1969 }
1960 """
1970 """
1961 # Restrict access to this api method to admins only.
1971 # Restrict access to this api method to admins only.
1962 if not has_superadmin_permission(apiuser):
1972 if not has_superadmin_permission(apiuser):
1963 raise JSONRPCForbidden()
1973 raise JSONRPCForbidden()
1964
1974
1965 if type(settings) is not dict:
1975 if type(settings) is not dict:
1966 raise JSONRPCError('Settings have to be a JSON Object.')
1976 raise JSONRPCError('Settings have to be a JSON Object.')
1967
1977
1968 try:
1978 try:
1969 settings_model = VcsSettingsModel(repo=repoid)
1979 settings_model = VcsSettingsModel(repo=repoid)
1970
1980
1971 # Merge global, repo and incoming settings.
1981 # Merge global, repo and incoming settings.
1972 new_settings = settings_model.get_global_settings()
1982 new_settings = settings_model.get_global_settings()
1973 new_settings.update(settings_model.get_repo_settings())
1983 new_settings.update(settings_model.get_repo_settings())
1974 new_settings.update(settings)
1984 new_settings.update(settings)
1975
1985
1976 # Update the settings.
1986 # Update the settings.
1977 inherit_global_settings = new_settings.get(
1987 inherit_global_settings = new_settings.get(
1978 'inherit_global_settings', False)
1988 'inherit_global_settings', False)
1979 settings_model.create_or_update_repo_settings(
1989 settings_model.create_or_update_repo_settings(
1980 new_settings, inherit_global_settings=inherit_global_settings)
1990 new_settings, inherit_global_settings=inherit_global_settings)
1981 Session().commit()
1991 Session().commit()
1982 except Exception:
1992 except Exception:
1983 msg = 'Failed to update settings for repository `{}`'.format(repoid)
1993 msg = 'Failed to update settings for repository `{}`'.format(repoid)
1984 log.exception(msg)
1994 log.exception(msg)
1985 raise JSONRPCError(msg)
1995 raise JSONRPCError(msg)
1986
1996
1987 # Indicate success.
1997 # Indicate success.
1988 return True
1998 return True
1989
1999
1990
2000
1991 @jsonrpc_method()
2001 @jsonrpc_method()
1992 def maintenance(request, apiuser, repoid):
2002 def maintenance(request, apiuser, repoid):
1993 """
2003 """
1994 Triggers a maintenance on the given repository.
2004 Triggers a maintenance on the given repository.
1995
2005
1996 This command can only be run using an |authtoken| with admin
2006 This command can only be run using an |authtoken| with admin
1997 rights to the specified repository. For more information,
2007 rights to the specified repository. For more information,
1998 see :ref:`config-token-ref`.
2008 see :ref:`config-token-ref`.
1999
2009
2000 This command takes the following options:
2010 This command takes the following options:
2001
2011
2002 :param apiuser: This is filled automatically from the |authtoken|.
2012 :param apiuser: This is filled automatically from the |authtoken|.
2003 :type apiuser: AuthUser
2013 :type apiuser: AuthUser
2004 :param repoid: The repository name or repository ID.
2014 :param repoid: The repository name or repository ID.
2005 :type repoid: str or int
2015 :type repoid: str or int
2006
2016
2007 Example output:
2017 Example output:
2008
2018
2009 .. code-block:: bash
2019 .. code-block:: bash
2010
2020
2011 id : <id_given_in_input>
2021 id : <id_given_in_input>
2012 result : {
2022 result : {
2013 "msg": "executed maintenance command",
2023 "msg": "executed maintenance command",
2014 "executed_actions": [
2024 "executed_actions": [
2015 <action_message>, <action_message2>...
2025 <action_message>, <action_message2>...
2016 ],
2026 ],
2017 "repository": "<repository name>"
2027 "repository": "<repository name>"
2018 }
2028 }
2019 error : null
2029 error : null
2020
2030
2021 Example error output:
2031 Example error output:
2022
2032
2023 .. code-block:: bash
2033 .. code-block:: bash
2024
2034
2025 id : <id_given_in_input>
2035 id : <id_given_in_input>
2026 result : null
2036 result : null
2027 error : {
2037 error : {
2028 "Unable to execute maintenance on `<reponame>`"
2038 "Unable to execute maintenance on `<reponame>`"
2029 }
2039 }
2030
2040
2031 """
2041 """
2032
2042
2033 repo = get_repo_or_error(repoid)
2043 repo = get_repo_or_error(repoid)
2034 if not has_superadmin_permission(apiuser):
2044 if not has_superadmin_permission(apiuser):
2035 _perms = ('repository.admin',)
2045 _perms = ('repository.admin',)
2036 validate_repo_permissions(apiuser, repoid, repo, _perms)
2046 validate_repo_permissions(apiuser, repoid, repo, _perms)
2037
2047
2038 try:
2048 try:
2039 maintenance = repo_maintenance.RepoMaintenance()
2049 maintenance = repo_maintenance.RepoMaintenance()
2040 executed_actions = maintenance.execute(repo)
2050 executed_actions = maintenance.execute(repo)
2041
2051
2042 return {
2052 return {
2043 'msg': 'executed maintenance command',
2053 'msg': 'executed maintenance command',
2044 'executed_actions': executed_actions,
2054 'executed_actions': executed_actions,
2045 'repository': repo.repo_name
2055 'repository': repo.repo_name
2046 }
2056 }
2047 except Exception:
2057 except Exception:
2048 log.exception("Exception occurred while trying to run maintenance")
2058 log.exception("Exception occurred while trying to run maintenance")
2049 raise JSONRPCError(
2059 raise JSONRPCError(
2050 'Unable to execute maintenance on `%s`' % repo.repo_name)
2060 'Unable to execute maintenance on `%s`' % repo.repo_name)
@@ -1,341 +1,342 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 Helpers for fixture generation
22 Helpers for fixture generation
23 """
23 """
24
24
25 import os
25 import os
26 import time
26 import time
27 import tempfile
27 import tempfile
28 import shutil
28 import shutil
29
29
30 import configobj
30 import configobj
31
31
32 from rhodecode.tests import *
32 from rhodecode.tests import *
33 from rhodecode.model.db import Repository, User, RepoGroup, UserGroup, Gist
33 from rhodecode.model.db import Repository, User, RepoGroup, UserGroup, Gist
34 from rhodecode.model.meta import Session
34 from rhodecode.model.meta import Session
35 from rhodecode.model.repo import RepoModel
35 from rhodecode.model.repo import RepoModel
36 from rhodecode.model.user import UserModel
36 from rhodecode.model.user import UserModel
37 from rhodecode.model.repo_group import RepoGroupModel
37 from rhodecode.model.repo_group import RepoGroupModel
38 from rhodecode.model.user_group import UserGroupModel
38 from rhodecode.model.user_group import UserGroupModel
39 from rhodecode.model.gist import GistModel
39 from rhodecode.model.gist import GistModel
40 from rhodecode.model.auth_token import AuthTokenModel
40 from rhodecode.model.auth_token import AuthTokenModel
41
41
42 dn = os.path.dirname
42 dn = os.path.dirname
43 FIXTURES = os.path.join(dn(dn(os.path.abspath(__file__))), 'tests', 'fixtures')
43 FIXTURES = os.path.join(dn(dn(os.path.abspath(__file__))), 'tests', 'fixtures')
44
44
45
45
46 def error_function(*args, **kwargs):
46 def error_function(*args, **kwargs):
47 raise Exception('Total Crash !')
47 raise Exception('Total Crash !')
48
48
49
49
50 class TestINI(object):
50 class TestINI(object):
51 """
51 """
52 Allows to create a new test.ini file as a copy of existing one with edited
52 Allows to create a new test.ini file as a copy of existing one with edited
53 data. Example usage::
53 data. Example usage::
54
54
55 with TestINI('test.ini', [{'section':{'key':val'}]) as new_test_ini_path:
55 with TestINI('test.ini', [{'section':{'key':val'}]) as new_test_ini_path:
56 print 'paster server %s' % new_test_ini
56 print 'paster server %s' % new_test_ini
57 """
57 """
58
58
59 def __init__(self, ini_file_path, ini_params, new_file_prefix='DEFAULT',
59 def __init__(self, ini_file_path, ini_params, new_file_prefix='DEFAULT',
60 destroy=True, dir=None):
60 destroy=True, dir=None):
61 self.ini_file_path = ini_file_path
61 self.ini_file_path = ini_file_path
62 self.ini_params = ini_params
62 self.ini_params = ini_params
63 self.new_path = None
63 self.new_path = None
64 self.new_path_prefix = new_file_prefix
64 self.new_path_prefix = new_file_prefix
65 self._destroy = destroy
65 self._destroy = destroy
66 self._dir = dir
66 self._dir = dir
67
67
68 def __enter__(self):
68 def __enter__(self):
69 return self.create()
69 return self.create()
70
70
71 def __exit__(self, exc_type, exc_val, exc_tb):
71 def __exit__(self, exc_type, exc_val, exc_tb):
72 self.destroy()
72 self.destroy()
73
73
74 def create(self):
74 def create(self):
75 config = configobj.ConfigObj(
75 config = configobj.ConfigObj(
76 self.ini_file_path, file_error=True, write_empty_values=True)
76 self.ini_file_path, file_error=True, write_empty_values=True)
77
77
78 for data in self.ini_params:
78 for data in self.ini_params:
79 section, ini_params = data.items()[0]
79 section, ini_params = data.items()[0]
80 for key, val in ini_params.items():
80 for key, val in ini_params.items():
81 config[section][key] = val
81 config[section][key] = val
82 with tempfile.NamedTemporaryFile(
82 with tempfile.NamedTemporaryFile(
83 prefix=self.new_path_prefix, suffix='.ini', dir=self._dir,
83 prefix=self.new_path_prefix, suffix='.ini', dir=self._dir,
84 delete=False) as new_ini_file:
84 delete=False) as new_ini_file:
85 config.write(new_ini_file)
85 config.write(new_ini_file)
86 self.new_path = new_ini_file.name
86 self.new_path = new_ini_file.name
87
87
88 return self.new_path
88 return self.new_path
89
89
90 def destroy(self):
90 def destroy(self):
91 if self._destroy:
91 if self._destroy:
92 os.remove(self.new_path)
92 os.remove(self.new_path)
93
93
94
94
95 class Fixture(object):
95 class Fixture(object):
96
96
97 def anon_access(self, status):
97 def anon_access(self, status):
98 """
98 """
99 Context process for disabling anonymous access. use like:
99 Context process for disabling anonymous access. use like:
100 fixture = Fixture()
100 fixture = Fixture()
101 with fixture.anon_access(False):
101 with fixture.anon_access(False):
102 #tests
102 #tests
103
103
104 after this block anon access will be set to `not status`
104 after this block anon access will be set to `not status`
105 """
105 """
106
106
107 class context(object):
107 class context(object):
108 def __enter__(self):
108 def __enter__(self):
109 anon = User.get_default_user()
109 anon = User.get_default_user()
110 anon.active = status
110 anon.active = status
111 Session().add(anon)
111 Session().add(anon)
112 Session().commit()
112 Session().commit()
113 time.sleep(1.5) # must sleep for cache (1s to expire)
113 time.sleep(1.5) # must sleep for cache (1s to expire)
114
114
115 def __exit__(self, exc_type, exc_val, exc_tb):
115 def __exit__(self, exc_type, exc_val, exc_tb):
116 anon = User.get_default_user()
116 anon = User.get_default_user()
117 anon.active = not status
117 anon.active = not status
118 Session().add(anon)
118 Session().add(anon)
119 Session().commit()
119 Session().commit()
120
120
121 return context()
121 return context()
122
122
123 def _get_repo_create_params(self, **custom):
123 def _get_repo_create_params(self, **custom):
124 defs = {
124 defs = {
125 'repo_name': None,
125 'repo_name': None,
126 'repo_type': 'hg',
126 'repo_type': 'hg',
127 'clone_uri': '',
127 'clone_uri': '',
128 'push_uri': '',
128 'repo_group': '-1',
129 'repo_group': '-1',
129 'repo_description': 'DESC',
130 'repo_description': 'DESC',
130 'repo_private': False,
131 'repo_private': False,
131 'repo_landing_rev': 'rev:tip',
132 'repo_landing_rev': 'rev:tip',
132 'repo_copy_permissions': False,
133 'repo_copy_permissions': False,
133 'repo_state': Repository.STATE_CREATED,
134 'repo_state': Repository.STATE_CREATED,
134 }
135 }
135 defs.update(custom)
136 defs.update(custom)
136 if 'repo_name_full' not in custom:
137 if 'repo_name_full' not in custom:
137 defs.update({'repo_name_full': defs['repo_name']})
138 defs.update({'repo_name_full': defs['repo_name']})
138
139
139 # fix the repo name if passed as repo_name_full
140 # fix the repo name if passed as repo_name_full
140 if defs['repo_name']:
141 if defs['repo_name']:
141 defs['repo_name'] = defs['repo_name'].split('/')[-1]
142 defs['repo_name'] = defs['repo_name'].split('/')[-1]
142
143
143 return defs
144 return defs
144
145
145 def _get_group_create_params(self, **custom):
146 def _get_group_create_params(self, **custom):
146 defs = {
147 defs = {
147 'group_name': None,
148 'group_name': None,
148 'group_description': 'DESC',
149 'group_description': 'DESC',
149 'perm_updates': [],
150 'perm_updates': [],
150 'perm_additions': [],
151 'perm_additions': [],
151 'perm_deletions': [],
152 'perm_deletions': [],
152 'group_parent_id': -1,
153 'group_parent_id': -1,
153 'enable_locking': False,
154 'enable_locking': False,
154 'recursive': False,
155 'recursive': False,
155 }
156 }
156 defs.update(custom)
157 defs.update(custom)
157
158
158 return defs
159 return defs
159
160
160 def _get_user_create_params(self, name, **custom):
161 def _get_user_create_params(self, name, **custom):
161 defs = {
162 defs = {
162 'username': name,
163 'username': name,
163 'password': 'qweqwe',
164 'password': 'qweqwe',
164 'email': '%s+test@rhodecode.org' % name,
165 'email': '%s+test@rhodecode.org' % name,
165 'firstname': 'TestUser',
166 'firstname': 'TestUser',
166 'lastname': 'Test',
167 'lastname': 'Test',
167 'active': True,
168 'active': True,
168 'admin': False,
169 'admin': False,
169 'extern_type': 'rhodecode',
170 'extern_type': 'rhodecode',
170 'extern_name': None,
171 'extern_name': None,
171 }
172 }
172 defs.update(custom)
173 defs.update(custom)
173
174
174 return defs
175 return defs
175
176
176 def _get_user_group_create_params(self, name, **custom):
177 def _get_user_group_create_params(self, name, **custom):
177 defs = {
178 defs = {
178 'users_group_name': name,
179 'users_group_name': name,
179 'user_group_description': 'DESC',
180 'user_group_description': 'DESC',
180 'users_group_active': True,
181 'users_group_active': True,
181 'user_group_data': {},
182 'user_group_data': {},
182 }
183 }
183 defs.update(custom)
184 defs.update(custom)
184
185
185 return defs
186 return defs
186
187
187 def create_repo(self, name, **kwargs):
188 def create_repo(self, name, **kwargs):
188 repo_group = kwargs.get('repo_group')
189 repo_group = kwargs.get('repo_group')
189 if isinstance(repo_group, RepoGroup):
190 if isinstance(repo_group, RepoGroup):
190 kwargs['repo_group'] = repo_group.group_id
191 kwargs['repo_group'] = repo_group.group_id
191 name = name.split(Repository.NAME_SEP)[-1]
192 name = name.split(Repository.NAME_SEP)[-1]
192 name = Repository.NAME_SEP.join((repo_group.group_name, name))
193 name = Repository.NAME_SEP.join((repo_group.group_name, name))
193
194
194 if 'skip_if_exists' in kwargs:
195 if 'skip_if_exists' in kwargs:
195 del kwargs['skip_if_exists']
196 del kwargs['skip_if_exists']
196 r = Repository.get_by_repo_name(name)
197 r = Repository.get_by_repo_name(name)
197 if r:
198 if r:
198 return r
199 return r
199
200
200 form_data = self._get_repo_create_params(repo_name=name, **kwargs)
201 form_data = self._get_repo_create_params(repo_name=name, **kwargs)
201 cur_user = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
202 cur_user = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
202 RepoModel().create(form_data, cur_user)
203 RepoModel().create(form_data, cur_user)
203 Session().commit()
204 Session().commit()
204 repo = Repository.get_by_repo_name(name)
205 repo = Repository.get_by_repo_name(name)
205 assert repo
206 assert repo
206 return repo
207 return repo
207
208
208 def create_fork(self, repo_to_fork, fork_name, **kwargs):
209 def create_fork(self, repo_to_fork, fork_name, **kwargs):
209 repo_to_fork = Repository.get_by_repo_name(repo_to_fork)
210 repo_to_fork = Repository.get_by_repo_name(repo_to_fork)
210
211
211 form_data = self._get_repo_create_params(repo_name=fork_name,
212 form_data = self._get_repo_create_params(repo_name=fork_name,
212 fork_parent_id=repo_to_fork.repo_id,
213 fork_parent_id=repo_to_fork.repo_id,
213 repo_type=repo_to_fork.repo_type,
214 repo_type=repo_to_fork.repo_type,
214 **kwargs)
215 **kwargs)
215 #TODO: fix it !!
216 #TODO: fix it !!
216 form_data['description'] = form_data['repo_description']
217 form_data['description'] = form_data['repo_description']
217 form_data['private'] = form_data['repo_private']
218 form_data['private'] = form_data['repo_private']
218 form_data['landing_rev'] = form_data['repo_landing_rev']
219 form_data['landing_rev'] = form_data['repo_landing_rev']
219
220
220 owner = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
221 owner = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
221 RepoModel().create_fork(form_data, cur_user=owner)
222 RepoModel().create_fork(form_data, cur_user=owner)
222 Session().commit()
223 Session().commit()
223 r = Repository.get_by_repo_name(fork_name)
224 r = Repository.get_by_repo_name(fork_name)
224 assert r
225 assert r
225 return r
226 return r
226
227
227 def destroy_repo(self, repo_name, **kwargs):
228 def destroy_repo(self, repo_name, **kwargs):
228 RepoModel().delete(repo_name, **kwargs)
229 RepoModel().delete(repo_name, **kwargs)
229 Session().commit()
230 Session().commit()
230
231
231 def destroy_repo_on_filesystem(self, repo_name):
232 def destroy_repo_on_filesystem(self, repo_name):
232 rm_path = os.path.join(RepoModel().repos_path, repo_name)
233 rm_path = os.path.join(RepoModel().repos_path, repo_name)
233 if os.path.isdir(rm_path):
234 if os.path.isdir(rm_path):
234 shutil.rmtree(rm_path)
235 shutil.rmtree(rm_path)
235
236
236 def create_repo_group(self, name, **kwargs):
237 def create_repo_group(self, name, **kwargs):
237 if 'skip_if_exists' in kwargs:
238 if 'skip_if_exists' in kwargs:
238 del kwargs['skip_if_exists']
239 del kwargs['skip_if_exists']
239 gr = RepoGroup.get_by_group_name(group_name=name)
240 gr = RepoGroup.get_by_group_name(group_name=name)
240 if gr:
241 if gr:
241 return gr
242 return gr
242 form_data = self._get_group_create_params(group_name=name, **kwargs)
243 form_data = self._get_group_create_params(group_name=name, **kwargs)
243 owner = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
244 owner = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
244 gr = RepoGroupModel().create(
245 gr = RepoGroupModel().create(
245 group_name=form_data['group_name'],
246 group_name=form_data['group_name'],
246 group_description=form_data['group_name'],
247 group_description=form_data['group_name'],
247 owner=owner)
248 owner=owner)
248 Session().commit()
249 Session().commit()
249 gr = RepoGroup.get_by_group_name(gr.group_name)
250 gr = RepoGroup.get_by_group_name(gr.group_name)
250 return gr
251 return gr
251
252
252 def destroy_repo_group(self, repogroupid):
253 def destroy_repo_group(self, repogroupid):
253 RepoGroupModel().delete(repogroupid)
254 RepoGroupModel().delete(repogroupid)
254 Session().commit()
255 Session().commit()
255
256
256 def create_user(self, name, **kwargs):
257 def create_user(self, name, **kwargs):
257 if 'skip_if_exists' in kwargs:
258 if 'skip_if_exists' in kwargs:
258 del kwargs['skip_if_exists']
259 del kwargs['skip_if_exists']
259 user = User.get_by_username(name)
260 user = User.get_by_username(name)
260 if user:
261 if user:
261 return user
262 return user
262 form_data = self._get_user_create_params(name, **kwargs)
263 form_data = self._get_user_create_params(name, **kwargs)
263 user = UserModel().create(form_data)
264 user = UserModel().create(form_data)
264
265
265 # create token for user
266 # create token for user
266 AuthTokenModel().create(
267 AuthTokenModel().create(
267 user=user, description=u'TEST_USER_TOKEN')
268 user=user, description=u'TEST_USER_TOKEN')
268
269
269 Session().commit()
270 Session().commit()
270 user = User.get_by_username(user.username)
271 user = User.get_by_username(user.username)
271 return user
272 return user
272
273
273 def destroy_user(self, userid):
274 def destroy_user(self, userid):
274 UserModel().delete(userid)
275 UserModel().delete(userid)
275 Session().commit()
276 Session().commit()
276
277
277 def destroy_users(self, userid_iter):
278 def destroy_users(self, userid_iter):
278 for user_id in userid_iter:
279 for user_id in userid_iter:
279 if User.get_by_username(user_id):
280 if User.get_by_username(user_id):
280 UserModel().delete(user_id)
281 UserModel().delete(user_id)
281 Session().commit()
282 Session().commit()
282
283
283 def create_user_group(self, name, **kwargs):
284 def create_user_group(self, name, **kwargs):
284 if 'skip_if_exists' in kwargs:
285 if 'skip_if_exists' in kwargs:
285 del kwargs['skip_if_exists']
286 del kwargs['skip_if_exists']
286 gr = UserGroup.get_by_group_name(group_name=name)
287 gr = UserGroup.get_by_group_name(group_name=name)
287 if gr:
288 if gr:
288 return gr
289 return gr
289 # map active flag to the real attribute. For API consistency of fixtures
290 # map active flag to the real attribute. For API consistency of fixtures
290 if 'active' in kwargs:
291 if 'active' in kwargs:
291 kwargs['users_group_active'] = kwargs['active']
292 kwargs['users_group_active'] = kwargs['active']
292 del kwargs['active']
293 del kwargs['active']
293 form_data = self._get_user_group_create_params(name, **kwargs)
294 form_data = self._get_user_group_create_params(name, **kwargs)
294 owner = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
295 owner = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
295 user_group = UserGroupModel().create(
296 user_group = UserGroupModel().create(
296 name=form_data['users_group_name'],
297 name=form_data['users_group_name'],
297 description=form_data['user_group_description'],
298 description=form_data['user_group_description'],
298 owner=owner, active=form_data['users_group_active'],
299 owner=owner, active=form_data['users_group_active'],
299 group_data=form_data['user_group_data'])
300 group_data=form_data['user_group_data'])
300 Session().commit()
301 Session().commit()
301 user_group = UserGroup.get_by_group_name(user_group.users_group_name)
302 user_group = UserGroup.get_by_group_name(user_group.users_group_name)
302 return user_group
303 return user_group
303
304
304 def destroy_user_group(self, usergroupid):
305 def destroy_user_group(self, usergroupid):
305 UserGroupModel().delete(user_group=usergroupid, force=True)
306 UserGroupModel().delete(user_group=usergroupid, force=True)
306 Session().commit()
307 Session().commit()
307
308
308 def create_gist(self, **kwargs):
309 def create_gist(self, **kwargs):
309 form_data = {
310 form_data = {
310 'description': 'new-gist',
311 'description': 'new-gist',
311 'owner': TEST_USER_ADMIN_LOGIN,
312 'owner': TEST_USER_ADMIN_LOGIN,
312 'gist_type': GistModel.cls.GIST_PUBLIC,
313 'gist_type': GistModel.cls.GIST_PUBLIC,
313 'lifetime': -1,
314 'lifetime': -1,
314 'acl_level': Gist.ACL_LEVEL_PUBLIC,
315 'acl_level': Gist.ACL_LEVEL_PUBLIC,
315 'gist_mapping': {'filename1.txt': {'content': 'hello world'},}
316 'gist_mapping': {'filename1.txt': {'content': 'hello world'},}
316 }
317 }
317 form_data.update(kwargs)
318 form_data.update(kwargs)
318 gist = GistModel().create(
319 gist = GistModel().create(
319 description=form_data['description'], owner=form_data['owner'],
320 description=form_data['description'], owner=form_data['owner'],
320 gist_mapping=form_data['gist_mapping'], gist_type=form_data['gist_type'],
321 gist_mapping=form_data['gist_mapping'], gist_type=form_data['gist_type'],
321 lifetime=form_data['lifetime'], gist_acl_level=form_data['acl_level']
322 lifetime=form_data['lifetime'], gist_acl_level=form_data['acl_level']
322 )
323 )
323 Session().commit()
324 Session().commit()
324 return gist
325 return gist
325
326
326 def destroy_gists(self, gistid=None):
327 def destroy_gists(self, gistid=None):
327 for g in GistModel.cls.get_all():
328 for g in GistModel.cls.get_all():
328 if gistid:
329 if gistid:
329 if gistid == g.gist_access_id:
330 if gistid == g.gist_access_id:
330 GistModel().delete(g)
331 GistModel().delete(g)
331 else:
332 else:
332 GistModel().delete(g)
333 GistModel().delete(g)
333 Session().commit()
334 Session().commit()
334
335
335 def load_resource(self, resource_name, strip=False):
336 def load_resource(self, resource_name, strip=False):
336 with open(os.path.join(FIXTURES, resource_name)) as f:
337 with open(os.path.join(FIXTURES, resource_name)) as f:
337 source = f.read()
338 source = f.read()
338 if strip:
339 if strip:
339 source = source.strip()
340 source = source.strip()
340
341
341 return source
342 return source
General Comments 0
You need to be logged in to leave comments. Login now