##// END OF EJS Templates
reviewers: use target repo owner as default reviewer in case of CE edition....
marcink -
r3230:3c9caf8e default
parent child Browse files
Show More
@@ -1,342 +1,349 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import pytest
22 22
23 23 from rhodecode.model.db import User
24 24 from rhodecode.model.pull_request import PullRequestModel
25 25 from rhodecode.model.repo import RepoModel
26 26 from rhodecode.model.user import UserModel
27 27 from rhodecode.tests import TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN
28 28 from rhodecode.api.tests.utils import build_data, api_call, assert_error
29 29
30 30
31 31 @pytest.mark.usefixtures("testuser_api", "app")
32 32 class TestCreatePullRequestApi(object):
33 33 finalizers = []
34 34
35 35 def teardown_method(self, method):
36 36 if self.finalizers:
37 37 for finalizer in self.finalizers:
38 38 finalizer()
39 39 self.finalizers = []
40 40
41 41 def test_create_with_wrong_data(self):
42 42 required_data = {
43 43 'source_repo': 'tests/source_repo',
44 44 'target_repo': 'tests/target_repo',
45 45 'source_ref': 'branch:default:initial',
46 46 'target_ref': 'branch:default:new-feature',
47 47 }
48 48 for key in required_data:
49 49 data = required_data.copy()
50 50 data.pop(key)
51 51 id_, params = build_data(
52 52 self.apikey, 'create_pull_request', **data)
53 53 response = api_call(self.app, params)
54 54
55 55 expected = 'Missing non optional `{}` arg in JSON DATA'.format(key)
56 56 assert_error(id_, expected, given=response.body)
57 57
58 58 @pytest.mark.backends("git", "hg")
59 59 def test_create_with_correct_data(self, backend):
60 60 data = self._prepare_data(backend)
61 61 RepoModel().revoke_user_permission(
62 62 self.source.repo_name, User.DEFAULT_USER)
63 63 id_, params = build_data(
64 64 self.apikey_regular, 'create_pull_request', **data)
65 65 response = api_call(self.app, params)
66 66 expected_message = "Created new pull request `{title}`".format(
67 67 title=data['title'])
68 68 result = response.json
69 assert result['error'] == None
69 assert result['error'] is None
70 70 assert result['result']['msg'] == expected_message
71 71 pull_request_id = result['result']['pull_request_id']
72 72 pull_request = PullRequestModel().get(pull_request_id)
73 73 assert pull_request.title == data['title']
74 74 assert pull_request.description == data['description']
75 75 assert pull_request.source_ref == data['source_ref']
76 76 assert pull_request.target_ref == data['target_ref']
77 77 assert pull_request.source_repo.repo_name == data['source_repo']
78 78 assert pull_request.target_repo.repo_name == data['target_repo']
79 79 assert pull_request.revisions == [self.commit_ids['change']]
80 80 assert len(pull_request.reviewers) == 1
81 81
82 82 @pytest.mark.backends("git", "hg")
83 83 def test_create_with_empty_description(self, backend):
84 84 data = self._prepare_data(backend)
85 85 data.pop('description')
86 86 id_, params = build_data(
87 87 self.apikey_regular, 'create_pull_request', **data)
88 88 response = api_call(self.app, params)
89 89 expected_message = "Created new pull request `{title}`".format(
90 90 title=data['title'])
91 91 result = response.json
92 assert result['error'] == None
92 assert result['error'] is None
93 93 assert result['result']['msg'] == expected_message
94 94 pull_request_id = result['result']['pull_request_id']
95 95 pull_request = PullRequestModel().get(pull_request_id)
96 96 assert pull_request.description == ''
97 97
98 98 @pytest.mark.backends("git", "hg")
99 99 def test_create_with_empty_title(self, backend):
100 100 data = self._prepare_data(backend)
101 101 data.pop('title')
102 102 id_, params = build_data(
103 103 self.apikey_regular, 'create_pull_request', **data)
104 104 response = api_call(self.app, params)
105 105 result = response.json
106 106 pull_request_id = result['result']['pull_request_id']
107 107 pull_request = PullRequestModel().get(pull_request_id)
108 108 data['ref'] = backend.default_branch_name
109 109 title = '{source_repo}#{ref} to {target_repo}'.format(**data)
110 110 assert pull_request.title == title
111 111
112 112 @pytest.mark.backends("git", "hg")
113 113 def test_create_with_reviewers_specified_by_names(
114 114 self, backend, no_notifications):
115 115 data = self._prepare_data(backend)
116 116 reviewers = [
117 117 {'username': TEST_USER_REGULAR_LOGIN,
118 118 'reasons': ['{} added manually'.format(TEST_USER_REGULAR_LOGIN)]},
119 119 {'username': TEST_USER_ADMIN_LOGIN,
120 120 'reasons': ['{} added manually'.format(TEST_USER_ADMIN_LOGIN)],
121 121 'mandatory': True},
122 122 ]
123 123 data['reviewers'] = reviewers
124 124
125 125 id_, params = build_data(
126 126 self.apikey_regular, 'create_pull_request', **data)
127 127 response = api_call(self.app, params)
128 128
129 129 expected_message = "Created new pull request `{title}`".format(
130 130 title=data['title'])
131 131 result = response.json
132 assert result['error'] == None
132 assert result['error'] is None
133 133 assert result['result']['msg'] == expected_message
134 134 pull_request_id = result['result']['pull_request_id']
135 135 pull_request = PullRequestModel().get(pull_request_id)
136 136
137 137 actual_reviewers = []
138 138 for rev in pull_request.reviewers:
139 139 entry = {
140 140 'username': rev.user.username,
141 141 'reasons': rev.reasons,
142 142 }
143 143 if rev.mandatory:
144 144 entry['mandatory'] = rev.mandatory
145 145 actual_reviewers.append(entry)
146 146
147 # default reviewer will be added who is an owner of the repo
148 reviewers.append(
149 {'username': pull_request.author.username,
150 'reasons': [u'Default reviewer', u'Repository owner']},
151 )
147 owner_username = pull_request.target_repo.user.username
148 for spec_reviewer in reviewers[::]:
149 # default reviewer will be added who is an owner of the repo
150 # this get's overridden by a add owner to reviewers rule
151 if spec_reviewer['username'] == owner_username:
152 spec_reviewer['reasons'] = [u'Default reviewer', u'Repository owner']
153 # since owner is more important, we don't inherit mandatory flag
154 del spec_reviewer['mandatory']
155
152 156 assert sorted(actual_reviewers, key=lambda e: e['username']) \
153 157 == sorted(reviewers, key=lambda e: e['username'])
154 158
155 159 @pytest.mark.backends("git", "hg")
156 160 def test_create_with_reviewers_specified_by_ids(
157 161 self, backend, no_notifications):
158 162 data = self._prepare_data(backend)
159 163 reviewers = [
160 164 {'username': UserModel().get_by_username(
161 165 TEST_USER_REGULAR_LOGIN).user_id,
162 166 'reasons': ['added manually']},
163 167 {'username': UserModel().get_by_username(
164 168 TEST_USER_ADMIN_LOGIN).user_id,
165 169 'reasons': ['added manually']},
166 170 ]
167 171
168 172 data['reviewers'] = reviewers
169 173 id_, params = build_data(
170 174 self.apikey_regular, 'create_pull_request', **data)
171 175 response = api_call(self.app, params)
172 176
173 177 expected_message = "Created new pull request `{title}`".format(
174 178 title=data['title'])
175 179 result = response.json
176 assert result['error'] == None
180 assert result['error'] is None
177 181 assert result['result']['msg'] == expected_message
178 182 pull_request_id = result['result']['pull_request_id']
179 183 pull_request = PullRequestModel().get(pull_request_id)
180 184
181 185 actual_reviewers = []
182 186 for rev in pull_request.reviewers:
183 187 entry = {
184 188 'username': rev.user.user_id,
185 189 'reasons': rev.reasons,
186 190 }
187 191 if rev.mandatory:
188 192 entry['mandatory'] = rev.mandatory
189 193 actual_reviewers.append(entry)
190 # default reviewer will be added who is an owner of the repo
191 reviewers.append(
192 {'username': pull_request.author.user_id,
193 'reasons': [u'Default reviewer', u'Repository owner']},
194 )
194
195 owner_user_id = pull_request.target_repo.user.user_id
196 for spec_reviewer in reviewers[::]:
197 # default reviewer will be added who is an owner of the repo
198 # this get's overridden by a add owner to reviewers rule
199 if spec_reviewer['username'] == owner_user_id:
200 spec_reviewer['reasons'] = [u'Default reviewer', u'Repository owner']
201
195 202 assert sorted(actual_reviewers, key=lambda e: e['username']) \
196 203 == sorted(reviewers, key=lambda e: e['username'])
197 204
198 205 @pytest.mark.backends("git", "hg")
199 206 def test_create_fails_when_the_reviewer_is_not_found(self, backend):
200 207 data = self._prepare_data(backend)
201 208 data['reviewers'] = [{'username': 'somebody'}]
202 209 id_, params = build_data(
203 210 self.apikey_regular, 'create_pull_request', **data)
204 211 response = api_call(self.app, params)
205 212 expected_message = 'user `somebody` does not exist'
206 213 assert_error(id_, expected_message, given=response.body)
207 214
208 215 @pytest.mark.backends("git", "hg")
209 216 def test_cannot_create_with_reviewers_in_wrong_format(self, backend):
210 217 data = self._prepare_data(backend)
211 218 reviewers = ','.join([TEST_USER_REGULAR_LOGIN, TEST_USER_ADMIN_LOGIN])
212 219 data['reviewers'] = reviewers
213 220 id_, params = build_data(
214 221 self.apikey_regular, 'create_pull_request', **data)
215 222 response = api_call(self.app, params)
216 223 expected_message = {u'': '"test_regular,test_admin" is not iterable'}
217 224 assert_error(id_, expected_message, given=response.body)
218 225
219 226 @pytest.mark.backends("git", "hg")
220 227 def test_create_with_no_commit_hashes(self, backend):
221 228 data = self._prepare_data(backend)
222 229 expected_source_ref = data['source_ref']
223 230 expected_target_ref = data['target_ref']
224 231 data['source_ref'] = 'branch:{}'.format(backend.default_branch_name)
225 232 data['target_ref'] = 'branch:{}'.format(backend.default_branch_name)
226 233 id_, params = build_data(
227 234 self.apikey_regular, 'create_pull_request', **data)
228 235 response = api_call(self.app, params)
229 236 expected_message = "Created new pull request `{title}`".format(
230 237 title=data['title'])
231 238 result = response.json
232 239 assert result['result']['msg'] == expected_message
233 240 pull_request_id = result['result']['pull_request_id']
234 241 pull_request = PullRequestModel().get(pull_request_id)
235 242 assert pull_request.source_ref == expected_source_ref
236 243 assert pull_request.target_ref == expected_target_ref
237 244
238 245 @pytest.mark.backends("git", "hg")
239 246 @pytest.mark.parametrize("data_key", ["source_repo", "target_repo"])
240 247 def test_create_fails_with_wrong_repo(self, backend, data_key):
241 248 repo_name = 'fake-repo'
242 249 data = self._prepare_data(backend)
243 250 data[data_key] = repo_name
244 251 id_, params = build_data(
245 252 self.apikey_regular, 'create_pull_request', **data)
246 253 response = api_call(self.app, params)
247 254 expected_message = 'repository `{}` does not exist'.format(repo_name)
248 255 assert_error(id_, expected_message, given=response.body)
249 256
250 257 @pytest.mark.backends("git", "hg")
251 258 @pytest.mark.parametrize("data_key", ["source_ref", "target_ref"])
252 259 def test_create_fails_with_non_existing_branch(self, backend, data_key):
253 260 branch_name = 'test-branch'
254 261 data = self._prepare_data(backend)
255 262 data[data_key] = "branch:{}".format(branch_name)
256 263 id_, params = build_data(
257 264 self.apikey_regular, 'create_pull_request', **data)
258 265 response = api_call(self.app, params)
259 266 expected_message = 'The specified value:{type}:`{name}` ' \
260 267 'does not exist, or is not allowed.'.format(type='branch',
261 268 name=branch_name)
262 269 assert_error(id_, expected_message, given=response.body)
263 270
264 271 @pytest.mark.backends("git", "hg")
265 272 @pytest.mark.parametrize("data_key", ["source_ref", "target_ref"])
266 273 def test_create_fails_with_ref_in_a_wrong_format(self, backend, data_key):
267 274 data = self._prepare_data(backend)
268 275 ref = 'stange-ref'
269 276 data[data_key] = ref
270 277 id_, params = build_data(
271 278 self.apikey_regular, 'create_pull_request', **data)
272 279 response = api_call(self.app, params)
273 280 expected_message = (
274 281 'Ref `{ref}` given in a wrong format. Please check the API'
275 282 ' documentation for more details'.format(ref=ref))
276 283 assert_error(id_, expected_message, given=response.body)
277 284
278 285 @pytest.mark.backends("git", "hg")
279 286 @pytest.mark.parametrize("data_key", ["source_ref", "target_ref"])
280 287 def test_create_fails_with_non_existing_ref(self, backend, data_key):
281 288 commit_id = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa10'
282 289 ref = self._get_full_ref(backend, commit_id)
283 290 data = self._prepare_data(backend)
284 291 data[data_key] = ref
285 292 id_, params = build_data(
286 293 self.apikey_regular, 'create_pull_request', **data)
287 294 response = api_call(self.app, params)
288 295 expected_message = 'Ref `{}` does not exist'.format(ref)
289 296 assert_error(id_, expected_message, given=response.body)
290 297
291 298 @pytest.mark.backends("git", "hg")
292 299 def test_create_fails_when_no_revisions(self, backend):
293 300 data = self._prepare_data(backend, source_head='initial')
294 301 id_, params = build_data(
295 302 self.apikey_regular, 'create_pull_request', **data)
296 303 response = api_call(self.app, params)
297 304 expected_message = 'no commits found'
298 305 assert_error(id_, expected_message, given=response.body)
299 306
300 307 @pytest.mark.backends("git", "hg")
301 308 def test_create_fails_when_no_permissions(self, backend):
302 309 data = self._prepare_data(backend)
303 310 RepoModel().revoke_user_permission(
304 311 self.source.repo_name, self.test_user)
305 312 RepoModel().revoke_user_permission(
306 313 self.source.repo_name, User.DEFAULT_USER)
307 314
308 315 id_, params = build_data(
309 316 self.apikey_regular, 'create_pull_request', **data)
310 317 response = api_call(self.app, params)
311 318 expected_message = 'repository `{}` does not exist'.format(
312 319 self.source.repo_name)
313 320 assert_error(id_, expected_message, given=response.body)
314 321
315 322 def _prepare_data(
316 323 self, backend, source_head='change', target_head='initial'):
317 324 commits = [
318 325 {'message': 'initial'},
319 326 {'message': 'change'},
320 327 {'message': 'new-feature', 'parents': ['initial']},
321 328 ]
322 329 self.commit_ids = backend.create_master_repo(commits)
323 330 self.source = backend.create_repo(heads=[source_head])
324 331 self.target = backend.create_repo(heads=[target_head])
325 332
326 333 data = {
327 334 'source_repo': self.source.repo_name,
328 335 'target_repo': self.target.repo_name,
329 336 'source_ref': self._get_full_ref(
330 337 backend, self.commit_ids[source_head]),
331 338 'target_ref': self._get_full_ref(
332 339 backend, self.commit_ids[target_head]),
333 340 'title': 'Test PR 1',
334 341 'description': 'Test'
335 342 }
336 343 RepoModel().grant_user_permission(
337 344 self.source.repo_name, self.TEST_USER_LOGIN, 'repository.read')
338 345 return data
339 346
340 347 def _get_full_ref(self, backend, commit_id):
341 348 return 'branch:{branch}:{commit_id}'.format(
342 349 branch=backend.default_branch_name, commit_id=commit_id)
@@ -1,79 +1,79 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 from rhodecode.lib import helpers as h
22 22 from rhodecode.lib.utils2 import safe_int
23 23
24 24
25 25 def reviewer_as_json(user, reasons=None, mandatory=False, rules=None, user_group=None):
26 26 """
27 27 Returns json struct of a reviewer for frontend
28 28
29 29 :param user: the reviewer
30 30 :param reasons: list of strings of why they are reviewers
31 31 :param mandatory: bool, to set user as mandatory
32 32 """
33 33
34 34 return {
35 35 'user_id': user.user_id,
36 36 'reasons': reasons or [],
37 37 'rules': rules or [],
38 38 'mandatory': mandatory,
39 39 'user_group': user_group,
40 40 'username': user.username,
41 41 'first_name': user.first_name,
42 42 'last_name': user.last_name,
43 43 'user_link': h.link_to_user(user),
44 44 'gravatar_link': h.gravatar_url(user.email, 14),
45 45 }
46 46
47 47
48 48 def get_default_reviewers_data(
49 49 current_user, source_repo, source_commit, target_repo, target_commit):
50 50
51 51 """ Return json for default reviewers of a repository """
52 52
53 53 reasons = ['Default reviewer', 'Repository owner']
54 default = reviewer_as_json(
55 user=current_user, reasons=reasons, mandatory=False)
54 json_reviewers = [reviewer_as_json(
55 user=target_repo.user, reasons=reasons, mandatory=False, rules=None)]
56 56
57 57 return {
58 58 'api_ver': 'v1', # define version for later possible schema upgrade
59 'reviewers': [default],
59 'reviewers': json_reviewers,
60 60 'rules': {},
61 61 'rules_data': {},
62 62 }
63 63
64 64
65 65 def validate_default_reviewers(review_members, reviewer_rules):
66 66 """
67 67 Function to validate submitted reviewers against the saved rules
68 68
69 69 """
70 70 reviewers = []
71 71 reviewer_by_id = {}
72 72 for r in review_members:
73 73 reviewer_user_id = safe_int(r['user_id'])
74 74 entry = (reviewer_user_id, r['reasons'], r['mandatory'], r['rules'])
75 75
76 76 reviewer_by_id[reviewer_user_id] = entry
77 77 reviewers.append(entry)
78 78
79 79 return reviewers
General Comments 0
You need to be logged in to leave comments. Login now