Show More
@@ -47,13 +47,12 b' class TestClosePullRequest(object):' | |||||
47 | 'closed': True, |
|
47 | 'closed': True, | |
48 | } |
|
48 | } | |
49 | assert_ok(id_, expected, response.body) |
|
49 | assert_ok(id_, expected, response.body) | |
50 | action = 'user_closed_pull_request:%d' % pull_request_id |
|
|||
51 | journal = UserLog.query()\ |
|
50 | journal = UserLog.query()\ | |
52 | .filter(UserLog.user_id == author)\ |
|
51 | .filter(UserLog.user_id == author) \ | |
|
52 | .order_by('user_log_id') \ | |||
53 | .filter(UserLog.repository_id == repo)\ |
|
53 | .filter(UserLog.repository_id == repo)\ | |
54 | .filter(UserLog.action == action)\ |
|
|||
55 | .all() |
|
54 | .all() | |
56 | assert len(journal) == 1 |
|
55 | assert journal[-1].action == 'repo.pull_request.close' | |
57 |
|
56 | |||
58 | @pytest.mark.backends("git", "hg") |
|
57 | @pytest.mark.backends("git", "hg") | |
59 | def test_api_close_pull_request_already_closed_error(self, pr_util): |
|
58 | def test_api_close_pull_request_already_closed_error(self, pr_util): |
@@ -62,13 +62,12 b' class TestCommentPullRequest(object):' | |||||
62 | } |
|
62 | } | |
63 | assert_ok(id_, expected, response.body) |
|
63 | assert_ok(id_, expected, response.body) | |
64 |
|
64 | |||
65 | action = 'user_commented_pull_request:%d' % pull_request_id |
|
|||
66 | journal = UserLog.query()\ |
|
65 | journal = UserLog.query()\ | |
67 | .filter(UserLog.user_id == author)\ |
|
66 | .filter(UserLog.user_id == author)\ | |
68 | .filter(UserLog.repository_id == repo)\ |
|
67 | .filter(UserLog.repository_id == repo) \ | |
69 | .filter(UserLog.action == action)\ |
|
68 | .order_by('user_log_id') \ | |
70 | .all() |
|
69 | .all() | |
71 | assert len(journal) == 2 |
|
70 | assert journal[-1].action == 'repo.pull_request.comment.create' | |
72 |
|
71 | |||
73 | @pytest.mark.backends("git", "hg") |
|
72 | @pytest.mark.backends("git", "hg") | |
74 | def test_api_comment_pull_request_change_status( |
|
73 | def test_api_comment_pull_request_change_status( |
@@ -33,7 +33,7 b' pytestmark = pytest.mark.backends("git",' | |||||
33 | @pytest.mark.usefixtures("testuser_api", "app") |
|
33 | @pytest.mark.usefixtures("testuser_api", "app") | |
34 | class TestGetPullRequest(object): |
|
34 | class TestGetPullRequest(object): | |
35 |
|
35 | |||
36 |
def test_api_get_pull_request(self, pr_util, |
|
36 | def test_api_get_pull_request(self, pr_util, http_host_only_stub): | |
37 | from rhodecode.model.pull_request import PullRequestModel |
|
37 | from rhodecode.model.pull_request import PullRequestModel | |
38 | pull_request = pr_util.create_pull_request(mergeable=True) |
|
38 | pull_request = pr_util.create_pull_request(mergeable=True) | |
39 | id_, params = build_data( |
|
39 | id_, params = build_data( | |
@@ -52,7 +52,7 b' class TestGetPullRequest(object):' | |||||
52 | pull_request_id=pull_request.pull_request_id, qualified=True)) |
|
52 | pull_request_id=pull_request.pull_request_id, qualified=True)) | |
53 |
|
53 | |||
54 | pr_url = safe_unicode( |
|
54 | pr_url = safe_unicode( | |
55 | url_obj.with_netloc(http_host_stub)) |
|
55 | url_obj.with_netloc(http_host_only_stub)) | |
56 | source_url = safe_unicode( |
|
56 | source_url = safe_unicode( | |
57 | pull_request.source_repo.clone_url().with_netloc(http_host_only_stub)) |
|
57 | pull_request.source_repo.clone_url().with_netloc(http_host_only_stub)) | |
58 | target_url = safe_unicode( |
|
58 | target_url = safe_unicode( |
@@ -95,13 +95,13 b' class TestMergePullRequest(object):' | |||||
95 |
|
95 | |||
96 | assert_ok(id_, expected, response.body) |
|
96 | assert_ok(id_, expected, response.body) | |
97 |
|
97 | |||
98 | action = 'user_merged_pull_request:%d' % (pull_request_id, ) |
|
|||
99 | journal = UserLog.query()\ |
|
98 | journal = UserLog.query()\ | |
100 | .filter(UserLog.user_id == author)\ |
|
99 | .filter(UserLog.user_id == author)\ | |
101 | .filter(UserLog.repository_id == repo)\ |
|
100 | .filter(UserLog.repository_id == repo) \ | |
102 | .filter(UserLog.action == action)\ |
|
101 | .order_by('user_log_id') \ | |
103 | .all() |
|
102 | .all() | |
104 | assert len(journal) == 1 |
|
103 | assert journal[-2].action == 'repo.pull_request.merge' | |
|
104 | assert journal[-1].action == 'repo.pull_request.close' | |||
105 |
|
105 | |||
106 | id_, params = build_data( |
|
106 | id_, params = build_data( | |
107 | self.apikey, 'merge_pull_request', |
|
107 | self.apikey, 'merge_pull_request', |
@@ -33,7 +33,7 b' class TestUpdatePullRequest(object):' | |||||
33 |
|
33 | |||
34 | @pytest.mark.backends("git", "hg") |
|
34 | @pytest.mark.backends("git", "hg") | |
35 | def test_api_update_pull_request_title_or_description( |
|
35 | def test_api_update_pull_request_title_or_description( | |
36 |
self, pr_util, |
|
36 | self, pr_util, no_notifications): | |
37 | pull_request = pr_util.create_pull_request() |
|
37 | pull_request = pr_util.create_pull_request() | |
38 |
|
38 | |||
39 | id_, params = build_data( |
|
39 | id_, params = build_data( | |
@@ -61,7 +61,7 b' class TestUpdatePullRequest(object):' | |||||
61 |
|
61 | |||
62 | @pytest.mark.backends("git", "hg") |
|
62 | @pytest.mark.backends("git", "hg") | |
63 | def test_api_try_update_closed_pull_request( |
|
63 | def test_api_try_update_closed_pull_request( | |
64 |
self, pr_util, |
|
64 | self, pr_util, no_notifications): | |
65 | pull_request = pr_util.create_pull_request() |
|
65 | pull_request = pr_util.create_pull_request() | |
66 | PullRequestModel().close_pull_request( |
|
66 | PullRequestModel().close_pull_request( | |
67 | pull_request, TEST_USER_ADMIN_LOGIN) |
|
67 | pull_request, TEST_USER_ADMIN_LOGIN) | |
@@ -78,8 +78,7 b' class TestUpdatePullRequest(object):' | |||||
78 | assert_error(id_, expected, response.body) |
|
78 | assert_error(id_, expected, response.body) | |
79 |
|
79 | |||
80 | @pytest.mark.backends("git", "hg") |
|
80 | @pytest.mark.backends("git", "hg") | |
81 | def test_api_update_update_commits( |
|
81 | def test_api_update_update_commits(self, pr_util, no_notifications): | |
82 | self, pr_util, silence_action_logger, no_notifications): |
|
|||
83 | commits = [ |
|
82 | commits = [ | |
84 | {'message': 'a'}, |
|
83 | {'message': 'a'}, | |
85 | {'message': 'b', 'added': [FileNode('file_b', 'test_content\n')]}, |
|
84 | {'message': 'b', 'added': [FileNode('file_b', 'test_content\n')]}, | |
@@ -119,7 +118,7 b' class TestUpdatePullRequest(object):' | |||||
119 |
|
118 | |||
120 | @pytest.mark.backends("git", "hg") |
|
119 | @pytest.mark.backends("git", "hg") | |
121 | def test_api_update_change_reviewers( |
|
120 | def test_api_update_change_reviewers( | |
122 |
self, user_util, pr_util, |
|
121 | self, user_util, pr_util, no_notifications): | |
123 | a = user_util.create_user() |
|
122 | a = user_util.create_user() | |
124 | b = user_util.create_user() |
|
123 | b = user_util.create_user() | |
125 | c = user_util.create_user() |
|
124 | c = user_util.create_user() |
@@ -669,7 +669,7 b' def update_pull_request(' | |||||
669 | if title or description: |
|
669 | if title or description: | |
670 | PullRequestModel().edit( |
|
670 | PullRequestModel().edit( | |
671 | pull_request, title or pull_request.title, |
|
671 | pull_request, title or pull_request.title, | |
672 | description or pull_request.description) |
|
672 | description or pull_request.description, apiuser) | |
673 | Session().commit() |
|
673 | Session().commit() | |
674 |
|
674 | |||
675 | commit_changes = {"added": [], "common": [], "removed": []} |
|
675 | commit_changes = {"added": [], "common": [], "removed": []} | |
@@ -683,7 +683,7 b' def update_pull_request(' | |||||
683 | reviewers_changes = {"added": [], "removed": []} |
|
683 | reviewers_changes = {"added": [], "removed": []} | |
684 | if reviewers: |
|
684 | if reviewers: | |
685 | added_reviewers, removed_reviewers = \ |
|
685 | added_reviewers, removed_reviewers = \ | |
686 | PullRequestModel().update_reviewers(pull_request, reviewers) |
|
686 | PullRequestModel().update_reviewers(pull_request, reviewers, apiuser) | |
687 |
|
687 | |||
688 | reviewers_changes['added'] = sorted( |
|
688 | reviewers_changes['added'] = sorted( | |
689 | [get_user_or_error(n).username for n in added_reviewers]) |
|
689 | [get_user_or_error(n).username for n in added_reviewers]) |
@@ -628,8 +628,8 b' class UsersController(BaseController):' | |||||
628 |
|
628 | |||
629 | ip_id = request.POST.get('del_ip_id') |
|
629 | ip_id = request.POST.get('del_ip_id') | |
630 | user_model = UserModel() |
|
630 | user_model = UserModel() | |
|
631 | user_data = c.user.get_api_data() | |||
631 | ip = UserIpMap.query().get(ip_id).ip_addr |
|
632 | ip = UserIpMap.query().get(ip_id).ip_addr | |
632 | user_data = c.user.get_api_data() |
|
|||
633 | user_model.delete_extra_ip(user_id, ip_id) |
|
633 | user_model.delete_extra_ip(user_id, ip_id) | |
634 | audit_logger.store_web( |
|
634 | audit_logger.store_web( | |
635 | 'user.edit.ip.delete', |
|
635 | 'user.edit.ip.delete', |
@@ -440,7 +440,7 b' class ChangesetController(BaseRepoContro' | |||||
440 | owner = (comment.author.user_id == c.rhodecode_user.user_id) |
|
440 | owner = (comment.author.user_id == c.rhodecode_user.user_id) | |
441 | is_repo_admin = h.HasRepoPermissionAny('repository.admin')(c.repo_name) |
|
441 | is_repo_admin = h.HasRepoPermissionAny('repository.admin')(c.repo_name) | |
442 | if h.HasPermissionAny('hg.admin')() or is_repo_admin or owner: |
|
442 | if h.HasPermissionAny('hg.admin')() or is_repo_admin or owner: | |
443 | CommentsModel().delete(comment=comment) |
|
443 | CommentsModel().delete(comment=comment, user=c.rhodecode_user) | |
444 | Session().commit() |
|
444 | Session().commit() | |
445 | return True |
|
445 | return True | |
446 | else: |
|
446 | else: |
@@ -38,7 +38,7 b' from rhodecode.lib import diffs, helpers' | |||||
38 | from rhodecode.lib import audit_logger |
|
38 | from rhodecode.lib import audit_logger | |
39 | from rhodecode.lib.codeblocks import ( |
|
39 | from rhodecode.lib.codeblocks import ( | |
40 | filenode_as_lines_tokens, filenode_as_annotated_lines_tokens) |
|
40 | filenode_as_lines_tokens, filenode_as_annotated_lines_tokens) | |
41 |
from rhodecode.lib.utils import jsonify |
|
41 | from rhodecode.lib.utils import jsonify | |
42 | from rhodecode.lib.utils2 import ( |
|
42 | from rhodecode.lib.utils2 import ( | |
43 | convert_line_endings, detect_mode, safe_str, str2bool) |
|
43 | convert_line_endings, detect_mode, safe_str, str2bool) | |
44 | from rhodecode.lib.auth import ( |
|
44 | from rhodecode.lib.auth import ( |
@@ -317,7 +317,7 b' class PullrequestsController(BaseRepoCon' | |||||
317 | try: |
|
317 | try: | |
318 | PullRequestModel().edit( |
|
318 | PullRequestModel().edit( | |
319 | pull_request, request.POST.get('title'), |
|
319 | pull_request, request.POST.get('title'), | |
320 | request.POST.get('description')) |
|
320 | request.POST.get('description'), c.rhodecode_user) | |
321 | except ValueError: |
|
321 | except ValueError: | |
322 | msg = _(u'Cannot update closed pull requests.') |
|
322 | msg = _(u'Cannot update closed pull requests.') | |
323 | h.flash(msg, category='error') |
|
323 | h.flash(msg, category='error') | |
@@ -456,7 +456,8 b' class PullrequestsController(BaseRepoCon' | |||||
456 | h.flash(e, category='error') |
|
456 | h.flash(e, category='error') | |
457 | return |
|
457 | return | |
458 |
|
458 | |||
459 |
PullRequestModel().update_reviewers( |
|
459 | PullRequestModel().update_reviewers( | |
|
460 | pull_request_id, reviewers, c.rhodecode_user) | |||
460 | h.flash(_('Pull request reviewers updated.'), category='success') |
|
461 | h.flash(_('Pull request reviewers updated.'), category='success') | |
461 | Session().commit() |
|
462 | Session().commit() | |
462 |
|
463 | |||
@@ -476,7 +477,7 b' class PullrequestsController(BaseRepoCon' | |||||
476 |
|
477 | |||
477 | # only owner can delete it ! |
|
478 | # only owner can delete it ! | |
478 | if allowed_to_delete: |
|
479 | if allowed_to_delete: | |
479 | PullRequestModel().delete(pull_request) |
|
480 | PullRequestModel().delete(pull_request, c.rhodecode_user) | |
480 | Session().commit() |
|
481 | Session().commit() | |
481 | h.flash(_('Successfully deleted pull request'), |
|
482 | h.flash(_('Successfully deleted pull request'), | |
482 | category='success') |
|
483 | category='success') | |
@@ -997,7 +998,7 b' class PullrequestsController(BaseRepoCon' | |||||
997 | is_repo_admin = h.HasRepoPermissionAny('repository.admin')(c.repo_name) |
|
998 | is_repo_admin = h.HasRepoPermissionAny('repository.admin')(c.repo_name) | |
998 | if h.HasPermissionAny('hg.admin')() or is_repo_admin or is_owner: |
|
999 | if h.HasPermissionAny('hg.admin')() or is_repo_admin or is_owner: | |
999 | old_calculated_status = co.pull_request.calculated_review_status() |
|
1000 | old_calculated_status = co.pull_request.calculated_review_status() | |
1000 | CommentsModel().delete(comment=co) |
|
1001 | CommentsModel().delete(comment=co, user=c.rhodecode_user) | |
1001 | Session().commit() |
|
1002 | Session().commit() | |
1002 | calculated_status = co.pull_request.calculated_review_status() |
|
1003 | calculated_status = co.pull_request.calculated_review_status() | |
1003 | if old_calculated_status != calculated_status: |
|
1004 | if old_calculated_status != calculated_status: |
@@ -28,7 +28,7 b' from rhodecode.model.db import User, Use' | |||||
28 | log = logging.getLogger(__name__) |
|
28 | log = logging.getLogger(__name__) | |
29 |
|
29 | |||
30 | # action as key, and expected action_data as value |
|
30 | # action as key, and expected action_data as value | |
31 | ACTIONS = { |
|
31 | ACTIONS_V1 = { | |
32 | 'user.login.success': {'user_agent': ''}, |
|
32 | 'user.login.success': {'user_agent': ''}, | |
33 | 'user.login.failure': {'user_agent': ''}, |
|
33 | 'user.login.failure': {'user_agent': ''}, | |
34 | 'user.logout': {'user_agent': ''}, |
|
34 | 'user.logout': {'user_agent': ''}, | |
@@ -64,11 +64,28 b' ACTIONS = {' | |||||
64 | 'repo.commit.strip': {}, |
|
64 | 'repo.commit.strip': {}, | |
65 | 'repo.archive.download': {}, |
|
65 | 'repo.archive.download': {}, | |
66 |
|
66 | |||
|
67 | 'repo.pull_request.create': '', | |||
|
68 | 'repo.pull_request.edit': '', | |||
|
69 | 'repo.pull_request.delete': '', | |||
|
70 | 'repo.pull_request.close': '', | |||
|
71 | 'repo.pull_request.merge': '', | |||
|
72 | 'repo.pull_request.vote': '', | |||
|
73 | 'repo.pull_request.comment.create': '', | |||
|
74 | 'repo.pull_request.comment.delete': '', | |||
|
75 | ||||
|
76 | 'repo.pull_request.reviewer.add': '', | |||
|
77 | 'repo.pull_request.reviewer.delete': '', | |||
|
78 | ||||
|
79 | 'repo.commit.comment.create': '', | |||
|
80 | 'repo.commit.comment.delete': '', | |||
|
81 | 'repo.commit.vote': '', | |||
|
82 | ||||
67 | 'repo_group.create': {'data': {}}, |
|
83 | 'repo_group.create': {'data': {}}, | |
68 | 'repo_group.edit': {'old_data': {}}, |
|
84 | 'repo_group.edit': {'old_data': {}}, | |
69 | 'repo_group.edit.permissions': {}, |
|
85 | 'repo_group.edit.permissions': {}, | |
70 | 'repo_group.delete': {'old_data': {}}, |
|
86 | 'repo_group.delete': {'old_data': {}}, | |
71 | } |
|
87 | } | |
|
88 | ACTIONS = ACTIONS_V1 | |||
72 |
|
89 | |||
73 | SOURCE_WEB = 'source_web' |
|
90 | SOURCE_WEB = 'source_web' | |
74 | SOURCE_API = 'source_api' |
|
91 | SOURCE_API = 'source_api' |
@@ -139,68 +139,6 b' def get_user_group_slug(request):' | |||||
139 | return _group |
|
139 | return _group | |
140 |
|
140 | |||
141 |
|
141 | |||
142 | def action_logger(user, action, repo, ipaddr='', sa=None, commit=False): |
|
|||
143 | """ |
|
|||
144 | Action logger for various actions made by users |
|
|||
145 |
|
||||
146 | :param user: user that made this action, can be a unique username string or |
|
|||
147 | object containing user_id attribute |
|
|||
148 | :param action: action to log, should be on of predefined unique actions for |
|
|||
149 | easy translations |
|
|||
150 | :param repo: string name of repository or object containing repo_id, |
|
|||
151 | that action was made on |
|
|||
152 | :param ipaddr: optional ip address from what the action was made |
|
|||
153 | :param sa: optional sqlalchemy session |
|
|||
154 |
|
||||
155 | """ |
|
|||
156 |
|
||||
157 | if not sa: |
|
|||
158 | sa = meta.Session() |
|
|||
159 | # if we don't get explicit IP address try to get one from registered user |
|
|||
160 | # in tmpl context var |
|
|||
161 | if not ipaddr: |
|
|||
162 | ipaddr = getattr(get_current_rhodecode_user(), 'ip_addr', '') |
|
|||
163 |
|
||||
164 | try: |
|
|||
165 | if getattr(user, 'user_id', None): |
|
|||
166 | user_obj = User.get(user.user_id) |
|
|||
167 | elif isinstance(user, basestring): |
|
|||
168 | user_obj = User.get_by_username(user) |
|
|||
169 | else: |
|
|||
170 | raise Exception('You have to provide a user object or a username') |
|
|||
171 |
|
||||
172 | if getattr(repo, 'repo_id', None): |
|
|||
173 | repo_obj = Repository.get(repo.repo_id) |
|
|||
174 | repo_name = repo_obj.repo_name |
|
|||
175 | elif isinstance(repo, basestring): |
|
|||
176 | repo_name = repo.lstrip('/') |
|
|||
177 | repo_obj = Repository.get_by_repo_name(repo_name) |
|
|||
178 | else: |
|
|||
179 | repo_obj = None |
|
|||
180 | repo_name = '' |
|
|||
181 |
|
||||
182 | user_log = UserLog() |
|
|||
183 | user_log.user_id = user_obj.user_id |
|
|||
184 | user_log.username = user_obj.username |
|
|||
185 | action = safe_unicode(action) |
|
|||
186 | user_log.action = action[:1200000] |
|
|||
187 |
|
||||
188 | user_log.repository = repo_obj |
|
|||
189 | user_log.repository_name = repo_name |
|
|||
190 |
|
||||
191 | user_log.action_date = datetime.datetime.now() |
|
|||
192 | user_log.user_ip = ipaddr |
|
|||
193 | sa.add(user_log) |
|
|||
194 |
|
||||
195 | log.info('Logging action:`%s` on repo:`%s` by user:%s ip:%s', |
|
|||
196 | action, safe_unicode(repo), user_obj, ipaddr) |
|
|||
197 | if commit: |
|
|||
198 | sa.commit() |
|
|||
199 | except Exception: |
|
|||
200 | log.error(traceback.format_exc()) |
|
|||
201 | raise |
|
|||
202 |
|
||||
203 |
|
||||
204 | def get_filesystem_repos(path, recursive=False, skip_removed_repos=True): |
|
142 | def get_filesystem_repos(path, recursive=False, skip_removed_repos=True): | |
205 | """ |
|
143 | """ | |
206 | Scans given path for repos and return (name,(type,path)) tuple |
|
144 | Scans given path for repos and return (name,(type,path)) tuple |
@@ -34,8 +34,8 b' from sqlalchemy.sql.expression import nu' | |||||
34 | from sqlalchemy.sql.functions import coalesce |
|
34 | from sqlalchemy.sql.functions import coalesce | |
35 |
|
35 | |||
36 | from rhodecode.lib import helpers as h, diffs |
|
36 | from rhodecode.lib import helpers as h, diffs | |
|
37 | from rhodecode.lib import audit_logger | |||
37 | from rhodecode.lib.channelstream import channelstream_request |
|
38 | from rhodecode.lib.channelstream import channelstream_request | |
38 | from rhodecode.lib.utils import action_logger |
|
|||
39 | from rhodecode.lib.utils2 import extract_mentioned_users, safe_str |
|
39 | from rhodecode.lib.utils2 import extract_mentioned_users, safe_str | |
40 | from rhodecode.model import BaseModel |
|
40 | from rhodecode.model import BaseModel | |
41 | from rhodecode.model.db import ( |
|
41 | from rhodecode.model.db import ( | |
@@ -163,6 +163,13 b' class CommentsModel(BaseModel):' | |||||
163 |
|
163 | |||
164 | return todos |
|
164 | return todos | |
165 |
|
165 | |||
|
166 | def _log_audit_action(self, action, action_data, user, comment): | |||
|
167 | audit_logger.store( | |||
|
168 | action=action, | |||
|
169 | action_data=action_data, | |||
|
170 | user=user, | |||
|
171 | repo=comment.repo) | |||
|
172 | ||||
166 | def create(self, text, repo, user, commit_id=None, pull_request=None, |
|
173 | def create(self, text, repo, user, commit_id=None, pull_request=None, | |
167 | f_path=None, line_no=None, status_change=None, |
|
174 | f_path=None, line_no=None, status_change=None, | |
168 | status_change_type=None, comment_type=None, |
|
175 | status_change_type=None, comment_type=None, | |
@@ -337,13 +344,15 b' class CommentsModel(BaseModel):' | |||||
337 | email_kwargs=kwargs, |
|
344 | email_kwargs=kwargs, | |
338 | ) |
|
345 | ) | |
339 |
|
346 | |||
340 | action = ( |
|
347 | Session().flush() | |
341 |
|
|
348 | if comment.pull_request: | |
342 | comment.pull_request.pull_request_id) |
|
349 | action = 'repo.pull_request.comment.create' | |
343 | if comment.pull_request |
|
350 | else: | |
344 | else 'user_commented_revision:{}'.format(comment.revision) |
|
351 | action = 'repo.commit.comment.create' | |
345 | ) |
|
352 | ||
346 | action_logger(user, action, comment.repo) |
|
353 | comment_data = comment.get_api_data() | |
|
354 | self._log_audit_action( | |||
|
355 | action, {'data': comment_data}, user, comment) | |||
347 |
|
356 | |||
348 | registry = get_current_registry() |
|
357 | registry = get_current_registry() | |
349 | rhodecode_plugins = getattr(registry, 'rhodecode_plugins', {}) |
|
358 | rhodecode_plugins = getattr(registry, 'rhodecode_plugins', {}) | |
@@ -385,15 +394,22 b' class CommentsModel(BaseModel):' | |||||
385 |
|
394 | |||
386 | return comment |
|
395 | return comment | |
387 |
|
396 | |||
388 | def delete(self, comment): |
|
397 | def delete(self, comment, user): | |
389 | """ |
|
398 | """ | |
390 | Deletes given comment |
|
399 | Deletes given comment | |
391 |
|
||||
392 | :param comment_id: |
|
|||
393 | """ |
|
400 | """ | |
394 | comment = self.__get_commit_comment(comment) |
|
401 | comment = self.__get_commit_comment(comment) | |
|
402 | old_data = comment.get_api_data() | |||
395 | Session().delete(comment) |
|
403 | Session().delete(comment) | |
396 |
|
404 | |||
|
405 | if comment.pull_request: | |||
|
406 | action = 'repo.pull_request.comment.delete' | |||
|
407 | else: | |||
|
408 | action = 'repo.commit.comment.delete' | |||
|
409 | ||||
|
410 | self._log_audit_action( | |||
|
411 | action, {'old_data': old_data}, user, comment) | |||
|
412 | ||||
397 | return comment |
|
413 | return comment | |
398 |
|
414 | |||
399 | def get_all_comments(self, repo_id, revision=None, pull_request=None): |
|
415 | def get_all_comments(self, repo_id, revision=None, pull_request=None): |
@@ -3122,6 +3122,25 b' class ChangesetComment(Base, BaseModel):' | |||||
3122 | else: |
|
3122 | else: | |
3123 | return '<DB:Comment at %#x>' % id(self) |
|
3123 | return '<DB:Comment at %#x>' % id(self) | |
3124 |
|
3124 | |||
|
3125 | def get_api_data(self): | |||
|
3126 | comment = self | |||
|
3127 | data = { | |||
|
3128 | 'comment_id': comment.comment_id, | |||
|
3129 | 'comment_type': comment.comment_type, | |||
|
3130 | 'comment_text': comment.text, | |||
|
3131 | 'comment_status': comment.status_change, | |||
|
3132 | 'comment_f_path': comment.f_path, | |||
|
3133 | 'comment_lineno': comment.line_no, | |||
|
3134 | 'comment_author': comment.author, | |||
|
3135 | 'comment_created_on': comment.created_on | |||
|
3136 | } | |||
|
3137 | return data | |||
|
3138 | ||||
|
3139 | def __json__(self): | |||
|
3140 | data = dict() | |||
|
3141 | data.update(self.get_api_data()) | |||
|
3142 | return data | |||
|
3143 | ||||
3125 |
|
3144 | |||
3126 | class ChangesetStatus(Base, BaseModel): |
|
3145 | class ChangesetStatus(Base, BaseModel): | |
3127 | __tablename__ = 'changeset_statuses' |
|
3146 | __tablename__ = 'changeset_statuses' | |
@@ -3173,6 +3192,19 b' class ChangesetStatus(Base, BaseModel):' | |||||
3173 | def status_lbl(self): |
|
3192 | def status_lbl(self): | |
3174 | return ChangesetStatus.get_status_lbl(self.status) |
|
3193 | return ChangesetStatus.get_status_lbl(self.status) | |
3175 |
|
3194 | |||
|
3195 | def get_api_data(self): | |||
|
3196 | status = self | |||
|
3197 | data = { | |||
|
3198 | 'status_id': status.changeset_status_id, | |||
|
3199 | 'status': status.status, | |||
|
3200 | } | |||
|
3201 | return data | |||
|
3202 | ||||
|
3203 | def __json__(self): | |||
|
3204 | data = dict() | |||
|
3205 | data.update(self.get_api_data()) | |||
|
3206 | return data | |||
|
3207 | ||||
3176 |
|
3208 | |||
3177 | class _PullRequestBase(BaseModel): |
|
3209 | class _PullRequestBase(BaseModel): | |
3178 | """ |
|
3210 | """ | |
@@ -3304,15 +3336,19 b' class _PullRequestBase(BaseModel):' | |||||
3304 | else: |
|
3336 | else: | |
3305 | return None |
|
3337 | return None | |
3306 |
|
3338 | |||
3307 | def get_api_data(self): |
|
3339 | def get_api_data(self, with_merge_state=True): | |
3308 | from pylons import url |
|
|||
3309 | from rhodecode.model.pull_request import PullRequestModel |
|
3340 | from rhodecode.model.pull_request import PullRequestModel | |
|
3341 | ||||
3310 | pull_request = self |
|
3342 | pull_request = self | |
|
3343 | if with_merge_state: | |||
3311 | merge_status = PullRequestModel().merge_status(pull_request) |
|
3344 | merge_status = PullRequestModel().merge_status(pull_request) | |
3312 |
|
3345 | merge_state = { | ||
3313 | pull_request_url = url( |
|
3346 | 'status': merge_status[0], | |
3314 | 'pullrequest_show', repo_name=self.target_repo.repo_name, |
|
3347 | 'message': safe_unicode(merge_status[1]), | |
3315 | pull_request_id=self.pull_request_id, qualified=True) |
|
3348 | } | |
|
3349 | else: | |||
|
3350 | merge_state = {'status': 'not_available', | |||
|
3351 | 'message': 'not_available'} | |||
3316 |
|
3352 | |||
3317 | merge_data = { |
|
3353 | merge_data = { | |
3318 | 'clone_url': PullRequestModel().get_shadow_clone_url(pull_request), |
|
3354 | 'clone_url': PullRequestModel().get_shadow_clone_url(pull_request), | |
@@ -3323,7 +3359,7 b' class _PullRequestBase(BaseModel):' | |||||
3323 |
|
3359 | |||
3324 | data = { |
|
3360 | data = { | |
3325 | 'pull_request_id': pull_request.pull_request_id, |
|
3361 | 'pull_request_id': pull_request.pull_request_id, | |
3326 |
'url': |
|
3362 | 'url': PullRequestModel().get_url(pull_request), | |
3327 | 'title': pull_request.title, |
|
3363 | 'title': pull_request.title, | |
3328 | 'description': pull_request.description, |
|
3364 | 'description': pull_request.description, | |
3329 | 'status': pull_request.status, |
|
3365 | 'status': pull_request.status, | |
@@ -3331,10 +3367,7 b' class _PullRequestBase(BaseModel):' | |||||
3331 | 'updated_on': pull_request.updated_on, |
|
3367 | 'updated_on': pull_request.updated_on, | |
3332 | 'commit_ids': pull_request.revisions, |
|
3368 | 'commit_ids': pull_request.revisions, | |
3333 | 'review_status': pull_request.calculated_review_status(), |
|
3369 | 'review_status': pull_request.calculated_review_status(), | |
3334 |
'mergeable': |
|
3370 | 'mergeable': merge_state, | |
3335 | 'status': merge_status[0], |
|
|||
3336 | 'message': unicode(merge_status[1]), |
|
|||
3337 | }, |
|
|||
3338 | 'source': { |
|
3371 | 'source': { | |
3339 | 'clone_url': pull_request.source_repo.clone_url(), |
|
3372 | 'clone_url': pull_request.source_repo.clone_url(), | |
3340 | 'repository': pull_request.source_repo.repo_name, |
|
3373 | 'repository': pull_request.source_repo.repo_name, | |
@@ -3389,7 +3422,8 b' class PullRequest(Base, _PullRequestBase' | |||||
3389 |
|
3422 | |||
3390 | reviewers = relationship('PullRequestReviewers', |
|
3423 | reviewers = relationship('PullRequestReviewers', | |
3391 | cascade="all, delete, delete-orphan") |
|
3424 | cascade="all, delete, delete-orphan") | |
3392 |
statuses = relationship('ChangesetStatus' |
|
3425 | statuses = relationship('ChangesetStatus', | |
|
3426 | cascade="all, delete, delete-orphan") | |||
3393 | comments = relationship('ChangesetComment', |
|
3427 | comments = relationship('ChangesetComment', | |
3394 | cascade="all, delete, delete-orphan") |
|
3428 | cascade="all, delete, delete-orphan") | |
3395 | versions = relationship('PullRequestVersion', |
|
3429 | versions = relationship('PullRequestVersion', |
@@ -36,11 +36,11 b' from sqlalchemy import or_' | |||||
36 |
|
36 | |||
37 | from rhodecode import events |
|
37 | from rhodecode import events | |
38 | from rhodecode.lib import helpers as h, hooks_utils, diffs |
|
38 | from rhodecode.lib import helpers as h, hooks_utils, diffs | |
|
39 | from rhodecode.lib import audit_logger | |||
39 | from rhodecode.lib.compat import OrderedDict |
|
40 | from rhodecode.lib.compat import OrderedDict | |
40 | from rhodecode.lib.hooks_daemon import prepare_callback_daemon |
|
41 | from rhodecode.lib.hooks_daemon import prepare_callback_daemon | |
41 | from rhodecode.lib.markup_renderer import ( |
|
42 | from rhodecode.lib.markup_renderer import ( | |
42 | DEFAULT_COMMENTS_RENDERER, RstTemplateRenderer) |
|
43 | DEFAULT_COMMENTS_RENDERER, RstTemplateRenderer) | |
43 | from rhodecode.lib.utils import action_logger |
|
|||
44 | from rhodecode.lib.utils2 import safe_unicode, safe_str, md5_safe |
|
44 | from rhodecode.lib.utils2 import safe_unicode, safe_str, md5_safe | |
45 | from rhodecode.lib.vcs.backends.base import ( |
|
45 | from rhodecode.lib.vcs.backends.base import ( | |
46 | Reference, MergeResponse, MergeFailureReason, UpdateFailureReason) |
|
46 | Reference, MergeResponse, MergeFailureReason, UpdateFailureReason) | |
@@ -470,6 +470,11 b' class PullRequestModel(BaseModel):' | |||||
470 | self._trigger_pull_request_hook( |
|
470 | self._trigger_pull_request_hook( | |
471 | pull_request, created_by_user, 'create') |
|
471 | pull_request, created_by_user, 'create') | |
472 |
|
472 | |||
|
473 | creation_data = pull_request.get_api_data(with_merge_state=False) | |||
|
474 | self._log_audit_action( | |||
|
475 | 'repo.pull_request.create', {'data': creation_data}, | |||
|
476 | created_by_user, pull_request) | |||
|
477 | ||||
473 | return pull_request |
|
478 | return pull_request | |
474 |
|
479 | |||
475 | def _trigger_pull_request_hook(self, pull_request, user, action): |
|
480 | def _trigger_pull_request_hook(self, pull_request, user, action): | |
@@ -520,7 +525,12 b' class PullRequestModel(BaseModel):' | |||||
520 | log.debug( |
|
525 | log.debug( | |
521 | "Merge was successful, updating the pull request comments.") |
|
526 | "Merge was successful, updating the pull request comments.") | |
522 | self._comment_and_close_pr(pull_request, user, merge_state) |
|
527 | self._comment_and_close_pr(pull_request, user, merge_state) | |
523 | self._log_action('user_merged_pull_request', user, pull_request) |
|
528 | ||
|
529 | self._log_audit_action( | |||
|
530 | 'repo.pull_request.merge', | |||
|
531 | {'merge_state': merge_state.__dict__}, | |||
|
532 | user, pull_request) | |||
|
533 | ||||
524 | else: |
|
534 | else: | |
525 | log.warn("Merge failed, not updating the pull request.") |
|
535 | log.warn("Merge failed, not updating the pull request.") | |
526 | return merge_state |
|
536 | return merge_state | |
@@ -899,8 +909,9 b' class PullRequestModel(BaseModel):' | |||||
899 | renderer = RstTemplateRenderer() |
|
909 | renderer = RstTemplateRenderer() | |
900 | return renderer.render('pull_request_update.mako', **params) |
|
910 | return renderer.render('pull_request_update.mako', **params) | |
901 |
|
911 | |||
902 | def edit(self, pull_request, title, description): |
|
912 | def edit(self, pull_request, title, description, user): | |
903 | pull_request = self.__get_pull_request(pull_request) |
|
913 | pull_request = self.__get_pull_request(pull_request) | |
|
914 | old_data = pull_request.get_api_data(with_merge_state=False) | |||
904 | if pull_request.is_closed(): |
|
915 | if pull_request.is_closed(): | |
905 | raise ValueError('This pull request is closed') |
|
916 | raise ValueError('This pull request is closed') | |
906 | if title: |
|
917 | if title: | |
@@ -908,8 +919,11 b' class PullRequestModel(BaseModel):' | |||||
908 | pull_request.description = description |
|
919 | pull_request.description = description | |
909 | pull_request.updated_on = datetime.datetime.now() |
|
920 | pull_request.updated_on = datetime.datetime.now() | |
910 | Session().add(pull_request) |
|
921 | Session().add(pull_request) | |
|
922 | self._log_audit_action( | |||
|
923 | 'repo.pull_request.edit', {'old_data': old_data}, | |||
|
924 | user, pull_request) | |||
911 |
|
925 | |||
912 | def update_reviewers(self, pull_request, reviewer_data): |
|
926 | def update_reviewers(self, pull_request, reviewer_data, user): | |
913 | """ |
|
927 | """ | |
914 | Update the reviewers in the pull request |
|
928 | Update the reviewers in the pull request | |
915 |
|
929 | |||
@@ -948,6 +962,9 b' class PullRequestModel(BaseModel):' | |||||
948 | # NOTE(marcink): mandatory shouldn't be changed now |
|
962 | # NOTE(marcink): mandatory shouldn't be changed now | |
949 | #reviewer.mandatory = reviewers[uid]['reasons'] |
|
963 | # reviewer.mandatory = reviewers[uid]['reasons'] | |
950 | Session().add(reviewer) |
|
964 | Session().add(reviewer) | |
|
965 | self._log_audit_action( | |||
|
966 | 'repo.pull_request.reviewer.add', {'data': reviewer.get_dict()}, | |||
|
967 | user, pull_request) | |||
951 |
|
968 | |||
952 | for uid in ids_to_remove: |
|
969 | for uid in ids_to_remove: | |
953 | changed = True |
|
970 | changed = True | |
@@ -958,7 +975,11 b' class PullRequestModel(BaseModel):' | |||||
958 | # use .all() in case we accidentally added the same person twice |
|
975 | # use .all() in case we accidentally added the same person twice | |
959 | # this CAN happen due to the lack of DB checks |
|
976 | # this CAN happen due to the lack of DB checks | |
960 | for obj in reviewers: |
|
977 | for obj in reviewers: | |
|
978 | old_data = obj.get_dict() | |||
961 | Session().delete(obj) |
|
979 | Session().delete(obj) | |
|
980 | self._log_audit_action( | |||
|
981 | 'repo.pull_request.reviewer.delete', | |||
|
982 | {'old_data': old_data}, user, pull_request) | |||
962 |
|
983 | |||
963 | if changed: |
|
984 | if changed: | |
964 | pull_request.updated_on = datetime.datetime.now() |
|
985 | pull_request.updated_on = datetime.datetime.now() | |
@@ -1054,9 +1075,13 b' class PullRequestModel(BaseModel):' | |||||
1054 | email_kwargs=kwargs, |
|
1075 | email_kwargs=kwargs, | |
1055 | ) |
|
1076 | ) | |
1056 |
|
1077 | |||
1057 | def delete(self, pull_request): |
|
1078 | def delete(self, pull_request, user): | |
1058 | pull_request = self.__get_pull_request(pull_request) |
|
1079 | pull_request = self.__get_pull_request(pull_request) | |
|
1080 | old_data = pull_request.get_api_data(with_merge_state=False) | |||
1059 | self._cleanup_merge_workspace(pull_request) |
|
1081 | self._cleanup_merge_workspace(pull_request) | |
|
1082 | self._log_audit_action( | |||
|
1083 | 'repo.pull_request.delete', {'old_data': old_data}, | |||
|
1084 | user, pull_request) | |||
1060 | Session().delete(pull_request) |
|
1085 | Session().delete(pull_request) | |
1061 |
|
1086 | |||
1062 | def close_pull_request(self, pull_request, user): |
|
1087 | def close_pull_request(self, pull_request, user): | |
@@ -1067,7 +1092,8 b' class PullRequestModel(BaseModel):' | |||||
1067 | Session().add(pull_request) |
|
1092 | Session().add(pull_request) | |
1068 | self._trigger_pull_request_hook( |
|
1093 | self._trigger_pull_request_hook( | |
1069 | pull_request, pull_request.author, 'close') |
|
1094 | pull_request, pull_request.author, 'close') | |
1070 | self._log_action('user_closed_pull_request', user, pull_request) |
|
1095 | self._log_audit_action( | |
|
1096 | 'repo.pull_request.close', {}, user, pull_request) | |||
1071 |
|
1097 | |||
1072 | def close_pull_request_with_comment( |
|
1098 | def close_pull_request_with_comment( | |
1073 | self, pull_request, user, repo, message=None): |
|
1099 | self, pull_request, user, repo, message=None): | |
@@ -1402,12 +1428,12 b' class PullRequestModel(BaseModel):' | |||||
1402 | settings = settings_model.get_general_settings() |
|
1428 | settings = settings_model.get_general_settings() | |
1403 | return settings.get('rhodecode_hg_use_rebase_for_merging', False) |
|
1429 | return settings.get('rhodecode_hg_use_rebase_for_merging', False) | |
1404 |
|
1430 | |||
1405 | def _log_action(self, action, user, pull_request): |
|
1431 | def _log_audit_action(self, action, action_data, user, pull_request): | |
1406 |
a |
|
1432 | audit_logger.store( | |
1407 |
|
|
1433 | action=action, | |
1408 | '{action}:{pr_id}'.format( |
|
1434 | action_data=action_data, | |
1409 | action=action, pr_id=pull_request.pull_request_id), |
|
1435 | user=user, | |
1410 | pull_request.target_repo) |
|
1436 | repo=pull_request.target_repo) | |
1411 |
|
1437 | |||
1412 | def get_reviewer_functions(self): |
|
1438 | def get_reviewer_functions(self): | |
1413 | """ |
|
1439 | """ |
@@ -199,6 +199,9 b' class TestAdminPermissionsController(Tes' | |||||
199 | url('edit_user_ips', user_id=default_user_id), |
|
199 | url('edit_user_ips', user_id=default_user_id), | |
200 | params={'_method': 'delete', 'del_ip_id': del_ip_id, |
|
200 | params={'_method': 'delete', 'del_ip_id': del_ip_id, | |
201 | 'csrf_token': self.csrf_token}) |
|
201 | 'csrf_token': self.csrf_token}) | |
|
202 | ||||
|
203 | assert_session_flash(response, 'Removed ip address from user whitelist') | |||
|
204 | ||||
202 | clear_all_caches() |
|
205 | clear_all_caches() | |
203 | response = self.app.get(url('admin_permissions_ips')) |
|
206 | response = self.app.get(url('admin_permissions_ips')) | |
204 | response.mustcontain('All IP addresses are allowed') |
|
207 | response.mustcontain('All IP addresses are allowed') |
@@ -27,7 +27,7 b' from rhodecode.lib.vcs.nodes import File' | |||||
27 | from rhodecode.lib import helpers as h |
|
27 | from rhodecode.lib import helpers as h | |
28 | from rhodecode.model.changeset_status import ChangesetStatusModel |
|
28 | from rhodecode.model.changeset_status import ChangesetStatusModel | |
29 | from rhodecode.model.db import ( |
|
29 | from rhodecode.model.db import ( | |
30 | PullRequest, ChangesetStatus, UserLog, Notification) |
|
30 | PullRequest, ChangesetStatus, UserLog, Notification, ChangesetComment) | |
31 | from rhodecode.model.meta import Session |
|
31 | from rhodecode.model.meta import Session | |
32 | from rhodecode.model.pull_request import PullRequestModel |
|
32 | from rhodecode.model.pull_request import PullRequestModel | |
33 | from rhodecode.model.user import UserModel |
|
33 | from rhodecode.model.user import UserModel | |
@@ -256,29 +256,32 b' class TestPullrequestsController(object)' | |||||
256 | 'csrf_token': csrf_token}, |
|
256 | 'csrf_token': csrf_token}, | |
257 | extra_environ=xhr_header,) |
|
257 | extra_environ=xhr_header,) | |
258 |
|
258 | |||
259 | action = 'user_closed_pull_request:%d' % pull_request_id |
|
|||
260 | journal = UserLog.query()\ |
|
259 | journal = UserLog.query()\ | |
261 | .filter(UserLog.user_id == author)\ |
|
260 | .filter(UserLog.user_id == author)\ | |
262 | .filter(UserLog.repository_id == repo)\ |
|
261 | .filter(UserLog.repository_id == repo) \ | |
263 | .filter(UserLog.action == action)\ |
|
262 | .order_by('user_log_id') \ | |
264 | .all() |
|
263 | .all() | |
265 | assert len(journal) == 1 |
|
264 | assert journal[-1].action == 'repo.pull_request.close' | |
266 |
|
265 | |||
267 | pull_request = PullRequest.get(pull_request_id) |
|
266 | pull_request = PullRequest.get(pull_request_id) | |
268 | assert pull_request.is_closed() |
|
267 | assert pull_request.is_closed() | |
269 |
|
268 | |||
270 | # check only the latest status, not the review status |
|
|||
271 | status = ChangesetStatusModel().get_status( |
|
269 | status = ChangesetStatusModel().get_status( | |
272 | pull_request.source_repo, pull_request=pull_request) |
|
270 | pull_request.source_repo, pull_request=pull_request) | |
273 | assert status == ChangesetStatus.STATUS_APPROVED |
|
271 | assert status == ChangesetStatus.STATUS_APPROVED | |
274 | assert pull_request.comments[-1].text == 'Closing a PR' |
|
272 | comments = ChangesetComment().query() \ | |
|
273 | .filter(ChangesetComment.pull_request == pull_request) \ | |||
|
274 | .order_by(ChangesetComment.comment_id.asc())\ | |||
|
275 | .all() | |||
|
276 | assert comments[-1].text == 'Closing a PR' | |||
275 |
|
277 | |||
276 | def test_comment_force_close_pull_request_rejected( |
|
278 | def test_comment_force_close_pull_request_rejected( | |
277 | self, pr_util, csrf_token, xhr_header): |
|
279 | self, pr_util, csrf_token, xhr_header): | |
278 | pull_request = pr_util.create_pull_request() |
|
280 | pull_request = pr_util.create_pull_request() | |
279 | pull_request_id = pull_request.pull_request_id |
|
281 | pull_request_id = pull_request.pull_request_id | |
280 | PullRequestModel().update_reviewers( |
|
282 | PullRequestModel().update_reviewers( | |
281 |
pull_request_id, [(1, ['reason'], False), (2, ['reason2'], False)] |
|
283 | pull_request_id, [(1, ['reason'], False), (2, ['reason2'], False)], | |
|
284 | pull_request.author) | |||
282 | author = pull_request.user_id |
|
285 | author = pull_request.user_id | |
283 | repo = pull_request.target_repo.repo_id |
|
286 | repo = pull_request.target_repo.repo_id | |
284 |
|
287 | |||
@@ -294,12 +297,11 b' class TestPullrequestsController(object)' | |||||
294 |
|
297 | |||
295 | pull_request = PullRequest.get(pull_request_id) |
|
298 | pull_request = PullRequest.get(pull_request_id) | |
296 |
|
299 | |||
297 | action = 'user_closed_pull_request:%d' % pull_request_id |
|
300 | journal = UserLog.query()\ | |
298 | journal = UserLog.query().filter( |
|
301 | .filter(UserLog.user_id == author, UserLog.repository_id == repo) \ | |
299 | UserLog.user_id == author, |
|
302 | .order_by('user_log_id') \ | |
300 | UserLog.repository_id == repo, |
|
303 | .all() | |
301 | UserLog.action == action).all() |
|
304 | assert journal[-1].action == 'repo.pull_request.close' | |
302 | assert len(journal) == 1 |
|
|||
303 |
|
305 | |||
304 | # check only the latest status, not the review status |
|
306 | # check only the latest status, not the review status | |
305 | status = ChangesetStatusModel().get_status( |
|
307 | status = ChangesetStatusModel().get_status( | |
@@ -449,7 +451,8 b' class TestPullrequestsController(object)' | |||||
449 |
|
451 | |||
450 | # Change reviewers and check that a notification was made |
|
452 | # Change reviewers and check that a notification was made | |
451 | PullRequestModel().update_reviewers( |
|
453 | PullRequestModel().update_reviewers( | |
452 |
pull_request.pull_request_id, [(1, [], False)] |
|
454 | pull_request.pull_request_id, [(1, [], False)], | |
|
455 | pull_request.author) | |||
453 | assert len(notifications.all()) == 2 |
|
456 | assert len(notifications.all()) == 2 | |
454 |
|
457 | |||
455 | def test_create_pull_request_stores_ancestor_commit_id(self, backend, |
|
458 | def test_create_pull_request_stores_ancestor_commit_id(self, backend, | |
@@ -541,25 +544,20 b' class TestPullrequestsController(object)' | |||||
541 | pull_request, ChangesetStatus.STATUS_APPROVED) |
|
544 | pull_request, ChangesetStatus.STATUS_APPROVED) | |
542 |
|
545 | |||
543 | # Check the relevant log entries were added |
|
546 | # Check the relevant log entries were added | |
544 |
user_logs = UserLog.query() |
|
547 | user_logs = UserLog.query().order_by('-user_log_id').limit(3) | |
545 | .filter(UserLog.version == UserLog.VERSION_1) \ |
|
|||
546 | .order_by('-user_log_id').limit(3) |
|
|||
547 | actions = [log.action for log in user_logs] |
|
548 | actions = [log.action for log in user_logs] | |
548 | pr_commit_ids = PullRequestModel()._get_commit_ids(pull_request) |
|
549 | pr_commit_ids = PullRequestModel()._get_commit_ids(pull_request) | |
549 | expected_actions = [ |
|
550 | expected_actions = [ | |
550 | u'user_closed_pull_request:%d' % pull_request_id, |
|
551 | u'repo.pull_request.close', | |
551 | u'user_merged_pull_request:%d' % pull_request_id, |
|
552 | u'repo.pull_request.merge', | |
552 | # The action below reflect that the post push actions were executed |
|
553 | u'repo.pull_request.comment.create' | |
553 | u'user_commented_pull_request:%d' % pull_request_id, |
|
|||
554 | ] |
|
554 | ] | |
555 | assert actions == expected_actions |
|
555 | assert actions == expected_actions | |
556 |
|
556 | |||
557 |
user_logs = UserLog.query() |
|
557 | user_logs = UserLog.query().order_by('-user_log_id').limit(4) | |
558 | .filter(UserLog.version == UserLog.VERSION_2) \ |
|
558 | actions = [log for log in user_logs] | |
559 | .order_by('-user_log_id').limit(1) |
|
559 | assert actions[-1].action == 'user.push' | |
560 | actions = [log.action for log in user_logs] |
|
560 | assert actions[-1].action_data['commit_ids'] == pr_commit_ids | |
561 | assert actions == ['user.push'] |
|
|||
562 | assert user_logs[0].action_data['commit_ids'] == pr_commit_ids |
|
|||
563 |
|
561 | |||
564 | # Check post_push rcextension was really executed |
|
562 | # Check post_push rcextension was really executed | |
565 | push_calls = rhodecode.EXTENSIONS.calls['post_push'] |
|
563 | push_calls = rhodecode.EXTENSIONS.calls['post_push'] |
@@ -50,7 +50,9 b' class TestPullRequestModel(object):' | |||||
50 | A pull request combined with multiples patches. |
|
50 | A pull request combined with multiples patches. | |
51 | """ |
|
51 | """ | |
52 | BackendClass = get_backend(backend.alias) |
|
52 | BackendClass = get_backend(backend.alias) | |
53 |
self.merge_patcher = mock.patch.object( |
|
53 | self.merge_patcher = mock.patch.object( | |
|
54 | BackendClass, 'merge', return_value=MergeResponse( | |||
|
55 | False, False, None, MergeFailureReason.UNKNOWN)) | |||
54 | self.workspace_remove_patcher = mock.patch.object( |
|
56 | self.workspace_remove_patcher = mock.patch.object( | |
55 | BackendClass, 'cleanup_merge_workspace') |
|
57 | BackendClass, 'cleanup_merge_workspace') | |
56 |
|
58 | |||
@@ -117,7 +119,8 b' class TestPullRequestModel(object):' | |||||
117 |
|
119 | |||
118 | def test_get_awaiting_my_review(self, pull_request): |
|
120 | def test_get_awaiting_my_review(self, pull_request): | |
119 | PullRequestModel().update_reviewers( |
|
121 | PullRequestModel().update_reviewers( | |
120 |
pull_request, [(pull_request.author, ['author'], False)] |
|
122 | pull_request, [(pull_request.author, ['author'], False)], | |
|
123 | pull_request.author) | |||
121 | prs = PullRequestModel().get_awaiting_my_review( |
|
124 | prs = PullRequestModel().get_awaiting_my_review( | |
122 | pull_request.target_repo, user_id=pull_request.author.user_id) |
|
125 | pull_request.target_repo, user_id=pull_request.author.user_id) | |
123 | assert isinstance(prs, list) |
|
126 | assert isinstance(prs, list) | |
@@ -125,13 +128,14 b' class TestPullRequestModel(object):' | |||||
125 |
|
128 | |||
126 | def test_count_awaiting_my_review(self, pull_request): |
|
129 | def test_count_awaiting_my_review(self, pull_request): | |
127 | PullRequestModel().update_reviewers( |
|
130 | PullRequestModel().update_reviewers( | |
128 |
pull_request, [(pull_request.author, ['author'], False)] |
|
131 | pull_request, [(pull_request.author, ['author'], False)], | |
|
132 | pull_request.author) | |||
129 | pr_count = PullRequestModel().count_awaiting_my_review( |
|
133 | pr_count = PullRequestModel().count_awaiting_my_review( | |
130 | pull_request.target_repo, user_id=pull_request.author.user_id) |
|
134 | pull_request.target_repo, user_id=pull_request.author.user_id) | |
131 | assert pr_count == 1 |
|
135 | assert pr_count == 1 | |
132 |
|
136 | |||
133 | def test_delete_calls_cleanup_merge(self, pull_request): |
|
137 | def test_delete_calls_cleanup_merge(self, pull_request): | |
134 | PullRequestModel().delete(pull_request) |
|
138 | PullRequestModel().delete(pull_request, pull_request.author) | |
135 |
|
139 | |||
136 | self.workspace_remove_mock.assert_called_once_with( |
|
140 | self.workspace_remove_mock.assert_called_once_with( | |
137 | self.workspace_id) |
|
141 | self.workspace_id) |
@@ -892,7 +892,7 b' class RepoServer(object):' | |||||
892 |
|
892 | |||
893 |
|
893 | |||
894 | @pytest.fixture |
|
894 | @pytest.fixture | |
895 | def pr_util(backend, request): |
|
895 | def pr_util(backend, request, config_stub): | |
896 | """ |
|
896 | """ | |
897 | Utility for tests of models and for functional tests around pull requests. |
|
897 | Utility for tests of models and for functional tests around pull requests. | |
898 |
|
898 | |||
@@ -1085,7 +1085,7 b' class PRTestUtility(object):' | |||||
1085 | # request will already be deleted. |
|
1085 | # request will already be deleted. | |
1086 | pull_request = PullRequest().get(self.pull_request_id) |
|
1086 | pull_request = PullRequest().get(self.pull_request_id) | |
1087 | if pull_request: |
|
1087 | if pull_request: | |
1088 | PullRequestModel().delete(pull_request) |
|
1088 | PullRequestModel().delete(pull_request, pull_request.author) | |
1089 | Session().commit() |
|
1089 | Session().commit() | |
1090 |
|
1090 | |||
1091 | if self.notification_patcher: |
|
1091 | if self.notification_patcher: | |
@@ -1648,14 +1648,6 b' def no_notifications(request):' | |||||
1648 | request.addfinalizer(notification_patcher.stop) |
|
1648 | request.addfinalizer(notification_patcher.stop) | |
1649 |
|
1649 | |||
1650 |
|
1650 | |||
1651 | @pytest.fixture |
|
|||
1652 | def silence_action_logger(request): |
|
|||
1653 | notification_patcher = mock.patch( |
|
|||
1654 | 'rhodecode.lib.utils.action_logger') |
|
|||
1655 | notification_patcher.start() |
|
|||
1656 | request.addfinalizer(notification_patcher.stop) |
|
|||
1657 |
|
||||
1658 |
|
||||
1659 | @pytest.fixture(scope='session') |
|
1651 | @pytest.fixture(scope='session') | |
1660 | def repeat(request): |
|
1652 | def repeat(request): | |
1661 | """ |
|
1653 | """ |
General Comments 0
You need to be logged in to leave comments.
Login now