##// END OF EJS Templates
compare: minor refactoring and comments
Mads Kiilerich -
r3443:3ac76dfd beta
parent child Browse files
Show More
@@ -1,192 +1,195 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.compare
3 rhodecode.controllers.compare
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 compare controller for pylons showing differences between two
6 compare controller for pylons showing differences between two
7 repos, branches, bookmarks or tips
7 repos, branches, bookmarks or tips
8
8
9 :created_on: May 6, 2012
9 :created_on: May 6, 2012
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
12 :license: GPLv3, see COPYING for more details.
13 """
13 """
14 # This program is free software: you can redistribute it and/or modify
14 # This program is free software: you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation, either version 3 of the License, or
16 # the Free Software Foundation, either version 3 of the License, or
17 # (at your option) any later version.
17 # (at your option) any later version.
18 #
18 #
19 # This program is distributed in the hope that it will be useful,
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
22 # GNU General Public License for more details.
23 #
23 #
24 # You should have received a copy of the GNU General Public License
24 # You should have received a copy of the GNU General Public License
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 import logging
26 import logging
27 import traceback
27 import traceback
28
28
29 from webob.exc import HTTPNotFound
29 from webob.exc import HTTPNotFound
30 from pylons import request, response, session, tmpl_context as c, url
30 from pylons import request, response, session, tmpl_context as c, url
31 from pylons.controllers.util import abort, redirect
31 from pylons.controllers.util import abort, redirect
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33
33
34 from rhodecode.lib.vcs.exceptions import EmptyRepositoryError, RepositoryError
34 from rhodecode.lib.vcs.exceptions import EmptyRepositoryError, RepositoryError
35 from rhodecode.lib import helpers as h
35 from rhodecode.lib import helpers as h
36 from rhodecode.lib.base import BaseRepoController, render
36 from rhodecode.lib.base import BaseRepoController, render
37 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
37 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
38 from rhodecode.lib import diffs
38 from rhodecode.lib import diffs
39
39
40 from rhodecode.model.db import Repository
40 from rhodecode.model.db import Repository
41 from rhodecode.model.pull_request import PullRequestModel
41 from rhodecode.model.pull_request import PullRequestModel
42 from webob.exc import HTTPBadRequest
42 from webob.exc import HTTPBadRequest
43 from rhodecode.lib.diffs import LimitedDiffContainer
43 from rhodecode.lib.diffs import LimitedDiffContainer
44 from rhodecode.lib.vcs.backends.base import EmptyChangeset
44 from rhodecode.lib.vcs.backends.base import EmptyChangeset
45
45
46 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
47
47
48
48
49 class CompareController(BaseRepoController):
49 class CompareController(BaseRepoController):
50
50
51 @LoginRequired()
51 @LoginRequired()
52 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
52 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
53 'repository.admin')
53 'repository.admin')
54 def __before__(self):
54 def __before__(self):
55 super(CompareController, self).__before__()
55 super(CompareController, self).__before__()
56
56
57 def __get_cs_or_redirect(self, rev, repo, redirect_after=True,
57 def __get_cs_or_redirect(self, rev, repo, redirect_after=True,
58 partial=False):
58 partial=False):
59 """
59 """
60 Safe way to get changeset if error occur it redirects to changeset with
60 Safe way to get changeset if error occur it redirects to changeset with
61 proper message. If partial is set then don't do redirect raise Exception
61 proper message. If partial is set then don't do redirect raise Exception
62 instead
62 instead
63
63
64 :param rev: revision to fetch
64 :param rev: revision to fetch
65 :param repo: repo instance
65 :param repo: repo instance
66 """
66 """
67
67
68 try:
68 try:
69 type_, rev = rev
69 type_, rev = rev
70 return repo.scm_instance.get_changeset(rev)
70 return repo.scm_instance.get_changeset(rev)
71 except EmptyRepositoryError, e:
71 except EmptyRepositoryError, e:
72 if not redirect_after:
72 if not redirect_after:
73 return None
73 return None
74 h.flash(h.literal(_('There are no changesets yet')),
74 h.flash(h.literal(_('There are no changesets yet')),
75 category='warning')
75 category='warning')
76 redirect(url('summary_home', repo_name=repo.repo_name))
76 redirect(url('summary_home', repo_name=repo.repo_name))
77
77
78 except RepositoryError, e:
78 except RepositoryError, e:
79 log.error(traceback.format_exc())
79 log.error(traceback.format_exc())
80 h.flash(str(e), category='warning')
80 h.flash(str(e), category='warning')
81 if not partial:
81 if not partial:
82 redirect(h.url('summary_home', repo_name=repo.repo_name))
82 redirect(h.url('summary_home', repo_name=repo.repo_name))
83 raise HTTPBadRequest()
83 raise HTTPBadRequest()
84
84
85 def index(self, org_ref_type, org_ref, other_ref_type, other_ref):
85 def index(self, org_ref_type, org_ref, other_ref_type, other_ref):
86
86 # org_ref will be evaluated in org_repo
87 org_repo = c.rhodecode_db_repo.repo_name
87 org_repo = c.rhodecode_db_repo.repo_name
88 org_ref = (org_ref_type, org_ref)
88 org_ref = (org_ref_type, org_ref)
89 # other_ref will be evaluated in other_repo
89 other_ref = (other_ref_type, other_ref)
90 other_ref = (other_ref_type, other_ref)
90 other_repo = request.GET.get('other_repo', org_repo)
91 other_repo = request.GET.get('other_repo', org_repo)
91 c.fulldiff = fulldiff = request.GET.get('fulldiff')
92 # fulldiff disables cut_off_limit
93 c.fulldiff = request.GET.get('fulldiff')
94 # only consider this range of changesets
92 rev_start = request.GET.get('rev_start')
95 rev_start = request.GET.get('rev_start')
93 rev_end = request.GET.get('rev_end')
96 rev_end = request.GET.get('rev_end')
94 # partial uses compare_cs.html template directly
97 # partial uses compare_cs.html template directly
95 partial = request.environ.get('HTTP_X_PARTIAL_XHR')
98 partial = request.environ.get('HTTP_X_PARTIAL_XHR')
96 # as_form puts hidden input field with changeset revisions
99 # as_form puts hidden input field with changeset revisions
97 c.as_form = partial and request.GET.get('as_form')
100 c.as_form = partial and request.GET.get('as_form')
98 # swap url for compare_diff page - never partial and never as_form
101 # swap url for compare_diff page - never partial and never as_form
99 c.swap_url = h.url('compare_url',
102 c.swap_url = h.url('compare_url',
100 repo_name=other_repo,
103 repo_name=other_repo,
101 org_ref_type=other_ref[0], org_ref=other_ref[1],
104 org_ref_type=other_ref[0], org_ref=other_ref[1],
102 other_repo=org_repo,
105 other_repo=org_repo,
103 other_ref_type=org_ref[0], other_ref=org_ref[1])
106 other_ref_type=org_ref[0], other_ref=org_ref[1])
104
107
105 org_repo = Repository.get_by_repo_name(org_repo)
108 org_repo = Repository.get_by_repo_name(org_repo)
106 other_repo = Repository.get_by_repo_name(other_repo)
109 other_repo = Repository.get_by_repo_name(other_repo)
107
110
108 self.__get_cs_or_redirect(rev=org_ref, repo=org_repo, partial=partial)
111 self.__get_cs_or_redirect(rev=org_ref, repo=org_repo, partial=partial)
109 self.__get_cs_or_redirect(rev=other_ref, repo=other_repo, partial=partial)
112 self.__get_cs_or_redirect(rev=other_ref, repo=other_repo, partial=partial)
110
113
111 if org_repo is None:
114 if org_repo is None:
112 log.error('Could not find org repo %s' % org_repo)
115 log.error('Could not find org repo %s' % org_repo)
113 raise HTTPNotFound
116 raise HTTPNotFound
114 if other_repo is None:
117 if other_repo is None:
115 log.error('Could not find other repo %s' % other_repo)
118 log.error('Could not find other repo %s' % other_repo)
116 raise HTTPNotFound
119 raise HTTPNotFound
117
120
118 if org_repo != other_repo and h.is_git(org_repo):
121 if org_repo != other_repo and h.is_git(org_repo):
119 log.error('compare of two remote repos not available for GIT REPOS')
122 log.error('compare of two remote repos not available for GIT REPOS')
120 raise HTTPNotFound
123 raise HTTPNotFound
121
124
122 if org_repo.scm_instance.alias != other_repo.scm_instance.alias:
125 if org_repo.scm_instance.alias != other_repo.scm_instance.alias:
123 log.error('compare of two different kind of remote repos not available')
126 log.error('compare of two different kind of remote repos not available')
124 raise HTTPNotFound
127 raise HTTPNotFound
125
128
126 c.org_repo = org_repo
129 c.org_repo = org_repo
127 c.other_repo = other_repo
130 c.other_repo = other_repo
128 c.org_ref = org_ref[1]
131 c.org_ref = org_ref[1]
129 c.other_ref = other_ref[1]
132 c.other_ref = other_ref[1]
130 c.org_ref_type = org_ref[0]
133 c.org_ref_type = org_ref[0]
131 c.other_ref_type = other_ref[0]
134 c.other_ref_type = other_ref[0]
132
135
133 if rev_start and rev_end:
136 if rev_start and rev_end:
134 # swap revs with cherry picked ones, save them for display
137 # swap revs with cherry picked ones, save them for display
135 #org_ref = ('rev', rev_start)
138 #org_ref = ('rev', rev_start)
136 #other_ref = ('rev', rev_end)
139 #other_ref = ('rev', rev_end)
137 c.org_ref = rev_start[:12]
140 c.org_ref = rev_start[:12]
138 c.other_ref = rev_end[:12]
141 c.other_ref = rev_end[:12]
139 # get parent of
142 # get parent of
140 # rev start to include it in the diff
143 # rev start to include it in the diff
141 _cs = other_repo.scm_instance.get_changeset(rev_start)
144 _cs = other_repo.scm_instance.get_changeset(rev_start)
142 rev_start = _cs.parents[0].raw_id if _cs.parents else EmptyChangeset().raw_id
145 rev_start = _cs.parents[0].raw_id if _cs.parents else EmptyChangeset().raw_id
143 org_ref = ('rev', rev_start)
146 org_ref = ('rev', rev_start)
144 other_ref = ('rev', rev_end)
147 other_ref = ('rev', rev_end)
145 #if we cherry pick it's not remote, make the other_repo org_repo
148 #if we cherry pick it's not remote, make the other_repo org_repo
146 org_repo = other_repo
149 org_repo = other_repo
147
150
148 c.cs_ranges, ancestor = PullRequestModel().get_compare_data(
151 c.cs_ranges, ancestor = PullRequestModel().get_compare_data(
149 org_repo, org_ref, other_repo, other_ref)
152 org_repo, org_ref, other_repo, other_ref)
150
153
151 c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
154 c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
152 c.cs_ranges])
155 c.cs_ranges])
153 if partial:
156 if partial:
154 return render('compare/compare_cs.html')
157 return render('compare/compare_cs.html')
155
158
156 if ancestor and org_repo != other_repo:
159 if ancestor and org_repo != other_repo:
157 # case we want a simple diff without incoming changesets,
160 # case we want a simple diff without incoming changesets,
158 # previewing what will be merged.
161 # previewing what will be merged.
159 # Make the diff on the forked repo, with
162 # Make the diff on the forked repo, with
160 # revision that is common ancestor
163 # revision that is common ancestor
161 log.debug('Using ancestor %s as org_ref instead of %s'
164 log.debug('Using ancestor %s as org_ref instead of %s'
162 % (ancestor, org_ref))
165 % (ancestor, org_ref))
163 org_ref = ('rev', ancestor)
166 org_ref = ('rev', ancestor)
164 org_repo = other_repo
167 org_repo = other_repo
165
168
166 diff_limit = self.cut_off_limit if not fulldiff else None
169 diff_limit = self.cut_off_limit if not c.fulldiff else None
167
170
168 _diff = diffs.differ(org_repo, org_ref, other_repo, other_ref)
171 _diff = diffs.differ(org_repo, org_ref, other_repo, other_ref)
169
172
170 diff_processor = diffs.DiffProcessor(_diff or '', format='gitdiff',
173 diff_processor = diffs.DiffProcessor(_diff or '', format='gitdiff',
171 diff_limit=diff_limit)
174 diff_limit=diff_limit)
172 _parsed = diff_processor.prepare()
175 _parsed = diff_processor.prepare()
173
176
174 c.limited_diff = False
177 c.limited_diff = False
175 if isinstance(_parsed, LimitedDiffContainer):
178 if isinstance(_parsed, LimitedDiffContainer):
176 c.limited_diff = True
179 c.limited_diff = True
177
180
178 c.files = []
181 c.files = []
179 c.changes = {}
182 c.changes = {}
180 c.lines_added = 0
183 c.lines_added = 0
181 c.lines_deleted = 0
184 c.lines_deleted = 0
182 for f in _parsed:
185 for f in _parsed:
183 st = f['stats']
186 st = f['stats']
184 if st[0] != 'b':
187 if st[0] != 'b':
185 c.lines_added += st[0]
188 c.lines_added += st[0]
186 c.lines_deleted += st[1]
189 c.lines_deleted += st[1]
187 fid = h.FID('', f['filename'])
190 fid = h.FID('', f['filename'])
188 c.files.append([fid, f['operation'], f['filename'], f['stats']])
191 c.files.append([fid, f['operation'], f['filename'], f['stats']])
189 diff = diff_processor.as_html(enable_comments=False, parsed_lines=[f])
192 diff = diff_processor.as_html(enable_comments=False, parsed_lines=[f])
190 c.changes[fid] = [f['operation'], f['filename'], diff]
193 c.changes[fid] = [f['operation'], f['filename'], diff]
191
194
192 return render('compare/compare_diff.html')
195 return render('compare/compare_diff.html')
@@ -1,259 +1,255 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.pull_request
3 rhodecode.model.pull_request
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 pull request model for RhodeCode
6 pull request model for RhodeCode
7
7
8 :created_on: Jun 6, 2012
8 :created_on: Jun 6, 2012
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2012-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2012-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 import datetime
27 import datetime
28 import re
28 import re
29
29
30 from pylons.i18n.translation import _
30 from pylons.i18n.translation import _
31
31
32 from rhodecode.model.meta import Session
32 from rhodecode.model.meta import Session
33 from rhodecode.lib import helpers as h, unionrepo
33 from rhodecode.lib import helpers as h, unionrepo
34 from rhodecode.model import BaseModel
34 from rhodecode.model import BaseModel
35 from rhodecode.model.db import PullRequest, PullRequestReviewers, Notification,\
35 from rhodecode.model.db import PullRequest, PullRequestReviewers, Notification,\
36 ChangesetStatus
36 ChangesetStatus
37 from rhodecode.model.notification import NotificationModel
37 from rhodecode.model.notification import NotificationModel
38 from rhodecode.lib.utils2 import safe_unicode
38 from rhodecode.lib.utils2 import safe_unicode
39
39
40 from rhodecode.lib.vcs.utils.hgcompat import scmutil
40 from rhodecode.lib.vcs.utils.hgcompat import scmutil
41 from rhodecode.lib.vcs.utils import safe_str
41 from rhodecode.lib.vcs.utils import safe_str
42 from rhodecode.lib.vcs.backends.base import EmptyChangeset
42 from rhodecode.lib.vcs.backends.base import EmptyChangeset
43
43
44 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
45
45
46
46
47 class PullRequestModel(BaseModel):
47 class PullRequestModel(BaseModel):
48
48
49 cls = PullRequest
49 cls = PullRequest
50
50
51 def __get_pull_request(self, pull_request):
51 def __get_pull_request(self, pull_request):
52 return self._get_instance(PullRequest, pull_request)
52 return self._get_instance(PullRequest, pull_request)
53
53
54 def get_all(self, repo):
54 def get_all(self, repo):
55 repo = self._get_repo(repo)
55 repo = self._get_repo(repo)
56 return PullRequest.query()\
56 return PullRequest.query()\
57 .filter(PullRequest.other_repo == repo)\
57 .filter(PullRequest.other_repo == repo)\
58 .order_by(PullRequest.created_on.desc())\
58 .order_by(PullRequest.created_on.desc())\
59 .all()
59 .all()
60
60
61 def create(self, created_by, org_repo, org_ref, other_repo, other_ref,
61 def create(self, created_by, org_repo, org_ref, other_repo, other_ref,
62 revisions, reviewers, title, description=None):
62 revisions, reviewers, title, description=None):
63 from rhodecode.model.changeset_status import ChangesetStatusModel
63 from rhodecode.model.changeset_status import ChangesetStatusModel
64
64
65 created_by_user = self._get_user(created_by)
65 created_by_user = self._get_user(created_by)
66 org_repo = self._get_repo(org_repo)
66 org_repo = self._get_repo(org_repo)
67 other_repo = self._get_repo(other_repo)
67 other_repo = self._get_repo(other_repo)
68
68
69 new = PullRequest()
69 new = PullRequest()
70 new.org_repo = org_repo
70 new.org_repo = org_repo
71 new.org_ref = org_ref
71 new.org_ref = org_ref
72 new.other_repo = other_repo
72 new.other_repo = other_repo
73 new.other_ref = other_ref
73 new.other_ref = other_ref
74 new.revisions = revisions
74 new.revisions = revisions
75 new.title = title
75 new.title = title
76 new.description = description
76 new.description = description
77 new.author = created_by_user
77 new.author = created_by_user
78 Session().add(new)
78 Session().add(new)
79 Session().flush()
79 Session().flush()
80 #members
80 #members
81 for member in set(reviewers):
81 for member in set(reviewers):
82 _usr = self._get_user(member)
82 _usr = self._get_user(member)
83 reviewer = PullRequestReviewers(_usr, new)
83 reviewer = PullRequestReviewers(_usr, new)
84 Session().add(reviewer)
84 Session().add(reviewer)
85
85
86 #reset state to under-review
86 #reset state to under-review
87 ChangesetStatusModel().set_status(
87 ChangesetStatusModel().set_status(
88 repo=org_repo,
88 repo=org_repo,
89 status=ChangesetStatus.STATUS_UNDER_REVIEW,
89 status=ChangesetStatus.STATUS_UNDER_REVIEW,
90 user=created_by_user,
90 user=created_by_user,
91 pull_request=new
91 pull_request=new
92 )
92 )
93 revision_data = [(x.raw_id, x.message)
93 revision_data = [(x.raw_id, x.message)
94 for x in map(org_repo.get_changeset, revisions)]
94 for x in map(org_repo.get_changeset, revisions)]
95 #notification to reviewers
95 #notification to reviewers
96 notif = NotificationModel()
96 notif = NotificationModel()
97
97
98 pr_url = h.url('pullrequest_show', repo_name=other_repo.repo_name,
98 pr_url = h.url('pullrequest_show', repo_name=other_repo.repo_name,
99 pull_request_id=new.pull_request_id,
99 pull_request_id=new.pull_request_id,
100 qualified=True,
100 qualified=True,
101 )
101 )
102 subject = safe_unicode(
102 subject = safe_unicode(
103 h.link_to(
103 h.link_to(
104 _('%(user)s wants you to review pull request #%(pr_id)s: %(pr_title)s') % \
104 _('%(user)s wants you to review pull request #%(pr_id)s: %(pr_title)s') % \
105 {'user': created_by_user.username,
105 {'user': created_by_user.username,
106 'pr_title': new.title,
106 'pr_title': new.title,
107 'pr_id': new.pull_request_id},
107 'pr_id': new.pull_request_id},
108 pr_url
108 pr_url
109 )
109 )
110 )
110 )
111 body = description
111 body = description
112 kwargs = {
112 kwargs = {
113 'pr_title': title,
113 'pr_title': title,
114 'pr_user_created': h.person(created_by_user.email),
114 'pr_user_created': h.person(created_by_user.email),
115 'pr_repo_url': h.url('summary_home', repo_name=other_repo.repo_name,
115 'pr_repo_url': h.url('summary_home', repo_name=other_repo.repo_name,
116 qualified=True,),
116 qualified=True,),
117 'pr_url': pr_url,
117 'pr_url': pr_url,
118 'pr_revisions': revision_data
118 'pr_revisions': revision_data
119 }
119 }
120
120
121 notif.create(created_by=created_by_user, subject=subject, body=body,
121 notif.create(created_by=created_by_user, subject=subject, body=body,
122 recipients=reviewers,
122 recipients=reviewers,
123 type_=Notification.TYPE_PULL_REQUEST, email_kwargs=kwargs)
123 type_=Notification.TYPE_PULL_REQUEST, email_kwargs=kwargs)
124 return new
124 return new
125
125
126 def update_reviewers(self, pull_request, reviewers_ids):
126 def update_reviewers(self, pull_request, reviewers_ids):
127 reviewers_ids = set(reviewers_ids)
127 reviewers_ids = set(reviewers_ids)
128 pull_request = self.__get_pull_request(pull_request)
128 pull_request = self.__get_pull_request(pull_request)
129 current_reviewers = PullRequestReviewers.query()\
129 current_reviewers = PullRequestReviewers.query()\
130 .filter(PullRequestReviewers.pull_request==
130 .filter(PullRequestReviewers.pull_request==
131 pull_request)\
131 pull_request)\
132 .all()
132 .all()
133 current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
133 current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
134
134
135 to_add = reviewers_ids.difference(current_reviewers_ids)
135 to_add = reviewers_ids.difference(current_reviewers_ids)
136 to_remove = current_reviewers_ids.difference(reviewers_ids)
136 to_remove = current_reviewers_ids.difference(reviewers_ids)
137
137
138 log.debug("Adding %s reviewers" % to_add)
138 log.debug("Adding %s reviewers" % to_add)
139 log.debug("Removing %s reviewers" % to_remove)
139 log.debug("Removing %s reviewers" % to_remove)
140
140
141 for uid in to_add:
141 for uid in to_add:
142 _usr = self._get_user(uid)
142 _usr = self._get_user(uid)
143 reviewer = PullRequestReviewers(_usr, pull_request)
143 reviewer = PullRequestReviewers(_usr, pull_request)
144 Session().add(reviewer)
144 Session().add(reviewer)
145
145
146 for uid in to_remove:
146 for uid in to_remove:
147 reviewer = PullRequestReviewers.query()\
147 reviewer = PullRequestReviewers.query()\
148 .filter(PullRequestReviewers.user_id==uid,
148 .filter(PullRequestReviewers.user_id==uid,
149 PullRequestReviewers.pull_request==pull_request)\
149 PullRequestReviewers.pull_request==pull_request)\
150 .scalar()
150 .scalar()
151 if reviewer:
151 if reviewer:
152 Session().delete(reviewer)
152 Session().delete(reviewer)
153
153
154 def delete(self, pull_request):
154 def delete(self, pull_request):
155 pull_request = self.__get_pull_request(pull_request)
155 pull_request = self.__get_pull_request(pull_request)
156 Session().delete(pull_request)
156 Session().delete(pull_request)
157
157
158 def close_pull_request(self, pull_request):
158 def close_pull_request(self, pull_request):
159 pull_request = self.__get_pull_request(pull_request)
159 pull_request = self.__get_pull_request(pull_request)
160 pull_request.status = PullRequest.STATUS_CLOSED
160 pull_request.status = PullRequest.STATUS_CLOSED
161 pull_request.updated_on = datetime.datetime.now()
161 pull_request.updated_on = datetime.datetime.now()
162 Session().add(pull_request)
162 Session().add(pull_request)
163
163
164 def _get_changesets(self, alias, org_repo, org_ref, other_repo, other_ref):
164 def _get_changesets(self, alias, org_repo, org_ref, other_repo, other_ref):
165 """
165 """
166 Returns a list of changesets that can be merged from org_repo@org_ref
166 Returns a list of changesets that can be merged from org_repo@org_ref
167 to other_repo@other_ref ... and the ancestor that would be used for merge
167 to other_repo@other_ref ... and the ancestor that would be used for merge
168
168
169 :param org_repo:
169 :param org_repo:
170 :param org_ref:
170 :param org_ref:
171 :param other_repo:
171 :param other_repo:
172 :param other_ref:
172 :param other_ref:
173 :param tmp:
173 :param tmp:
174 """
174 """
175
175
176 ancestor = None
176 ancestor = None
177
177
178 if alias == 'hg':
178 if alias == 'hg':
179 # lookup up the exact node id
179 # lookup up the exact node id
180 _revset_predicates = {
180 _revset_predicates = {
181 'branch': 'branch',
181 'branch': 'branch',
182 'book': 'bookmark',
182 'book': 'bookmark',
183 'tag': 'tag',
183 'tag': 'tag',
184 'rev': 'id',
184 'rev': 'id',
185 }
185 }
186
186
187 org_rev_spec = "%s('%s')" % (_revset_predicates[org_ref[0]],
187 org_rev_spec = "%s('%s')" % (_revset_predicates[org_ref[0]],
188 safe_str(org_ref[1]))
188 safe_str(org_ref[1]))
189 if org_ref[1] == EmptyChangeset().raw_id:
189 if org_ref[1] == EmptyChangeset().raw_id:
190 org_rev = org_ref[1]
190 org_rev = org_ref[1]
191 else:
191 else:
192 org_rev = org_repo._repo[scmutil.revrange(org_repo._repo,
192 org_rev = org_repo._repo[scmutil.revrange(org_repo._repo,
193 [org_rev_spec])[-1]]
193 [org_rev_spec])[-1]]
194 other_rev_spec = "%s('%s')" % (_revset_predicates[other_ref[0]],
194 other_rev_spec = "%s('%s')" % (_revset_predicates[other_ref[0]],
195 safe_str(other_ref[1]))
195 safe_str(other_ref[1]))
196 if other_ref[1] == EmptyChangeset().raw_id:
196 if other_ref[1] == EmptyChangeset().raw_id:
197 other_rev = other_ref[1]
197 other_rev = other_ref[1]
198 else:
198 else:
199 other_rev = other_repo._repo[scmutil.revrange(other_repo._repo,
199 other_rev = other_repo._repo[scmutil.revrange(other_repo._repo,
200 [other_rev_spec])[-1]]
200 [other_rev_spec])[-1]]
201
201
202 #case two independent repos
202 #case two independent repos
203 if org_repo != other_repo:
203 if org_repo != other_repo:
204 hgrepo = unionrepo.unionrepository(other_repo.baseui,
204 hgrepo = unionrepo.unionrepository(other_repo.baseui,
205 other_repo.path,
205 other_repo.path,
206 org_repo.path)
206 org_repo.path)
207 # all the changesets we are looking for will be in other_repo,
207 # all the changesets we are looking for will be in other_repo,
208 # so rev numbers from hgrepo can be used in other_repo
208 # so rev numbers from hgrepo can be used in other_repo
209
209
210 #no remote compare do it on the same repository
210 #no remote compare do it on the same repository
211 else:
211 else:
212 hgrepo = other_repo._repo
212 hgrepo = other_repo._repo
213
213
214 revs = ["ancestors(id('%s')) and not ancestors(id('%s'))" %
214 revs = ["ancestors(id('%s')) and not ancestors(id('%s'))" %
215 (other_rev, org_rev)]
215 (other_rev, org_rev)]
216 changesets = [other_repo.get_changeset(cs)
216 changesets = [other_repo.get_changeset(cs)
217 for cs in scmutil.revrange(hgrepo, revs)]
217 for cs in scmutil.revrange(hgrepo, revs)]
218
218
219 if org_repo != other_repo:
219 if org_repo != other_repo:
220 ancestors = scmutil.revrange(hgrepo,
220 ancestors = scmutil.revrange(hgrepo,
221 ["ancestor(id('%s'), id('%s'))" % (org_rev, other_rev)])
221 ["ancestor(id('%s'), id('%s'))" % (org_rev, other_rev)])
222 if len(ancestors) == 1:
222 if len(ancestors) == 1:
223 ancestor = hgrepo[ancestors[0]].hex()
223 ancestor = hgrepo[ancestors[0]].hex()
224
224
225 elif alias == 'git':
225 elif alias == 'git':
226 assert org_repo == other_repo, (org_repo, other_repo) # no git support for different repos
226 assert org_repo == other_repo, (org_repo, other_repo) # no git support for different repos
227 so, se = org_repo.run_git_command(
227 so, se = org_repo.run_git_command(
228 'log --reverse --pretty="format: %%H" -s -p %s..%s' % (org_ref[1],
228 'log --reverse --pretty="format: %%H" -s -p %s..%s' % (org_ref[1],
229 other_ref[1])
229 other_ref[1])
230 )
230 )
231 changesets = [org_repo.get_changeset(cs)
231 changesets = [org_repo.get_changeset(cs)
232 for cs in re.findall(r'[0-9a-fA-F]{40}', so)]
232 for cs in re.findall(r'[0-9a-fA-F]{40}', so)]
233
233
234 return changesets, ancestor
234 return changesets, ancestor
235
235
236 def get_compare_data(self, org_repo, org_ref, other_repo, other_ref):
236 def get_compare_data(self, org_repo, org_ref, other_repo, other_ref):
237 """
237 """
238 Returns incoming changesets for mercurial repositories
238 Returns incoming changesets for mercurial repositories
239
239
240 :param org_repo:
240 :param org_repo:
241 :param org_ref:
241 :param org_ref:
242 :param other_repo:
242 :param other_repo:
243 :param other_ref:
243 :param other_ref:
244 """
244 """
245
245
246 if len(org_ref) != 2 or not isinstance(org_ref, (list, tuple)):
246 if len(org_ref) != 2 or not isinstance(org_ref, (list, tuple)):
247 raise Exception('org_ref must be a two element list/tuple')
247 raise Exception('org_ref must be a two element list/tuple')
248
248
249 if len(other_ref) != 2 or not isinstance(org_ref, (list, tuple)):
249 if len(other_ref) != 2 or not isinstance(org_ref, (list, tuple)):
250 raise Exception('other_ref must be a two element list/tuple')
250 raise Exception('other_ref must be a two element list/tuple')
251
251
252 org_repo_scm = org_repo.scm_instance
252 cs_ranges, ancestor = self._get_changesets(org_repo.scm_instance.alias,
253 other_repo_scm = other_repo.scm_instance
253 org_repo.scm_instance, org_ref,
254
254 other_repo.scm_instance, other_ref)
255 alias = org_repo.scm_instance.alias
256 cs_ranges, ancestor = self._get_changesets(alias,
257 org_repo_scm, org_ref,
258 other_repo_scm, other_ref)
259 return cs_ranges, ancestor
255 return cs_ranges, ancestor
General Comments 0
You need to be logged in to leave comments. Login now