##// END OF EJS Templates
pull requeset: move stuff around, preparing for next change...
Mads Kiilerich -
r3301:3c91ec44 beta
parent child Browse files
Show More
@@ -1,260 +1,264
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.pull_request
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 pull request model for RhodeCode
7 7
8 8 :created_on: Jun 6, 2012
9 9 :author: marcink
10 10 :copyright: (C) 2012-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import logging
27 27 import binascii
28 28 import datetime
29 29 import re
30 30
31 31 from pylons.i18n.translation import _
32 32
33 33 from rhodecode.model.meta import Session
34 34 from rhodecode.lib import helpers as h
35 35 from rhodecode.model import BaseModel
36 36 from rhodecode.model.db import PullRequest, PullRequestReviewers, Notification,\
37 37 ChangesetStatus
38 38 from rhodecode.model.notification import NotificationModel
39 39 from rhodecode.lib.utils2 import safe_unicode
40 40
41 41 from rhodecode.lib.vcs.utils.hgcompat import discovery, localrepo, scmutil, \
42 42 findcommonoutgoing
43 from rhodecode.lib.vcs.utils import safe_str
43 44
44 45 log = logging.getLogger(__name__)
45 46
46 47
47 48 class PullRequestModel(BaseModel):
48 49
49 50 cls = PullRequest
50 51
51 52 def __get_pull_request(self, pull_request):
52 53 return self._get_instance(PullRequest, pull_request)
53 54
54 55 def get_all(self, repo):
55 56 repo = self._get_repo(repo)
56 57 return PullRequest.query()\
57 58 .filter(PullRequest.other_repo == repo)\
58 59 .order_by(PullRequest.created_on)\
59 60 .all()
60 61
61 62 def create(self, created_by, org_repo, org_ref, other_repo, other_ref,
62 63 revisions, reviewers, title, description=None):
63 64 from rhodecode.model.changeset_status import ChangesetStatusModel
64 65
65 66 created_by_user = self._get_user(created_by)
66 67 org_repo = self._get_repo(org_repo)
67 68 other_repo = self._get_repo(other_repo)
68 69
69 70 new = PullRequest()
70 71 new.org_repo = org_repo
71 72 new.org_ref = org_ref
72 73 new.other_repo = other_repo
73 74 new.other_ref = other_ref
74 75 new.revisions = revisions
75 76 new.title = title
76 77 new.description = description
77 78 new.author = created_by_user
78 79 self.sa.add(new)
79 80 Session().flush()
80 81 #members
81 82 for member in reviewers:
82 83 _usr = self._get_user(member)
83 84 reviewer = PullRequestReviewers(_usr, new)
84 85 self.sa.add(reviewer)
85 86
86 87 #reset state to under-review
87 88 ChangesetStatusModel().set_status(
88 89 repo=org_repo,
89 90 status=ChangesetStatus.STATUS_UNDER_REVIEW,
90 91 user=created_by_user,
91 92 pull_request=new
92 93 )
93 94
94 95 #notification to reviewers
95 96 notif = NotificationModel()
96 97
97 98 pr_url = h.url('pullrequest_show', repo_name=other_repo.repo_name,
98 99 pull_request_id=new.pull_request_id,
99 100 qualified=True,
100 101 )
101 102 subject = safe_unicode(
102 103 h.link_to(
103 104 _('%(user)s wants you to review pull request #%(pr_id)s: %(pr_title)s') % \
104 105 {'user': created_by_user.username,
105 106 'pr_title': new.title,
106 107 'pr_id': new.pull_request_id},
107 108 pr_url
108 109 )
109 110 )
110 111 body = description
111 112 kwargs = {
112 113 'pr_title': title,
113 114 'pr_user_created': h.person(created_by_user.email),
114 115 'pr_repo_url': h.url('summary_home', repo_name=other_repo.repo_name,
115 116 qualified=True,),
116 117 'pr_url': pr_url,
117 118 'pr_revisions': revisions
118 119 }
119 120 notif.create(created_by=created_by_user, subject=subject, body=body,
120 121 recipients=reviewers,
121 122 type_=Notification.TYPE_PULL_REQUEST, email_kwargs=kwargs)
122 123 return new
123 124
124 125 def update_reviewers(self, pull_request, reviewers_ids):
125 126 reviewers_ids = set(reviewers_ids)
126 127 pull_request = self.__get_pull_request(pull_request)
127 128 current_reviewers = PullRequestReviewers.query()\
128 129 .filter(PullRequestReviewers.pull_request==
129 130 pull_request)\
130 131 .all()
131 132 current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
132 133
133 134 to_add = reviewers_ids.difference(current_reviewers_ids)
134 135 to_remove = current_reviewers_ids.difference(reviewers_ids)
135 136
136 137 log.debug("Adding %s reviewers" % to_add)
137 138 log.debug("Removing %s reviewers" % to_remove)
138 139
139 140 for uid in to_add:
140 141 _usr = self._get_user(uid)
141 142 reviewer = PullRequestReviewers(_usr, pull_request)
142 143 self.sa.add(reviewer)
143 144
144 145 for uid in to_remove:
145 146 reviewer = PullRequestReviewers.query()\
146 147 .filter(PullRequestReviewers.user_id==uid,
147 148 PullRequestReviewers.pull_request==pull_request)\
148 149 .scalar()
149 150 if reviewer:
150 151 self.sa.delete(reviewer)
151 152
152 153 def delete(self, pull_request):
153 154 pull_request = self.__get_pull_request(pull_request)
154 155 Session().delete(pull_request)
155 156
156 157 def close_pull_request(self, pull_request):
157 158 pull_request = self.__get_pull_request(pull_request)
158 159 pull_request.status = PullRequest.STATUS_CLOSED
159 160 pull_request.updated_on = datetime.datetime.now()
160 161 self.sa.add(pull_request)
161 162
162 163 def _get_changesets(self, alias, org_repo, org_ref, other_repo, other_ref):
163 164 """
164 165 Returns a list of changesets that are incoming from org_repo@org_ref
165 166 to other_repo@other_ref
166 167
167 168 :param org_repo:
168 169 :param org_ref:
169 170 :param other_repo:
170 171 :param other_ref:
171 172 :param tmp:
172 173 """
173 174
174 175 changesets = []
175 176
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 org_rev_spec = "%s('%s')" % (_revset_predicates[org_ref[0]],
186 safe_str(org_ref[1]))
187 org_rev = scmutil.revsingle(org_repo._repo,
188 org_rev_spec)
189 other_rev_spec = "%s('%s')" % (_revset_predicates[other_ref[0]],
190 safe_str(other_ref[1]))
191 other_rev = scmutil.revsingle(other_repo._repo, other_rev_spec)
177 192
178 193 #case two independent repos
179 194 if org_repo != other_repo:
180 195 revs = [
181 196 org_repo._repo.lookup(org_ref[1]),
182 org_repo._repo.lookup(other_ref[1]),
197 org_repo._repo.lookup(other_ref[1]), # lookup up in the wrong repo!
183 198 ]
184 199
185 200 obj = findcommonoutgoing(org_repo._repo,
186 201 localrepo.locallegacypeer(other_repo._repo.local()),
187 202 revs,
188 203 force=True)
189 204 revs = obj.missing
190 205
191 206 for cs in map(binascii.hexlify, revs):
192 207 _cs = org_repo.get_changeset(cs)
193 208 changesets.append(_cs)
194 209 # in case we have revisions filter out the ones not in given range
195 210 if org_ref[0] == 'rev' and other_ref[0] == 'rev':
196 211 revs = [x.raw_id for x in changesets]
197 212 start = org_ref[1]
198 213 stop = other_ref[1]
199 214 changesets = changesets[revs.index(start):revs.index(stop) + 1]
200 215
201 216 #no remote compare do it on the same repository
202 217 else:
203 _revset_predicates = {
204 'branch': 'branch',
205 'book': 'bookmark',
206 'tag': 'tag',
207 'rev': 'id',
208 }
209
210 revs = [
211 "ancestors(%s('%s')) and not ancestors(%s('%s'))" % (
212 _revset_predicates[other_ref[0]], other_ref[1],
213 _revset_predicates[org_ref[0]], org_ref[1],
214 )
215 ]
218 revs = ["ancestors(id('%s')) and not ancestors(id('%s'))" %
219 (other_rev, org_rev)]
216 220
217 221 out = scmutil.revrange(org_repo._repo, revs)
218 222 for cs in (out):
219 223 changesets.append(org_repo.get_changeset(cs))
220 224
221 225 elif alias == 'git':
222 226 assert org_repo == other_repo, (org_repo, other_repo) # no git support for different repos
223 227 so, se = org_repo.run_git_command(
224 228 'log --reverse --pretty="format: %%H" -s -p %s..%s' % (org_ref[1],
225 229 other_ref[1])
226 230 )
227 231 ids = re.findall(r'[0-9a-fA-F]{40}', so)
228 232 for cs in (ids):
229 233 changesets.append(org_repo.get_changeset(cs))
230 234
231 235 return changesets
232 236
233 237 def get_compare_data(self, org_repo, org_ref, other_repo, other_ref):
234 238 """
235 Returns incomming changesets for mercurial repositories
239 Returns incoming changesets for mercurial repositories
236 240
237 241 :param org_repo:
238 242 :type org_repo:
239 243 :param org_ref:
240 244 :type org_ref:
241 245 :param other_repo:
242 246 :type other_repo:
243 247 :param other_ref:
244 248 :type other_ref:
245 249 """
246 250
247 251 if len(org_ref) != 2 or not isinstance(org_ref, (list, tuple)):
248 252 raise Exception('org_ref must be a two element list/tuple')
249 253
250 254 if len(other_ref) != 2 or not isinstance(org_ref, (list, tuple)):
251 255 raise Exception('other_ref must be a two element list/tuple')
252 256
253 257 org_repo_scm = org_repo.scm_instance
254 258 other_repo_scm = other_repo.scm_instance
255 259
256 260 alias = org_repo.scm_instance.alias
257 261 cs_ranges = self._get_changesets(alias,
258 262 org_repo_scm, org_ref,
259 263 other_repo_scm, other_ref)
260 264 return cs_ranges
General Comments 0
You need to be logged in to leave comments. Login now