##// END OF EJS Templates
pull request: shuffle different-repo and hg-git conditionals around, no code change
Mads Kiilerich -
r3300:2c0208bd beta
parent child Browse files
Show More
@@ -1,255 +1,260 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 binascii
27 import binascii
28 import datetime
28 import datetime
29 import re
29 import re
30
30
31 from pylons.i18n.translation import _
31 from pylons.i18n.translation import _
32
32
33 from rhodecode.model.meta import Session
33 from rhodecode.model.meta import Session
34 from rhodecode.lib import helpers as h
34 from rhodecode.lib import helpers as h
35 from rhodecode.model import BaseModel
35 from rhodecode.model import BaseModel
36 from rhodecode.model.db import PullRequest, PullRequestReviewers, Notification,\
36 from rhodecode.model.db import PullRequest, PullRequestReviewers, Notification,\
37 ChangesetStatus
37 ChangesetStatus
38 from rhodecode.model.notification import NotificationModel
38 from rhodecode.model.notification import NotificationModel
39 from rhodecode.lib.utils2 import safe_unicode
39 from rhodecode.lib.utils2 import safe_unicode
40
40
41 from rhodecode.lib.vcs.utils.hgcompat import discovery, localrepo, scmutil, \
41 from rhodecode.lib.vcs.utils.hgcompat import discovery, localrepo, scmutil, \
42 findcommonoutgoing
42 findcommonoutgoing
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)\
58 .order_by(PullRequest.created_on)\
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 self.sa.add(new)
78 self.sa.add(new)
79 Session().flush()
79 Session().flush()
80 #members
80 #members
81 for member in reviewers:
81 for member in reviewers:
82 _usr = self._get_user(member)
82 _usr = self._get_user(member)
83 reviewer = PullRequestReviewers(_usr, new)
83 reviewer = PullRequestReviewers(_usr, new)
84 self.sa.add(reviewer)
84 self.sa.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
93
94 #notification to reviewers
94 #notification to reviewers
95 notif = NotificationModel()
95 notif = NotificationModel()
96
96
97 pr_url = h.url('pullrequest_show', repo_name=other_repo.repo_name,
97 pr_url = h.url('pullrequest_show', repo_name=other_repo.repo_name,
98 pull_request_id=new.pull_request_id,
98 pull_request_id=new.pull_request_id,
99 qualified=True,
99 qualified=True,
100 )
100 )
101 subject = safe_unicode(
101 subject = safe_unicode(
102 h.link_to(
102 h.link_to(
103 _('%(user)s wants you to review pull request #%(pr_id)s: %(pr_title)s') % \
103 _('%(user)s wants you to review pull request #%(pr_id)s: %(pr_title)s') % \
104 {'user': created_by_user.username,
104 {'user': created_by_user.username,
105 'pr_title': new.title,
105 'pr_title': new.title,
106 'pr_id': new.pull_request_id},
106 'pr_id': new.pull_request_id},
107 pr_url
107 pr_url
108 )
108 )
109 )
109 )
110 body = description
110 body = description
111 kwargs = {
111 kwargs = {
112 'pr_title': title,
112 'pr_title': title,
113 'pr_user_created': h.person(created_by_user.email),
113 'pr_user_created': h.person(created_by_user.email),
114 'pr_repo_url': h.url('summary_home', repo_name=other_repo.repo_name,
114 'pr_repo_url': h.url('summary_home', repo_name=other_repo.repo_name,
115 qualified=True,),
115 qualified=True,),
116 'pr_url': pr_url,
116 'pr_url': pr_url,
117 'pr_revisions': revisions
117 'pr_revisions': revisions
118 }
118 }
119 notif.create(created_by=created_by_user, subject=subject, body=body,
119 notif.create(created_by=created_by_user, subject=subject, body=body,
120 recipients=reviewers,
120 recipients=reviewers,
121 type_=Notification.TYPE_PULL_REQUEST, email_kwargs=kwargs)
121 type_=Notification.TYPE_PULL_REQUEST, email_kwargs=kwargs)
122 return new
122 return new
123
123
124 def update_reviewers(self, pull_request, reviewers_ids):
124 def update_reviewers(self, pull_request, reviewers_ids):
125 reviewers_ids = set(reviewers_ids)
125 reviewers_ids = set(reviewers_ids)
126 pull_request = self.__get_pull_request(pull_request)
126 pull_request = self.__get_pull_request(pull_request)
127 current_reviewers = PullRequestReviewers.query()\
127 current_reviewers = PullRequestReviewers.query()\
128 .filter(PullRequestReviewers.pull_request==
128 .filter(PullRequestReviewers.pull_request==
129 pull_request)\
129 pull_request)\
130 .all()
130 .all()
131 current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
131 current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
132
132
133 to_add = reviewers_ids.difference(current_reviewers_ids)
133 to_add = reviewers_ids.difference(current_reviewers_ids)
134 to_remove = current_reviewers_ids.difference(reviewers_ids)
134 to_remove = current_reviewers_ids.difference(reviewers_ids)
135
135
136 log.debug("Adding %s reviewers" % to_add)
136 log.debug("Adding %s reviewers" % to_add)
137 log.debug("Removing %s reviewers" % to_remove)
137 log.debug("Removing %s reviewers" % to_remove)
138
138
139 for uid in to_add:
139 for uid in to_add:
140 _usr = self._get_user(uid)
140 _usr = self._get_user(uid)
141 reviewer = PullRequestReviewers(_usr, pull_request)
141 reviewer = PullRequestReviewers(_usr, pull_request)
142 self.sa.add(reviewer)
142 self.sa.add(reviewer)
143
143
144 for uid in to_remove:
144 for uid in to_remove:
145 reviewer = PullRequestReviewers.query()\
145 reviewer = PullRequestReviewers.query()\
146 .filter(PullRequestReviewers.user_id==uid,
146 .filter(PullRequestReviewers.user_id==uid,
147 PullRequestReviewers.pull_request==pull_request)\
147 PullRequestReviewers.pull_request==pull_request)\
148 .scalar()
148 .scalar()
149 if reviewer:
149 if reviewer:
150 self.sa.delete(reviewer)
150 self.sa.delete(reviewer)
151
151
152 def delete(self, pull_request):
152 def delete(self, pull_request):
153 pull_request = self.__get_pull_request(pull_request)
153 pull_request = self.__get_pull_request(pull_request)
154 Session().delete(pull_request)
154 Session().delete(pull_request)
155
155
156 def close_pull_request(self, pull_request):
156 def close_pull_request(self, pull_request):
157 pull_request = self.__get_pull_request(pull_request)
157 pull_request = self.__get_pull_request(pull_request)
158 pull_request.status = PullRequest.STATUS_CLOSED
158 pull_request.status = PullRequest.STATUS_CLOSED
159 pull_request.updated_on = datetime.datetime.now()
159 pull_request.updated_on = datetime.datetime.now()
160 self.sa.add(pull_request)
160 self.sa.add(pull_request)
161
161
162 def _get_changesets(self, alias, org_repo, org_ref, other_repo, other_ref):
162 def _get_changesets(self, alias, org_repo, org_ref, other_repo, other_ref):
163 """
163 """
164 Returns a list of changesets that are incoming from org_repo@org_ref
164 Returns a list of changesets that are incoming from org_repo@org_ref
165 to other_repo@other_ref
165 to other_repo@other_ref
166
166
167 :param org_repo:
167 :param org_repo:
168 :param org_ref:
168 :param org_ref:
169 :param other_repo:
169 :param other_repo:
170 :param other_ref:
170 :param other_ref:
171 :param tmp:
171 :param tmp:
172 """
172 """
173
173
174 changesets = []
174 changesets = []
175
176 if alias == 'hg':
177
175 #case two independent repos
178 #case two independent repos
176 if org_repo != other_repo:
179 if org_repo != other_repo:
177 revs = [
180 revs = [
178 org_repo._repo.lookup(org_ref[1]),
181 org_repo._repo.lookup(org_ref[1]),
179 org_repo._repo.lookup(other_ref[1]),
182 org_repo._repo.lookup(other_ref[1]),
180 ]
183 ]
181
184
182 obj = findcommonoutgoing(org_repo._repo,
185 obj = findcommonoutgoing(org_repo._repo,
183 localrepo.locallegacypeer(other_repo._repo.local()),
186 localrepo.locallegacypeer(other_repo._repo.local()),
184 revs,
187 revs,
185 force=True)
188 force=True)
186 revs = obj.missing
189 revs = obj.missing
187
190
188 for cs in map(binascii.hexlify, revs):
191 for cs in map(binascii.hexlify, revs):
189 _cs = org_repo.get_changeset(cs)
192 _cs = org_repo.get_changeset(cs)
190 changesets.append(_cs)
193 changesets.append(_cs)
191 # in case we have revisions filter out the ones not in given range
194 # in case we have revisions filter out the ones not in given range
192 if org_ref[0] == 'rev' and other_ref[0] == 'rev':
195 if org_ref[0] == 'rev' and other_ref[0] == 'rev':
193 revs = [x.raw_id for x in changesets]
196 revs = [x.raw_id for x in changesets]
194 start = org_ref[1]
197 start = org_ref[1]
195 stop = other_ref[1]
198 stop = other_ref[1]
196 changesets = changesets[revs.index(start):revs.index(stop) + 1]
199 changesets = changesets[revs.index(start):revs.index(stop) + 1]
197 else:
200
198 #no remote compare do it on the same repository
201 #no remote compare do it on the same repository
199 if alias == 'hg':
202 else:
200 _revset_predicates = {
203 _revset_predicates = {
201 'branch': 'branch',
204 'branch': 'branch',
202 'book': 'bookmark',
205 'book': 'bookmark',
203 'tag': 'tag',
206 'tag': 'tag',
204 'rev': 'id',
207 'rev': 'id',
205 }
208 }
206
209
207 revs = [
210 revs = [
208 "ancestors(%s('%s')) and not ancestors(%s('%s'))" % (
211 "ancestors(%s('%s')) and not ancestors(%s('%s'))" % (
209 _revset_predicates[other_ref[0]], other_ref[1],
212 _revset_predicates[other_ref[0]], other_ref[1],
210 _revset_predicates[org_ref[0]], org_ref[1],
213 _revset_predicates[org_ref[0]], org_ref[1],
211 )
214 )
212 ]
215 ]
213
216
214 out = scmutil.revrange(org_repo._repo, revs)
217 out = scmutil.revrange(org_repo._repo, revs)
215 for cs in (out):
218 for cs in (out):
216 changesets.append(org_repo.get_changeset(cs))
219 changesets.append(org_repo.get_changeset(cs))
220
217 elif alias == 'git':
221 elif alias == 'git':
222 assert org_repo == other_repo, (org_repo, other_repo) # no git support for different repos
218 so, se = org_repo.run_git_command(
223 so, se = org_repo.run_git_command(
219 'log --reverse --pretty="format: %%H" -s -p %s..%s' % (org_ref[1],
224 'log --reverse --pretty="format: %%H" -s -p %s..%s' % (org_ref[1],
220 other_ref[1])
225 other_ref[1])
221 )
226 )
222 ids = re.findall(r'[0-9a-fA-F]{40}', so)
227 ids = re.findall(r'[0-9a-fA-F]{40}', so)
223 for cs in (ids):
228 for cs in (ids):
224 changesets.append(org_repo.get_changeset(cs))
229 changesets.append(org_repo.get_changeset(cs))
225
230
226 return changesets
231 return changesets
227
232
228 def get_compare_data(self, org_repo, org_ref, other_repo, other_ref):
233 def get_compare_data(self, org_repo, org_ref, other_repo, other_ref):
229 """
234 """
230 Returns incomming changesets for mercurial repositories
235 Returns incomming changesets for mercurial repositories
231
236
232 :param org_repo:
237 :param org_repo:
233 :type org_repo:
238 :type org_repo:
234 :param org_ref:
239 :param org_ref:
235 :type org_ref:
240 :type org_ref:
236 :param other_repo:
241 :param other_repo:
237 :type other_repo:
242 :type other_repo:
238 :param other_ref:
243 :param other_ref:
239 :type other_ref:
244 :type other_ref:
240 """
245 """
241
246
242 if len(org_ref) != 2 or not isinstance(org_ref, (list, tuple)):
247 if len(org_ref) != 2 or not isinstance(org_ref, (list, tuple)):
243 raise Exception('org_ref must be a two element list/tuple')
248 raise Exception('org_ref must be a two element list/tuple')
244
249
245 if len(other_ref) != 2 or not isinstance(org_ref, (list, tuple)):
250 if len(other_ref) != 2 or not isinstance(org_ref, (list, tuple)):
246 raise Exception('other_ref must be a two element list/tuple')
251 raise Exception('other_ref must be a two element list/tuple')
247
252
248 org_repo_scm = org_repo.scm_instance
253 org_repo_scm = org_repo.scm_instance
249 other_repo_scm = other_repo.scm_instance
254 other_repo_scm = other_repo.scm_instance
250
255
251 alias = org_repo.scm_instance.alias
256 alias = org_repo.scm_instance.alias
252 cs_ranges = self._get_changesets(alias,
257 cs_ranges = self._get_changesets(alias,
253 org_repo_scm, org_ref,
258 org_repo_scm, org_ref,
254 other_repo_scm, other_ref)
259 other_repo_scm, other_ref)
255 return cs_ranges
260 return cs_ranges
General Comments 0
You need to be logged in to leave comments. Login now