##// END OF EJS Templates
vcs: don't use deprecated get_changeset[s] methods.
dan -
r3112:f3f66eb3 default
parent child Browse files
Show More
@@ -1,81 +1,81 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import pytest
21 import pytest
22
22
23 from rhodecode.model.db import ChangesetStatus
23 from rhodecode.model.db import ChangesetStatus
24 from rhodecode.api.tests.utils import (
24 from rhodecode.api.tests.utils import (
25 build_data, api_call, assert_error, assert_ok)
25 build_data, api_call, assert_error, assert_ok)
26
26
27
27
28 @pytest.mark.usefixtures("testuser_api", "app")
28 @pytest.mark.usefixtures("testuser_api", "app")
29 class TestCommentCommit(object):
29 class TestCommentCommit(object):
30 def test_api_comment_commit_on_empty_repo(self, backend):
30 def test_api_comment_commit_on_empty_repo(self, backend):
31 repo = backend.create_repo()
31 repo = backend.create_repo()
32 id_, params = build_data(
32 id_, params = build_data(
33 self.apikey, 'comment_commit', repoid=repo.repo_name,
33 self.apikey, 'comment_commit', repoid=repo.repo_name,
34 commit_id='tip', message='message', status_change=None)
34 commit_id='tip', message='message', status_change=None)
35 response = api_call(self.app, params)
35 response = api_call(self.app, params)
36 expected = 'There are no commits yet'
36 expected = 'There are no commits yet'
37 assert_error(id_, expected, given=response.body)
37 assert_error(id_, expected, given=response.body)
38
38
39 @pytest.mark.parametrize("commit_id, expected_err", [
39 @pytest.mark.parametrize("commit_id, expected_err", [
40 ('abcabca', {'hg': 'Commit {commit} does not exist for {repo}',
40 ('abcabca', {'hg': 'Commit {commit} does not exist for {repo}',
41 'git': 'Commit {commit} does not exist for {repo}',
41 'git': 'Commit {commit} does not exist for {repo}',
42 'svn': 'Commit id {commit} not understood.'}),
42 'svn': 'Commit id {commit} not understood.'}),
43 ('idontexist', {'hg': 'Commit {commit} does not exist for {repo}',
43 ('idontexist', {'hg': 'Commit {commit} does not exist for {repo}',
44 'git': 'Commit {commit} does not exist for {repo}',
44 'git': 'Commit {commit} does not exist for {repo}',
45 'svn': 'Commit id {commit} not understood.'}),
45 'svn': 'Commit id {commit} not understood.'}),
46 ])
46 ])
47 def test_api_comment_commit_wrong_hash(self, backend, commit_id, expected_err):
47 def test_api_comment_commit_wrong_hash(self, backend, commit_id, expected_err):
48 repo_name = backend.repo.repo_name
48 repo_name = backend.repo.repo_name
49 id_, params = build_data(
49 id_, params = build_data(
50 self.apikey, 'comment_commit', repoid=repo_name,
50 self.apikey, 'comment_commit', repoid=repo_name,
51 commit_id=commit_id, message='message', status_change=None)
51 commit_id=commit_id, message='message', status_change=None)
52 response = api_call(self.app, params)
52 response = api_call(self.app, params)
53
53
54 expected_err = expected_err[backend.alias]
54 expected_err = expected_err[backend.alias]
55 expected_err = expected_err.format(
55 expected_err = expected_err.format(
56 repo=backend.repo.scm_instance(), commit=commit_id)
56 repo=backend.repo.scm_instance(), commit=commit_id)
57 assert_error(id_, expected_err, given=response.body)
57 assert_error(id_, expected_err, given=response.body)
58
58
59 @pytest.mark.parametrize("status_change, message, commit_id", [
59 @pytest.mark.parametrize("status_change, message, commit_id", [
60 (None, 'Hallo', 'tip'),
60 (None, 'Hallo', 'tip'),
61 (ChangesetStatus.STATUS_APPROVED, 'Approved', 'tip'),
61 (ChangesetStatus.STATUS_APPROVED, 'Approved', 'tip'),
62 (ChangesetStatus.STATUS_REJECTED, 'Rejected', 'tip'),
62 (ChangesetStatus.STATUS_REJECTED, 'Rejected', 'tip'),
63 ])
63 ])
64 def test_api_comment_commit(
64 def test_api_comment_commit(
65 self, backend, status_change, message, commit_id,
65 self, backend, status_change, message, commit_id,
66 no_notifications):
66 no_notifications):
67
67
68 commit_id = backend.repo.scm_instance().get_changeset(commit_id).raw_id
68 commit_id = backend.repo.scm_instance().get_commit(commit_id).raw_id
69
69
70 id_, params = build_data(
70 id_, params = build_data(
71 self.apikey, 'comment_commit', repoid=backend.repo_name,
71 self.apikey, 'comment_commit', repoid=backend.repo_name,
72 commit_id=commit_id, message=message, status=status_change)
72 commit_id=commit_id, message=message, status=status_change)
73 response = api_call(self.app, params)
73 response = api_call(self.app, params)
74 repo = backend.repo.scm_instance()
74 repo = backend.repo.scm_instance()
75 expected = {
75 expected = {
76 'msg': 'Commented on commit `%s` for repository `%s`' % (
76 'msg': 'Commented on commit `%s` for repository `%s`' % (
77 repo.get_changeset().raw_id, backend.repo_name),
77 repo.get_commit().raw_id, backend.repo_name),
78 'status_change': status_change,
78 'status_change': status_change,
79 'success': True
79 'success': True
80 }
80 }
81 assert_ok(id_, expected, given=response.body)
81 assert_ok(id_, expected, given=response.body)
@@ -1,113 +1,113 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2017-2018 RhodeCode GmbH
3 # Copyright (C) 2017-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22 from pyramid.view import view_config
22 from pyramid.view import view_config
23
23
24 from rhodecode.apps._base import RepoAppView
24 from rhodecode.apps._base import RepoAppView
25 from rhodecode.lib import audit_logger
25 from rhodecode.lib import audit_logger
26 from rhodecode.lib import helpers as h
26 from rhodecode.lib import helpers as h
27 from rhodecode.lib.auth import (
27 from rhodecode.lib.auth import (
28 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
28 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
29 from rhodecode.lib.ext_json import json
29 from rhodecode.lib.ext_json import json
30
30
31 log = logging.getLogger(__name__)
31 log = logging.getLogger(__name__)
32
32
33
33
34 class StripView(RepoAppView):
34 class StripView(RepoAppView):
35 def load_default_context(self):
35 def load_default_context(self):
36 c = self._get_local_tmpl_context()
36 c = self._get_local_tmpl_context()
37
37
38
38
39 return c
39 return c
40
40
41 @LoginRequired()
41 @LoginRequired()
42 @HasRepoPermissionAnyDecorator('repository.admin')
42 @HasRepoPermissionAnyDecorator('repository.admin')
43 @view_config(
43 @view_config(
44 route_name='edit_repo_strip', request_method='GET',
44 route_name='edit_repo_strip', request_method='GET',
45 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
45 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
46 def strip(self):
46 def strip(self):
47 c = self.load_default_context()
47 c = self.load_default_context()
48 c.active = 'strip'
48 c.active = 'strip'
49 c.strip_limit = 10
49 c.strip_limit = 10
50
50
51 return self._get_template_context(c)
51 return self._get_template_context(c)
52
52
53 @LoginRequired()
53 @LoginRequired()
54 @HasRepoPermissionAnyDecorator('repository.admin')
54 @HasRepoPermissionAnyDecorator('repository.admin')
55 @CSRFRequired()
55 @CSRFRequired()
56 @view_config(
56 @view_config(
57 route_name='strip_check', request_method='POST',
57 route_name='strip_check', request_method='POST',
58 renderer='json', xhr=True)
58 renderer='json', xhr=True)
59 def strip_check(self):
59 def strip_check(self):
60 from rhodecode.lib.vcs.backends.base import EmptyCommit
60 from rhodecode.lib.vcs.backends.base import EmptyCommit
61 data = {}
61 data = {}
62 rp = self.request.POST
62 rp = self.request.POST
63 for i in range(1, 11):
63 for i in range(1, 11):
64 chset = 'changeset_id-%d' % (i,)
64 chset = 'changeset_id-%d' % (i,)
65 check = rp.get(chset)
65 check = rp.get(chset)
66
66
67 if check:
67 if check:
68 data[i] = self.db_repo.get_changeset(rp[chset])
68 data[i] = self.db_repo.get_commit(rp[chset])
69 if isinstance(data[i], EmptyCommit):
69 if isinstance(data[i], EmptyCommit):
70 data[i] = {'rev': None, 'commit': h.escape(rp[chset])}
70 data[i] = {'rev': None, 'commit': h.escape(rp[chset])}
71 else:
71 else:
72 data[i] = {'rev': data[i].raw_id, 'branch': data[i].branch,
72 data[i] = {'rev': data[i].raw_id, 'branch': data[i].branch,
73 'author': h.escape(data[i].author),
73 'author': h.escape(data[i].author),
74 'comment': h.escape(data[i].message)}
74 'comment': h.escape(data[i].message)}
75 else:
75 else:
76 break
76 break
77 return data
77 return data
78
78
79 @LoginRequired()
79 @LoginRequired()
80 @HasRepoPermissionAnyDecorator('repository.admin')
80 @HasRepoPermissionAnyDecorator('repository.admin')
81 @CSRFRequired()
81 @CSRFRequired()
82 @view_config(
82 @view_config(
83 route_name='strip_execute', request_method='POST',
83 route_name='strip_execute', request_method='POST',
84 renderer='json', xhr=True)
84 renderer='json', xhr=True)
85 def strip_execute(self):
85 def strip_execute(self):
86 from rhodecode.model.scm import ScmModel
86 from rhodecode.model.scm import ScmModel
87
87
88 c = self.load_default_context()
88 c = self.load_default_context()
89 user = self._rhodecode_user
89 user = self._rhodecode_user
90 rp = self.request.POST
90 rp = self.request.POST
91 data = {}
91 data = {}
92 for idx in rp:
92 for idx in rp:
93 commit = json.loads(rp[idx])
93 commit = json.loads(rp[idx])
94 # If someone put two times the same branch
94 # If someone put two times the same branch
95 if commit['branch'] in data.keys():
95 if commit['branch'] in data.keys():
96 continue
96 continue
97 try:
97 try:
98 ScmModel().strip(
98 ScmModel().strip(
99 repo=self.db_repo,
99 repo=self.db_repo,
100 commit_id=commit['rev'], branch=commit['branch'])
100 commit_id=commit['rev'], branch=commit['branch'])
101 log.info('Stripped commit %s from repo `%s` by %s',
101 log.info('Stripped commit %s from repo `%s` by %s',
102 commit['rev'], self.db_repo_name, user)
102 commit['rev'], self.db_repo_name, user)
103 data[commit['rev']] = True
103 data[commit['rev']] = True
104
104
105 audit_logger.store_web(
105 audit_logger.store_web(
106 'repo.commit.strip', action_data={'commit_id': commit['rev']},
106 'repo.commit.strip', action_data={'commit_id': commit['rev']},
107 repo=self.db_repo, user=self._rhodecode_user, commit=True)
107 repo=self.db_repo, user=self._rhodecode_user, commit=True)
108
108
109 except Exception as e:
109 except Exception as e:
110 data[commit['rev']] = False
110 data[commit['rev']] = False
111 log.debug('Stripped commit %s from repo `%s` failed by %s, exeption %s',
111 log.debug('Stripped commit %s from repo `%s` failed by %s, exeption %s',
112 commit['rev'], self.db_repo_name, user, e.message)
112 commit['rev'], self.db_repo_name, user, e.message)
113 return data
113 return data
@@ -1,356 +1,356 b''
1 # Copyright (C) 2016-2018 RhodeCode GmbH
1 # Copyright (C) 2016-2018 RhodeCode GmbH
2 #
2 #
3 # This program is free software: you can redistribute it and/or modify
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
5 # (only), as published by the Free Software Foundation.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU Affero General Public License
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
14 #
15 # This program is dual-licensed. If you wish to learn more about the
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 import collections
19 import collections
20 import logging
20 import logging
21 import datetime
21 import datetime
22
22
23 from rhodecode.translation import lazy_ugettext
23 from rhodecode.translation import lazy_ugettext
24 from rhodecode.model.db import User, Repository, Session
24 from rhodecode.model.db import User, Repository, Session
25 from rhodecode.events.base import RhodeCodeIntegrationEvent
25 from rhodecode.events.base import RhodeCodeIntegrationEvent
26 from rhodecode.lib.vcs.exceptions import CommitDoesNotExistError
26 from rhodecode.lib.vcs.exceptions import CommitDoesNotExistError
27
27
28 log = logging.getLogger(__name__)
28 log = logging.getLogger(__name__)
29
29
30
30
31 def _commits_as_dict(event, commit_ids, repos):
31 def _commits_as_dict(event, commit_ids, repos):
32 """
32 """
33 Helper function to serialize commit_ids
33 Helper function to serialize commit_ids
34
34
35 :param event: class calling this method
35 :param event: class calling this method
36 :param commit_ids: commits to get
36 :param commit_ids: commits to get
37 :param repos: list of repos to check
37 :param repos: list of repos to check
38 """
38 """
39 from rhodecode.lib.utils2 import extract_mentioned_users
39 from rhodecode.lib.utils2 import extract_mentioned_users
40 from rhodecode.lib.helpers import (
40 from rhodecode.lib.helpers import (
41 urlify_commit_message, process_patterns, chop_at_smart)
41 urlify_commit_message, process_patterns, chop_at_smart)
42 from rhodecode.model.repo import RepoModel
42 from rhodecode.model.repo import RepoModel
43
43
44 if not repos:
44 if not repos:
45 raise Exception('no repo defined')
45 raise Exception('no repo defined')
46
46
47 if not isinstance(repos, (tuple, list)):
47 if not isinstance(repos, (tuple, list)):
48 repos = [repos]
48 repos = [repos]
49
49
50 if not commit_ids:
50 if not commit_ids:
51 return []
51 return []
52
52
53 needed_commits = list(commit_ids)
53 needed_commits = list(commit_ids)
54
54
55 commits = []
55 commits = []
56 reviewers = []
56 reviewers = []
57 for repo in repos:
57 for repo in repos:
58 if not needed_commits:
58 if not needed_commits:
59 return commits # return early if we have the commits we need
59 return commits # return early if we have the commits we need
60
60
61 vcs_repo = repo.scm_instance(cache=False)
61 vcs_repo = repo.scm_instance(cache=False)
62
62
63 try:
63 try:
64 # use copy of needed_commits since we modify it while iterating
64 # use copy of needed_commits since we modify it while iterating
65 for commit_id in list(needed_commits):
65 for commit_id in list(needed_commits):
66 if commit_id.startswith('tag=>'):
66 if commit_id.startswith('tag=>'):
67 raw_id = commit_id[5:]
67 raw_id = commit_id[5:]
68 cs_data = {
68 cs_data = {
69 'raw_id': commit_id, 'short_id': commit_id,
69 'raw_id': commit_id, 'short_id': commit_id,
70 'branch': None,
70 'branch': None,
71 'git_ref_change': 'tag_add',
71 'git_ref_change': 'tag_add',
72 'message': 'Added new tag {}'.format(raw_id),
72 'message': 'Added new tag {}'.format(raw_id),
73 'author': event.actor.full_contact,
73 'author': event.actor.full_contact,
74 'date': datetime.datetime.now(),
74 'date': datetime.datetime.now(),
75 'refs': {
75 'refs': {
76 'branches': [],
76 'branches': [],
77 'bookmarks': [],
77 'bookmarks': [],
78 'tags': []
78 'tags': []
79 }
79 }
80 }
80 }
81 commits.append(cs_data)
81 commits.append(cs_data)
82
82
83 elif commit_id.startswith('delete_branch=>'):
83 elif commit_id.startswith('delete_branch=>'):
84 raw_id = commit_id[15:]
84 raw_id = commit_id[15:]
85 cs_data = {
85 cs_data = {
86 'raw_id': commit_id, 'short_id': commit_id,
86 'raw_id': commit_id, 'short_id': commit_id,
87 'branch': None,
87 'branch': None,
88 'git_ref_change': 'branch_delete',
88 'git_ref_change': 'branch_delete',
89 'message': 'Deleted branch {}'.format(raw_id),
89 'message': 'Deleted branch {}'.format(raw_id),
90 'author': event.actor.full_contact,
90 'author': event.actor.full_contact,
91 'date': datetime.datetime.now(),
91 'date': datetime.datetime.now(),
92 'refs': {
92 'refs': {
93 'branches': [],
93 'branches': [],
94 'bookmarks': [],
94 'bookmarks': [],
95 'tags': []
95 'tags': []
96 }
96 }
97 }
97 }
98 commits.append(cs_data)
98 commits.append(cs_data)
99
99
100 else:
100 else:
101 try:
101 try:
102 cs = vcs_repo.get_changeset(commit_id)
102 cs = vcs_repo.get_commit(commit_id)
103 except CommitDoesNotExistError:
103 except CommitDoesNotExistError:
104 continue # maybe its in next repo
104 continue # maybe its in next repo
105
105
106 cs_data = cs.__json__()
106 cs_data = cs.__json__()
107 cs_data['refs'] = cs._get_refs()
107 cs_data['refs'] = cs._get_refs()
108
108
109 cs_data['mentions'] = extract_mentioned_users(cs_data['message'])
109 cs_data['mentions'] = extract_mentioned_users(cs_data['message'])
110 cs_data['reviewers'] = reviewers
110 cs_data['reviewers'] = reviewers
111 cs_data['url'] = RepoModel().get_commit_url(
111 cs_data['url'] = RepoModel().get_commit_url(
112 repo, cs_data['raw_id'], request=event.request)
112 repo, cs_data['raw_id'], request=event.request)
113 cs_data['permalink_url'] = RepoModel().get_commit_url(
113 cs_data['permalink_url'] = RepoModel().get_commit_url(
114 repo, cs_data['raw_id'], request=event.request,
114 repo, cs_data['raw_id'], request=event.request,
115 permalink=True)
115 permalink=True)
116 urlified_message, issues_data = process_patterns(
116 urlified_message, issues_data = process_patterns(
117 cs_data['message'], repo.repo_name)
117 cs_data['message'], repo.repo_name)
118 cs_data['issues'] = issues_data
118 cs_data['issues'] = issues_data
119 cs_data['message_html'] = urlify_commit_message(
119 cs_data['message_html'] = urlify_commit_message(
120 cs_data['message'], repo.repo_name)
120 cs_data['message'], repo.repo_name)
121 cs_data['message_html_title'] = chop_at_smart(
121 cs_data['message_html_title'] = chop_at_smart(
122 cs_data['message'], '\n', suffix_if_chopped='...')
122 cs_data['message'], '\n', suffix_if_chopped='...')
123 commits.append(cs_data)
123 commits.append(cs_data)
124
124
125 needed_commits.remove(commit_id)
125 needed_commits.remove(commit_id)
126
126
127 except Exception:
127 except Exception:
128 log.exception('Failed to extract commits data')
128 log.exception('Failed to extract commits data')
129 # we don't send any commits when crash happens, only full list
129 # we don't send any commits when crash happens, only full list
130 # matters we short circuit then.
130 # matters we short circuit then.
131 return []
131 return []
132
132
133 missing_commits = set(commit_ids) - set(c['raw_id'] for c in commits)
133 missing_commits = set(commit_ids) - set(c['raw_id'] for c in commits)
134 if missing_commits:
134 if missing_commits:
135 log.error('Inconsistent repository state. '
135 log.error('Inconsistent repository state. '
136 'Missing commits: %s', ', '.join(missing_commits))
136 'Missing commits: %s', ', '.join(missing_commits))
137
137
138 return commits
138 return commits
139
139
140
140
141 def _issues_as_dict(commits):
141 def _issues_as_dict(commits):
142 """ Helper function to serialize issues from commits """
142 """ Helper function to serialize issues from commits """
143 issues = {}
143 issues = {}
144 for commit in commits:
144 for commit in commits:
145 for issue in commit['issues']:
145 for issue in commit['issues']:
146 issues[issue['id']] = issue
146 issues[issue['id']] = issue
147 return issues
147 return issues
148
148
149
149
150 class RepoEvent(RhodeCodeIntegrationEvent):
150 class RepoEvent(RhodeCodeIntegrationEvent):
151 """
151 """
152 Base class for events acting on a repository.
152 Base class for events acting on a repository.
153
153
154 :param repo: a :class:`Repository` instance
154 :param repo: a :class:`Repository` instance
155 """
155 """
156
156
157 def __init__(self, repo):
157 def __init__(self, repo):
158 super(RepoEvent, self).__init__()
158 super(RepoEvent, self).__init__()
159 self.repo = repo
159 self.repo = repo
160
160
161 def as_dict(self):
161 def as_dict(self):
162 from rhodecode.model.repo import RepoModel
162 from rhodecode.model.repo import RepoModel
163 data = super(RepoEvent, self).as_dict()
163 data = super(RepoEvent, self).as_dict()
164
164
165 extra_fields = collections.OrderedDict()
165 extra_fields = collections.OrderedDict()
166 for field in self.repo.extra_fields:
166 for field in self.repo.extra_fields:
167 extra_fields[field.field_key] = field.field_value
167 extra_fields[field.field_key] = field.field_value
168
168
169 data.update({
169 data.update({
170 'repo': {
170 'repo': {
171 'repo_id': self.repo.repo_id,
171 'repo_id': self.repo.repo_id,
172 'repo_name': self.repo.repo_name,
172 'repo_name': self.repo.repo_name,
173 'repo_type': self.repo.repo_type,
173 'repo_type': self.repo.repo_type,
174 'url': RepoModel().get_url(
174 'url': RepoModel().get_url(
175 self.repo, request=self.request),
175 self.repo, request=self.request),
176 'permalink_url': RepoModel().get_url(
176 'permalink_url': RepoModel().get_url(
177 self.repo, request=self.request, permalink=True),
177 self.repo, request=self.request, permalink=True),
178 'extra_fields': extra_fields
178 'extra_fields': extra_fields
179 }
179 }
180 })
180 })
181 return data
181 return data
182
182
183
183
184 class RepoPreCreateEvent(RepoEvent):
184 class RepoPreCreateEvent(RepoEvent):
185 """
185 """
186 An instance of this class is emitted as an :term:`event` before a repo is
186 An instance of this class is emitted as an :term:`event` before a repo is
187 created.
187 created.
188 """
188 """
189 name = 'repo-pre-create'
189 name = 'repo-pre-create'
190 display_name = lazy_ugettext('repository pre create')
190 display_name = lazy_ugettext('repository pre create')
191
191
192
192
193 class RepoCreateEvent(RepoEvent):
193 class RepoCreateEvent(RepoEvent):
194 """
194 """
195 An instance of this class is emitted as an :term:`event` whenever a repo is
195 An instance of this class is emitted as an :term:`event` whenever a repo is
196 created.
196 created.
197 """
197 """
198 name = 'repo-create'
198 name = 'repo-create'
199 display_name = lazy_ugettext('repository created')
199 display_name = lazy_ugettext('repository created')
200
200
201
201
202 class RepoPreDeleteEvent(RepoEvent):
202 class RepoPreDeleteEvent(RepoEvent):
203 """
203 """
204 An instance of this class is emitted as an :term:`event` whenever a repo is
204 An instance of this class is emitted as an :term:`event` whenever a repo is
205 created.
205 created.
206 """
206 """
207 name = 'repo-pre-delete'
207 name = 'repo-pre-delete'
208 display_name = lazy_ugettext('repository pre delete')
208 display_name = lazy_ugettext('repository pre delete')
209
209
210
210
211 class RepoDeleteEvent(RepoEvent):
211 class RepoDeleteEvent(RepoEvent):
212 """
212 """
213 An instance of this class is emitted as an :term:`event` whenever a repo is
213 An instance of this class is emitted as an :term:`event` whenever a repo is
214 created.
214 created.
215 """
215 """
216 name = 'repo-delete'
216 name = 'repo-delete'
217 display_name = lazy_ugettext('repository deleted')
217 display_name = lazy_ugettext('repository deleted')
218
218
219
219
220 class RepoVCSEvent(RepoEvent):
220 class RepoVCSEvent(RepoEvent):
221 """
221 """
222 Base class for events triggered by the VCS
222 Base class for events triggered by the VCS
223 """
223 """
224 def __init__(self, repo_name, extras):
224 def __init__(self, repo_name, extras):
225 self.repo = Repository.get_by_repo_name(repo_name)
225 self.repo = Repository.get_by_repo_name(repo_name)
226 if not self.repo:
226 if not self.repo:
227 raise Exception('repo by this name %s does not exist' % repo_name)
227 raise Exception('repo by this name %s does not exist' % repo_name)
228 self.extras = extras
228 self.extras = extras
229 super(RepoVCSEvent, self).__init__(self.repo)
229 super(RepoVCSEvent, self).__init__(self.repo)
230
230
231 @property
231 @property
232 def actor(self):
232 def actor(self):
233 if self.extras.get('username'):
233 if self.extras.get('username'):
234 return User.get_by_username(self.extras['username'])
234 return User.get_by_username(self.extras['username'])
235
235
236 @property
236 @property
237 def actor_ip(self):
237 def actor_ip(self):
238 if self.extras.get('ip'):
238 if self.extras.get('ip'):
239 return self.extras['ip']
239 return self.extras['ip']
240
240
241 @property
241 @property
242 def server_url(self):
242 def server_url(self):
243 if self.extras.get('server_url'):
243 if self.extras.get('server_url'):
244 return self.extras['server_url']
244 return self.extras['server_url']
245
245
246 @property
246 @property
247 def request(self):
247 def request(self):
248 return self.extras.get('request') or self.get_request()
248 return self.extras.get('request') or self.get_request()
249
249
250
250
251 class RepoPrePullEvent(RepoVCSEvent):
251 class RepoPrePullEvent(RepoVCSEvent):
252 """
252 """
253 An instance of this class is emitted as an :term:`event` before commits
253 An instance of this class is emitted as an :term:`event` before commits
254 are pulled from a repo.
254 are pulled from a repo.
255 """
255 """
256 name = 'repo-pre-pull'
256 name = 'repo-pre-pull'
257 display_name = lazy_ugettext('repository pre pull')
257 display_name = lazy_ugettext('repository pre pull')
258
258
259
259
260 class RepoPullEvent(RepoVCSEvent):
260 class RepoPullEvent(RepoVCSEvent):
261 """
261 """
262 An instance of this class is emitted as an :term:`event` after commits
262 An instance of this class is emitted as an :term:`event` after commits
263 are pulled from a repo.
263 are pulled from a repo.
264 """
264 """
265 name = 'repo-pull'
265 name = 'repo-pull'
266 display_name = lazy_ugettext('repository pull')
266 display_name = lazy_ugettext('repository pull')
267
267
268
268
269 class RepoPrePushEvent(RepoVCSEvent):
269 class RepoPrePushEvent(RepoVCSEvent):
270 """
270 """
271 An instance of this class is emitted as an :term:`event` before commits
271 An instance of this class is emitted as an :term:`event` before commits
272 are pushed to a repo.
272 are pushed to a repo.
273 """
273 """
274 name = 'repo-pre-push'
274 name = 'repo-pre-push'
275 display_name = lazy_ugettext('repository pre push')
275 display_name = lazy_ugettext('repository pre push')
276
276
277
277
278 class RepoPushEvent(RepoVCSEvent):
278 class RepoPushEvent(RepoVCSEvent):
279 """
279 """
280 An instance of this class is emitted as an :term:`event` after commits
280 An instance of this class is emitted as an :term:`event` after commits
281 are pushed to a repo.
281 are pushed to a repo.
282
282
283 :param extras: (optional) dict of data from proxied VCS actions
283 :param extras: (optional) dict of data from proxied VCS actions
284 """
284 """
285 name = 'repo-push'
285 name = 'repo-push'
286 display_name = lazy_ugettext('repository push')
286 display_name = lazy_ugettext('repository push')
287
287
288 def __init__(self, repo_name, pushed_commit_ids, extras):
288 def __init__(self, repo_name, pushed_commit_ids, extras):
289 super(RepoPushEvent, self).__init__(repo_name, extras)
289 super(RepoPushEvent, self).__init__(repo_name, extras)
290 self.pushed_commit_ids = pushed_commit_ids
290 self.pushed_commit_ids = pushed_commit_ids
291 self.new_refs = extras.new_refs
291 self.new_refs = extras.new_refs
292
292
293 def as_dict(self):
293 def as_dict(self):
294 data = super(RepoPushEvent, self).as_dict()
294 data = super(RepoPushEvent, self).as_dict()
295
295
296 def branch_url(branch_name):
296 def branch_url(branch_name):
297 return '{}/changelog?branch={}'.format(
297 return '{}/changelog?branch={}'.format(
298 data['repo']['url'], branch_name)
298 data['repo']['url'], branch_name)
299
299
300 def tag_url(tag_name):
300 def tag_url(tag_name):
301 return '{}/files/{}/'.format(
301 return '{}/files/{}/'.format(
302 data['repo']['url'], tag_name)
302 data['repo']['url'], tag_name)
303
303
304 commits = _commits_as_dict(
304 commits = _commits_as_dict(
305 self, commit_ids=self.pushed_commit_ids, repos=[self.repo])
305 self, commit_ids=self.pushed_commit_ids, repos=[self.repo])
306
306
307 last_branch = None
307 last_branch = None
308 for commit in reversed(commits):
308 for commit in reversed(commits):
309 commit['branch'] = commit['branch'] or last_branch
309 commit['branch'] = commit['branch'] or last_branch
310 last_branch = commit['branch']
310 last_branch = commit['branch']
311 issues = _issues_as_dict(commits)
311 issues = _issues_as_dict(commits)
312
312
313 branches = set()
313 branches = set()
314 tags = set()
314 tags = set()
315 for commit in commits:
315 for commit in commits:
316 if commit['refs']['tags']:
316 if commit['refs']['tags']:
317 for tag in commit['refs']['tags']:
317 for tag in commit['refs']['tags']:
318 tags.add(tag)
318 tags.add(tag)
319 if commit['branch']:
319 if commit['branch']:
320 branches.add(commit['branch'])
320 branches.add(commit['branch'])
321
321
322 # maybe we have branches in new_refs ?
322 # maybe we have branches in new_refs ?
323 try:
323 try:
324 branches = branches.union(set(self.new_refs['branches']))
324 branches = branches.union(set(self.new_refs['branches']))
325 except Exception:
325 except Exception:
326 pass
326 pass
327
327
328 branches = [
328 branches = [
329 {
329 {
330 'name': branch,
330 'name': branch,
331 'url': branch_url(branch)
331 'url': branch_url(branch)
332 }
332 }
333 for branch in branches
333 for branch in branches
334 ]
334 ]
335
335
336 # maybe we have branches in new_refs ?
336 # maybe we have branches in new_refs ?
337 try:
337 try:
338 tags = tags.union(set(self.new_refs['tags']))
338 tags = tags.union(set(self.new_refs['tags']))
339 except Exception:
339 except Exception:
340 pass
340 pass
341
341
342 tags = [
342 tags = [
343 {
343 {
344 'name': tag,
344 'name': tag,
345 'url': tag_url(tag)
345 'url': tag_url(tag)
346 }
346 }
347 for tag in tags
347 for tag in tags
348 ]
348 ]
349
349
350 data['push'] = {
350 data['push'] = {
351 'commits': commits,
351 'commits': commits,
352 'issues': issues,
352 'issues': issues,
353 'branches': branches,
353 'branches': branches,
354 'tags': tags,
354 'tags': tags,
355 }
355 }
356 return data
356 return data
@@ -1,196 +1,196 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22 import stat
22 import stat
23 import sys
23 import sys
24
24
25 import pytest
25 import pytest
26 from mock import Mock, patch, DEFAULT
26 from mock import Mock, patch, DEFAULT
27
27
28 import rhodecode
28 import rhodecode
29 from rhodecode.model import db, scm
29 from rhodecode.model import db, scm
30 from rhodecode.tests import no_newline_id_generator
30 from rhodecode.tests import no_newline_id_generator
31
31
32
32
33 def test_scm_instance_config(backend):
33 def test_scm_instance_config(backend):
34 repo = backend.create_repo()
34 repo = backend.create_repo()
35 with patch.multiple('rhodecode.model.db.Repository',
35 with patch.multiple('rhodecode.model.db.Repository',
36 _get_instance=DEFAULT,
36 _get_instance=DEFAULT,
37 _get_instance_cached=DEFAULT) as mocks:
37 _get_instance_cached=DEFAULT) as mocks:
38 repo.scm_instance()
38 repo.scm_instance()
39 mocks['_get_instance'].assert_called_with(
39 mocks['_get_instance'].assert_called_with(
40 config=None, cache=False)
40 config=None, cache=False)
41
41
42 config = {'some': 'value'}
42 config = {'some': 'value'}
43 repo.scm_instance(config=config)
43 repo.scm_instance(config=config)
44 mocks['_get_instance'].assert_called_with(
44 mocks['_get_instance'].assert_called_with(
45 config=config, cache=False)
45 config=config, cache=False)
46
46
47 with patch.dict(rhodecode.CONFIG, {'vcs_full_cache': 'true'}):
47 with patch.dict(rhodecode.CONFIG, {'vcs_full_cache': 'true'}):
48 repo.scm_instance(config=config)
48 repo.scm_instance(config=config)
49 mocks['_get_instance_cached'].assert_called()
49 mocks['_get_instance_cached'].assert_called()
50
50
51
51
52 def test__get_instance_config(backend):
52 def test__get_instance_config(backend):
53 repo = backend.create_repo()
53 repo = backend.create_repo()
54 vcs_class = Mock()
54 vcs_class = Mock()
55 with patch.multiple('rhodecode.lib.vcs.backends',
55 with patch.multiple('rhodecode.lib.vcs.backends',
56 get_scm=DEFAULT,
56 get_scm=DEFAULT,
57 get_backend=DEFAULT) as mocks:
57 get_backend=DEFAULT) as mocks:
58 mocks['get_scm'].return_value = backend.alias
58 mocks['get_scm'].return_value = backend.alias
59 mocks['get_backend'].return_value = vcs_class
59 mocks['get_backend'].return_value = vcs_class
60 with patch('rhodecode.model.db.Repository._config') as config_mock:
60 with patch('rhodecode.model.db.Repository._config') as config_mock:
61 repo._get_instance()
61 repo._get_instance()
62 vcs_class.assert_called_with(
62 vcs_class.assert_called_with(
63 repo_path=repo.repo_full_path, config=config_mock,
63 repo_path=repo.repo_full_path, config=config_mock,
64 create=False, with_wire={'cache': True})
64 create=False, with_wire={'cache': True})
65
65
66 new_config = {'override': 'old_config'}
66 new_config = {'override': 'old_config'}
67 repo._get_instance(config=new_config)
67 repo._get_instance(config=new_config)
68 vcs_class.assert_called_with(
68 vcs_class.assert_called_with(
69 repo_path=repo.repo_full_path, config=new_config, create=False,
69 repo_path=repo.repo_full_path, config=new_config, create=False,
70 with_wire={'cache': True})
70 with_wire={'cache': True})
71
71
72
72
73 def test_mark_for_invalidation_config(backend):
73 def test_mark_for_invalidation_config(backend):
74 repo = backend.create_repo()
74 repo = backend.create_repo()
75 with patch('rhodecode.model.db.Repository.update_commit_cache') as _mock:
75 with patch('rhodecode.model.db.Repository.update_commit_cache') as _mock:
76 scm.ScmModel().mark_for_invalidation(repo.repo_name)
76 scm.ScmModel().mark_for_invalidation(repo.repo_name)
77 _, kwargs = _mock.call_args
77 _, kwargs = _mock.call_args
78 assert kwargs['config'].__dict__ == repo._config.__dict__
78 assert kwargs['config'].__dict__ == repo._config.__dict__
79
79
80
80
81 def test_mark_for_invalidation_with_delete_updates_last_commit(backend):
81 def test_mark_for_invalidation_with_delete_updates_last_commit(backend):
82 commits = [{'message': 'A'}, {'message': 'B'}]
82 commits = [{'message': 'A'}, {'message': 'B'}]
83 repo = backend.create_repo(commits=commits)
83 repo = backend.create_repo(commits=commits)
84 scm.ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
84 scm.ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
85 assert repo.changeset_cache['revision'] == 1
85 assert repo.changeset_cache['revision'] == 1
86
86
87
87
88 def test_mark_for_invalidation_with_delete_updates_last_commit_empty(backend):
88 def test_mark_for_invalidation_with_delete_updates_last_commit_empty(backend):
89 repo = backend.create_repo()
89 repo = backend.create_repo()
90 scm.ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
90 scm.ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
91 assert repo.changeset_cache['revision'] == -1
91 assert repo.changeset_cache['revision'] == -1
92
92
93
93
94 def test_strip_with_multiple_heads(backend_hg):
94 def test_strip_with_multiple_heads(backend_hg):
95 commits = [
95 commits = [
96 {'message': 'A'},
96 {'message': 'A'},
97 {'message': 'a'},
97 {'message': 'a'},
98 {'message': 'b'},
98 {'message': 'b'},
99 {'message': 'B', 'parents': ['A']},
99 {'message': 'B', 'parents': ['A']},
100 {'message': 'a1'},
100 {'message': 'a1'},
101 ]
101 ]
102 repo = backend_hg.create_repo(commits=commits)
102 repo = backend_hg.create_repo(commits=commits)
103 commit_ids = backend_hg.commit_ids
103 commit_ids = backend_hg.commit_ids
104
104
105 model = scm.ScmModel()
105 model = scm.ScmModel()
106 model.strip(repo, commit_ids['b'], branch=None)
106 model.strip(repo, commit_ids['b'], branch=None)
107
107
108 vcs_repo = repo.scm_instance()
108 vcs_repo = repo.scm_instance()
109 rest_commit_ids = [c.raw_id for c in vcs_repo.get_changesets()]
109 rest_commit_ids = [c.raw_id for c in vcs_repo.get_commits()]
110 assert len(rest_commit_ids) == 4
110 assert len(rest_commit_ids) == 4
111 assert commit_ids['b'] not in rest_commit_ids
111 assert commit_ids['b'] not in rest_commit_ids
112
112
113
113
114 def test_strip_with_single_heads(backend_hg):
114 def test_strip_with_single_heads(backend_hg):
115 commits = [
115 commits = [
116 {'message': 'A'},
116 {'message': 'A'},
117 {'message': 'a'},
117 {'message': 'a'},
118 {'message': 'b'},
118 {'message': 'b'},
119 ]
119 ]
120 repo = backend_hg.create_repo(commits=commits)
120 repo = backend_hg.create_repo(commits=commits)
121 commit_ids = backend_hg.commit_ids
121 commit_ids = backend_hg.commit_ids
122
122
123 model = scm.ScmModel()
123 model = scm.ScmModel()
124 model.strip(repo, commit_ids['b'], branch=None)
124 model.strip(repo, commit_ids['b'], branch=None)
125
125
126 vcs_repo = repo.scm_instance()
126 vcs_repo = repo.scm_instance()
127 rest_commit_ids = [c.raw_id for c in vcs_repo.get_changesets()]
127 rest_commit_ids = [c.raw_id for c in vcs_repo.get_commits()]
128 assert len(rest_commit_ids) == 2
128 assert len(rest_commit_ids) == 2
129 assert commit_ids['b'] not in rest_commit_ids
129 assert commit_ids['b'] not in rest_commit_ids
130
130
131
131
132 def test_get_nodes_returns_unicode_flat(backend_random):
132 def test_get_nodes_returns_unicode_flat(backend_random):
133 repo = backend_random.repo
133 repo = backend_random.repo
134 directories, files = scm.ScmModel().get_nodes(
134 directories, files = scm.ScmModel().get_nodes(
135 repo.repo_name, repo.get_commit(commit_idx=0).raw_id,
135 repo.repo_name, repo.get_commit(commit_idx=0).raw_id,
136 flat=True)
136 flat=True)
137 assert_contains_only_unicode(directories)
137 assert_contains_only_unicode(directories)
138 assert_contains_only_unicode(files)
138 assert_contains_only_unicode(files)
139
139
140
140
141 def test_get_nodes_returns_unicode_non_flat(backend_random):
141 def test_get_nodes_returns_unicode_non_flat(backend_random):
142 repo = backend_random.repo
142 repo = backend_random.repo
143 directories, files = scm.ScmModel().get_nodes(
143 directories, files = scm.ScmModel().get_nodes(
144 repo.repo_name, repo.get_commit(commit_idx=0).raw_id,
144 repo.repo_name, repo.get_commit(commit_idx=0).raw_id,
145 flat=False)
145 flat=False)
146 # johbo: Checking only the names for now, since that is the critical
146 # johbo: Checking only the names for now, since that is the critical
147 # part.
147 # part.
148 assert_contains_only_unicode([d['name'] for d in directories])
148 assert_contains_only_unicode([d['name'] for d in directories])
149 assert_contains_only_unicode([f['name'] for f in files])
149 assert_contains_only_unicode([f['name'] for f in files])
150
150
151
151
152 def test_get_nodes_max_file_bytes(backend_random):
152 def test_get_nodes_max_file_bytes(backend_random):
153 repo = backend_random.repo
153 repo = backend_random.repo
154 max_file_bytes = 10
154 max_file_bytes = 10
155 directories, files = scm.ScmModel().get_nodes(
155 directories, files = scm.ScmModel().get_nodes(
156 repo.repo_name, repo.get_commit(commit_idx=0).raw_id, content=True,
156 repo.repo_name, repo.get_commit(commit_idx=0).raw_id, content=True,
157 extended_info=True, flat=False)
157 extended_info=True, flat=False)
158 assert any(file['content'] and len(file['content']) > max_file_bytes
158 assert any(file['content'] and len(file['content']) > max_file_bytes
159 for file in files)
159 for file in files)
160
160
161 directories, files = scm.ScmModel().get_nodes(
161 directories, files = scm.ScmModel().get_nodes(
162 repo.repo_name, repo.get_commit(commit_idx=0).raw_id, content=True,
162 repo.repo_name, repo.get_commit(commit_idx=0).raw_id, content=True,
163 extended_info=True, flat=False, max_file_bytes=max_file_bytes)
163 extended_info=True, flat=False, max_file_bytes=max_file_bytes)
164 assert all(
164 assert all(
165 file['content'] is None if file['size'] > max_file_bytes else True
165 file['content'] is None if file['size'] > max_file_bytes else True
166 for file in files)
166 for file in files)
167
167
168
168
169 def assert_contains_only_unicode(structure):
169 def assert_contains_only_unicode(structure):
170 assert structure
170 assert structure
171 for value in structure:
171 for value in structure:
172 assert isinstance(value, unicode)
172 assert isinstance(value, unicode)
173
173
174
174
175 @pytest.mark.backends("hg", "git")
175 @pytest.mark.backends("hg", "git")
176 def test_get_non_unicode_reference(backend):
176 def test_get_non_unicode_reference(backend):
177 model = scm.ScmModel()
177 model = scm.ScmModel()
178 non_unicode_list = ["Adını".decode("cp1254")]
178 non_unicode_list = ["Adını".decode("cp1254")]
179
179
180 def scm_instance():
180 def scm_instance():
181 return Mock(
181 return Mock(
182 branches=non_unicode_list, bookmarks=non_unicode_list,
182 branches=non_unicode_list, bookmarks=non_unicode_list,
183 tags=non_unicode_list, alias=backend.alias)
183 tags=non_unicode_list, alias=backend.alias)
184
184
185 repo = Mock(__class__=db.Repository, scm_instance=scm_instance)
185 repo = Mock(__class__=db.Repository, scm_instance=scm_instance)
186 choices, __ = model.get_repo_landing_revs(translator=lambda s: s, repo=repo)
186 choices, __ = model.get_repo_landing_revs(translator=lambda s: s, repo=repo)
187 if backend.alias == 'hg':
187 if backend.alias == 'hg':
188 valid_choices = [
188 valid_choices = [
189 'rev:tip', u'branch:Ad\xc4\xb1n\xc4\xb1',
189 'rev:tip', u'branch:Ad\xc4\xb1n\xc4\xb1',
190 u'book:Ad\xc4\xb1n\xc4\xb1', u'tag:Ad\xc4\xb1n\xc4\xb1']
190 u'book:Ad\xc4\xb1n\xc4\xb1', u'tag:Ad\xc4\xb1n\xc4\xb1']
191 else:
191 else:
192 valid_choices = [
192 valid_choices = [
193 'rev:tip', u'branch:Ad\xc4\xb1n\xc4\xb1',
193 'rev:tip', u'branch:Ad\xc4\xb1n\xc4\xb1',
194 u'tag:Ad\xc4\xb1n\xc4\xb1']
194 u'tag:Ad\xc4\xb1n\xc4\xb1']
195
195
196 assert choices == valid_choices
196 assert choices == valid_choices
General Comments 0
You need to be logged in to leave comments. Login now