Show More
@@ -77,7 +77,7 b' class TestCreatePullRequestApi(object):' | |||||
77 | assert pull_request.source_repo.repo_name == data['source_repo'] |
|
77 | assert pull_request.source_repo.repo_name == data['source_repo'] | |
78 | assert pull_request.target_repo.repo_name == data['target_repo'] |
|
78 | assert pull_request.target_repo.repo_name == data['target_repo'] | |
79 | assert pull_request.revisions == [self.commit_ids['change']] |
|
79 | assert pull_request.revisions == [self.commit_ids['change']] | |
80 |
assert pull_request.reviewers == |
|
80 | assert len(pull_request.reviewers) == 1 | |
81 |
|
81 | |||
82 | @pytest.mark.backends("git", "hg") |
|
82 | @pytest.mark.backends("git", "hg") | |
83 | def test_create_with_empty_description(self, backend): |
|
83 | def test_create_with_empty_description(self, backend): |
@@ -482,24 +482,26 b' def create_pull_request(' | |||||
482 | :param description: Set the pull request description. |
|
482 | :param description: Set the pull request description. | |
483 | :type description: Optional(str) |
|
483 | :type description: Optional(str) | |
484 | :param reviewers: Set the new pull request reviewers list. |
|
484 | :param reviewers: Set the new pull request reviewers list. | |
|
485 | Reviewer defined by review rules will be added automatically to the | |||
|
486 | defined list. | |||
485 | :type reviewers: Optional(list) |
|
487 | :type reviewers: Optional(list) | |
486 | Accepts username strings or objects of the format: |
|
488 | Accepts username strings or objects of the format: | |
487 |
|
489 | |||
488 | {'username': 'nick', 'reasons': ['original author'], 'mandatory': <bool>} |
|
490 | [{'username': 'nick', 'reasons': ['original author'], 'mandatory': <bool>}] | |
489 | """ |
|
491 | """ | |
490 |
|
492 | |||
491 | source = get_repo_or_error(source_repo) |
|
493 | source_db_repo = get_repo_or_error(source_repo) | |
492 | target = get_repo_or_error(target_repo) |
|
494 | target_db_repo = get_repo_or_error(target_repo) | |
493 | if not has_superadmin_permission(apiuser): |
|
495 | if not has_superadmin_permission(apiuser): | |
494 | _perms = ('repository.admin', 'repository.write', 'repository.read',) |
|
496 | _perms = ('repository.admin', 'repository.write', 'repository.read',) | |
495 | validate_repo_permissions(apiuser, source_repo, source, _perms) |
|
497 | validate_repo_permissions(apiuser, source_repo, source_db_repo, _perms) | |
496 |
|
498 | |||
497 | full_source_ref = resolve_ref_or_error(source_ref, source) |
|
499 | full_source_ref = resolve_ref_or_error(source_ref, source_db_repo) | |
498 | full_target_ref = resolve_ref_or_error(target_ref, target) |
|
500 | full_target_ref = resolve_ref_or_error(target_ref, target_db_repo) | |
499 | source_commit = get_commit_or_error(full_source_ref, source) |
|
501 | source_commit = get_commit_or_error(full_source_ref, source_db_repo) | |
500 | target_commit = get_commit_or_error(full_target_ref, target) |
|
502 | target_commit = get_commit_or_error(full_target_ref, target_db_repo) | |
501 | source_scm = source.scm_instance() |
|
503 | source_scm = source_db_repo.scm_instance() | |
502 | target_scm = target.scm_instance() |
|
504 | target_scm = target_db_repo.scm_instance() | |
503 |
|
505 | |||
504 | commit_ranges = target_scm.compare( |
|
506 | commit_ranges = target_scm.compare( | |
505 | target_commit.raw_id, source_commit.raw_id, source_scm, |
|
507 | target_commit.raw_id, source_commit.raw_id, source_scm, | |
@@ -515,6 +517,7 b' def create_pull_request(' | |||||
515 | raise JSONRPCError('no common ancestor found') |
|
517 | raise JSONRPCError('no common ancestor found') | |
516 |
|
518 | |||
517 | reviewer_objects = Optional.extract(reviewers) or [] |
|
519 | reviewer_objects = Optional.extract(reviewers) or [] | |
|
520 | ||||
518 | if reviewer_objects: |
|
521 | if reviewer_objects: | |
519 | schema = ReviewerListSchema() |
|
522 | schema = ReviewerListSchema() | |
520 | try: |
|
523 | try: | |
@@ -522,12 +525,28 b' def create_pull_request(' | |||||
522 | except Invalid as err: |
|
525 | except Invalid as err: | |
523 | raise JSONRPCValidationError(colander_exc=err) |
|
526 | raise JSONRPCValidationError(colander_exc=err) | |
524 |
|
527 | |||
525 | reviewers = [] |
|
528 | # validate users | |
526 | for reviewer_object in reviewer_objects: |
|
529 | for reviewer_object in reviewer_objects: | |
527 | user = get_user_or_error(reviewer_object['username']) |
|
530 | user = get_user_or_error(reviewer_object['username']) | |
528 |
|
|
531 | reviewer_object['user_id'] = user.user_id | |
529 | mandatory = reviewer_object['mandatory'] |
|
532 | ||
530 | reviewers.append((user.user_id, reasons, mandatory)) |
|
533 | get_default_reviewers_data, get_validated_reviewers = \ | |
|
534 | PullRequestModel().get_reviewer_functions() | |||
|
535 | ||||
|
536 | reviewer_rules = get_default_reviewers_data( | |||
|
537 | apiuser.get_instance(), source_db_repo, | |||
|
538 | source_commit, target_db_repo, target_commit) | |||
|
539 | ||||
|
540 | # specified rules are later re-validated, thus we can assume users will | |||
|
541 | # eventually provide those that meet the reviewer criteria. | |||
|
542 | if not reviewer_objects: | |||
|
543 | reviewer_objects = reviewer_rules['reviewers'] | |||
|
544 | ||||
|
545 | try: | |||
|
546 | reviewers = get_validated_reviewers( | |||
|
547 | reviewer_objects, reviewer_rules) | |||
|
548 | except ValueError as e: | |||
|
549 | raise JSONRPCError('Reviewers Validation: {}'.format(e)) | |||
531 |
|
550 | |||
532 | pull_request_model = PullRequestModel() |
|
551 | pull_request_model = PullRequestModel() | |
533 | pull_request = pull_request_model.create( |
|
552 | pull_request = pull_request_model.create( | |
@@ -573,7 +592,7 b' def update_pull_request(' | |||||
573 | :type reviewers: Optional(list) |
|
592 | :type reviewers: Optional(list) | |
574 | Accepts username strings or objects of the format: |
|
593 | Accepts username strings or objects of the format: | |
575 |
|
594 | |||
576 | {'username': 'nick', 'reasons': ['original author'], 'mandatory': <bool>} |
|
595 | [{'username': 'nick', 'reasons': ['original author'], 'mandatory': <bool>}] | |
577 |
|
596 | |||
578 | :param update_commits: Trigger update of commits for this pull request |
|
597 | :param update_commits: Trigger update of commits for this pull request | |
579 | :type: update_commits: Optional(bool) |
|
598 | :type: update_commits: Optional(bool) | |
@@ -619,6 +638,7 b' def update_pull_request(' | |||||
619 | pullrequestid,)) |
|
638 | pullrequestid,)) | |
620 |
|
639 | |||
621 | reviewer_objects = Optional.extract(reviewers) or [] |
|
640 | reviewer_objects = Optional.extract(reviewers) or [] | |
|
641 | ||||
622 | if reviewer_objects: |
|
642 | if reviewer_objects: | |
623 | schema = ReviewerListSchema() |
|
643 | schema = ReviewerListSchema() | |
624 | try: |
|
644 | try: | |
@@ -626,12 +646,23 b' def update_pull_request(' | |||||
626 | except Invalid as err: |
|
646 | except Invalid as err: | |
627 | raise JSONRPCValidationError(colander_exc=err) |
|
647 | raise JSONRPCValidationError(colander_exc=err) | |
628 |
|
648 | |||
629 | reviewers = [] |
|
649 | # validate users | |
630 | for reviewer_object in reviewer_objects: |
|
650 | for reviewer_object in reviewer_objects: | |
631 | user = get_user_or_error(reviewer_object['username']) |
|
651 | user = get_user_or_error(reviewer_object['username']) | |
632 |
|
|
652 | reviewer_object['user_id'] = user.user_id | |
633 | mandatory = reviewer_object['mandatory'] |
|
653 | ||
634 | reviewers.append((user.user_id, reasons, mandatory)) |
|
654 | get_default_reviewers_data, get_validated_reviewers = \ | |
|
655 | PullRequestModel().get_reviewer_functions() | |||
|
656 | ||||
|
657 | # re-use stored rules | |||
|
658 | reviewer_rules = pull_request.reviewer_data | |||
|
659 | try: | |||
|
660 | reviewers = get_validated_reviewers( | |||
|
661 | reviewer_objects, reviewer_rules) | |||
|
662 | except ValueError as e: | |||
|
663 | raise JSONRPCError('Reviewers Validation: {}'.format(e)) | |||
|
664 | else: | |||
|
665 | reviewers = [] | |||
635 |
|
666 | |||
636 | title = Optional.extract(title) |
|
667 | title = Optional.extract(title) | |
637 | description = Optional.extract(description) |
|
668 | description = Optional.extract(description) |
@@ -264,8 +264,8 b' class PullrequestsController(BaseRepoCon' | |||||
264 | c.rhodecode_user.get_instance(), source_db_repo, |
|
264 | c.rhodecode_user.get_instance(), source_db_repo, | |
265 | source_commit, target_db_repo, target_commit) |
|
265 | source_commit, target_db_repo, target_commit) | |
266 |
|
266 | |||
267 |
reviewers = |
|
267 | given_reviewers = _form['review_members'] | |
268 | _form['review_members'], reviewer_rules) |
|
268 | reviewers = validate_default_reviewers(given_reviewers, reviewer_rules) | |
269 |
|
269 | |||
270 | try: |
|
270 | try: | |
271 | pull_request = PullRequestModel().create( |
|
271 | pull_request = PullRequestModel().create( | |
@@ -452,7 +452,7 b' class PullrequestsController(BaseRepoCon' | |||||
452 | try: |
|
452 | try: | |
453 | reviewers = validate_default_reviewers(review_members, reviewer_rules) |
|
453 | reviewers = validate_default_reviewers(review_members, reviewer_rules) | |
454 | except ValueError as e: |
|
454 | except ValueError as e: | |
455 | log.error('Reviewers Validation:{}'.format(e)) |
|
455 | log.error('Reviewers Validation: {}'.format(e)) | |
456 | h.flash(e, category='error') |
|
456 | h.flash(e, category='error') | |
457 | return |
|
457 | return | |
458 |
|
458 |
@@ -1248,12 +1248,19 b' def initials_gravatar(email_address, fir' | |||||
1248 | return klass.generate_svg(svg_type=svg_type) |
|
1248 | return klass.generate_svg(svg_type=svg_type) | |
1249 |
|
1249 | |||
1250 |
|
1250 | |||
1251 | def gravatar_url(email_address, size=30): |
|
1251 | def gravatar_url(email_address, size=30, request=None): | |
1252 | # doh, we need to re-import those to mock it later |
|
1252 | request = get_current_request() | |
1253 | from pylons import tmpl_context as c |
|
1253 | if request and hasattr(request, 'call_context'): | |
|
1254 | _use_gravatar = request.call_context.visual.use_gravatar | |||
|
1255 | _gravatar_url = request.call_context.visual.gravatar_url | |||
|
1256 | else: | |||
|
1257 | # doh, we need to re-import those to mock it later | |||
|
1258 | from pylons import tmpl_context as c | |||
1254 |
|
1259 | |||
1255 | _use_gravatar = c.visual.use_gravatar |
|
1260 | _use_gravatar = c.visual.use_gravatar | |
1256 |
_gravatar_url = c.visual.gravatar_url |
|
1261 | _gravatar_url = c.visual.gravatar_url | |
|
1262 | ||||
|
1263 | _gravatar_url = _gravatar_url or User.DEFAULT_GRAVATAR_URL | |||
1257 |
|
1264 | |||
1258 | email_address = email_address or User.DEFAULT_USER_EMAIL |
|
1265 | email_address = email_address or User.DEFAULT_USER_EMAIL | |
1259 | if isinstance(email_address, unicode): |
|
1266 | if isinstance(email_address, unicode): |
@@ -24,7 +24,7 b' from rhodecode.model.validation_schema i' | |||||
24 |
|
24 | |||
25 | class ReviewerSchema(colander.MappingSchema): |
|
25 | class ReviewerSchema(colander.MappingSchema): | |
26 | username = colander.SchemaNode(types.StrOrIntType()) |
|
26 | username = colander.SchemaNode(types.StrOrIntType()) | |
27 | reasons = colander.SchemaNode(colander.List(), missing=[]) |
|
27 | reasons = colander.SchemaNode(colander.List(), missing=['no reason specified']) | |
28 | mandatory = colander.SchemaNode(colander.Boolean(), missing=False) |
|
28 | mandatory = colander.SchemaNode(colander.Boolean(), missing=False) | |
29 |
|
29 | |||
30 |
|
30 |
General Comments 0
You need to be logged in to leave comments.
Login now