##// END OF EJS Templates
fix order of pull-requests in show all page
marcink -
r3262:14e9a06c beta
parent child Browse files
Show More
@@ -1,252 +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 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().filter(PullRequest.other_repo == repo).all()
56 return PullRequest.query()\
57 .filter(PullRequest.other_repo == repo)\
58 .order_by(PullRequest.created_on)\
59 .all()
57
60
58 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,
59 revisions, reviewers, title, description=None):
62 revisions, reviewers, title, description=None):
60 from rhodecode.model.changeset_status import ChangesetStatusModel
63 from rhodecode.model.changeset_status import ChangesetStatusModel
61
64
62 created_by_user = self._get_user(created_by)
65 created_by_user = self._get_user(created_by)
63 org_repo = self._get_repo(org_repo)
66 org_repo = self._get_repo(org_repo)
64 other_repo = self._get_repo(other_repo)
67 other_repo = self._get_repo(other_repo)
65
68
66 new = PullRequest()
69 new = PullRequest()
67 new.org_repo = org_repo
70 new.org_repo = org_repo
68 new.org_ref = org_ref
71 new.org_ref = org_ref
69 new.other_repo = other_repo
72 new.other_repo = other_repo
70 new.other_ref = other_ref
73 new.other_ref = other_ref
71 new.revisions = revisions
74 new.revisions = revisions
72 new.title = title
75 new.title = title
73 new.description = description
76 new.description = description
74 new.author = created_by_user
77 new.author = created_by_user
75 self.sa.add(new)
78 self.sa.add(new)
76 Session().flush()
79 Session().flush()
77 #members
80 #members
78 for member in reviewers:
81 for member in reviewers:
79 _usr = self._get_user(member)
82 _usr = self._get_user(member)
80 reviewer = PullRequestReviewers(_usr, new)
83 reviewer = PullRequestReviewers(_usr, new)
81 self.sa.add(reviewer)
84 self.sa.add(reviewer)
82
85
83 #reset state to under-review
86 #reset state to under-review
84 ChangesetStatusModel().set_status(
87 ChangesetStatusModel().set_status(
85 repo=org_repo,
88 repo=org_repo,
86 status=ChangesetStatus.STATUS_UNDER_REVIEW,
89 status=ChangesetStatus.STATUS_UNDER_REVIEW,
87 user=created_by_user,
90 user=created_by_user,
88 pull_request=new
91 pull_request=new
89 )
92 )
90
93
91 #notification to reviewers
94 #notification to reviewers
92 notif = NotificationModel()
95 notif = NotificationModel()
93
96
94 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,
95 pull_request_id=new.pull_request_id,
98 pull_request_id=new.pull_request_id,
96 qualified=True,
99 qualified=True,
97 )
100 )
98 subject = safe_unicode(
101 subject = safe_unicode(
99 h.link_to(
102 h.link_to(
100 _('%(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') % \
101 {'user': created_by_user.username,
104 {'user': created_by_user.username,
102 'pr_title': new.title,
105 'pr_title': new.title,
103 'pr_id': new.pull_request_id},
106 'pr_id': new.pull_request_id},
104 pr_url
107 pr_url
105 )
108 )
106 )
109 )
107 body = description
110 body = description
108 kwargs = {
111 kwargs = {
109 'pr_title': title,
112 'pr_title': title,
110 'pr_user_created': h.person(created_by_user.email),
113 'pr_user_created': h.person(created_by_user.email),
111 '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,
112 qualified=True,),
115 qualified=True,),
113 'pr_url': pr_url,
116 'pr_url': pr_url,
114 'pr_revisions': revisions
117 'pr_revisions': revisions
115 }
118 }
116 notif.create(created_by=created_by_user, subject=subject, body=body,
119 notif.create(created_by=created_by_user, subject=subject, body=body,
117 recipients=reviewers,
120 recipients=reviewers,
118 type_=Notification.TYPE_PULL_REQUEST, email_kwargs=kwargs)
121 type_=Notification.TYPE_PULL_REQUEST, email_kwargs=kwargs)
119 return new
122 return new
120
123
121 def update_reviewers(self, pull_request, reviewers_ids):
124 def update_reviewers(self, pull_request, reviewers_ids):
122 reviewers_ids = set(reviewers_ids)
125 reviewers_ids = set(reviewers_ids)
123 pull_request = self.__get_pull_request(pull_request)
126 pull_request = self.__get_pull_request(pull_request)
124 current_reviewers = PullRequestReviewers.query()\
127 current_reviewers = PullRequestReviewers.query()\
125 .filter(PullRequestReviewers.pull_request==
128 .filter(PullRequestReviewers.pull_request==
126 pull_request)\
129 pull_request)\
127 .all()
130 .all()
128 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])
129
132
130 to_add = reviewers_ids.difference(current_reviewers_ids)
133 to_add = reviewers_ids.difference(current_reviewers_ids)
131 to_remove = current_reviewers_ids.difference(reviewers_ids)
134 to_remove = current_reviewers_ids.difference(reviewers_ids)
132
135
133 log.debug("Adding %s reviewers" % to_add)
136 log.debug("Adding %s reviewers" % to_add)
134 log.debug("Removing %s reviewers" % to_remove)
137 log.debug("Removing %s reviewers" % to_remove)
135
138
136 for uid in to_add:
139 for uid in to_add:
137 _usr = self._get_user(uid)
140 _usr = self._get_user(uid)
138 reviewer = PullRequestReviewers(_usr, pull_request)
141 reviewer = PullRequestReviewers(_usr, pull_request)
139 self.sa.add(reviewer)
142 self.sa.add(reviewer)
140
143
141 for uid in to_remove:
144 for uid in to_remove:
142 reviewer = PullRequestReviewers.query()\
145 reviewer = PullRequestReviewers.query()\
143 .filter(PullRequestReviewers.user_id==uid,
146 .filter(PullRequestReviewers.user_id==uid,
144 PullRequestReviewers.pull_request==pull_request)\
147 PullRequestReviewers.pull_request==pull_request)\
145 .scalar()
148 .scalar()
146 if reviewer:
149 if reviewer:
147 self.sa.delete(reviewer)
150 self.sa.delete(reviewer)
148
151
149 def delete(self, pull_request):
152 def delete(self, pull_request):
150 pull_request = self.__get_pull_request(pull_request)
153 pull_request = self.__get_pull_request(pull_request)
151 Session().delete(pull_request)
154 Session().delete(pull_request)
152
155
153 def close_pull_request(self, pull_request):
156 def close_pull_request(self, pull_request):
154 pull_request = self.__get_pull_request(pull_request)
157 pull_request = self.__get_pull_request(pull_request)
155 pull_request.status = PullRequest.STATUS_CLOSED
158 pull_request.status = PullRequest.STATUS_CLOSED
156 pull_request.updated_on = datetime.datetime.now()
159 pull_request.updated_on = datetime.datetime.now()
157 self.sa.add(pull_request)
160 self.sa.add(pull_request)
158
161
159 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):
160 """
163 """
161 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
162 to other_repo@other_ref
165 to other_repo@other_ref
163
166
164 :param org_repo:
167 :param org_repo:
165 :param org_ref:
168 :param org_ref:
166 :param other_repo:
169 :param other_repo:
167 :param other_ref:
170 :param other_ref:
168 :param tmp:
171 :param tmp:
169 """
172 """
170
173
171 changesets = []
174 changesets = []
172 #case two independent repos
175 #case two independent repos
173 if org_repo != other_repo:
176 if org_repo != other_repo:
174 revs = [
177 revs = [
175 org_repo._repo.lookup(org_ref[1]),
178 org_repo._repo.lookup(org_ref[1]),
176 org_repo._repo.lookup(other_ref[1]),
179 org_repo._repo.lookup(other_ref[1]),
177 ]
180 ]
178
181
179 obj = findcommonoutgoing(org_repo._repo,
182 obj = findcommonoutgoing(org_repo._repo,
180 localrepo.locallegacypeer(other_repo._repo.local()),
183 localrepo.locallegacypeer(other_repo._repo.local()),
181 revs,
184 revs,
182 force=True)
185 force=True)
183 revs = obj.missing
186 revs = obj.missing
184
187
185 for cs in map(binascii.hexlify, revs):
188 for cs in map(binascii.hexlify, revs):
186 _cs = org_repo.get_changeset(cs)
189 _cs = org_repo.get_changeset(cs)
187 changesets.append(_cs)
190 changesets.append(_cs)
188 # in case we have revisions filter out the ones not in given range
191 # in case we have revisions filter out the ones not in given range
189 if org_ref[0] == 'rev' and other_ref[0] == 'rev':
192 if org_ref[0] == 'rev' and other_ref[0] == 'rev':
190 revs = [x.raw_id for x in changesets]
193 revs = [x.raw_id for x in changesets]
191 start = org_ref[1]
194 start = org_ref[1]
192 stop = other_ref[1]
195 stop = other_ref[1]
193 changesets = changesets[revs.index(start):revs.index(stop) + 1]
196 changesets = changesets[revs.index(start):revs.index(stop) + 1]
194 else:
197 else:
195 #no remote compare do it on the same repository
198 #no remote compare do it on the same repository
196 if alias == 'hg':
199 if alias == 'hg':
197 _revset_predicates = {
200 _revset_predicates = {
198 'branch': 'branch',
201 'branch': 'branch',
199 'book': 'bookmark',
202 'book': 'bookmark',
200 'tag': 'tag',
203 'tag': 'tag',
201 'rev': 'id',
204 'rev': 'id',
202 }
205 }
203
206
204 revs = [
207 revs = [
205 "ancestors(%s('%s')) and not ancestors(%s('%s'))" % (
208 "ancestors(%s('%s')) and not ancestors(%s('%s'))" % (
206 _revset_predicates[other_ref[0]], other_ref[1],
209 _revset_predicates[other_ref[0]], other_ref[1],
207 _revset_predicates[org_ref[0]], org_ref[1],
210 _revset_predicates[org_ref[0]], org_ref[1],
208 )
211 )
209 ]
212 ]
210
213
211 out = scmutil.revrange(org_repo._repo, revs)
214 out = scmutil.revrange(org_repo._repo, revs)
212 for cs in (out):
215 for cs in (out):
213 changesets.append(org_repo.get_changeset(cs))
216 changesets.append(org_repo.get_changeset(cs))
214 elif alias == 'git':
217 elif alias == 'git':
215 so, se = org_repo.run_git_command(
218 so, se = org_repo.run_git_command(
216 'log --reverse --pretty="format: %%H" -s -p %s..%s' % (org_ref[1],
219 'log --reverse --pretty="format: %%H" -s -p %s..%s' % (org_ref[1],
217 other_ref[1])
220 other_ref[1])
218 )
221 )
219 ids = re.findall(r'[0-9a-fA-F]{40}', so)
222 ids = re.findall(r'[0-9a-fA-F]{40}', so)
220 for cs in (ids):
223 for cs in (ids):
221 changesets.append(org_repo.get_changeset(cs))
224 changesets.append(org_repo.get_changeset(cs))
222
225
223 return changesets
226 return changesets
224
227
225 def get_compare_data(self, org_repo, org_ref, other_repo, other_ref):
228 def get_compare_data(self, org_repo, org_ref, other_repo, other_ref):
226 """
229 """
227 Returns incomming changesets for mercurial repositories
230 Returns incomming changesets for mercurial repositories
228
231
229 :param org_repo:
232 :param org_repo:
230 :type org_repo:
233 :type org_repo:
231 :param org_ref:
234 :param org_ref:
232 :type org_ref:
235 :type org_ref:
233 :param other_repo:
236 :param other_repo:
234 :type other_repo:
237 :type other_repo:
235 :param other_ref:
238 :param other_ref:
236 :type other_ref:
239 :type other_ref:
237 """
240 """
238
241
239 if len(org_ref) != 2 or not isinstance(org_ref, (list, tuple)):
242 if len(org_ref) != 2 or not isinstance(org_ref, (list, tuple)):
240 raise Exception('org_ref must be a two element list/tuple')
243 raise Exception('org_ref must be a two element list/tuple')
241
244
242 if len(other_ref) != 2 or not isinstance(org_ref, (list, tuple)):
245 if len(other_ref) != 2 or not isinstance(org_ref, (list, tuple)):
243 raise Exception('other_ref must be a two element list/tuple')
246 raise Exception('other_ref must be a two element list/tuple')
244
247
245 org_repo_scm = org_repo.scm_instance
248 org_repo_scm = org_repo.scm_instance
246 other_repo_scm = other_repo.scm_instance
249 other_repo_scm = other_repo.scm_instance
247
250
248 alias = org_repo.scm_instance.alias
251 alias = org_repo.scm_instance.alias
249 cs_ranges = self._get_changesets(alias,
252 cs_ranges = self._get_changesets(alias,
250 org_repo_scm, org_ref,
253 org_repo_scm, org_ref,
251 other_repo_scm, other_ref)
254 other_repo_scm, other_ref)
252 return cs_ranges
255 return cs_ranges
General Comments 0
You need to be logged in to leave comments. Login now