##// END OF EJS Templates
pull request: move code around and rename default variables
Mads Kiilerich -
r3327:f285faa3 beta
parent child Browse files
Show More
@@ -1,485 +1,484
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.pullrequests
3 rhodecode.controllers.pullrequests
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 pull requests controller for rhodecode for initializing pull requests
6 pull requests controller for rhodecode for initializing pull requests
7
7
8 :created_on: May 7, 2012
8 :created_on: May 7, 2012
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-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 import logging
25 import logging
26 import traceback
26 import traceback
27 import formencode
27 import formencode
28
28
29 from webob.exc import HTTPNotFound, HTTPForbidden
29 from webob.exc import HTTPNotFound, HTTPForbidden
30 from collections import defaultdict
30 from collections import defaultdict
31 from itertools import groupby
31 from itertools import groupby
32
32
33 from pylons import request, response, session, tmpl_context as c, url
33 from pylons import request, response, session, tmpl_context as c, url
34 from pylons.controllers.util import abort, redirect
34 from pylons.controllers.util import abort, redirect
35 from pylons.i18n.translation import _
35 from pylons.i18n.translation import _
36
36
37 from rhodecode.lib.compat import json
37 from rhodecode.lib.compat import json
38 from rhodecode.lib.base import BaseRepoController, render
38 from rhodecode.lib.base import BaseRepoController, render
39 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
39 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
40 NotAnonymous
40 NotAnonymous
41 from rhodecode.lib import helpers as h
41 from rhodecode.lib import helpers as h
42 from rhodecode.lib import diffs
42 from rhodecode.lib import diffs
43 from rhodecode.lib.utils import action_logger, jsonify
43 from rhodecode.lib.utils import action_logger, jsonify
44 from rhodecode.lib.vcs.exceptions import EmptyRepositoryError
44 from rhodecode.lib.vcs.exceptions import EmptyRepositoryError
45 from rhodecode.lib.vcs.backends.base import EmptyChangeset
45 from rhodecode.lib.vcs.backends.base import EmptyChangeset
46 from rhodecode.lib.diffs import LimitedDiffContainer
46 from rhodecode.lib.diffs import LimitedDiffContainer
47 from rhodecode.model.db import User, PullRequest, ChangesetStatus,\
47 from rhodecode.model.db import User, PullRequest, ChangesetStatus,\
48 ChangesetComment
48 ChangesetComment
49 from rhodecode.model.pull_request import PullRequestModel
49 from rhodecode.model.pull_request import PullRequestModel
50 from rhodecode.model.meta import Session
50 from rhodecode.model.meta import Session
51 from rhodecode.model.repo import RepoModel
51 from rhodecode.model.repo import RepoModel
52 from rhodecode.model.comment import ChangesetCommentsModel
52 from rhodecode.model.comment import ChangesetCommentsModel
53 from rhodecode.model.changeset_status import ChangesetStatusModel
53 from rhodecode.model.changeset_status import ChangesetStatusModel
54 from rhodecode.model.forms import PullRequestForm
54 from rhodecode.model.forms import PullRequestForm
55
55
56 log = logging.getLogger(__name__)
56 log = logging.getLogger(__name__)
57
57
58
58
59 class PullrequestsController(BaseRepoController):
59 class PullrequestsController(BaseRepoController):
60
60
61 @LoginRequired()
61 @LoginRequired()
62 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
62 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
63 'repository.admin')
63 'repository.admin')
64 def __before__(self):
64 def __before__(self):
65 super(PullrequestsController, self).__before__()
65 super(PullrequestsController, self).__before__()
66 repo_model = RepoModel()
66 repo_model = RepoModel()
67 c.users_array = repo_model.get_users_js()
67 c.users_array = repo_model.get_users_js()
68 c.users_groups_array = repo_model.get_users_groups_js()
68 c.users_groups_array = repo_model.get_users_groups_js()
69
69
70 def _get_repo_refs(self, repo):
70 def _get_repo_refs(self, repo):
71 hist_l = []
71 hist_l = []
72
72
73 branches_group = ([('branch:%s:%s' % (k, v), k) for
73 branches_group = ([('branch:%s:%s' % (k, v), k) for
74 k, v in repo.branches.iteritems()], _("Branches"))
74 k, v in repo.branches.iteritems()], _("Branches"))
75 bookmarks_group = ([('book:%s:%s' % (k, v), k) for
75 bookmarks_group = ([('book:%s:%s' % (k, v), k) for
76 k, v in repo.bookmarks.iteritems()], _("Bookmarks"))
76 k, v in repo.bookmarks.iteritems()], _("Bookmarks"))
77 tags_group = ([('tag:%s:%s' % (k, v), k) for
77 tags_group = ([('tag:%s:%s' % (k, v), k) for
78 k, v in repo.tags.iteritems()], _("Tags"))
78 k, v in repo.tags.iteritems()], _("Tags"))
79
79
80 hist_l.append(bookmarks_group)
80 hist_l.append(bookmarks_group)
81 hist_l.append(branches_group)
81 hist_l.append(branches_group)
82 hist_l.append(tags_group)
82 hist_l.append(tags_group)
83
83
84 return hist_l
84 return hist_l
85
85
86 def _get_default_rev(self, repo):
86 def _get_default_rev(self, repo):
87 """
87 """
88 Get's default revision to do compare on pull request
88 Get's default revision to do compare on pull request
89
89
90 :param repo:
90 :param repo:
91 """
91 """
92 repo = repo.scm_instance
92 repo = repo.scm_instance
93 if 'default' in repo.branches:
93 if 'default' in repo.branches:
94 return 'default'
94 return 'default'
95 else:
95 else:
96 #if repo doesn't have default branch return first found
96 #if repo doesn't have default branch return first found
97 return repo.branches.keys()[0]
97 return repo.branches.keys()[0]
98
98
99 def _get_is_allowed_change_status(self, pull_request):
99 def _get_is_allowed_change_status(self, pull_request):
100 owner = self.rhodecode_user.user_id == pull_request.user_id
100 owner = self.rhodecode_user.user_id == pull_request.user_id
101 reviewer = self.rhodecode_user.user_id in [x.user_id for x in
101 reviewer = self.rhodecode_user.user_id in [x.user_id for x in
102 pull_request.reviewers]
102 pull_request.reviewers]
103 return (self.rhodecode_user.admin or owner or reviewer)
103 return (self.rhodecode_user.admin or owner or reviewer)
104
104
105 def show_all(self, repo_name):
105 def show_all(self, repo_name):
106 c.pull_requests = PullRequestModel().get_all(repo_name)
106 c.pull_requests = PullRequestModel().get_all(repo_name)
107 c.repo_name = repo_name
107 c.repo_name = repo_name
108 return render('/pullrequests/pullrequest_show_all.html')
108 return render('/pullrequests/pullrequest_show_all.html')
109
109
110 @NotAnonymous()
110 @NotAnonymous()
111 def index(self):
111 def index(self):
112 org_repo = c.rhodecode_db_repo
112 org_repo = c.rhodecode_db_repo
113
113
114 if org_repo.scm_instance.alias != 'hg':
114 if org_repo.scm_instance.alias != 'hg':
115 log.error('Review not available for GIT REPOS')
115 log.error('Review not available for GIT REPOS')
116 raise HTTPNotFound
116 raise HTTPNotFound
117
117
118 try:
118 try:
119 org_repo.scm_instance.get_changeset()
119 org_repo.scm_instance.get_changeset()
120 except EmptyRepositoryError, e:
120 except EmptyRepositoryError, e:
121 h.flash(h.literal(_('There are no changesets yet')),
121 h.flash(h.literal(_('There are no changesets yet')),
122 category='warning')
122 category='warning')
123 redirect(url('summary_home', repo_name=org_repo.repo_name))
123 redirect(url('summary_home', repo_name=org_repo.repo_name))
124
124
125 other_repos_info = {}
125 other_repos_info = {}
126
126
127 c.org_refs = self._get_repo_refs(c.rhodecode_repo)
128 c.org_repos = []
127 c.org_repos = []
129 c.other_repos = []
130 c.org_repos.append((org_repo.repo_name, '%s/%s' % (
128 c.org_repos.append((org_repo.repo_name, '%s/%s' % (
131 org_repo.user.username, c.repo_name))
129 org_repo.user.username, c.repo_name))
132 )
130 )
133
131 c.org_refs = self._get_repo_refs(c.rhodecode_repo)
134 # add org repo to other so we can open pull request agains itself
135 c.other_repos.extend(c.org_repos)
136
132
137 c.default_pull_request = org_repo.repo_name # repo name pre-selected
133 c.other_repos = []
138 c.default_pull_request_rev = self._get_default_rev(org_repo) # revision pre-selected
134 # add org repo to other so we can open pull request against itself
139 c.default_revs = self._get_repo_refs(org_repo.scm_instance)
135 c.other_repos.extend(c.org_repos)
140 #add orginal repo
136 c.default_other_repo = org_repo.repo_name
137 c.default_other_refs = self._get_repo_refs(org_repo.scm_instance)
138 c.default_other_ref = self._get_default_rev(org_repo)
141 other_repos_info[org_repo.repo_name] = {
139 other_repos_info[org_repo.repo_name] = {
142 'gravatar': h.gravatar_url(org_repo.user.email, 24),
140 'gravatar': h.gravatar_url(org_repo.user.email, 24),
143 'description': org_repo.description,
141 'description': org_repo.description,
144 'revs': h.select('other_ref', '', c.default_revs, class_='refs')
142 'revs': h.select('other_ref', '', c.default_other_refs, class_='refs')
145 }
143 }
146
144
147 #gather forks and add to this list
145 # gather forks and add to this list ... even though it is rare to request forks to pull their parent
148 for fork in org_repo.forks:
146 for fork in org_repo.forks:
149 c.other_repos.append((fork.repo_name, '%s/%s' % (
147 c.other_repos.append((fork.repo_name, '%s/%s' % (
150 fork.user.username, fork.repo_name))
148 fork.user.username, fork.repo_name))
151 )
149 )
152 other_repos_info[fork.repo_name] = {
150 other_repos_info[fork.repo_name] = {
153 'gravatar': h.gravatar_url(fork.user.email, 24),
151 'gravatar': h.gravatar_url(fork.user.email, 24),
154 'description': fork.description,
152 'description': fork.description,
155 'revs': h.select('other_ref', '',
153 'revs': h.select('other_ref', '',
156 self._get_repo_refs(fork.scm_instance),
154 self._get_repo_refs(fork.scm_instance),
157 class_='refs')
155 class_='refs')
158 }
156 }
159 #add parents of this fork also, but only if it's not empty
157
158 # add parents of this fork also, but only if it's not empty
160 if org_repo.parent and org_repo.parent.scm_instance.revisions:
159 if org_repo.parent and org_repo.parent.scm_instance.revisions:
161 c.default_pull_request = org_repo.parent.repo_name
160 c.default_other_repo = org_repo.parent.repo_name
162 c.default_pull_request_rev = self._get_default_rev(org_repo.parent)
161 c.default_other_refs = self._get_repo_refs(org_repo.parent.scm_instance)
163 c.default_revs = self._get_repo_refs(org_repo.parent.scm_instance)
162 c.default_other_ref = self._get_default_rev(org_repo.parent)
164 c.other_repos.append((org_repo.parent.repo_name, '%s/%s' % (
163 c.other_repos.append((org_repo.parent.repo_name, '%s/%s' % (
165 org_repo.parent.user.username,
164 org_repo.parent.user.username,
166 org_repo.parent.repo_name))
165 org_repo.parent.repo_name))
167 )
166 )
168 other_repos_info[org_repo.parent.repo_name] = {
167 other_repos_info[org_repo.parent.repo_name] = {
169 'gravatar': h.gravatar_url(org_repo.parent.user.email, 24),
168 'gravatar': h.gravatar_url(org_repo.parent.user.email, 24),
170 'description': org_repo.parent.description,
169 'description': org_repo.parent.description,
171 'revs': h.select('other_ref', '',
170 'revs': h.select('other_ref', '',
172 self._get_repo_refs(org_repo.parent.scm_instance),
171 self._get_repo_refs(org_repo.parent.scm_instance),
173 class_='refs')
172 class_='refs')
174 }
173 }
175
174
176 c.other_repos_info = json.dumps(other_repos_info)
175 c.other_repos_info = json.dumps(other_repos_info)
177 c.review_members = [org_repo.user]
176 c.review_members = [org_repo.user]
178 return render('/pullrequests/pullrequest.html')
177 return render('/pullrequests/pullrequest.html')
179
178
180 @NotAnonymous()
179 @NotAnonymous()
181 def create(self, repo_name):
180 def create(self, repo_name):
182 repo = RepoModel()._get_repo(repo_name)
181 repo = RepoModel()._get_repo(repo_name)
183 try:
182 try:
184 _form = PullRequestForm(repo.repo_id)().to_python(request.POST)
183 _form = PullRequestForm(repo.repo_id)().to_python(request.POST)
185 except formencode.Invalid, errors:
184 except formencode.Invalid, errors:
186 log.error(traceback.format_exc())
185 log.error(traceback.format_exc())
187 if errors.error_dict.get('revisions'):
186 if errors.error_dict.get('revisions'):
188 msg = 'Revisions: %s' % errors.error_dict['revisions']
187 msg = 'Revisions: %s' % errors.error_dict['revisions']
189 elif errors.error_dict.get('pullrequest_title'):
188 elif errors.error_dict.get('pullrequest_title'):
190 msg = _('Pull request requires a title with min. 3 chars')
189 msg = _('Pull request requires a title with min. 3 chars')
191 else:
190 else:
192 msg = _('error during creation of pull request')
191 msg = _('error during creation of pull request')
193
192
194 h.flash(msg, 'error')
193 h.flash(msg, 'error')
195 return redirect(url('pullrequest_home', repo_name=repo_name))
194 return redirect(url('pullrequest_home', repo_name=repo_name))
196
195
197 org_repo = _form['org_repo']
196 org_repo = _form['org_repo']
198 org_ref = _form['org_ref']
197 org_ref = _form['org_ref']
199 other_repo = _form['other_repo']
198 other_repo = _form['other_repo']
200 other_ref = _form['other_ref']
199 other_ref = _form['other_ref']
201 revisions = _form['revisions']
200 revisions = _form['revisions']
202 reviewers = _form['review_members']
201 reviewers = _form['review_members']
203
202
204 # if we have cherry picked pull request we don't care what is in
203 # if we have cherry picked pull request we don't care what is in
205 # org_ref/other_ref
204 # org_ref/other_ref
206 rev_start = request.POST.get('rev_start')
205 rev_start = request.POST.get('rev_start')
207 rev_end = request.POST.get('rev_end')
206 rev_end = request.POST.get('rev_end')
208
207
209 if rev_start and rev_end:
208 if rev_start and rev_end:
210 # this is swapped to simulate that rev_end is a revision from
209 # this is swapped to simulate that rev_end is a revision from
211 # parent of the fork
210 # parent of the fork
212 org_ref = 'rev:%s:%s' % (rev_end, rev_end)
211 org_ref = 'rev:%s:%s' % (rev_end, rev_end)
213 other_ref = 'rev:%s:%s' % (rev_start, rev_start)
212 other_ref = 'rev:%s:%s' % (rev_start, rev_start)
214
213
215 title = _form['pullrequest_title']
214 title = _form['pullrequest_title']
216 description = _form['pullrequest_desc']
215 description = _form['pullrequest_desc']
217
216
218 try:
217 try:
219 pull_request = PullRequestModel().create(
218 pull_request = PullRequestModel().create(
220 self.rhodecode_user.user_id, org_repo, org_ref, other_repo,
219 self.rhodecode_user.user_id, org_repo, org_ref, other_repo,
221 other_ref, revisions, reviewers, title, description
220 other_ref, revisions, reviewers, title, description
222 )
221 )
223 Session().commit()
222 Session().commit()
224 h.flash(_('Successfully opened new pull request'),
223 h.flash(_('Successfully opened new pull request'),
225 category='success')
224 category='success')
226 except Exception:
225 except Exception:
227 h.flash(_('Error occurred during sending pull request'),
226 h.flash(_('Error occurred during sending pull request'),
228 category='error')
227 category='error')
229 log.error(traceback.format_exc())
228 log.error(traceback.format_exc())
230 return redirect(url('pullrequest_home', repo_name=repo_name))
229 return redirect(url('pullrequest_home', repo_name=repo_name))
231
230
232 return redirect(url('pullrequest_show', repo_name=other_repo,
231 return redirect(url('pullrequest_show', repo_name=other_repo,
233 pull_request_id=pull_request.pull_request_id))
232 pull_request_id=pull_request.pull_request_id))
234
233
235 @NotAnonymous()
234 @NotAnonymous()
236 @jsonify
235 @jsonify
237 def update(self, repo_name, pull_request_id):
236 def update(self, repo_name, pull_request_id):
238 pull_request = PullRequest.get_or_404(pull_request_id)
237 pull_request = PullRequest.get_or_404(pull_request_id)
239 if pull_request.is_closed():
238 if pull_request.is_closed():
240 raise HTTPForbidden()
239 raise HTTPForbidden()
241 #only owner or admin can update it
240 #only owner or admin can update it
242 owner = pull_request.author.user_id == c.rhodecode_user.user_id
241 owner = pull_request.author.user_id == c.rhodecode_user.user_id
243 if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
242 if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
244 reviewers_ids = map(int, filter(lambda v: v not in [None, ''],
243 reviewers_ids = map(int, filter(lambda v: v not in [None, ''],
245 request.POST.get('reviewers_ids', '').split(',')))
244 request.POST.get('reviewers_ids', '').split(',')))
246
245
247 PullRequestModel().update_reviewers(pull_request_id, reviewers_ids)
246 PullRequestModel().update_reviewers(pull_request_id, reviewers_ids)
248 Session().commit()
247 Session().commit()
249 return True
248 return True
250 raise HTTPForbidden()
249 raise HTTPForbidden()
251
250
252 @NotAnonymous()
251 @NotAnonymous()
253 @jsonify
252 @jsonify
254 def delete(self, repo_name, pull_request_id):
253 def delete(self, repo_name, pull_request_id):
255 pull_request = PullRequest.get_or_404(pull_request_id)
254 pull_request = PullRequest.get_or_404(pull_request_id)
256 #only owner can delete it !
255 #only owner can delete it !
257 if pull_request.author.user_id == c.rhodecode_user.user_id:
256 if pull_request.author.user_id == c.rhodecode_user.user_id:
258 PullRequestModel().delete(pull_request)
257 PullRequestModel().delete(pull_request)
259 Session().commit()
258 Session().commit()
260 h.flash(_('Successfully deleted pull request'),
259 h.flash(_('Successfully deleted pull request'),
261 category='success')
260 category='success')
262 return redirect(url('admin_settings_my_account', anchor='pullrequests'))
261 return redirect(url('admin_settings_my_account', anchor='pullrequests'))
263 raise HTTPForbidden()
262 raise HTTPForbidden()
264
263
265 def _load_compare_data(self, pull_request, enable_comments=True):
264 def _load_compare_data(self, pull_request, enable_comments=True):
266 """
265 """
267 Load context data needed for generating compare diff
266 Load context data needed for generating compare diff
268
267
269 :param pull_request:
268 :param pull_request:
270 :type pull_request:
269 :type pull_request:
271 """
270 """
272 rev_start = request.GET.get('rev_start')
271 rev_start = request.GET.get('rev_start')
273 rev_end = request.GET.get('rev_end')
272 rev_end = request.GET.get('rev_end')
274
273
275 org_repo = pull_request.org_repo
274 org_repo = pull_request.org_repo
276 (org_ref_type,
275 (org_ref_type,
277 org_ref_name,
276 org_ref_name,
278 org_ref_rev) = pull_request.org_ref.split(':')
277 org_ref_rev) = pull_request.org_ref.split(':')
279
278
280 other_repo = org_repo
279 other_repo = org_repo
281 (other_ref_type,
280 (other_ref_type,
282 other_ref_name,
281 other_ref_name,
283 other_ref_rev) = pull_request.other_ref.split(':')
282 other_ref_rev) = pull_request.other_ref.split(':')
284
283
285 # despite opening revisions for bookmarks/branches/tags, we always
284 # despite opening revisions for bookmarks/branches/tags, we always
286 # convert this to rev to prevent changes after book or branch change
285 # convert this to rev to prevent changes after book or branch change
287 org_ref = ('rev', org_ref_rev)
286 org_ref = ('rev', org_ref_rev)
288 other_ref = ('rev', other_ref_rev)
287 other_ref = ('rev', other_ref_rev)
289
288
290 c.org_repo = org_repo
289 c.org_repo = org_repo
291 c.other_repo = other_repo
290 c.other_repo = other_repo
292
291
293 c.fulldiff = fulldiff = request.GET.get('fulldiff')
292 c.fulldiff = fulldiff = request.GET.get('fulldiff')
294
293
295 c.cs_ranges = [org_repo.get_changeset(x) for x in pull_request.revisions]
294 c.cs_ranges = [org_repo.get_changeset(x) for x in pull_request.revisions]
296
295
297 other_ref = ('rev', getattr(c.cs_ranges[0].parents[0]
296 other_ref = ('rev', getattr(c.cs_ranges[0].parents[0]
298 if c.cs_ranges[0].parents
297 if c.cs_ranges[0].parents
299 else EmptyChangeset(), 'raw_id'))
298 else EmptyChangeset(), 'raw_id'))
300
299
301 c.statuses = org_repo.statuses([x.raw_id for x in c.cs_ranges])
300 c.statuses = org_repo.statuses([x.raw_id for x in c.cs_ranges])
302 # defines that we need hidden inputs with changesets
301 # defines that we need hidden inputs with changesets
303 c.as_form = request.GET.get('as_form', False)
302 c.as_form = request.GET.get('as_form', False)
304
303
305 c.org_ref = org_ref[1]
304 c.org_ref = org_ref[1]
306 c.other_ref = other_ref[1]
305 c.other_ref = other_ref[1]
307
306
308 diff_limit = self.cut_off_limit if not fulldiff else None
307 diff_limit = self.cut_off_limit if not fulldiff else None
309
308
310 #we swap org/other ref since we run a simple diff on one repo
309 #we swap org/other ref since we run a simple diff on one repo
311 _diff = diffs.differ(org_repo, other_ref, other_repo, org_ref)
310 _diff = diffs.differ(org_repo, other_ref, other_repo, org_ref)
312
311
313 diff_processor = diffs.DiffProcessor(_diff or '', format='gitdiff',
312 diff_processor = diffs.DiffProcessor(_diff or '', format='gitdiff',
314 diff_limit=diff_limit)
313 diff_limit=diff_limit)
315 _parsed = diff_processor.prepare()
314 _parsed = diff_processor.prepare()
316
315
317 c.limited_diff = False
316 c.limited_diff = False
318 if isinstance(_parsed, LimitedDiffContainer):
317 if isinstance(_parsed, LimitedDiffContainer):
319 c.limited_diff = True
318 c.limited_diff = True
320
319
321 c.files = []
320 c.files = []
322 c.changes = {}
321 c.changes = {}
323 c.lines_added = 0
322 c.lines_added = 0
324 c.lines_deleted = 0
323 c.lines_deleted = 0
325 for f in _parsed:
324 for f in _parsed:
326 st = f['stats']
325 st = f['stats']
327 if st[0] != 'b':
326 if st[0] != 'b':
328 c.lines_added += st[0]
327 c.lines_added += st[0]
329 c.lines_deleted += st[1]
328 c.lines_deleted += st[1]
330 fid = h.FID('', f['filename'])
329 fid = h.FID('', f['filename'])
331 c.files.append([fid, f['operation'], f['filename'], f['stats']])
330 c.files.append([fid, f['operation'], f['filename'], f['stats']])
332 diff = diff_processor.as_html(enable_comments=enable_comments,
331 diff = diff_processor.as_html(enable_comments=enable_comments,
333 parsed_lines=[f])
332 parsed_lines=[f])
334 c.changes[fid] = [f['operation'], f['filename'], diff]
333 c.changes[fid] = [f['operation'], f['filename'], diff]
335
334
336 def show(self, repo_name, pull_request_id):
335 def show(self, repo_name, pull_request_id):
337 repo_model = RepoModel()
336 repo_model = RepoModel()
338 c.users_array = repo_model.get_users_js()
337 c.users_array = repo_model.get_users_js()
339 c.users_groups_array = repo_model.get_users_groups_js()
338 c.users_groups_array = repo_model.get_users_groups_js()
340 c.pull_request = PullRequest.get_or_404(pull_request_id)
339 c.pull_request = PullRequest.get_or_404(pull_request_id)
341 c.allowed_to_change_status = self._get_is_allowed_change_status(c.pull_request)
340 c.allowed_to_change_status = self._get_is_allowed_change_status(c.pull_request)
342 cc_model = ChangesetCommentsModel()
341 cc_model = ChangesetCommentsModel()
343 cs_model = ChangesetStatusModel()
342 cs_model = ChangesetStatusModel()
344 _cs_statuses = cs_model.get_statuses(c.pull_request.org_repo,
343 _cs_statuses = cs_model.get_statuses(c.pull_request.org_repo,
345 pull_request=c.pull_request,
344 pull_request=c.pull_request,
346 with_revisions=True)
345 with_revisions=True)
347
346
348 cs_statuses = defaultdict(list)
347 cs_statuses = defaultdict(list)
349 for st in _cs_statuses:
348 for st in _cs_statuses:
350 cs_statuses[st.author.username] += [st]
349 cs_statuses[st.author.username] += [st]
351
350
352 c.pull_request_reviewers = []
351 c.pull_request_reviewers = []
353 c.pull_request_pending_reviewers = []
352 c.pull_request_pending_reviewers = []
354 for o in c.pull_request.reviewers:
353 for o in c.pull_request.reviewers:
355 st = cs_statuses.get(o.user.username, None)
354 st = cs_statuses.get(o.user.username, None)
356 if st:
355 if st:
357 sorter = lambda k: k.version
356 sorter = lambda k: k.version
358 st = [(x, list(y)[0])
357 st = [(x, list(y)[0])
359 for x, y in (groupby(sorted(st, key=sorter), sorter))]
358 for x, y in (groupby(sorted(st, key=sorter), sorter))]
360 else:
359 else:
361 c.pull_request_pending_reviewers.append(o.user)
360 c.pull_request_pending_reviewers.append(o.user)
362 c.pull_request_reviewers.append([o.user, st])
361 c.pull_request_reviewers.append([o.user, st])
363
362
364 # pull_requests repo_name we opened it against
363 # pull_requests repo_name we opened it against
365 # ie. other_repo must match
364 # ie. other_repo must match
366 if repo_name != c.pull_request.other_repo.repo_name:
365 if repo_name != c.pull_request.other_repo.repo_name:
367 raise HTTPNotFound
366 raise HTTPNotFound
368
367
369 # load compare data into template context
368 # load compare data into template context
370 enable_comments = not c.pull_request.is_closed()
369 enable_comments = not c.pull_request.is_closed()
371 self._load_compare_data(c.pull_request, enable_comments=enable_comments)
370 self._load_compare_data(c.pull_request, enable_comments=enable_comments)
372
371
373 # inline comments
372 # inline comments
374 c.inline_cnt = 0
373 c.inline_cnt = 0
375 c.inline_comments = cc_model.get_inline_comments(
374 c.inline_comments = cc_model.get_inline_comments(
376 c.rhodecode_db_repo.repo_id,
375 c.rhodecode_db_repo.repo_id,
377 pull_request=pull_request_id)
376 pull_request=pull_request_id)
378 # count inline comments
377 # count inline comments
379 for __, lines in c.inline_comments:
378 for __, lines in c.inline_comments:
380 for comments in lines.values():
379 for comments in lines.values():
381 c.inline_cnt += len(comments)
380 c.inline_cnt += len(comments)
382 # comments
381 # comments
383 c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id,
382 c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id,
384 pull_request=pull_request_id)
383 pull_request=pull_request_id)
385
384
386 try:
385 try:
387 cur_status = c.statuses[c.pull_request.revisions[0]][0]
386 cur_status = c.statuses[c.pull_request.revisions[0]][0]
388 except:
387 except:
389 log.error(traceback.format_exc())
388 log.error(traceback.format_exc())
390 cur_status = 'undefined'
389 cur_status = 'undefined'
391 if c.pull_request.is_closed() and 0:
390 if c.pull_request.is_closed() and 0:
392 c.current_changeset_status = cur_status
391 c.current_changeset_status = cur_status
393 else:
392 else:
394 # changeset(pull-request) status calulation based on reviewers
393 # changeset(pull-request) status calulation based on reviewers
395 c.current_changeset_status = cs_model.calculate_status(
394 c.current_changeset_status = cs_model.calculate_status(
396 c.pull_request_reviewers,
395 c.pull_request_reviewers,
397 )
396 )
398 c.changeset_statuses = ChangesetStatus.STATUSES
397 c.changeset_statuses = ChangesetStatus.STATUSES
399
398
400 return render('/pullrequests/pullrequest_show.html')
399 return render('/pullrequests/pullrequest_show.html')
401
400
402 @NotAnonymous()
401 @NotAnonymous()
403 @jsonify
402 @jsonify
404 def comment(self, repo_name, pull_request_id):
403 def comment(self, repo_name, pull_request_id):
405 pull_request = PullRequest.get_or_404(pull_request_id)
404 pull_request = PullRequest.get_or_404(pull_request_id)
406 if pull_request.is_closed():
405 if pull_request.is_closed():
407 raise HTTPForbidden()
406 raise HTTPForbidden()
408
407
409 status = request.POST.get('changeset_status')
408 status = request.POST.get('changeset_status')
410 change_status = request.POST.get('change_changeset_status')
409 change_status = request.POST.get('change_changeset_status')
411 text = request.POST.get('text')
410 text = request.POST.get('text')
412
411
413 allowed_to_change_status = self._get_is_allowed_change_status(pull_request)
412 allowed_to_change_status = self._get_is_allowed_change_status(pull_request)
414 if status and change_status and allowed_to_change_status:
413 if status and change_status and allowed_to_change_status:
415 text = text or (_('Status change -> %s')
414 text = text or (_('Status change -> %s')
416 % ChangesetStatus.get_status_lbl(status))
415 % ChangesetStatus.get_status_lbl(status))
417 comm = ChangesetCommentsModel().create(
416 comm = ChangesetCommentsModel().create(
418 text=text,
417 text=text,
419 repo=c.rhodecode_db_repo.repo_id,
418 repo=c.rhodecode_db_repo.repo_id,
420 user=c.rhodecode_user.user_id,
419 user=c.rhodecode_user.user_id,
421 pull_request=pull_request_id,
420 pull_request=pull_request_id,
422 f_path=request.POST.get('f_path'),
421 f_path=request.POST.get('f_path'),
423 line_no=request.POST.get('line'),
422 line_no=request.POST.get('line'),
424 status_change=(ChangesetStatus.get_status_lbl(status)
423 status_change=(ChangesetStatus.get_status_lbl(status)
425 if status and change_status and allowed_to_change_status else None)
424 if status and change_status and allowed_to_change_status else None)
426 )
425 )
427
426
428 action_logger(self.rhodecode_user,
427 action_logger(self.rhodecode_user,
429 'user_commented_pull_request:%s' % pull_request_id,
428 'user_commented_pull_request:%s' % pull_request_id,
430 c.rhodecode_db_repo, self.ip_addr, self.sa)
429 c.rhodecode_db_repo, self.ip_addr, self.sa)
431
430
432 if allowed_to_change_status:
431 if allowed_to_change_status:
433 # get status if set !
432 # get status if set !
434 if status and change_status:
433 if status and change_status:
435 ChangesetStatusModel().set_status(
434 ChangesetStatusModel().set_status(
436 c.rhodecode_db_repo.repo_id,
435 c.rhodecode_db_repo.repo_id,
437 status,
436 status,
438 c.rhodecode_user.user_id,
437 c.rhodecode_user.user_id,
439 comm,
438 comm,
440 pull_request=pull_request_id
439 pull_request=pull_request_id
441 )
440 )
442
441
443 if request.POST.get('save_close'):
442 if request.POST.get('save_close'):
444 if status in ['rejected', 'approved']:
443 if status in ['rejected', 'approved']:
445 PullRequestModel().close_pull_request(pull_request_id)
444 PullRequestModel().close_pull_request(pull_request_id)
446 action_logger(self.rhodecode_user,
445 action_logger(self.rhodecode_user,
447 'user_closed_pull_request:%s' % pull_request_id,
446 'user_closed_pull_request:%s' % pull_request_id,
448 c.rhodecode_db_repo, self.ip_addr, self.sa)
447 c.rhodecode_db_repo, self.ip_addr, self.sa)
449 else:
448 else:
450 h.flash(_('Closing pull request on other statuses than '
449 h.flash(_('Closing pull request on other statuses than '
451 'rejected or approved forbidden'),
450 'rejected or approved forbidden'),
452 category='warning')
451 category='warning')
453
452
454 Session().commit()
453 Session().commit()
455
454
456 if not request.environ.get('HTTP_X_PARTIAL_XHR'):
455 if not request.environ.get('HTTP_X_PARTIAL_XHR'):
457 return redirect(h.url('pullrequest_show', repo_name=repo_name,
456 return redirect(h.url('pullrequest_show', repo_name=repo_name,
458 pull_request_id=pull_request_id))
457 pull_request_id=pull_request_id))
459
458
460 data = {
459 data = {
461 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
460 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
462 }
461 }
463 if comm:
462 if comm:
464 c.co = comm
463 c.co = comm
465 data.update(comm.get_dict())
464 data.update(comm.get_dict())
466 data.update({'rendered_text':
465 data.update({'rendered_text':
467 render('changeset/changeset_comment_block.html')})
466 render('changeset/changeset_comment_block.html')})
468
467
469 return data
468 return data
470
469
471 @NotAnonymous()
470 @NotAnonymous()
472 @jsonify
471 @jsonify
473 def delete_comment(self, repo_name, comment_id):
472 def delete_comment(self, repo_name, comment_id):
474 co = ChangesetComment.get(comment_id)
473 co = ChangesetComment.get(comment_id)
475 if co.pull_request.is_closed():
474 if co.pull_request.is_closed():
476 #don't allow deleting comments on closed pull request
475 #don't allow deleting comments on closed pull request
477 raise HTTPForbidden()
476 raise HTTPForbidden()
478
477
479 owner = co.author.user_id == c.rhodecode_user.user_id
478 owner = co.author.user_id == c.rhodecode_user.user_id
480 if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
479 if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
481 ChangesetCommentsModel().delete(comment=co)
480 ChangesetCommentsModel().delete(comment=co)
482 Session().commit()
481 Session().commit()
483 return True
482 return True
484 else:
483 else:
485 raise HTTPForbidden()
484 raise HTTPForbidden()
@@ -1,202 +1,202
1 <%inherit file="/base/base.html"/>
1 <%inherit file="/base/base.html"/>
2
2
3 <%def name="title()">
3 <%def name="title()">
4 ${c.repo_name} ${_('New pull request')}
4 ${c.repo_name} ${_('New pull request')}
5 </%def>
5 </%def>
6
6
7 <%def name="breadcrumbs_links()">
7 <%def name="breadcrumbs_links()">
8 ${h.link_to(_(u'Home'),h.url('/'))}
8 ${h.link_to(_(u'Home'),h.url('/'))}
9 &raquo;
9 &raquo;
10 ${h.link_to(c.repo_name,h.url('changelog_home',repo_name=c.repo_name))}
10 ${h.link_to(c.repo_name,h.url('changelog_home',repo_name=c.repo_name))}
11 &raquo;
11 &raquo;
12 ${_('New pull request')}
12 ${_('New pull request')}
13 </%def>
13 </%def>
14
14
15 <%def name="main()">
15 <%def name="main()">
16
16
17 <div class="box">
17 <div class="box">
18 <!-- box / title -->
18 <!-- box / title -->
19 <div class="title">
19 <div class="title">
20 ${self.breadcrumbs()}
20 ${self.breadcrumbs()}
21 </div>
21 </div>
22 ${h.form(url('pullrequest', repo_name=c.repo_name), method='post', id='pull_request_form')}
22 ${h.form(url('pullrequest', repo_name=c.repo_name), method='post', id='pull_request_form')}
23 <div style="float:left;padding:0px 30px 30px 30px">
23 <div style="float:left;padding:0px 30px 30px 30px">
24 <input type="hidden" name="rev_start" value="${request.GET.get('rev_start')}" />
24 <input type="hidden" name="rev_start" value="${request.GET.get('rev_start')}" />
25 <input type="hidden" name="rev_end" value="${request.GET.get('rev_end')}" />
25 <input type="hidden" name="rev_end" value="${request.GET.get('rev_end')}" />
26
26
27 ##ORG
27 ##ORG
28 <div style="float:left">
28 <div style="float:left">
29 <div class="fork_user">
29 <div class="fork_user">
30 <div class="gravatar">
30 <div class="gravatar">
31 <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_db_repo.user.email,24)}"/>
31 <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_db_repo.user.email,24)}"/>
32 </div>
32 </div>
33 <span style="font-size: 20px">
33 <span style="font-size: 20px">
34 ${h.select('org_repo','',c.org_repos,class_='refs')}:${h.select('org_ref','',c.org_refs,class_='refs')}
34 ${h.select('org_repo','',c.org_repos,class_='refs')}:${h.select('org_ref','',c.org_refs,class_='refs')}
35 </span>
35 </span>
36 <div style="padding:5px 3px 3px 42px;">${c.rhodecode_db_repo.description}</div>
36 <div style="padding:5px 3px 3px 42px;">${c.rhodecode_db_repo.description}</div>
37 </div>
37 </div>
38 <div style="clear:both;padding-top: 10px"></div>
38 <div style="clear:both;padding-top: 10px"></div>
39 </div>
39 </div>
40 <div style="float:left;font-size:24px;padding:0px 20px">
40 <div style="float:left;font-size:24px;padding:0px 20px">
41 <img height=32 width=32 src="${h.url('/images/arrow_right_64.png')}"/>
41 <img height=32 width=32 src="${h.url('/images/arrow_right_64.png')}"/>
42 </div>
42 </div>
43
43
44 ##OTHER, most Probably the PARENT OF THIS FORK
44 ##OTHER, most Probably the PARENT OF THIS FORK
45 <div style="float:left">
45 <div style="float:left">
46 <div class="fork_user">
46 <div class="fork_user">
47 <div class="gravatar">
47 <div class="gravatar">
48 <img id="other_repo_gravatar" alt="gravatar" src=""/>
48 <img id="other_repo_gravatar" alt="gravatar" src=""/>
49 </div>
49 </div>
50 <span style="font-size: 20px">
50 <span style="font-size: 20px">
51 ${h.select('other_repo',c.default_pull_request,c.other_repos,class_='refs')}:${h.select('other_ref',c.default_pull_request_rev,c.default_revs,class_='refs')}
51 ${h.select('other_repo',c.default_other_repo,c.other_repos,class_='refs')}:${h.select('other_ref',c.default_other_ref,c.default_other_refs,class_='refs')}
52 </span>
52 </span>
53 <div id="other_repo_desc" style="padding:5px 3px 3px 42px;"></div>
53 <div id="other_repo_desc" style="padding:5px 3px 3px 42px;"></div>
54 </div>
54 </div>
55 <div style="clear:both;padding-top: 10px"></div>
55 <div style="clear:both;padding-top: 10px"></div>
56 </div>
56 </div>
57 <div style="clear:both;padding-top: 10px"></div>
57 <div style="clear:both;padding-top: 10px"></div>
58 ## overview pulled by ajax
58 ## overview pulled by ajax
59 <div style="float:left" id="pull_request_overview"></div>
59 <div style="float:left" id="pull_request_overview"></div>
60 <div style="float:left;clear:both;padding:10px 10px 10px 0px;display:none">
60 <div style="float:left;clear:both;padding:10px 10px 10px 0px;display:none">
61 <a id="pull_request_overview_url" href="#">${_('Detailed compare view')}</a>
61 <a id="pull_request_overview_url" href="#">${_('Detailed compare view')}</a>
62 </div>
62 </div>
63 </div>
63 </div>
64 <div style="float:left; border-left:1px dashed #eee">
64 <div style="float:left; border-left:1px dashed #eee">
65 <h4>${_('Pull request reviewers')}</h4>
65 <h4>${_('Pull request reviewers')}</h4>
66 <div id="reviewers" style="padding:0px 0px 0px 15px">
66 <div id="reviewers" style="padding:0px 0px 0px 15px">
67 ## members goes here !
67 ## members goes here !
68 <div class="group_members_wrap">
68 <div class="group_members_wrap">
69 <ul id="review_members" class="group_members">
69 <ul id="review_members" class="group_members">
70 %for member in c.review_members:
70 %for member in c.review_members:
71 <li id="reviewer_${member.user_id}">
71 <li id="reviewer_${member.user_id}">
72 <div class="reviewers_member">
72 <div class="reviewers_member">
73 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(member.email,14)}"/> </div>
73 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(member.email,14)}"/> </div>
74 <div style="float:left">${member.full_name} (${_('owner')})</div>
74 <div style="float:left">${member.full_name} (${_('owner')})</div>
75 <input type="hidden" value="${member.user_id}" name="review_members" />
75 <input type="hidden" value="${member.user_id}" name="review_members" />
76 <span class="delete_icon action_button" onclick="removeReviewer(${member.user_id})"></span>
76 <span class="delete_icon action_button" onclick="removeReviewer(${member.user_id})"></span>
77 </div>
77 </div>
78 </li>
78 </li>
79 %endfor
79 %endfor
80 </ul>
80 </ul>
81 </div>
81 </div>
82
82
83 <div class='ac'>
83 <div class='ac'>
84 <div class="reviewer_ac">
84 <div class="reviewer_ac">
85 ${h.text('user', class_='yui-ac-input')}
85 ${h.text('user', class_='yui-ac-input')}
86 <span class="help-block">${_('Add reviewer to this pull request.')}</span>
86 <span class="help-block">${_('Add reviewer to this pull request.')}</span>
87 <div id="reviewers_container"></div>
87 <div id="reviewers_container"></div>
88 </div>
88 </div>
89 </div>
89 </div>
90 </div>
90 </div>
91 </div>
91 </div>
92 <h3>${_('Create new pull request')}</h3>
92 <h3>${_('Create new pull request')}</h3>
93
93
94 <div class="form">
94 <div class="form">
95 <!-- fields -->
95 <!-- fields -->
96
96
97 <div class="fields">
97 <div class="fields">
98
98
99 <div class="field">
99 <div class="field">
100 <div class="label">
100 <div class="label">
101 <label for="pullrequest_title">${_('Title')}:</label>
101 <label for="pullrequest_title">${_('Title')}:</label>
102 </div>
102 </div>
103 <div class="input">
103 <div class="input">
104 ${h.text('pullrequest_title',size=30)}
104 ${h.text('pullrequest_title',size=30)}
105 </div>
105 </div>
106 </div>
106 </div>
107
107
108 <div class="field">
108 <div class="field">
109 <div class="label label-textarea">
109 <div class="label label-textarea">
110 <label for="pullrequest_desc">${_('description')}:</label>
110 <label for="pullrequest_desc">${_('description')}:</label>
111 </div>
111 </div>
112 <div class="textarea text-area editor">
112 <div class="textarea text-area editor">
113 ${h.textarea('pullrequest_desc',size=30)}
113 ${h.textarea('pullrequest_desc',size=30)}
114 </div>
114 </div>
115 </div>
115 </div>
116
116
117 <div class="buttons">
117 <div class="buttons">
118 ${h.submit('save',_('Send pull request'),class_="ui-btn large")}
118 ${h.submit('save',_('Send pull request'),class_="ui-btn large")}
119 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
119 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
120 </div>
120 </div>
121 </div>
121 </div>
122 </div>
122 </div>
123 ${h.end_form()}
123 ${h.end_form()}
124
124
125 </div>
125 </div>
126
126
127 <script type="text/javascript">
127 <script type="text/javascript">
128 var _USERS_AC_DATA = ${c.users_array|n};
128 var _USERS_AC_DATA = ${c.users_array|n};
129 var _GROUPS_AC_DATA = ${c.users_groups_array|n};
129 var _GROUPS_AC_DATA = ${c.users_groups_array|n};
130 PullRequestAutoComplete('user', 'reviewers_container', _USERS_AC_DATA, _GROUPS_AC_DATA);
130 PullRequestAutoComplete('user', 'reviewers_container', _USERS_AC_DATA, _GROUPS_AC_DATA);
131
131
132 var other_repos_info = ${c.other_repos_info|n};
132 var other_repos_info = ${c.other_repos_info|n};
133
133
134 var loadPreview = function(){
134 var loadPreview = function(){
135 YUD.setStyle(YUD.get('pull_request_overview_url').parentElement,'display','none');
135 YUD.setStyle(YUD.get('pull_request_overview_url').parentElement,'display','none');
136 //url template
136 //url template
137 var url = "${h.url('compare_url',
137 var url = "${h.url('compare_url',
138 repo_name='__other_repo__',
138 repo_name='__other_repo__',
139 org_ref_type='__other_ref_type__',
139 org_ref_type='__other_ref_type__',
140 org_ref='__other_ref__',
140 org_ref='__other_ref__',
141 other_repo='__org_repo__',
141 other_repo='__org_repo__',
142 other_ref_type='__org_ref_type__',
142 other_ref_type='__org_ref_type__',
143 other_ref='__org_ref__',
143 other_ref='__org_ref__',
144 as_form=True,
144 as_form=True,
145 rev_start=request.GET.get('rev_start',''),
145 rev_start=request.GET.get('rev_start',''),
146 rev_end=request.GET.get('rev_end',''))}";
146 rev_end=request.GET.get('rev_end',''))}";
147 var org_repo = YUQ('#pull_request_form #org_repo')[0].value;
147 var org_repo = YUQ('#pull_request_form #org_repo')[0].value;
148 var org_ref = YUQ('#pull_request_form #org_ref')[0].value.split(':');
148 var org_ref = YUQ('#pull_request_form #org_ref')[0].value.split(':');
149
149
150 var other_repo = YUQ('#pull_request_form #other_repo')[0].value;
150 var other_repo = YUQ('#pull_request_form #other_repo')[0].value;
151 var other_ref = YUQ('#pull_request_form #other_ref')[0].value.split(':');
151 var other_ref = YUQ('#pull_request_form #other_ref')[0].value.split(':');
152
152
153 var select_refs = YUQ('#pull_request_form select.refs')
153 var select_refs = YUQ('#pull_request_form select.refs')
154 var rev_data = {
154 var rev_data = {
155 'org_repo': org_repo,
155 'org_repo': org_repo,
156 'org_ref': org_ref[1],
156 'org_ref': org_ref[1],
157 'org_ref_type': org_ref[0],
157 'org_ref_type': org_ref[0],
158 'other_repo': other_repo,
158 'other_repo': other_repo,
159 'other_ref': other_ref[1],
159 'other_ref': other_ref[1],
160 'other_ref_type': other_ref[0],
160 'other_ref_type': other_ref[0],
161 }; // gather the org/other ref and repo here
161 }; // gather the org/other ref and repo here
162
162
163 for (k in rev_data){
163 for (k in rev_data){
164 url = url.replace('__'+k+'__',rev_data[k]);
164 url = url.replace('__'+k+'__',rev_data[k]);
165 }
165 }
166
166
167 ypjax(url,'pull_request_overview', function(data){
167 ypjax(url,'pull_request_overview', function(data){
168 var sel_box = YUQ('#pull_request_form #other_repo')[0];
168 var sel_box = YUQ('#pull_request_form #other_repo')[0];
169 var repo_name = sel_box.options[sel_box.selectedIndex].value;
169 var repo_name = sel_box.options[sel_box.selectedIndex].value;
170 YUD.get('pull_request_overview_url').href = url;
170 YUD.get('pull_request_overview_url').href = url;
171 YUD.setStyle(YUD.get('pull_request_overview_url').parentElement,'display','');
171 YUD.setStyle(YUD.get('pull_request_overview_url').parentElement,'display','');
172 YUD.get('other_repo_gravatar').src = other_repos_info[repo_name]['gravatar'];
172 YUD.get('other_repo_gravatar').src = other_repos_info[repo_name]['gravatar'];
173 YUD.get('other_repo_desc').innerHTML = other_repos_info[repo_name]['description'];
173 YUD.get('other_repo_desc').innerHTML = other_repos_info[repo_name]['description'];
174 YUD.get('other_ref').innerHTML = other_repos_info[repo_name]['revs'];
174 YUD.get('other_ref').innerHTML = other_repos_info[repo_name]['revs'];
175 // select back the revision that was just compared
175 // select back the revision that was just compared
176 setSelectValue(YUD.get('other_ref'), rev_data['other_ref']);
176 setSelectValue(YUD.get('other_ref'), rev_data['other_ref']);
177 })
177 })
178 }
178 }
179
179
180 ## refresh automatically when something changes (org_repo can't change)
180 ## refresh automatically when something changes (org_repo can't change)
181
181
182 YUE.on('org_ref', 'change', function(e){
182 YUE.on('org_ref', 'change', function(e){
183 loadPreview();
183 loadPreview();
184 });
184 });
185
185
186 YUE.on('other_repo', 'change', function(e){
186 YUE.on('other_repo', 'change', function(e){
187 var repo_name = e.currentTarget.value;
187 var repo_name = e.currentTarget.value;
188 // replace the <select> of changed repo
188 // replace the <select> of changed repo
189 YUD.get('other_ref').innerHTML = other_repos_info[repo_name]['revs'];
189 YUD.get('other_ref').innerHTML = other_repos_info[repo_name]['revs'];
190 loadPreview();
190 loadPreview();
191 });
191 });
192
192
193 YUE.on('other_ref', 'change', function(e){
193 YUE.on('other_ref', 'change', function(e){
194 loadPreview();
194 loadPreview();
195 });
195 });
196
196
197 //lazy load overview after 0.5s
197 //lazy load overview after 0.5s
198 setTimeout(loadPreview, 500)
198 setTimeout(loadPreview, 500)
199
199
200 </script>
200 </script>
201
201
202 </%def>
202 </%def>
General Comments 0
You need to be logged in to leave comments. Login now