diff --git a/rhodecode/api/tests/test_create_pull_request.py b/rhodecode/api/tests/test_create_pull_request.py --- a/rhodecode/api/tests/test_create_pull_request.py +++ b/rhodecode/api/tests/test_create_pull_request.py @@ -77,7 +77,7 @@ class TestCreatePullRequestApi(object): assert pull_request.source_repo.repo_name == data['source_repo'] assert pull_request.target_repo.repo_name == data['target_repo'] assert pull_request.revisions == [self.commit_ids['change']] - assert pull_request.reviewers == [] + assert len(pull_request.reviewers) == 1 @pytest.mark.backends("git", "hg") def test_create_with_empty_description(self, backend): diff --git a/rhodecode/api/views/pull_request_api.py b/rhodecode/api/views/pull_request_api.py --- a/rhodecode/api/views/pull_request_api.py +++ b/rhodecode/api/views/pull_request_api.py @@ -482,24 +482,26 @@ def create_pull_request( :param description: Set the pull request description. :type description: Optional(str) :param reviewers: Set the new pull request reviewers list. + Reviewer defined by review rules will be added automatically to the + defined list. :type reviewers: Optional(list) Accepts username strings or objects of the format: - {'username': 'nick', 'reasons': ['original author'], 'mandatory': } + [{'username': 'nick', 'reasons': ['original author'], 'mandatory': }] """ - source = get_repo_or_error(source_repo) - target = get_repo_or_error(target_repo) + source_db_repo = get_repo_or_error(source_repo) + target_db_repo = get_repo_or_error(target_repo) if not has_superadmin_permission(apiuser): _perms = ('repository.admin', 'repository.write', 'repository.read',) - validate_repo_permissions(apiuser, source_repo, source, _perms) + validate_repo_permissions(apiuser, source_repo, source_db_repo, _perms) - full_source_ref = resolve_ref_or_error(source_ref, source) - full_target_ref = resolve_ref_or_error(target_ref, target) - source_commit = get_commit_or_error(full_source_ref, source) - target_commit = get_commit_or_error(full_target_ref, target) - source_scm = source.scm_instance() - target_scm = target.scm_instance() + full_source_ref = resolve_ref_or_error(source_ref, source_db_repo) + full_target_ref = resolve_ref_or_error(target_ref, target_db_repo) + source_commit = get_commit_or_error(full_source_ref, source_db_repo) + target_commit = get_commit_or_error(full_target_ref, target_db_repo) + source_scm = source_db_repo.scm_instance() + target_scm = target_db_repo.scm_instance() commit_ranges = target_scm.compare( target_commit.raw_id, source_commit.raw_id, source_scm, @@ -515,6 +517,7 @@ def create_pull_request( raise JSONRPCError('no common ancestor found') reviewer_objects = Optional.extract(reviewers) or [] + if reviewer_objects: schema = ReviewerListSchema() try: @@ -522,12 +525,28 @@ def create_pull_request( except Invalid as err: raise JSONRPCValidationError(colander_exc=err) - reviewers = [] - for reviewer_object in reviewer_objects: - user = get_user_or_error(reviewer_object['username']) - reasons = reviewer_object['reasons'] - mandatory = reviewer_object['mandatory'] - reviewers.append((user.user_id, reasons, mandatory)) + # validate users + for reviewer_object in reviewer_objects: + user = get_user_or_error(reviewer_object['username']) + reviewer_object['user_id'] = user.user_id + + get_default_reviewers_data, get_validated_reviewers = \ + PullRequestModel().get_reviewer_functions() + + reviewer_rules = get_default_reviewers_data( + apiuser.get_instance(), source_db_repo, + source_commit, target_db_repo, target_commit) + + # specified rules are later re-validated, thus we can assume users will + # eventually provide those that meet the reviewer criteria. + if not reviewer_objects: + reviewer_objects = reviewer_rules['reviewers'] + + try: + reviewers = get_validated_reviewers( + reviewer_objects, reviewer_rules) + except ValueError as e: + raise JSONRPCError('Reviewers Validation: {}'.format(e)) pull_request_model = PullRequestModel() pull_request = pull_request_model.create( @@ -573,7 +592,7 @@ def update_pull_request( :type reviewers: Optional(list) Accepts username strings or objects of the format: - {'username': 'nick', 'reasons': ['original author'], 'mandatory': } + [{'username': 'nick', 'reasons': ['original author'], 'mandatory': }] :param update_commits: Trigger update of commits for this pull request :type: update_commits: Optional(bool) @@ -619,6 +638,7 @@ def update_pull_request( pullrequestid,)) reviewer_objects = Optional.extract(reviewers) or [] + if reviewer_objects: schema = ReviewerListSchema() try: @@ -626,12 +646,23 @@ def update_pull_request( except Invalid as err: raise JSONRPCValidationError(colander_exc=err) - reviewers = [] - for reviewer_object in reviewer_objects: - user = get_user_or_error(reviewer_object['username']) - reasons = reviewer_object['reasons'] - mandatory = reviewer_object['mandatory'] - reviewers.append((user.user_id, reasons, mandatory)) + # validate users + for reviewer_object in reviewer_objects: + user = get_user_or_error(reviewer_object['username']) + reviewer_object['user_id'] = user.user_id + + get_default_reviewers_data, get_validated_reviewers = \ + PullRequestModel().get_reviewer_functions() + + # re-use stored rules + reviewer_rules = pull_request.reviewer_data + try: + reviewers = get_validated_reviewers( + reviewer_objects, reviewer_rules) + except ValueError as e: + raise JSONRPCError('Reviewers Validation: {}'.format(e)) + else: + reviewers = [] title = Optional.extract(title) description = Optional.extract(description) diff --git a/rhodecode/controllers/pullrequests.py b/rhodecode/controllers/pullrequests.py --- a/rhodecode/controllers/pullrequests.py +++ b/rhodecode/controllers/pullrequests.py @@ -264,8 +264,8 @@ class PullrequestsController(BaseRepoCon c.rhodecode_user.get_instance(), source_db_repo, source_commit, target_db_repo, target_commit) - reviewers = validate_default_reviewers( - _form['review_members'], reviewer_rules) + given_reviewers = _form['review_members'] + reviewers = validate_default_reviewers(given_reviewers, reviewer_rules) try: pull_request = PullRequestModel().create( @@ -452,7 +452,7 @@ class PullrequestsController(BaseRepoCon try: reviewers = validate_default_reviewers(review_members, reviewer_rules) except ValueError as e: - log.error('Reviewers Validation:{}'.format(e)) + log.error('Reviewers Validation: {}'.format(e)) h.flash(e, category='error') return diff --git a/rhodecode/lib/helpers.py b/rhodecode/lib/helpers.py --- a/rhodecode/lib/helpers.py +++ b/rhodecode/lib/helpers.py @@ -1248,12 +1248,19 @@ def initials_gravatar(email_address, fir return klass.generate_svg(svg_type=svg_type) -def gravatar_url(email_address, size=30): - # doh, we need to re-import those to mock it later - from pylons import tmpl_context as c +def gravatar_url(email_address, size=30, request=None): + request = get_current_request() + if request and hasattr(request, 'call_context'): + _use_gravatar = request.call_context.visual.use_gravatar + _gravatar_url = request.call_context.visual.gravatar_url + else: + # doh, we need to re-import those to mock it later + from pylons import tmpl_context as c - _use_gravatar = c.visual.use_gravatar - _gravatar_url = c.visual.gravatar_url or User.DEFAULT_GRAVATAR_URL + _use_gravatar = c.visual.use_gravatar + _gravatar_url = c.visual.gravatar_url + + _gravatar_url = _gravatar_url or User.DEFAULT_GRAVATAR_URL email_address = email_address or User.DEFAULT_USER_EMAIL if isinstance(email_address, unicode): diff --git a/rhodecode/model/validation_schema/schemas/reviewer_schema.py b/rhodecode/model/validation_schema/schemas/reviewer_schema.py --- a/rhodecode/model/validation_schema/schemas/reviewer_schema.py +++ b/rhodecode/model/validation_schema/schemas/reviewer_schema.py @@ -24,7 +24,7 @@ from rhodecode.model.validation_schema i class ReviewerSchema(colander.MappingSchema): username = colander.SchemaNode(types.StrOrIntType()) - reasons = colander.SchemaNode(colander.List(), missing=[]) + reasons = colander.SchemaNode(colander.List(), missing=['no reason specified']) mandatory = colander.SchemaNode(colander.Boolean(), missing=False)