##// END OF EJS Templates
compare: drop target_repo - it is always other_repo
Mads Kiilerich -
r3324:c9b85375 beta
parent child Browse files
Show More
@@ -1,179 +1,178
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.compare
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 compare controller for pylons showing differences between two
7 7 repos, branches, bookmarks or tips
8 8
9 9 :created_on: May 6, 2012
10 10 :author: marcink
11 11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 12 :license: GPLv3, see COPYING for more details.
13 13 """
14 14 # This program is free software: you can redistribute it and/or modify
15 15 # it under the terms of the GNU General Public License as published by
16 16 # the Free Software Foundation, either version 3 of the License, or
17 17 # (at your option) any later version.
18 18 #
19 19 # This program is distributed in the hope that it will be useful,
20 20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 22 # GNU General Public License for more details.
23 23 #
24 24 # You should have received a copy of the GNU General Public License
25 25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 26 import logging
27 27 import traceback
28 28
29 29 from webob.exc import HTTPNotFound
30 30 from pylons import request, response, session, tmpl_context as c, url
31 31 from pylons.controllers.util import abort, redirect
32 32 from pylons.i18n.translation import _
33 33
34 34 from rhodecode.lib.vcs.exceptions import EmptyRepositoryError, RepositoryError
35 35 from rhodecode.lib import helpers as h
36 36 from rhodecode.lib.base import BaseRepoController, render
37 37 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
38 38 from rhodecode.lib import diffs
39 39
40 40 from rhodecode.model.db import Repository
41 41 from rhodecode.model.pull_request import PullRequestModel
42 42 from webob.exc import HTTPBadRequest
43 43 from rhodecode.lib.utils2 import str2bool
44 44 from rhodecode.lib.diffs import LimitedDiffContainer
45 45 from rhodecode.lib.vcs.backends.base import EmptyChangeset
46 46
47 47 log = logging.getLogger(__name__)
48 48
49 49
50 50 class CompareController(BaseRepoController):
51 51
52 52 @LoginRequired()
53 53 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
54 54 'repository.admin')
55 55 def __before__(self):
56 56 super(CompareController, self).__before__()
57 57
58 58 def __get_cs_or_redirect(self, rev, repo, redirect_after=True,
59 59 partial=False):
60 60 """
61 61 Safe way to get changeset if error occur it redirects to changeset with
62 62 proper message. If partial is set then don't do redirect raise Exception
63 63 instead
64 64
65 65 :param rev: revision to fetch
66 66 :param repo: repo instance
67 67 """
68 68
69 69 try:
70 70 type_, rev = rev
71 71 return repo.scm_instance.get_changeset(rev)
72 72 except EmptyRepositoryError, e:
73 73 if not redirect_after:
74 74 return None
75 75 h.flash(h.literal(_('There are no changesets yet')),
76 76 category='warning')
77 77 redirect(url('summary_home', repo_name=repo.repo_name))
78 78
79 79 except RepositoryError, e:
80 80 log.error(traceback.format_exc())
81 81 h.flash(str(e), category='warning')
82 82 if not partial:
83 83 redirect(h.url('summary_home', repo_name=repo.repo_name))
84 84 raise HTTPBadRequest()
85 85
86 86 def index(self, org_ref_type, org_ref, other_ref_type, other_ref):
87 87
88 88 org_repo = c.rhodecode_db_repo.repo_name
89 89 org_ref = (org_ref_type, org_ref)
90 90 other_ref = (other_ref_type, other_ref)
91 91 other_repo = request.GET.get('other_repo', org_repo)
92 92 c.fulldiff = fulldiff = request.GET.get('fulldiff')
93 93 rev_start = request.GET.get('rev_start')
94 94 rev_end = request.GET.get('rev_end')
95 95
96 96 c.swap_url = h.url('compare_url', as_form=request.GET.get('as_form'),
97 97 repo_name=other_repo,
98 98 org_ref_type=other_ref[0], org_ref=other_ref[1],
99 99 other_repo=org_repo,
100 100 other_ref_type=org_ref[0], other_ref=org_ref[1])
101 101
102 102 c.org_repo = org_repo = Repository.get_by_repo_name(org_repo)
103 103 c.other_repo = other_repo = Repository.get_by_repo_name(other_repo)
104 104
105 105 if c.org_repo is None:
106 106 log.error('Could not find org repo %s' % org_repo)
107 107 raise HTTPNotFound
108 108 if c.other_repo is None:
109 109 log.error('Could not find other repo %s' % other_repo)
110 110 raise HTTPNotFound
111 111
112 112 if c.org_repo != c.other_repo and h.is_git(c.rhodecode_repo):
113 113 log.error('compare of two remote repos not available for GIT REPOS')
114 114 raise HTTPNotFound
115 115
116 116 if c.org_repo.scm_instance.alias != c.other_repo.scm_instance.alias:
117 117 log.error('compare of two different kind of remote repos not available')
118 118 raise HTTPNotFound
119 119
120 120 partial = request.environ.get('HTTP_X_PARTIAL_XHR')
121 121 self.__get_cs_or_redirect(rev=org_ref, repo=org_repo, partial=partial)
122 122 self.__get_cs_or_redirect(rev=other_ref, repo=other_repo, partial=partial)
123 123
124 124 if rev_start and rev_end:
125 125 #replace our org_ref with given CS
126 126 org_ref = ('rev', rev_start)
127 127 other_ref = ('rev', rev_end)
128 128
129 129 c.cs_ranges, ancestor = PullRequestModel().get_compare_data(
130 130 org_repo, org_ref, other_repo, other_ref)
131 131
132 132 c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
133 133 c.cs_ranges])
134 c.target_repo = c.other_repo.repo_name
135 134 # defines that we need hidden inputs with changesets
136 135 c.as_form = request.GET.get('as_form', False)
137 136 if partial:
138 137 return render('compare/compare_cs.html')
139 138
140 139 c.org_ref = org_ref[1]
141 140 c.other_ref = other_ref[1]
142 141
143 142 if ancestor and c.org_repo != c.other_repo:
144 143 # case we want a simple diff without incoming changesets,
145 144 # previewing what will be merged.
146 145 # Make the diff on the forked repo, with
147 146 # revision that is common ancestor
148 147 _org_ref = org_ref
149 148 log.debug('Using ancestor %s as org_ref instead of %s', ancestor, _org_ref)
150 149 org_ref = ('rev', ancestor)
151 150 org_repo = other_repo
152 151
153 152 diff_limit = self.cut_off_limit if not fulldiff else None
154 153
155 154 _diff = diffs.differ(org_repo, org_ref, other_repo, other_ref)
156 155
157 156 diff_processor = diffs.DiffProcessor(_diff or '', format='gitdiff',
158 157 diff_limit=diff_limit)
159 158 _parsed = diff_processor.prepare()
160 159
161 160 c.limited_diff = False
162 161 if isinstance(_parsed, LimitedDiffContainer):
163 162 c.limited_diff = True
164 163
165 164 c.files = []
166 165 c.changes = {}
167 166 c.lines_added = 0
168 167 c.lines_deleted = 0
169 168 for f in _parsed:
170 169 st = f['stats']
171 170 if st[0] != 'b':
172 171 c.lines_added += st[0]
173 172 c.lines_deleted += st[1]
174 173 fid = h.FID('', f['filename'])
175 174 c.files.append([fid, f['operation'], f['filename'], f['stats']])
176 175 diff = diff_processor.as_html(enable_comments=False, parsed_lines=[f])
177 176 c.changes[fid] = [f['operation'], f['filename'], diff]
178 177
179 178 return render('compare/compare_diff.html')
@@ -1,486 +1,485
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.pullrequests
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 pull requests controller for rhodecode for initializing pull requests
7 7
8 8 :created_on: May 7, 2012
9 9 :author: marcink
10 10 :copyright: (C) 2010-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 import logging
26 26 import traceback
27 27 import formencode
28 28
29 29 from webob.exc import HTTPNotFound, HTTPForbidden
30 30 from collections import defaultdict
31 31 from itertools import groupby
32 32
33 33 from pylons import request, response, session, tmpl_context as c, url
34 34 from pylons.controllers.util import abort, redirect
35 35 from pylons.i18n.translation import _
36 36
37 37 from rhodecode.lib.compat import json
38 38 from rhodecode.lib.base import BaseRepoController, render
39 39 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
40 40 NotAnonymous
41 41 from rhodecode.lib import helpers as h
42 42 from rhodecode.lib import diffs
43 43 from rhodecode.lib.utils import action_logger, jsonify
44 44 from rhodecode.lib.vcs.exceptions import EmptyRepositoryError
45 45 from rhodecode.lib.vcs.backends.base import EmptyChangeset
46 46 from rhodecode.lib.diffs import LimitedDiffContainer
47 47 from rhodecode.model.db import User, PullRequest, ChangesetStatus,\
48 48 ChangesetComment
49 49 from rhodecode.model.pull_request import PullRequestModel
50 50 from rhodecode.model.meta import Session
51 51 from rhodecode.model.repo import RepoModel
52 52 from rhodecode.model.comment import ChangesetCommentsModel
53 53 from rhodecode.model.changeset_status import ChangesetStatusModel
54 54 from rhodecode.model.forms import PullRequestForm
55 55
56 56 log = logging.getLogger(__name__)
57 57
58 58
59 59 class PullrequestsController(BaseRepoController):
60 60
61 61 @LoginRequired()
62 62 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
63 63 'repository.admin')
64 64 def __before__(self):
65 65 super(PullrequestsController, self).__before__()
66 66 repo_model = RepoModel()
67 67 c.users_array = repo_model.get_users_js()
68 68 c.users_groups_array = repo_model.get_users_groups_js()
69 69
70 70 def _get_repo_refs(self, repo):
71 71 hist_l = []
72 72
73 73 branches_group = ([('branch:%s:%s' % (k, v), k) for
74 74 k, v in repo.branches.iteritems()], _("Branches"))
75 75 bookmarks_group = ([('book:%s:%s' % (k, v), k) for
76 76 k, v in repo.bookmarks.iteritems()], _("Bookmarks"))
77 77 tags_group = ([('tag:%s:%s' % (k, v), k) for
78 78 k, v in repo.tags.iteritems()], _("Tags"))
79 79
80 80 hist_l.append(bookmarks_group)
81 81 hist_l.append(branches_group)
82 82 hist_l.append(tags_group)
83 83
84 84 return hist_l
85 85
86 86 def _get_default_rev(self, repo):
87 87 """
88 88 Get's default revision to do compare on pull request
89 89
90 90 :param repo:
91 91 """
92 92 repo = repo.scm_instance
93 93 if 'default' in repo.branches:
94 94 return 'default'
95 95 else:
96 96 #if repo doesn't have default branch return first found
97 97 return repo.branches.keys()[0]
98 98
99 99 def _get_is_allowed_change_status(self, pull_request):
100 100 owner = self.rhodecode_user.user_id == pull_request.user_id
101 101 reviewer = self.rhodecode_user.user_id in [x.user_id for x in
102 102 pull_request.reviewers]
103 103 return (self.rhodecode_user.admin or owner or reviewer)
104 104
105 105 def show_all(self, repo_name):
106 106 c.pull_requests = PullRequestModel().get_all(repo_name)
107 107 c.repo_name = repo_name
108 108 return render('/pullrequests/pullrequest_show_all.html')
109 109
110 110 @NotAnonymous()
111 111 def index(self):
112 112 org_repo = c.rhodecode_db_repo
113 113
114 114 if org_repo.scm_instance.alias != 'hg':
115 115 log.error('Review not available for GIT REPOS')
116 116 raise HTTPNotFound
117 117
118 118 try:
119 119 org_repo.scm_instance.get_changeset()
120 120 except EmptyRepositoryError, e:
121 121 h.flash(h.literal(_('There are no changesets yet')),
122 122 category='warning')
123 123 redirect(url('summary_home', repo_name=org_repo.repo_name))
124 124
125 125 other_repos_info = {}
126 126
127 127 c.org_refs = self._get_repo_refs(c.rhodecode_repo)
128 128 c.org_repos = []
129 129 c.other_repos = []
130 130 c.org_repos.append((org_repo.repo_name, '%s/%s' % (
131 131 org_repo.user.username, c.repo_name))
132 132 )
133 133
134 134 # add org repo to other so we can open pull request agains itself
135 135 c.other_repos.extend(c.org_repos)
136 136
137 137 c.default_pull_request = org_repo.repo_name # repo name pre-selected
138 138 c.default_pull_request_rev = self._get_default_rev(org_repo) # revision pre-selected
139 139 c.default_revs = self._get_repo_refs(org_repo.scm_instance)
140 140 #add orginal repo
141 141 other_repos_info[org_repo.repo_name] = {
142 142 'gravatar': h.gravatar_url(org_repo.user.email, 24),
143 143 'description': org_repo.description,
144 144 'revs': h.select('other_ref', '', c.default_revs, class_='refs')
145 145 }
146 146
147 147 #gather forks and add to this list
148 148 for fork in org_repo.forks:
149 149 c.other_repos.append((fork.repo_name, '%s/%s' % (
150 150 fork.user.username, fork.repo_name))
151 151 )
152 152 other_repos_info[fork.repo_name] = {
153 153 'gravatar': h.gravatar_url(fork.user.email, 24),
154 154 'description': fork.description,
155 155 'revs': h.select('other_ref', '',
156 156 self._get_repo_refs(fork.scm_instance),
157 157 class_='refs')
158 158 }
159 159 #add parents of this fork also, but only if it's not empty
160 160 if org_repo.parent and org_repo.parent.scm_instance.revisions:
161 161 c.default_pull_request = org_repo.parent.repo_name
162 162 c.default_pull_request_rev = self._get_default_rev(org_repo.parent)
163 163 c.default_revs = self._get_repo_refs(org_repo.parent.scm_instance)
164 164 c.other_repos.append((org_repo.parent.repo_name, '%s/%s' % (
165 165 org_repo.parent.user.username,
166 166 org_repo.parent.repo_name))
167 167 )
168 168 other_repos_info[org_repo.parent.repo_name] = {
169 169 'gravatar': h.gravatar_url(org_repo.parent.user.email, 24),
170 170 'description': org_repo.parent.description,
171 171 'revs': h.select('other_ref', '',
172 172 self._get_repo_refs(org_repo.parent.scm_instance),
173 173 class_='refs')
174 174 }
175 175
176 176 c.other_repos_info = json.dumps(other_repos_info)
177 177 c.review_members = [org_repo.user]
178 178 return render('/pullrequests/pullrequest.html')
179 179
180 180 @NotAnonymous()
181 181 def create(self, repo_name):
182 182 repo = RepoModel()._get_repo(repo_name)
183 183 try:
184 184 _form = PullRequestForm(repo.repo_id)().to_python(request.POST)
185 185 except formencode.Invalid, errors:
186 186 log.error(traceback.format_exc())
187 187 if errors.error_dict.get('revisions'):
188 188 msg = 'Revisions: %s' % errors.error_dict['revisions']
189 189 elif errors.error_dict.get('pullrequest_title'):
190 190 msg = _('Pull request requires a title with min. 3 chars')
191 191 else:
192 192 msg = _('error during creation of pull request')
193 193
194 194 h.flash(msg, 'error')
195 195 return redirect(url('pullrequest_home', repo_name=repo_name))
196 196
197 197 org_repo = _form['org_repo']
198 198 org_ref = _form['org_ref']
199 199 other_repo = _form['other_repo']
200 200 other_ref = _form['other_ref']
201 201 revisions = _form['revisions']
202 202 reviewers = _form['review_members']
203 203
204 204 # if we have cherry picked pull request we don't care what is in
205 205 # org_ref/other_ref
206 206 rev_start = request.POST.get('rev_start')
207 207 rev_end = request.POST.get('rev_end')
208 208
209 209 if rev_start and rev_end:
210 210 # this is swapped to simulate that rev_end is a revision from
211 211 # parent of the fork
212 212 org_ref = 'rev:%s:%s' % (rev_end, rev_end)
213 213 other_ref = 'rev:%s:%s' % (rev_start, rev_start)
214 214
215 215 title = _form['pullrequest_title']
216 216 description = _form['pullrequest_desc']
217 217
218 218 try:
219 219 pull_request = PullRequestModel().create(
220 220 self.rhodecode_user.user_id, org_repo, org_ref, other_repo,
221 221 other_ref, revisions, reviewers, title, description
222 222 )
223 223 Session().commit()
224 224 h.flash(_('Successfully opened new pull request'),
225 225 category='success')
226 226 except Exception:
227 227 h.flash(_('Error occurred during sending pull request'),
228 228 category='error')
229 229 log.error(traceback.format_exc())
230 230 return redirect(url('pullrequest_home', repo_name=repo_name))
231 231
232 232 return redirect(url('pullrequest_show', repo_name=other_repo,
233 233 pull_request_id=pull_request.pull_request_id))
234 234
235 235 @NotAnonymous()
236 236 @jsonify
237 237 def update(self, repo_name, pull_request_id):
238 238 pull_request = PullRequest.get_or_404(pull_request_id)
239 239 if pull_request.is_closed():
240 240 raise HTTPForbidden()
241 241 #only owner or admin can update it
242 242 owner = pull_request.author.user_id == c.rhodecode_user.user_id
243 243 if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
244 244 reviewers_ids = map(int, filter(lambda v: v not in [None, ''],
245 245 request.POST.get('reviewers_ids', '').split(',')))
246 246
247 247 PullRequestModel().update_reviewers(pull_request_id, reviewers_ids)
248 248 Session().commit()
249 249 return True
250 250 raise HTTPForbidden()
251 251
252 252 @NotAnonymous()
253 253 @jsonify
254 254 def delete(self, repo_name, pull_request_id):
255 255 pull_request = PullRequest.get_or_404(pull_request_id)
256 256 #only owner can delete it !
257 257 if pull_request.author.user_id == c.rhodecode_user.user_id:
258 258 PullRequestModel().delete(pull_request)
259 259 Session().commit()
260 260 h.flash(_('Successfully deleted pull request'),
261 261 category='success')
262 262 return redirect(url('admin_settings_my_account', anchor='pullrequests'))
263 263 raise HTTPForbidden()
264 264
265 265 def _load_compare_data(self, pull_request, enable_comments=True):
266 266 """
267 267 Load context data needed for generating compare diff
268 268
269 269 :param pull_request:
270 270 :type pull_request:
271 271 """
272 272 rev_start = request.GET.get('rev_start')
273 273 rev_end = request.GET.get('rev_end')
274 274
275 275 org_repo = pull_request.org_repo
276 276 (org_ref_type,
277 277 org_ref_name,
278 278 org_ref_rev) = pull_request.org_ref.split(':')
279 279
280 280 other_repo = org_repo
281 281 (other_ref_type,
282 282 other_ref_name,
283 283 other_ref_rev) = pull_request.other_ref.split(':')
284 284
285 285 # despite opening revisions for bookmarks/branches/tags, we always
286 286 # convert this to rev to prevent changes after book or branch change
287 287 org_ref = ('rev', org_ref_rev)
288 288 other_ref = ('rev', other_ref_rev)
289 289
290 290 c.org_repo = org_repo
291 291 c.other_repo = other_repo
292 292
293 293 c.fulldiff = fulldiff = request.GET.get('fulldiff')
294 294
295 295 c.cs_ranges = [org_repo.get_changeset(x) for x in pull_request.revisions]
296 296
297 297 other_ref = ('rev', getattr(c.cs_ranges[0].parents[0]
298 298 if c.cs_ranges[0].parents
299 299 else EmptyChangeset(), 'raw_id'))
300 300
301 301 c.statuses = org_repo.statuses([x.raw_id for x in c.cs_ranges])
302 c.target_repo = other_repo.repo_name
303 302 # defines that we need hidden inputs with changesets
304 303 c.as_form = request.GET.get('as_form', False)
305 304
306 305 c.org_ref = org_ref[1]
307 306 c.other_ref = other_ref[1]
308 307
309 308 diff_limit = self.cut_off_limit if not fulldiff else None
310 309
311 310 #we swap org/other ref since we run a simple diff on one repo
312 311 _diff = diffs.differ(org_repo, other_ref, other_repo, org_ref)
313 312
314 313 diff_processor = diffs.DiffProcessor(_diff or '', format='gitdiff',
315 314 diff_limit=diff_limit)
316 315 _parsed = diff_processor.prepare()
317 316
318 317 c.limited_diff = False
319 318 if isinstance(_parsed, LimitedDiffContainer):
320 319 c.limited_diff = True
321 320
322 321 c.files = []
323 322 c.changes = {}
324 323 c.lines_added = 0
325 324 c.lines_deleted = 0
326 325 for f in _parsed:
327 326 st = f['stats']
328 327 if st[0] != 'b':
329 328 c.lines_added += st[0]
330 329 c.lines_deleted += st[1]
331 330 fid = h.FID('', f['filename'])
332 331 c.files.append([fid, f['operation'], f['filename'], f['stats']])
333 332 diff = diff_processor.as_html(enable_comments=enable_comments,
334 333 parsed_lines=[f])
335 334 c.changes[fid] = [f['operation'], f['filename'], diff]
336 335
337 336 def show(self, repo_name, pull_request_id):
338 337 repo_model = RepoModel()
339 338 c.users_array = repo_model.get_users_js()
340 339 c.users_groups_array = repo_model.get_users_groups_js()
341 340 c.pull_request = PullRequest.get_or_404(pull_request_id)
342 341 c.allowed_to_change_status = self._get_is_allowed_change_status(c.pull_request)
343 342 cc_model = ChangesetCommentsModel()
344 343 cs_model = ChangesetStatusModel()
345 344 _cs_statuses = cs_model.get_statuses(c.pull_request.org_repo,
346 345 pull_request=c.pull_request,
347 346 with_revisions=True)
348 347
349 348 cs_statuses = defaultdict(list)
350 349 for st in _cs_statuses:
351 350 cs_statuses[st.author.username] += [st]
352 351
353 352 c.pull_request_reviewers = []
354 353 c.pull_request_pending_reviewers = []
355 354 for o in c.pull_request.reviewers:
356 355 st = cs_statuses.get(o.user.username, None)
357 356 if st:
358 357 sorter = lambda k: k.version
359 358 st = [(x, list(y)[0])
360 359 for x, y in (groupby(sorted(st, key=sorter), sorter))]
361 360 else:
362 361 c.pull_request_pending_reviewers.append(o.user)
363 362 c.pull_request_reviewers.append([o.user, st])
364 363
365 364 # pull_requests repo_name we opened it against
366 365 # ie. other_repo must match
367 366 if repo_name != c.pull_request.other_repo.repo_name:
368 367 raise HTTPNotFound
369 368
370 369 # load compare data into template context
371 370 enable_comments = not c.pull_request.is_closed()
372 371 self._load_compare_data(c.pull_request, enable_comments=enable_comments)
373 372
374 373 # inline comments
375 374 c.inline_cnt = 0
376 375 c.inline_comments = cc_model.get_inline_comments(
377 376 c.rhodecode_db_repo.repo_id,
378 377 pull_request=pull_request_id)
379 378 # count inline comments
380 379 for __, lines in c.inline_comments:
381 380 for comments in lines.values():
382 381 c.inline_cnt += len(comments)
383 382 # comments
384 383 c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id,
385 384 pull_request=pull_request_id)
386 385
387 386 try:
388 387 cur_status = c.statuses[c.pull_request.revisions[0]][0]
389 388 except:
390 389 log.error(traceback.format_exc())
391 390 cur_status = 'undefined'
392 391 if c.pull_request.is_closed() and 0:
393 392 c.current_changeset_status = cur_status
394 393 else:
395 394 # changeset(pull-request) status calulation based on reviewers
396 395 c.current_changeset_status = cs_model.calculate_status(
397 396 c.pull_request_reviewers,
398 397 )
399 398 c.changeset_statuses = ChangesetStatus.STATUSES
400 399
401 400 return render('/pullrequests/pullrequest_show.html')
402 401
403 402 @NotAnonymous()
404 403 @jsonify
405 404 def comment(self, repo_name, pull_request_id):
406 405 pull_request = PullRequest.get_or_404(pull_request_id)
407 406 if pull_request.is_closed():
408 407 raise HTTPForbidden()
409 408
410 409 status = request.POST.get('changeset_status')
411 410 change_status = request.POST.get('change_changeset_status')
412 411 text = request.POST.get('text')
413 412
414 413 allowed_to_change_status = self._get_is_allowed_change_status(pull_request)
415 414 if status and change_status and allowed_to_change_status:
416 415 text = text or (_('Status change -> %s')
417 416 % ChangesetStatus.get_status_lbl(status))
418 417 comm = ChangesetCommentsModel().create(
419 418 text=text,
420 419 repo=c.rhodecode_db_repo.repo_id,
421 420 user=c.rhodecode_user.user_id,
422 421 pull_request=pull_request_id,
423 422 f_path=request.POST.get('f_path'),
424 423 line_no=request.POST.get('line'),
425 424 status_change=(ChangesetStatus.get_status_lbl(status)
426 425 if status and change_status and allowed_to_change_status else None)
427 426 )
428 427
429 428 action_logger(self.rhodecode_user,
430 429 'user_commented_pull_request:%s' % pull_request_id,
431 430 c.rhodecode_db_repo, self.ip_addr, self.sa)
432 431
433 432 if allowed_to_change_status:
434 433 # get status if set !
435 434 if status and change_status:
436 435 ChangesetStatusModel().set_status(
437 436 c.rhodecode_db_repo.repo_id,
438 437 status,
439 438 c.rhodecode_user.user_id,
440 439 comm,
441 440 pull_request=pull_request_id
442 441 )
443 442
444 443 if request.POST.get('save_close'):
445 444 if status in ['rejected', 'approved']:
446 445 PullRequestModel().close_pull_request(pull_request_id)
447 446 action_logger(self.rhodecode_user,
448 447 'user_closed_pull_request:%s' % pull_request_id,
449 448 c.rhodecode_db_repo, self.ip_addr, self.sa)
450 449 else:
451 450 h.flash(_('Closing pull request on other statuses than '
452 451 'rejected or approved forbidden'),
453 452 category='warning')
454 453
455 454 Session().commit()
456 455
457 456 if not request.environ.get('HTTP_X_PARTIAL_XHR'):
458 457 return redirect(h.url('pullrequest_show', repo_name=repo_name,
459 458 pull_request_id=pull_request_id))
460 459
461 460 data = {
462 461 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
463 462 }
464 463 if comm:
465 464 c.co = comm
466 465 data.update(comm.get_dict())
467 466 data.update({'rendered_text':
468 467 render('changeset/changeset_comment_block.html')})
469 468
470 469 return data
471 470
472 471 @NotAnonymous()
473 472 @jsonify
474 473 def delete_comment(self, repo_name, comment_id):
475 474 co = ChangesetComment.get(comment_id)
476 475 if co.pull_request.is_closed():
477 476 #don't allow deleting comments on closed pull request
478 477 raise HTTPForbidden()
479 478
480 479 owner = co.author.user_id == c.rhodecode_user.user_id
481 480 if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
482 481 ChangesetCommentsModel().delete(comment=co)
483 482 Session().commit()
484 483 return True
485 484 else:
486 485 raise HTTPForbidden()
@@ -1,28 +1,28
1 1 ## Changesets table !
2 2 <div class="container">
3 3 <table class="compare_view_commits noborder">
4 4 %if not c.cs_ranges:
5 5 <span class="empty_data">${_('No changesets')}</span>
6 6 %else:
7 7 %for cnt, cs in enumerate(c.cs_ranges):
8 8 <tr>
9 9 <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),14)}"/></div></td>
10 10 <td>
11 11 %if cs.raw_id in c.statuses:
12 12 <div title="${c.statuses[cs.raw_id][1]}" class="changeset-status-ico"><img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses[cs.raw_id][0])}" /></div>
13 13 %endif
14 14 </td>
15 <td>${h.link_to('r%s:%s' % (cs.revision,h.short_id(cs.raw_id)),h.url('changeset_home',repo_name=c.target_repo,revision=cs.raw_id))}
15 <td>${h.link_to('r%s:%s' % (cs.revision,h.short_id(cs.raw_id)),h.url('changeset_home',repo_name=c.other_repo.repo_name,revision=cs.raw_id))}
16 16 %if c.as_form:
17 17 ${h.hidden('revisions',cs.raw_id)}
18 18 %endif
19 19 </td>
20 20 <td><div class="author">${h.person(cs.author)}</div></td>
21 21 <td><span class="tooltip" title="${h.tooltip(h.age(cs.date))}">${cs.date}</span></td>
22 22 <td><div class="message tooltip" title="${h.tooltip(cs.message)}" style="white-space:normal">${h.urlify_commit(h.shorter(cs.message, 60),c.repo_name)}</div></td>
23 23 </tr>
24 24 %endfor
25 25
26 26 %endif
27 27 </table>
28 28 </div>
General Comments 0
You need to be logged in to leave comments. Login now