##// END OF EJS Templates
compare: move get_changesets to compare controller where it is used - 2nd half that was lost in 6c79bfcd3b54...
Mads Kiilerich -
r3754:8beaaea7 beta
parent child Browse files
Show More
@@ -1,256 +1,158 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
29
28
30 from pylons.i18n.translation import _
29 from pylons.i18n.translation import _
31
30
32 from rhodecode.model.meta import Session
31 from rhodecode.model.meta import Session
33 from rhodecode.lib import helpers as h, unionrepo
32 from rhodecode.lib import helpers as h
34 from rhodecode.model import BaseModel
33 from rhodecode.model import BaseModel
35 from rhodecode.model.db import PullRequest, PullRequestReviewers, Notification,\
34 from rhodecode.model.db import PullRequest, PullRequestReviewers, Notification,\
36 ChangesetStatus
35 ChangesetStatus
37 from rhodecode.model.notification import NotificationModel
36 from rhodecode.model.notification import NotificationModel
38 from rhodecode.lib.utils2 import safe_unicode
37 from rhodecode.lib.utils2 import safe_unicode
39
38
40 from rhodecode.lib.vcs.utils.hgcompat import scmutil
41 from rhodecode.lib.vcs.utils import safe_str
42
39
43 log = logging.getLogger(__name__)
40 log = logging.getLogger(__name__)
44
41
45
42
46 class PullRequestModel(BaseModel):
43 class PullRequestModel(BaseModel):
47
44
48 cls = PullRequest
45 cls = PullRequest
49
46
50 def __get_pull_request(self, pull_request):
47 def __get_pull_request(self, pull_request):
51 return self._get_instance(PullRequest, pull_request)
48 return self._get_instance(PullRequest, pull_request)
52
49
53 def get_all(self, repo):
50 def get_all(self, repo):
54 repo = self._get_repo(repo)
51 repo = self._get_repo(repo)
55 return PullRequest.query()\
52 return PullRequest.query()\
56 .filter(PullRequest.other_repo == repo)\
53 .filter(PullRequest.other_repo == repo)\
57 .order_by(PullRequest.created_on.desc())\
54 .order_by(PullRequest.created_on.desc())\
58 .all()
55 .all()
59
56
60 def create(self, created_by, org_repo, org_ref, other_repo, other_ref,
57 def create(self, created_by, org_repo, org_ref, other_repo, other_ref,
61 revisions, reviewers, title, description=None):
58 revisions, reviewers, title, description=None):
62 from rhodecode.model.changeset_status import ChangesetStatusModel
59 from rhodecode.model.changeset_status import ChangesetStatusModel
63
60
64 created_by_user = self._get_user(created_by)
61 created_by_user = self._get_user(created_by)
65 org_repo = self._get_repo(org_repo)
62 org_repo = self._get_repo(org_repo)
66 other_repo = self._get_repo(other_repo)
63 other_repo = self._get_repo(other_repo)
67
64
68 new = PullRequest()
65 new = PullRequest()
69 new.org_repo = org_repo
66 new.org_repo = org_repo
70 new.org_ref = org_ref
67 new.org_ref = org_ref
71 new.other_repo = other_repo
68 new.other_repo = other_repo
72 new.other_ref = other_ref
69 new.other_ref = other_ref
73 new.revisions = revisions
70 new.revisions = revisions
74 new.title = title
71 new.title = title
75 new.description = description
72 new.description = description
76 new.author = created_by_user
73 new.author = created_by_user
77 Session().add(new)
74 Session().add(new)
78 Session().flush()
75 Session().flush()
79 #members
76 #members
80 for member in set(reviewers):
77 for member in set(reviewers):
81 _usr = self._get_user(member)
78 _usr = self._get_user(member)
82 reviewer = PullRequestReviewers(_usr, new)
79 reviewer = PullRequestReviewers(_usr, new)
83 Session().add(reviewer)
80 Session().add(reviewer)
84
81
85 #reset state to under-review
82 #reset state to under-review
86 ChangesetStatusModel().set_status(
83 ChangesetStatusModel().set_status(
87 repo=org_repo,
84 repo=org_repo,
88 status=ChangesetStatus.STATUS_UNDER_REVIEW,
85 status=ChangesetStatus.STATUS_UNDER_REVIEW,
89 user=created_by_user,
86 user=created_by_user,
90 pull_request=new
87 pull_request=new
91 )
88 )
92 revision_data = [(x.raw_id, x.message)
89 revision_data = [(x.raw_id, x.message)
93 for x in map(org_repo.get_changeset, revisions)]
90 for x in map(org_repo.get_changeset, revisions)]
94 #notification to reviewers
91 #notification to reviewers
95 notif = NotificationModel()
92 notif = NotificationModel()
96
93
97 pr_url = h.url('pullrequest_show', repo_name=other_repo.repo_name,
94 pr_url = h.url('pullrequest_show', repo_name=other_repo.repo_name,
98 pull_request_id=new.pull_request_id,
95 pull_request_id=new.pull_request_id,
99 qualified=True,
96 qualified=True,
100 )
97 )
101 subject = safe_unicode(
98 subject = safe_unicode(
102 h.link_to(
99 h.link_to(
103 _('%(user)s wants you to review pull request #%(pr_id)s: %(pr_title)s') % \
100 _('%(user)s wants you to review pull request #%(pr_id)s: %(pr_title)s') % \
104 {'user': created_by_user.username,
101 {'user': created_by_user.username,
105 'pr_title': new.title,
102 'pr_title': new.title,
106 'pr_id': new.pull_request_id},
103 'pr_id': new.pull_request_id},
107 pr_url
104 pr_url
108 )
105 )
109 )
106 )
110 body = description
107 body = description
111 kwargs = {
108 kwargs = {
112 'pr_title': title,
109 'pr_title': title,
113 'pr_user_created': h.person(created_by_user.email),
110 'pr_user_created': h.person(created_by_user.email),
114 'pr_repo_url': h.url('summary_home', repo_name=other_repo.repo_name,
111 'pr_repo_url': h.url('summary_home', repo_name=other_repo.repo_name,
115 qualified=True,),
112 qualified=True,),
116 'pr_url': pr_url,
113 'pr_url': pr_url,
117 'pr_revisions': revision_data
114 'pr_revisions': revision_data
118 }
115 }
119
116
120 notif.create(created_by=created_by_user, subject=subject, body=body,
117 notif.create(created_by=created_by_user, subject=subject, body=body,
121 recipients=reviewers,
118 recipients=reviewers,
122 type_=Notification.TYPE_PULL_REQUEST, email_kwargs=kwargs)
119 type_=Notification.TYPE_PULL_REQUEST, email_kwargs=kwargs)
123 return new
120 return new
124
121
125 def update_reviewers(self, pull_request, reviewers_ids):
122 def update_reviewers(self, pull_request, reviewers_ids):
126 reviewers_ids = set(reviewers_ids)
123 reviewers_ids = set(reviewers_ids)
127 pull_request = self.__get_pull_request(pull_request)
124 pull_request = self.__get_pull_request(pull_request)
128 current_reviewers = PullRequestReviewers.query()\
125 current_reviewers = PullRequestReviewers.query()\
129 .filter(PullRequestReviewers.pull_request==
126 .filter(PullRequestReviewers.pull_request==
130 pull_request)\
127 pull_request)\
131 .all()
128 .all()
132 current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
129 current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
133
130
134 to_add = reviewers_ids.difference(current_reviewers_ids)
131 to_add = reviewers_ids.difference(current_reviewers_ids)
135 to_remove = current_reviewers_ids.difference(reviewers_ids)
132 to_remove = current_reviewers_ids.difference(reviewers_ids)
136
133
137 log.debug("Adding %s reviewers" % to_add)
134 log.debug("Adding %s reviewers" % to_add)
138 log.debug("Removing %s reviewers" % to_remove)
135 log.debug("Removing %s reviewers" % to_remove)
139
136
140 for uid in to_add:
137 for uid in to_add:
141 _usr = self._get_user(uid)
138 _usr = self._get_user(uid)
142 reviewer = PullRequestReviewers(_usr, pull_request)
139 reviewer = PullRequestReviewers(_usr, pull_request)
143 Session().add(reviewer)
140 Session().add(reviewer)
144
141
145 for uid in to_remove:
142 for uid in to_remove:
146 reviewer = PullRequestReviewers.query()\
143 reviewer = PullRequestReviewers.query()\
147 .filter(PullRequestReviewers.user_id==uid,
144 .filter(PullRequestReviewers.user_id==uid,
148 PullRequestReviewers.pull_request==pull_request)\
145 PullRequestReviewers.pull_request==pull_request)\
149 .scalar()
146 .scalar()
150 if reviewer:
147 if reviewer:
151 Session().delete(reviewer)
148 Session().delete(reviewer)
152
149
153 def delete(self, pull_request):
150 def delete(self, pull_request):
154 pull_request = self.__get_pull_request(pull_request)
151 pull_request = self.__get_pull_request(pull_request)
155 Session().delete(pull_request)
152 Session().delete(pull_request)
156
153
157 def close_pull_request(self, pull_request):
154 def close_pull_request(self, pull_request):
158 pull_request = self.__get_pull_request(pull_request)
155 pull_request = self.__get_pull_request(pull_request)
159 pull_request.status = PullRequest.STATUS_CLOSED
156 pull_request.status = PullRequest.STATUS_CLOSED
160 pull_request.updated_on = datetime.datetime.now()
157 pull_request.updated_on = datetime.datetime.now()
161 Session().add(pull_request)
158 Session().add(pull_request)
162
163 def _get_changesets(self, alias, org_repo, org_ref, other_repo, other_ref, merge):
164 """
165 Returns a list of changesets that can be merged from org_repo@org_ref
166 to other_repo@other_ref ... and the ancestor that would be used for merge
167
168 :param org_repo:
169 :param org_ref:
170 :param other_repo:
171 :param other_ref:
172 :param tmp:
173 """
174
175 ancestor = None
176
177 if alias == 'hg':
178 # lookup up the exact node id
179 _revset_predicates = {
180 'branch': 'branch',
181 'book': 'bookmark',
182 'tag': 'tag',
183 'rev': 'id',
184 }
185
186 org_rev_spec = "max(%s('%s'))" % (_revset_predicates[org_ref[0]],
187 safe_str(org_ref[1]))
188 org_revs = scmutil.revrange(org_repo._repo, [org_rev_spec])
189 org_rev = org_repo._repo[org_revs[-1] if org_revs else -1].hex()
190
191 other_rev_spec = "max(%s('%s'))" % (_revset_predicates[other_ref[0]],
192 safe_str(other_ref[1]))
193 other_revs = scmutil.revrange(other_repo._repo, [other_rev_spec])
194 other_rev = other_repo._repo[other_revs[-1] if other_revs else -1].hex()
195
196 #case two independent repos
197 if org_repo != other_repo:
198 hgrepo = unionrepo.unionrepository(other_repo.baseui,
199 other_repo.path,
200 org_repo.path)
201 # all the changesets we are looking for will be in other_repo,
202 # so rev numbers from hgrepo can be used in other_repo
203
204 #no remote compare do it on the same repository
205 else:
206 hgrepo = other_repo._repo
207
208 if merge:
209 revs = ["ancestors(id('%s')) and not ancestors(id('%s')) and not id('%s')" %
210 (other_rev, org_rev, org_rev)]
211
212 ancestors = scmutil.revrange(hgrepo,
213 ["ancestor(id('%s'), id('%s'))" % (org_rev, other_rev)])
214 if ancestors:
215 # pick arbitrary ancestor - but there is usually only one
216 ancestor = hgrepo[ancestors[0]].hex()
217 else:
218 # TODO: have both + and - changesets
219 revs = ["id('%s') :: id('%s') - id('%s')" %
220 (org_rev, other_rev, org_rev)]
221
222 changesets = [other_repo.get_changeset(cs)
223 for cs in scmutil.revrange(hgrepo, revs)]
224
225 elif alias == 'git':
226 assert org_repo == other_repo, (org_repo, other_repo) # no git support for different repos
227 so, se = org_repo.run_git_command(
228 'log --reverse --pretty="format: %%H" -s -p %s..%s' % (org_ref[1],
229 other_ref[1])
230 )
231 changesets = [org_repo.get_changeset(cs)
232 for cs in re.findall(r'[0-9a-fA-F]{40}', so)]
233
234 return changesets, ancestor
235
236 def get_compare_data(self, org_repo, org_ref, other_repo, other_ref, merge):
237 """
238 Returns incoming changesets for mercurial repositories
239
240 :param org_repo:
241 :param org_ref:
242 :param other_repo:
243 :param other_ref:
244 """
245
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')
248
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')
251
252 cs_ranges, ancestor = self._get_changesets(org_repo.scm_instance.alias,
253 org_repo.scm_instance, org_ref,
254 other_repo.scm_instance, other_ref,
255 merge)
256 return cs_ranges, ancestor
General Comments 0
You need to be logged in to leave comments. Login now