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 @@ -320,7 +320,7 @@ class TestCreatePullRequestApi(object): id_, params = build_data( self.apikey_regular, 'create_pull_request', **data) response = api_call(self.app, params) - expected_message = 'no commits found' + expected_message = 'no commits found for merge between specified references' assert_error(id_, expected_message, given=response.body) @pytest.mark.backends("git", "hg") diff --git a/rhodecode/api/tests/test_get_pull_requests.py b/rhodecode/api/tests/test_get_pull_requests.py --- a/rhodecode/api/tests/test_get_pull_requests.py +++ b/rhodecode/api/tests/test_get_pull_requests.py @@ -29,6 +29,7 @@ from rhodecode.api.tests.utils import ( @pytest.mark.usefixtures("testuser_api", "app") class TestGetPullRequest(object): + @pytest.mark.backends("git", "hg") def test_api_get_pull_requests(self, pr_util): pull_request = pr_util.create_pull_request() @@ -40,6 +41,7 @@ class TestGetPullRequest(object): target_ref=pull_request.target_ref, revisions=pull_request.revisions, reviewers=(), + observers=(), title=pull_request.title, description=pull_request.description, ) diff --git a/rhodecode/api/tests/test_update_pull_request.py b/rhodecode/api/tests/test_update_pull_request.py --- a/rhodecode/api/tests/test_update_pull_request.py +++ b/rhodecode/api/tests/test_update_pull_request.py @@ -51,6 +51,7 @@ class TestUpdatePullRequest(object): "pull_request": response.json['result']['pull_request'], "updated_commits": {"added": [], "common": [], "removed": []}, "updated_reviewers": {"added": [], "removed": []}, + "updated_observers": {"added": [], "removed": []}, } response_json = response.json['result'] @@ -111,6 +112,7 @@ class TestUpdatePullRequest(object): "total": total_commits, "removed": []}, "updated_reviewers": {"added": [], "removed": []}, + "updated_observers": {"added": [], "removed": []}, } assert_ok(id_, expected, response.body) @@ -122,7 +124,7 @@ class TestUpdatePullRequest(object): b = user_util.create_user() c = user_util.create_user() new_reviewers = [ - {'username': b.username,'reasons': ['updated via API'], + {'username': b.username, 'reasons': ['updated via API'], 'mandatory':False}, {'username': c.username, 'reasons': ['updated via API'], 'mandatory':False}, @@ -132,7 +134,7 @@ class TestUpdatePullRequest(object): removed = [a.username] pull_request = pr_util.create_pull_request( - reviewers=[(a.username, ['added via API'], False, [])]) + reviewers=[(a.username, ['added via API'], False, 'reviewer', [])]) id_, params = build_data( self.apikey, 'update_pull_request', @@ -146,6 +148,7 @@ class TestUpdatePullRequest(object): "pull_request": response.json['result']['pull_request'], "updated_commits": {"added": [], "common": [], "removed": []}, "updated_reviewers": {"added": added, "removed": removed}, + "updated_observers": {"added": [], "removed": []}, } assert_ok(id_, expected, response.body) 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 @@ -30,9 +30,11 @@ from rhodecode.lib import channelstream from rhodecode.lib.auth import (HasRepoPermissionAnyApi) from rhodecode.lib.base import vcs_operation_context from rhodecode.lib.utils2 import str2bool +from rhodecode.lib.vcs.backends.base import unicode_to_reference from rhodecode.model.changeset_status import ChangesetStatusModel from rhodecode.model.comment import CommentsModel -from rhodecode.model.db import Session, ChangesetStatus, ChangesetComment, PullRequest +from rhodecode.model.db import ( + Session, ChangesetStatus, ChangesetComment, PullRequest, PullRequestReviewers) from rhodecode.model.pull_request import PullRequestModel, MergeCheck from rhodecode.model.settings import SettingsModel from rhodecode.model.validation_schema import Invalid @@ -600,7 +602,7 @@ def comment_pull_request( extra_recipients=extra_recipients, send_email=send_email ) - is_inline = bool(comment.f_path and comment.line_no) + is_inline = comment.is_inline if allowed_to_change_status and status: old_calculated_status = pull_request.calculated_review_status() @@ -646,12 +648,26 @@ def comment_pull_request( return data +def _reviewers_validation(obj_list): + schema = ReviewerListSchema() + try: + reviewer_objects = schema.deserialize(obj_list) + except Invalid as err: + raise JSONRPCValidationError(colander_exc=err) + + # validate users + for reviewer_object in reviewer_objects: + user = get_user_or_error(reviewer_object['username']) + reviewer_object['user_id'] = user.user_id + return reviewer_objects + @jsonrpc_method() def create_pull_request( request, apiuser, source_repo, target_repo, source_ref, target_ref, owner=Optional(OAttr('apiuser')), title=Optional(''), description=Optional(''), - description_renderer=Optional(''), reviewers=Optional(None)): + description_renderer=Optional(''), + reviewers=Optional(None), observers=Optional(None)): """ Creates a new pull request. @@ -689,6 +705,13 @@ def create_pull_request( Accepts username strings or objects of the format: [{'username': 'nick', 'reasons': ['original author'], 'mandatory': }] + :param observers: Set the new pull request observers list. + Reviewer defined by review rules will be added automatically to the + defined list. This feature is only available in RhodeCode EE + :type observers: Optional(list) + Accepts username strings or objects of the format: + + [{'username': 'nick', 'reasons': ['original author']}] """ source_db_repo = get_repo_or_error(source_repo) @@ -702,38 +725,39 @@ def create_pull_request( 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) + get_commit_or_error(full_source_ref, source_db_repo) + get_commit_or_error(full_target_ref, target_db_repo) reviewer_objects = Optional.extract(reviewers) or [] + observer_objects = Optional.extract(observers) or [] # serialize and validate passed in given reviewers if reviewer_objects: - schema = ReviewerListSchema() - try: - reviewer_objects = schema.deserialize(reviewer_objects) - except Invalid as err: - raise JSONRPCValidationError(colander_exc=err) + reviewer_objects = _reviewers_validation(reviewer_objects) - # validate users - for reviewer_object in reviewer_objects: - user = get_user_or_error(reviewer_object['username']) - reviewer_object['user_id'] = user.user_id + if observer_objects: + observer_objects = _reviewers_validation(reviewer_objects) get_default_reviewers_data, validate_default_reviewers, validate_observers = \ PullRequestModel().get_reviewer_functions() + source_ref_obj = unicode_to_reference(full_source_ref) + target_ref_obj = unicode_to_reference(full_target_ref) + # recalculate reviewers logic, to make sure we can validate this default_reviewers_data = get_default_reviewers_data( owner, - source_repo, - Reference(source_type, source_name, source_commit_id), - target_repo, - Reference(target_type, target_name, target_commit_id) + source_db_repo, + source_ref_obj, + target_db_repo, + target_ref_obj, ) - # now MERGE our given with the calculated - reviewer_objects = default_reviewers_data['reviewers'] + reviewer_objects + # now MERGE our given with the calculated from the default rules + just_reviewers = [ + x for x in default_reviewers_data['reviewers'] + if x['role'] == PullRequestReviewers.ROLE_REVIEWER] + reviewer_objects = just_reviewers + reviewer_objects try: reviewers = validate_default_reviewers( @@ -741,9 +765,21 @@ def create_pull_request( except ValueError as e: raise JSONRPCError('Reviewers Validation: {}'.format(e)) + # now MERGE our given with the calculated from the default rules + just_observers = [ + x for x in default_reviewers_data['reviewers'] + if x['role'] == PullRequestReviewers.ROLE_OBSERVER] + observer_objects = just_observers + observer_objects + + try: + observers = validate_observers( + observer_objects, default_reviewers_data) + except ValueError as e: + raise JSONRPCError('Observer Validation: {}'.format(e)) + title = Optional.extract(title) if not title: - title_source_ref = source_ref.split(':', 2)[1] + title_source_ref = source_ref_obj.name title = PullRequestModel().generate_pullrequest_title( source=source_repo, source_ref=title_source_ref, @@ -752,20 +788,17 @@ def create_pull_request( diff_info = default_reviewers_data['diff_info'] common_ancestor_id = diff_info['ancestor'] - commits = diff_info['commits'] + # NOTE(marcink): reversed is consistent with how we open it in the WEB interface + commits = [commit['commit_id'] for commit in reversed(diff_info['commits'])] if not common_ancestor_id: - raise JSONRPCError('no common ancestor found') + raise JSONRPCError('no common ancestor found between specified references') if not commits: - raise JSONRPCError('no commits found') - - # NOTE(marcink): reversed is consistent with how we open it in the WEB interface - revisions = [commit.raw_id for commit in reversed(commits)] + raise JSONRPCError('no commits found for merge between specified references') # recalculate target ref based on ancestor - target_ref_type, target_ref_name, __ = full_target_ref.split(':') - full_target_ref = ':'.join((target_ref_type, target_ref_name, common_ancestor_id)) + full_target_ref = ':'.join((target_ref_obj.type, target_ref_obj.name, common_ancestor_id)) # fetch renderer, if set fallback to plain in case of PR rc_config = SettingsModel().get_all_settings() @@ -780,8 +813,9 @@ def create_pull_request( target_repo=target_repo, target_ref=full_target_ref, common_ancestor_id=common_ancestor_id, - revisions=revisions, + revisions=commits, reviewers=reviewers, + observers=observers, title=title, description=description, description_renderer=description_renderer, @@ -801,7 +835,7 @@ def create_pull_request( def update_pull_request( request, apiuser, pullrequestid, repoid=Optional(None), title=Optional(''), description=Optional(''), description_renderer=Optional(''), - reviewers=Optional(None), update_commits=Optional(None)): + reviewers=Optional(None), observers=Optional(None), update_commits=Optional(None)): """ Updates a pull request. @@ -823,7 +857,11 @@ def update_pull_request( Accepts username strings or objects of the format: [{'username': 'nick', 'reasons': ['original author'], 'mandatory': }] + :param observers: Update pull request observers list with new value. + :type observers: Optional(list) + Accepts username strings or objects of the format: + [{'username': 'nick', 'reasons': ['should be aware about this PR']}] :param update_commits: Trigger update of commits for this pull request :type: update_commits: Optional(bool) @@ -841,6 +879,12 @@ def update_pull_request( ], "removed": [] }, + "updated_observers": { + "added": [ + "username" + ], + "removed": [] + }, "updated_commits": { "added": [ "" @@ -872,30 +916,7 @@ def update_pull_request( pullrequestid,)) reviewer_objects = Optional.extract(reviewers) or [] - - if reviewer_objects: - schema = ReviewerListSchema() - try: - reviewer_objects = schema.deserialize(reviewer_objects) - except Invalid as err: - raise JSONRPCValidationError(colander_exc=err) - - # 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, validate_observers = \ - 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 = [] + observer_objects = Optional.extract(observers) or [] title = Optional.extract(title) description = Optional.extract(description) @@ -935,12 +956,41 @@ def update_pull_request( commits_changed = True # Update reviewers + # serialize and validate passed in given reviewers + if reviewer_objects: + reviewer_objects = _reviewers_validation(reviewer_objects) + + if observer_objects: + observer_objects = _reviewers_validation(reviewer_objects) + + # re-use stored rules + default_reviewers_data = pull_request.reviewer_data + + __, validate_default_reviewers, validate_observers = \ + PullRequestModel().get_reviewer_functions() + + if reviewer_objects: + try: + reviewers = validate_default_reviewers(reviewer_objects, default_reviewers_data) + except ValueError as e: + raise JSONRPCError('Reviewers Validation: {}'.format(e)) + else: + reviewers = [] + + if observer_objects: + try: + observers = validate_default_reviewers(reviewer_objects, default_reviewers_data) + except ValueError as e: + raise JSONRPCError('Observer Validation: {}'.format(e)) + else: + observers = [] + reviewers_changed = False reviewers_changes = {"added": [], "removed": []} if reviewers: old_calculated_status = pull_request.calculated_review_status() added_reviewers, removed_reviewers = \ - PullRequestModel().update_reviewers(pull_request, reviewers, apiuser) + PullRequestModel().update_reviewers(pull_request, reviewers, apiuser.get_instance()) reviewers_changes['added'] = sorted( [get_user_or_error(n).username for n in added_reviewers]) @@ -957,6 +1007,18 @@ def update_pull_request( reviewers_changed = True observers_changed = False + observers_changes = {"added": [], "removed": []} + if observers: + added_observers, removed_observers = \ + PullRequestModel().update_observers(pull_request, observers, apiuser.get_instance()) + + observers_changes['added'] = sorted( + [get_user_or_error(n).username for n in added_observers]) + observers_changes['removed'] = sorted( + [get_user_or_error(n).username for n in removed_observers]) + Session().commit() + + reviewers_changed = True # push changed to channelstream if commits_changed or reviewers_changed or observers_changed: @@ -966,11 +1028,11 @@ def update_pull_request( request, pr_broadcast_channel, apiuser, msg) data = { - 'msg': 'Updated pull request `{}`'.format( - pull_request.pull_request_id), + 'msg': 'Updated pull request `{}`'.format(pull_request.pull_request_id), 'pull_request': pull_request.get_api_data(), 'updated_commits': commit_changes, - 'updated_reviewers': reviewers_changes + 'updated_reviewers': reviewers_changes, + 'updated_observers': observers_changes, } return data diff --git a/rhodecode/api/views/repo_api.py b/rhodecode/api/views/repo_api.py --- a/rhodecode/api/views/repo_api.py +++ b/rhodecode/api/views/repo_api.py @@ -1653,7 +1653,7 @@ def comment_commit( extra_recipients=extra_recipients, send_email=send_email ) - is_inline = bool(comment.f_path and comment.line_no) + is_inline = comment.is_inline if status: # also do a status change diff --git a/rhodecode/apps/repository/tests/test_repo_pullrequests.py b/rhodecode/apps/repository/tests/test_repo_pullrequests.py --- a/rhodecode/apps/repository/tests/test_repo_pullrequests.py +++ b/rhodecode/apps/repository/tests/test_repo_pullrequests.py @@ -523,7 +523,9 @@ class TestPullrequestsView(object): pull_request = pr_util.create_pull_request() pull_request_id = pull_request.pull_request_id PullRequestModel().update_reviewers( - pull_request_id, [(1, ['reason'], False, []), (2, ['reason2'], False, [])], + pull_request_id, [ + (1, ['reason'], False, 'reviewer', []), + (2, ['reason2'], False, 'reviewer', [])], pull_request.author) author = pull_request.user_id repo = pull_request.target_repo.repo_id @@ -906,12 +908,13 @@ class TestPullrequestsView(object): # Change reviewers and check that a notification was made PullRequestModel().update_reviewers( - pull_request.pull_request_id, [(1, [], False, [])], + pull_request.pull_request_id, [ + (1, [], False, 'reviewer', []) + ], pull_request.author) assert len(notifications.all()) == 2 - def test_create_pull_request_stores_ancestor_commit_id(self, backend, - csrf_token): + def test_create_pull_request_stores_ancestor_commit_id(self, backend, csrf_token): commits = [ {'message': 'ancestor', 'added': [FileNode('file_A', content='content_of_ancestor')]}, diff --git a/rhodecode/apps/repository/views/repo_commits.py b/rhodecode/apps/repository/views/repo_commits.py --- a/rhodecode/apps/repository/views/repo_commits.py +++ b/rhodecode/apps/repository/views/repo_commits.py @@ -413,7 +413,7 @@ class RepoCommitsView(RepoAppView): resolves_comment_id=resolves_comment_id, auth_user=self._rhodecode_user ) - is_inline = bool(comment.f_path and comment.line_no) + is_inline = comment.is_inline # get status if set ! if status: diff --git a/rhodecode/apps/repository/views/repo_pull_requests.py b/rhodecode/apps/repository/views/repo_pull_requests.py --- a/rhodecode/apps/repository/views/repo_pull_requests.py +++ b/rhodecode/apps/repository/views/repo_pull_requests.py @@ -40,7 +40,8 @@ from rhodecode.lib.auth import ( LoginRequired, HasRepoPermissionAny, HasRepoPermissionAnyDecorator, NotAnonymous, CSRFRequired) from rhodecode.lib.utils2 import str2bool, safe_str, safe_unicode, safe_int, aslist -from rhodecode.lib.vcs.backends.base import EmptyCommit, UpdateFailureReason, Reference +from rhodecode.lib.vcs.backends.base import ( + EmptyCommit, UpdateFailureReason, unicode_to_reference) from rhodecode.lib.vcs.exceptions import ( CommitDoesNotExistError, RepositoryRequirementError, EmptyRepositoryError) from rhodecode.model.changeset_status import ChangesetStatusModel @@ -1146,16 +1147,17 @@ class RepoPullRequestsView(RepoAppView, source_scm = source_db_repo.scm_instance() target_scm = target_db_repo.scm_instance() - source_commit = source_scm.get_commit(source_ref.split(':')[-1]) - target_commit = target_scm.get_commit(target_ref.split(':')[-1]) + source_ref_obj = unicode_to_reference(source_ref) + target_ref_obj = unicode_to_reference(target_ref) + + source_commit = source_scm.get_commit(source_ref_obj.commit_id) + target_commit = target_scm.get_commit(target_ref_obj.commit_id) ancestor = source_scm.get_common_ancestor( source_commit.raw_id, target_commit.raw_id, target_scm) - source_ref_type, source_ref_name, source_commit_id = _form['target_ref'].split(':') - target_ref_type, target_ref_name, target_commit_id = _form['source_ref'].split(':') # recalculate target ref based on ancestor - target_ref = ':'.join((target_ref_type, target_ref_name, ancestor)) + target_ref = ':'.join((target_ref_obj.type, target_ref_obj.name, ancestor)) get_default_reviewers_data, validate_default_reviewers, validate_observers = \ PullRequestModel().get_reviewer_functions() @@ -1164,16 +1166,16 @@ class RepoPullRequestsView(RepoAppView, reviewer_rules = get_default_reviewers_data( self._rhodecode_db_user, source_db_repo, - Reference(source_ref_type, source_ref_name, source_commit_id), + source_ref_obj, target_db_repo, - Reference(target_ref_type, target_ref_name, target_commit_id), + target_ref_obj, include_diff_info=False) reviewers = validate_default_reviewers(_form['review_members'], reviewer_rules) observers = validate_observers(_form['observer_members'], reviewer_rules) pullrequest_title = _form['pullrequest_title'] - title_source_ref = source_ref.split(':', 2)[1] + title_source_ref = source_ref_obj.name if not pullrequest_title: pullrequest_title = PullRequestModel().generate_pullrequest_title( source=source_repo, @@ -1371,7 +1373,7 @@ class RepoPullRequestsView(RepoAppView, old_calculated_status = pull_request.calculated_review_status() PullRequestModel().update_reviewers( - pull_request, reviewers, self._rhodecode_user) + pull_request, reviewers, self._rhodecode_db_user) Session().commit() @@ -1396,7 +1398,7 @@ class RepoPullRequestsView(RepoAppView, return PullRequestModel().update_observers( - pull_request, observers, self._rhodecode_user) + pull_request, observers, self._rhodecode_db_user) Session().commit() msg = _('Pull request observers updated.') @@ -1563,6 +1565,7 @@ class RepoPullRequestsView(RepoAppView, pull_request, self._rhodecode_user, self.db_repo, message=text, auth_user=self._rhodecode_user) Session().flush() + is_inline = comment.is_inline PullRequestModel().trigger_pull_request_hook( pull_request, self._rhodecode_user, 'comment', @@ -1596,7 +1599,7 @@ class RepoPullRequestsView(RepoAppView, resolves_comment_id=resolves_comment_id, auth_user=self._rhodecode_user ) - is_inline = bool(comment.f_path and comment.line_no) + is_inline = comment.is_inline if allowed_to_change_status: # calculate old status before we change it diff --git a/rhodecode/lib/vcs/backends/base.py b/rhodecode/lib/vcs/backends/base.py --- a/rhodecode/lib/vcs/backends/base.py +++ b/rhodecode/lib/vcs/backends/base.py @@ -73,6 +73,29 @@ class Reference(_Reference): return self.name +def unicode_to_reference(raw): + """ + Convert a unicode (or string) to a reference object. + If unicode evaluates to False it returns None. + """ + if raw: + refs = raw.split(':') + return Reference(*refs) + else: + return None + + +def reference_to_unicode(ref): + """ + Convert a reference object to unicode. + If reference is None it returns None. + """ + if ref: + return u':'.join(ref) + else: + return None + + class MergeFailureReason(object): """ Enumeration with all the reasons why the server side merge could fail. diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py --- a/rhodecode/model/db.py +++ b/rhodecode/model/db.py @@ -56,7 +56,8 @@ from webhelpers2.text import remove_form from rhodecode.translation import _ from rhodecode.lib.vcs import get_vcs_instance, VCSError -from rhodecode.lib.vcs.backends.base import EmptyCommit, Reference +from rhodecode.lib.vcs.backends.base import ( + EmptyCommit, Reference, unicode_to_reference, reference_to_unicode) from rhodecode.lib.utils2 import ( str2bool, safe_str, get_commit_safe, safe_unicode, sha1_safe, time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict, @@ -4248,26 +4249,11 @@ class _PullRequestBase(BaseModel): @staticmethod def unicode_to_reference(raw): - """ - Convert a unicode (or string) to a reference object. - If unicode evaluates to False it returns None. - """ - if raw: - refs = raw.split(':') - return Reference(*refs) - else: - return None + return unicode_to_reference(raw) @staticmethod def reference_to_unicode(ref): - """ - Convert a reference object to unicode. - If reference is None it returns None. - """ - if ref: - return u':'.join(ref) - else: - return None + return reference_to_unicode(ref) def get_api_data(self, with_merge_state=True): from rhodecode.model.pull_request import PullRequestModel @@ -4543,6 +4529,9 @@ class PullRequestVersion(Base, _PullRequ @property def reviewers(self): return self.pull_request.reviewers + @property + def reviewers(self): + return self.pull_request.reviewers @property def versions(self): @@ -4561,7 +4550,7 @@ class PullRequestVersion(Base, _PullRequ def reviewers_statuses(self): return self.pull_request.reviewers_statuses() - def observer(self): + def observers(self): return self.pull_request.observers() diff --git a/rhodecode/model/pull_request.py b/rhodecode/model/pull_request.py --- a/rhodecode/model/pull_request.py +++ b/rhodecode/model/pull_request.py @@ -1342,7 +1342,7 @@ class PullRequestModel(BaseModel): 'repo.pull_request.reviewer.delete', {'old_data': user_data}, user, pull_request) - self.notify_reviewers(pull_request, ids_to_add, user.get_instance()) + self.notify_reviewers(pull_request, ids_to_add, user) return ids_to_add, ids_to_remove def update_observers(self, pull_request, observer_data, user): @@ -1425,7 +1425,7 @@ class PullRequestModel(BaseModel): 'repo.pull_request.observer.delete', {'old_data': user_data}, user, pull_request) - self.notify_observers(pull_request, ids_to_add, user.get_instance()) + self.notify_observers(pull_request, ids_to_add, user) return ids_to_add, ids_to_remove def get_url(self, pull_request, request=None, permalink=False): 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 @@ -21,12 +21,17 @@ import colander from rhodecode.model.validation_schema import validators, preparers, types +DEFAULT_ROLE = 'reviewer' +VALID_ROLES = ['reviewer', 'observer'] + class ReviewerSchema(colander.MappingSchema): username = colander.SchemaNode(types.StrOrIntType()) reasons = colander.SchemaNode(colander.List(), missing=['no reason specified']) mandatory = colander.SchemaNode(colander.Boolean(), missing=False) rules = colander.SchemaNode(colander.List(), missing=[]) + role = colander.SchemaNode(colander.String(), missing=DEFAULT_ROLE, + validator=colander.OneOf(VALID_ROLES)) class ReviewerListSchema(colander.SequenceSchema): diff --git a/rhodecode/public/502.html b/rhodecode/public/502.html --- a/rhodecode/public/502.html +++ b/rhodecode/public/502.html @@ -97,6 +97,7 @@
  • The server is being restarted.
  • The server is overloaded.
  • The link may be incorrect.
  • +
  • Reload page
  • diff --git a/rhodecode/tests/models/test_pullrequest.py b/rhodecode/tests/models/test_pullrequest.py --- a/rhodecode/tests/models/test_pullrequest.py +++ b/rhodecode/tests/models/test_pullrequest.py @@ -122,7 +122,7 @@ class TestPullRequestModel(object): def test_get_awaiting_my_review(self, pull_request): PullRequestModel().update_reviewers( - pull_request, [(pull_request.author, ['author'], False, [])], + pull_request, [(pull_request.author, ['author'], False, 'reviewer', [])], pull_request.author) Session().commit() @@ -133,7 +133,7 @@ class TestPullRequestModel(object): def test_count_awaiting_my_review(self, pull_request): PullRequestModel().update_reviewers( - pull_request, [(pull_request.author, ['author'], False, [])], + pull_request, [(pull_request.author, ['author'], False, 'reviewer', [])], pull_request.author) Session().commit() diff --git a/rhodecode/tests/plugin.py b/rhodecode/tests/plugin.py --- a/rhodecode/tests/plugin.py +++ b/rhodecode/tests/plugin.py @@ -43,8 +43,8 @@ from rhodecode.lib.utils2 import Attribu from rhodecode.model.changeset_status import ChangesetStatusModel from rhodecode.model.comment import CommentsModel from rhodecode.model.db import ( - PullRequest, Repository, RhodeCodeSetting, ChangesetStatus, RepoGroup, - UserGroup, RepoRhodeCodeUi, RepoRhodeCodeSetting, RhodeCodeUi) + PullRequest, PullRequestReviewers, Repository, RhodeCodeSetting, ChangesetStatus, + RepoGroup, UserGroup, RepoRhodeCodeUi, RepoRhodeCodeSetting, RhodeCodeUi) from rhodecode.model.meta import Session from rhodecode.model.pull_request import PullRequestModel from rhodecode.model.repo import RepoModel @@ -968,7 +968,7 @@ class PRTestUtility(object): def create_pull_request( self, commits=None, target_head=None, source_head=None, revisions=None, approved=False, author=None, mergeable=False, - enable_notifications=True, name_suffix=u'', reviewers=None, + enable_notifications=True, name_suffix=u'', reviewers=None, observers=None, title=u"Test", description=u"Description"): self.set_mergeable(mergeable) if not enable_notifications: @@ -1005,6 +1005,7 @@ class PRTestUtility(object): 'target_ref': self._default_branch_reference(target_head), 'revisions': [self.commit_ids[r] for r in revisions], 'reviewers': reviewers or self._get_reviewers(), + 'observers': observers or self._get_observers(), 'title': title, 'description': description, } @@ -1037,9 +1038,15 @@ class PRTestUtility(object): return reference def _get_reviewers(self): + role = PullRequestReviewers.ROLE_REVIEWER return [ - (TEST_USER_REGULAR_LOGIN, ['default1'], False, []), - (TEST_USER_REGULAR2_LOGIN, ['default2'], False, []), + (TEST_USER_REGULAR_LOGIN, ['default1'], False, role, []), + (TEST_USER_REGULAR2_LOGIN, ['default2'], False, role, []), + ] + + def _get_observers(self): + return [ + ] def update_source_repository(self, head=None):