##// END OF EJS Templates
fixes #668 cherry picking of changeset should also work now on picking single changesets, and the ones from top
marcink -
r3076:5deb16cd beta
parent child Browse files
Show More
@@ -1,280 +1,285 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 from rhodecode.model.notification import NotificationModel
37 from rhodecode.model.notification import NotificationModel
38 from rhodecode.lib.utils2 import safe_unicode
38 from rhodecode.lib.utils2 import safe_unicode
39
39
40 from rhodecode.lib.vcs.utils.hgcompat import discovery, localrepo, scmutil, \
40 from rhodecode.lib.vcs.utils.hgcompat import discovery, localrepo, scmutil, \
41 findcommonoutgoing
41 findcommonoutgoing
42
42
43 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
44
44
45
45
46 class PullRequestModel(BaseModel):
46 class PullRequestModel(BaseModel):
47
47
48 cls = PullRequest
48 cls = PullRequest
49
49
50 def __get_pull_request(self, pull_request):
50 def __get_pull_request(self, pull_request):
51 return self._get_instance(PullRequest, pull_request)
51 return self._get_instance(PullRequest, pull_request)
52
52
53 def get_all(self, repo):
53 def get_all(self, repo):
54 repo = self._get_repo(repo)
54 repo = self._get_repo(repo)
55 return PullRequest.query().filter(PullRequest.other_repo == repo).all()
55 return PullRequest.query().filter(PullRequest.other_repo == repo).all()
56
56
57 def create(self, created_by, org_repo, org_ref, other_repo,
57 def create(self, created_by, org_repo, org_ref, other_repo,
58 other_ref, revisions, reviewers, title, description=None):
58 other_ref, revisions, reviewers, title, description=None):
59
59
60 created_by_user = self._get_user(created_by)
60 created_by_user = self._get_user(created_by)
61 org_repo = self._get_repo(org_repo)
61 org_repo = self._get_repo(org_repo)
62 other_repo = self._get_repo(other_repo)
62 other_repo = self._get_repo(other_repo)
63
63
64 new = PullRequest()
64 new = PullRequest()
65 new.org_repo = org_repo
65 new.org_repo = org_repo
66 new.org_ref = org_ref
66 new.org_ref = org_ref
67 new.other_repo = other_repo
67 new.other_repo = other_repo
68 new.other_ref = other_ref
68 new.other_ref = other_ref
69 new.revisions = revisions
69 new.revisions = revisions
70 new.title = title
70 new.title = title
71 new.description = description
71 new.description = description
72 new.author = created_by_user
72 new.author = created_by_user
73 self.sa.add(new)
73 self.sa.add(new)
74 Session().flush()
74 Session().flush()
75 #members
75 #members
76 for member in reviewers:
76 for member in reviewers:
77 _usr = self._get_user(member)
77 _usr = self._get_user(member)
78 reviewer = PullRequestReviewers(_usr, new)
78 reviewer = PullRequestReviewers(_usr, new)
79 self.sa.add(reviewer)
79 self.sa.add(reviewer)
80
80
81 #notification to reviewers
81 #notification to reviewers
82 notif = NotificationModel()
82 notif = NotificationModel()
83
83
84 pr_url = h.url('pullrequest_show', repo_name=other_repo.repo_name,
84 pr_url = h.url('pullrequest_show', repo_name=other_repo.repo_name,
85 pull_request_id=new.pull_request_id,
85 pull_request_id=new.pull_request_id,
86 qualified=True,
86 qualified=True,
87 )
87 )
88 subject = safe_unicode(
88 subject = safe_unicode(
89 h.link_to(
89 h.link_to(
90 _('%(user)s wants you to review pull request #%(pr_id)s') % \
90 _('%(user)s wants you to review pull request #%(pr_id)s') % \
91 {'user': created_by_user.username,
91 {'user': created_by_user.username,
92 'pr_id': new.pull_request_id},
92 'pr_id': new.pull_request_id},
93 pr_url
93 pr_url
94 )
94 )
95 )
95 )
96 body = description
96 body = description
97 kwargs = {
97 kwargs = {
98 'pr_title': title,
98 'pr_title': title,
99 'pr_user_created': h.person(created_by_user.email),
99 'pr_user_created': h.person(created_by_user.email),
100 'pr_repo_url': h.url('summary_home', repo_name=other_repo.repo_name,
100 'pr_repo_url': h.url('summary_home', repo_name=other_repo.repo_name,
101 qualified=True,),
101 qualified=True,),
102 'pr_url': pr_url,
102 'pr_url': pr_url,
103 'pr_revisions': revisions
103 'pr_revisions': revisions
104 }
104 }
105 notif.create(created_by=created_by_user, subject=subject, body=body,
105 notif.create(created_by=created_by_user, subject=subject, body=body,
106 recipients=reviewers,
106 recipients=reviewers,
107 type_=Notification.TYPE_PULL_REQUEST, email_kwargs=kwargs)
107 type_=Notification.TYPE_PULL_REQUEST, email_kwargs=kwargs)
108 return new
108 return new
109
109
110 def update_reviewers(self, pull_request, reviewers_ids):
110 def update_reviewers(self, pull_request, reviewers_ids):
111 reviewers_ids = set(reviewers_ids)
111 reviewers_ids = set(reviewers_ids)
112 pull_request = self.__get_pull_request(pull_request)
112 pull_request = self.__get_pull_request(pull_request)
113 current_reviewers = PullRequestReviewers.query()\
113 current_reviewers = PullRequestReviewers.query()\
114 .filter(PullRequestReviewers.pull_request==
114 .filter(PullRequestReviewers.pull_request==
115 pull_request)\
115 pull_request)\
116 .all()
116 .all()
117 current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
117 current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
118
118
119 to_add = reviewers_ids.difference(current_reviewers_ids)
119 to_add = reviewers_ids.difference(current_reviewers_ids)
120 to_remove = current_reviewers_ids.difference(reviewers_ids)
120 to_remove = current_reviewers_ids.difference(reviewers_ids)
121
121
122 log.debug("Adding %s reviewers" % to_add)
122 log.debug("Adding %s reviewers" % to_add)
123 log.debug("Removing %s reviewers" % to_remove)
123 log.debug("Removing %s reviewers" % to_remove)
124
124
125 for uid in to_add:
125 for uid in to_add:
126 _usr = self._get_user(uid)
126 _usr = self._get_user(uid)
127 reviewer = PullRequestReviewers(_usr, pull_request)
127 reviewer = PullRequestReviewers(_usr, pull_request)
128 self.sa.add(reviewer)
128 self.sa.add(reviewer)
129
129
130 for uid in to_remove:
130 for uid in to_remove:
131 reviewer = PullRequestReviewers.query()\
131 reviewer = PullRequestReviewers.query()\
132 .filter(PullRequestReviewers.user_id==uid,
132 .filter(PullRequestReviewers.user_id==uid,
133 PullRequestReviewers.pull_request==pull_request)\
133 PullRequestReviewers.pull_request==pull_request)\
134 .scalar()
134 .scalar()
135 if reviewer:
135 if reviewer:
136 self.sa.delete(reviewer)
136 self.sa.delete(reviewer)
137
137
138 def delete(self, pull_request):
138 def delete(self, pull_request):
139 pull_request = self.__get_pull_request(pull_request)
139 pull_request = self.__get_pull_request(pull_request)
140 Session().delete(pull_request)
140 Session().delete(pull_request)
141
141
142 def close_pull_request(self, pull_request):
142 def close_pull_request(self, pull_request):
143 pull_request = self.__get_pull_request(pull_request)
143 pull_request = self.__get_pull_request(pull_request)
144 pull_request.status = PullRequest.STATUS_CLOSED
144 pull_request.status = PullRequest.STATUS_CLOSED
145 pull_request.updated_on = datetime.datetime.now()
145 pull_request.updated_on = datetime.datetime.now()
146 self.sa.add(pull_request)
146 self.sa.add(pull_request)
147
147
148 def _get_changesets(self, alias, org_repo, org_ref, other_repo, other_ref,
148 def _get_changesets(self, alias, org_repo, org_ref, other_repo, other_ref,
149 discovery_data):
149 discovery_data):
150 """
150 """
151 Returns a list of changesets that are incoming from org_repo@org_ref
151 Returns a list of changesets that are incoming from org_repo@org_ref
152 to other_repo@other_ref
152 to other_repo@other_ref
153
153
154 :param org_repo:
154 :param org_repo:
155 :param org_ref:
155 :param org_ref:
156 :param other_repo:
156 :param other_repo:
157 :param other_ref:
157 :param other_ref:
158 :param tmp:
158 :param tmp:
159 """
159 """
160
160
161 changesets = []
161 changesets = []
162 #case two independent repos
162 #case two independent repos
163 common, incoming, rheads = discovery_data
163 common, incoming, rheads = discovery_data
164 if org_repo != other_repo:
164 if org_repo != other_repo:
165 revs = [
165 revs = [
166 org_repo._repo.lookup(org_ref[1]),
166 org_repo._repo.lookup(org_ref[1]),
167 org_repo._repo.lookup(other_ref[1]),
167 org_repo._repo.lookup(other_ref[1]),
168 ]
168 ]
169
169
170 obj = findcommonoutgoing(org_repo._repo,
170 obj = findcommonoutgoing(org_repo._repo,
171 localrepo.locallegacypeer(other_repo._repo.local()),
171 localrepo.locallegacypeer(other_repo._repo.local()),
172 revs,
172 revs,
173 force=True)
173 force=True)
174 revs = obj.missing
174 revs = obj.missing
175
175
176 for cs in map(binascii.hexlify, revs):
176 for cs in map(binascii.hexlify, revs):
177 _cs = org_repo.get_changeset(cs)
177 _cs = org_repo.get_changeset(cs)
178 changesets.append(_cs)
178 changesets.append(_cs)
179 # in case we have revisions filter out the ones not in given range
180 if org_ref[0] == 'rev' and other_ref[0] == 'rev':
181 revs = [x.raw_id for x in changesets]
182 start = org_ref[1]
183 stop = other_ref[1]
184 changesets = changesets[revs.index(start):revs.index(stop) + 1]
179 else:
185 else:
180 #no remote compare do it on the same repository
186 #no remote compare do it on the same repository
181 if alias == 'hg':
187 if alias == 'hg':
182 _revset_predicates = {
188 _revset_predicates = {
183 'branch': 'branch',
189 'branch': 'branch',
184 'book': 'bookmark',
190 'book': 'bookmark',
185 'tag': 'tag',
191 'tag': 'tag',
186 'rev': 'id',
192 'rev': 'id',
187 }
193 }
188
194
189 revs = [
195 revs = [
190 "ancestors(%s('%s')) and not ancestors(%s('%s'))" % (
196 "ancestors(%s('%s')) and not ancestors(%s('%s'))" % (
191 _revset_predicates[other_ref[0]], other_ref[1],
197 _revset_predicates[other_ref[0]], other_ref[1],
192 _revset_predicates[org_ref[0]], org_ref[1],
198 _revset_predicates[org_ref[0]], org_ref[1],
193 )
199 )
194 ]
200 ]
195
201
196 out = scmutil.revrange(org_repo._repo, revs)
202 out = scmutil.revrange(org_repo._repo, revs)
197 for cs in (out):
203 for cs in (out):
198 changesets.append(org_repo.get_changeset(cs))
204 changesets.append(org_repo.get_changeset(cs))
199 elif alias == 'git':
205 elif alias == 'git':
200 so, se = org_repo.run_git_command(
206 so, se = org_repo.run_git_command(
201 'log --reverse --pretty="format: %%H" -s -p %s..%s' % (org_ref[1],
207 'log --reverse --pretty="format: %%H" -s -p %s..%s' % (org_ref[1],
202 other_ref[1])
208 other_ref[1])
203 )
209 )
204 ids = re.findall(r'[0-9a-fA-F]{40}', so)
210 ids = re.findall(r'[0-9a-fA-F]{40}', so)
205 for cs in (ids):
211 for cs in (ids):
206 changesets.append(org_repo.get_changeset(cs))
212 changesets.append(org_repo.get_changeset(cs))
207
213
208 return changesets
214 return changesets
209
215
210 def _get_discovery(self, org_repo, org_ref, other_repo, other_ref):
216 def _get_discovery(self, org_repo, org_ref, other_repo, other_ref):
211 """
217 """
212 Get's mercurial discovery data used to calculate difference between
218 Get's mercurial discovery data used to calculate difference between
213 repos and refs
219 repos and refs
214
220
215 :param org_repo:
221 :param org_repo:
216 :type org_repo:
222 :type org_repo:
217 :param org_ref:
223 :param org_ref:
218 :type org_ref:
224 :type org_ref:
219 :param other_repo:
225 :param other_repo:
220 :type other_repo:
226 :type other_repo:
221 :param other_ref:
227 :param other_ref:
222 :type other_ref:
228 :type other_ref:
223 """
229 """
224
230
225 _org_repo = org_repo._repo
231 _org_repo = org_repo._repo
226 org_rev_type, org_rev = org_ref
232 org_rev_type, org_rev = org_ref
227
233
228 _other_repo = other_repo._repo
234 _other_repo = other_repo._repo
229 other_rev_type, other_rev = other_ref
235 other_rev_type, other_rev = other_ref
230
236
231 log.debug('Doing discovery for %s@%s vs %s@%s' % (
237 log.debug('Doing discovery for %s@%s vs %s@%s' % (
232 org_repo, org_ref, other_repo, other_ref)
238 org_repo, org_ref, other_repo, other_ref)
233 )
239 )
234
240
235 #log.debug('Filter heads are %s[%s]' % ('', org_ref[1]))
241 #log.debug('Filter heads are %s[%s]' % ('', org_ref[1]))
236 org_peer = localrepo.locallegacypeer(_org_repo.local())
242 org_peer = localrepo.locallegacypeer(_org_repo.local())
237 tmp = discovery.findcommonincoming(
243 tmp = discovery.findcommonincoming(
238 repo=_other_repo, # other_repo we check for incoming
244 repo=_other_repo, # other_repo we check for incoming
239 remote=org_peer, # org_repo source for incoming
245 remote=org_peer, # org_repo source for incoming
240 # heads=[_other_repo[other_rev].node(),
246 # heads=[_other_repo[other_rev].node(),
241 # _org_repo[org_rev].node()],
247 # _org_repo[org_rev].node()],
242 force=True
248 force=True
243 )
249 )
244 return tmp
250 return tmp
245
251
246 def get_compare_data(self, org_repo, org_ref, other_repo, other_ref):
252 def get_compare_data(self, org_repo, org_ref, other_repo, other_ref):
247 """
253 """
248 Returns a tuple of incomming changesets, and discoverydata cache for
254 Returns a tuple of incomming changesets, and discoverydata cache for
249 mercurial repositories
255 mercurial repositories
250
256
251 :param org_repo:
257 :param org_repo:
252 :type org_repo:
258 :type org_repo:
253 :param org_ref:
259 :param org_ref:
254 :type org_ref:
260 :type org_ref:
255 :param other_repo:
261 :param other_repo:
256 :type other_repo:
262 :type other_repo:
257 :param other_ref:
263 :param other_ref:
258 :type other_ref:
264 :type other_ref:
259 """
265 """
260
266
261 if len(org_ref) != 2 or not isinstance(org_ref, (list, tuple)):
267 if len(org_ref) != 2 or not isinstance(org_ref, (list, tuple)):
262 raise Exception('org_ref must be a two element list/tuple')
268 raise Exception('org_ref must be a two element list/tuple')
263
269
264 if len(other_ref) != 2 or not isinstance(org_ref, (list, tuple)):
270 if len(other_ref) != 2 or not isinstance(org_ref, (list, tuple)):
265 raise Exception('other_ref must be a two element list/tuple')
271 raise Exception('other_ref must be a two element list/tuple')
266
272
267 org_repo_scm = org_repo.scm_instance
273 org_repo_scm = org_repo.scm_instance
268 other_repo_scm = other_repo.scm_instance
274 other_repo_scm = other_repo.scm_instance
269
275
270 alias = org_repo.scm_instance.alias
276 alias = org_repo.scm_instance.alias
271 discovery_data = [None, None, None]
277 discovery_data = [None, None, None]
272 if alias == 'hg':
278 if alias == 'hg':
273 discovery_data = self._get_discovery(org_repo_scm, org_ref,
279 discovery_data = self._get_discovery(org_repo_scm, org_ref,
274 other_repo_scm, other_ref)
280 other_repo_scm, other_ref)
275 cs_ranges = self._get_changesets(alias,
281 cs_ranges = self._get_changesets(alias,
276 org_repo_scm, org_ref,
282 org_repo_scm, org_ref,
277 other_repo_scm, other_ref,
283 other_repo_scm, other_ref,
278 discovery_data)
284 discovery_data)
279
280 return cs_ranges, discovery_data
285 return cs_ranges, discovery_data
@@ -1,305 +1,305 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2
2
3 <%inherit file="/base/base.html"/>
3 <%inherit file="/base/base.html"/>
4
4
5 <%def name="title()">
5 <%def name="title()">
6 ${_('%s Changelog') % c.repo_name} - ${c.rhodecode_name}
6 ${_('%s Changelog') % c.repo_name} - ${c.rhodecode_name}
7 </%def>
7 </%def>
8
8
9 <%def name="breadcrumbs_links()">
9 <%def name="breadcrumbs_links()">
10 ${h.link_to(_(u'Home'),h.url('/'))}
10 ${h.link_to(_(u'Home'),h.url('/'))}
11 &raquo;
11 &raquo;
12 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
12 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
13 &raquo;
13 &raquo;
14 <% size = c.size if c.size <= c.total_cs else c.total_cs %>
14 <% size = c.size if c.size <= c.total_cs else c.total_cs %>
15 ${_('Changelog')} - ${ungettext('showing %d out of %d revision', 'showing %d out of %d revisions', size) % (size, c.total_cs)}
15 ${_('Changelog')} - ${ungettext('showing %d out of %d revision', 'showing %d out of %d revisions', size) % (size, c.total_cs)}
16 </%def>
16 </%def>
17
17
18 <%def name="page_nav()">
18 <%def name="page_nav()">
19 ${self.menu('changelog')}
19 ${self.menu('changelog')}
20 </%def>
20 </%def>
21
21
22 <%def name="main()">
22 <%def name="main()">
23 <div class="box">
23 <div class="box">
24 <!-- box / title -->
24 <!-- box / title -->
25 <div class="title">
25 <div class="title">
26 ${self.breadcrumbs()}
26 ${self.breadcrumbs()}
27 </div>
27 </div>
28 <div class="table">
28 <div class="table">
29 % if c.pagination:
29 % if c.pagination:
30 <div id="graph">
30 <div id="graph">
31 <div id="graph_nodes">
31 <div id="graph_nodes">
32 <canvas id="graph_canvas"></canvas>
32 <canvas id="graph_canvas"></canvas>
33 </div>
33 </div>
34 <div id="graph_content">
34 <div id="graph_content">
35 <div class="info_box" style="clear: both;padding: 10px 6px;vertical-align: right;text-align: right;">
35 <div class="info_box" style="clear: both;padding: 10px 6px;vertical-align: right;text-align: right;">
36 <a href="#" class="ui-btn small" id="rev_range_container" style="display:none"></a>
36 <a href="#" class="ui-btn small" id="rev_range_container" style="display:none"></a>
37 <a href="#" class="ui-btn small" id="rev_range_clear" style="display:none">${_('Clear selection')}</a>
37 <a href="#" class="ui-btn small" id="rev_range_clear" style="display:none">${_('Clear selection')}</a>
38
38
39 %if c.rhodecode_db_repo.fork:
39 %if c.rhodecode_db_repo.fork:
40 <a title="${_('compare fork with %s' % c.rhodecode_db_repo.fork.repo_name)}" href="${h.url('compare_url',repo_name=c.repo_name,org_ref_type='branch',org_ref=request.GET.get('branch') or 'default',other_ref_type='branch',other_ref='default',repo=c.rhodecode_db_repo.fork.repo_name)}" class="ui-btn small">${_('Compare fork with parent')}</a>
40 <a title="${_('compare fork with %s' % c.rhodecode_db_repo.fork.repo_name)}" href="${h.url('compare_url',repo_name=c.repo_name,org_ref_type='branch',org_ref=request.GET.get('branch') or 'default',other_ref_type='branch',other_ref='default',repo=c.rhodecode_db_repo.fork.repo_name)}" class="ui-btn small">${_('Compare fork with parent')}</a>
41 %endif
41 %endif
42 %if h.is_hg(c.rhodecode_repo):
42 %if h.is_hg(c.rhodecode_repo):
43 <a id="open_new_pr" href="${h.url('pullrequest_home',repo_name=c.repo_name)}" class="ui-btn small">${_('Open new pull request')}</a>
43 <a id="open_new_pr" href="${h.url('pullrequest_home',repo_name=c.repo_name)}" class="ui-btn small">${_('Open new pull request')}</a>
44 %endif
44 %endif
45 </div>
45 </div>
46 <div class="container_header">
46 <div class="container_header">
47 ${h.form(h.url.current(),method='get')}
47 ${h.form(h.url.current(),method='get')}
48 <div class="info_box" style="float:left">
48 <div class="info_box" style="float:left">
49 ${h.submit('set',_('Show'),class_="ui-btn")}
49 ${h.submit('set',_('Show'),class_="ui-btn")}
50 ${h.text('size',size=1,value=c.size)}
50 ${h.text('size',size=1,value=c.size)}
51 ${_('revisions')}
51 ${_('revisions')}
52 </div>
52 </div>
53 ${h.end_form()}
53 ${h.end_form()}
54 <div style="float:right">${h.select('branch_filter',c.branch_name,c.branch_filters)}</div>
54 <div style="float:right">${h.select('branch_filter',c.branch_name,c.branch_filters)}</div>
55 </div>
55 </div>
56
56
57 %for cnt,cs in enumerate(c.pagination):
57 %for cnt,cs in enumerate(c.pagination):
58 <div id="chg_${cnt+1}" class="container ${'tablerow%s' % (cnt%2)}">
58 <div id="chg_${cnt+1}" class="container ${'tablerow%s' % (cnt%2)}">
59 <div class="left">
59 <div class="left">
60 <div>
60 <div>
61 ${h.checkbox(cs.raw_id,class_="changeset_range")}
61 ${h.checkbox(cs.raw_id,class_="changeset_range")}
62 <span class="tooltip" title="${h.tooltip(h.age(cs.date))}"><a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}"><span class="changeset_id">${cs.revision}:<span class="changeset_hash">${h.short_id(cs.raw_id)}</span></span></a></span>
62 <span class="tooltip" title="${h.tooltip(h.age(cs.date))}"><a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}"><span class="changeset_id">${cs.revision}:<span class="changeset_hash">${h.short_id(cs.raw_id)}</span></span></a></span>
63 </div>
63 </div>
64 <div class="author">
64 <div class="author">
65 <div class="gravatar">
65 <div class="gravatar">
66 <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),16)}"/>
66 <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),16)}"/>
67 </div>
67 </div>
68 <div title="${cs.author}" class="user">${h.shorter(h.person(cs.author),22)}</div>
68 <div title="${cs.author}" class="user">${h.shorter(h.person(cs.author),22)}</div>
69 </div>
69 </div>
70 <div class="date">${h.fmt_date(cs.date)}</div>
70 <div class="date">${h.fmt_date(cs.date)}</div>
71 </div>
71 </div>
72 <div class="mid">
72 <div class="mid">
73 <div class="message">${h.urlify_commit(cs.message, c.repo_name,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div>
73 <div class="message">${h.urlify_commit(cs.message, c.repo_name,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div>
74 <div class="expand"><span class="expandtext">&darr; ${_('show more')} &darr;</span></div>
74 <div class="expand"><span class="expandtext">&darr; ${_('show more')} &darr;</span></div>
75 </div>
75 </div>
76 <div class="right">
76 <div class="right">
77 <div class="changes">
77 <div class="changes">
78 <div id="changed_total_${cs.raw_id}" style="float:right;" class="changed_total tooltip" title="${h.tooltip(_('Affected number of files, click to show more details'))}">${len(cs.affected_files)}</div>
78 <div id="changed_total_${cs.raw_id}" style="float:right;" class="changed_total tooltip" title="${h.tooltip(_('Affected number of files, click to show more details'))}">${len(cs.affected_files)}</div>
79 <div class="comments-container">
79 <div class="comments-container">
80 %if len(c.comments.get(cs.raw_id,[])) > 0:
80 %if len(c.comments.get(cs.raw_id,[])) > 0:
81 <div class="comments-cnt" title="${('comments')}">
81 <div class="comments-cnt" title="${('comments')}">
82 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id,anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}">
82 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id,anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}">
83 <div class="comments-cnt">${len(c.comments[cs.raw_id])}</div>
83 <div class="comments-cnt">${len(c.comments[cs.raw_id])}</div>
84 <img src="${h.url('/images/icons/comments.png')}">
84 <img src="${h.url('/images/icons/comments.png')}">
85 </a>
85 </a>
86 </div>
86 </div>
87 %endif
87 %endif
88 </div>
88 </div>
89 <div class="changeset-status-container">
89 <div class="changeset-status-container">
90 %if c.statuses.get(cs.raw_id):
90 %if c.statuses.get(cs.raw_id):
91 <div title="${_('Changeset status')}" class="changeset-status-lbl">${c.statuses.get(cs.raw_id)[1]}</div>
91 <div title="${_('Changeset status')}" class="changeset-status-lbl">${c.statuses.get(cs.raw_id)[1]}</div>
92 <div class="changeset-status-ico">
92 <div class="changeset-status-ico">
93 %if c.statuses.get(cs.raw_id)[2]:
93 %if c.statuses.get(cs.raw_id)[2]:
94 <a class="tooltip" title="${_('Click to open associated pull request')}" href="${h.url('pullrequest_show',repo_name=c.statuses.get(cs.raw_id)[3],pull_request_id=c.statuses.get(cs.raw_id)[2])}"><img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" /></a>
94 <a class="tooltip" title="${_('Click to open associated pull request')}" href="${h.url('pullrequest_show',repo_name=c.statuses.get(cs.raw_id)[3],pull_request_id=c.statuses.get(cs.raw_id)[2])}"><img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" /></a>
95 %else:
95 %else:
96 <img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" />
96 <img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" />
97 %endif
97 %endif
98 </div>
98 </div>
99 %endif
99 %endif
100 </div>
100 </div>
101 </div>
101 </div>
102 %if cs.parents:
102 %if cs.parents:
103 %for p_cs in reversed(cs.parents):
103 %for p_cs in reversed(cs.parents):
104 <div class="parent">${_('Parent')}
104 <div class="parent">${_('Parent')}
105 <span class="changeset_id">${p_cs.revision}:<span class="changeset_hash">${h.link_to(h.short_id(p_cs.raw_id),
105 <span class="changeset_id">${p_cs.revision}:<span class="changeset_hash">${h.link_to(h.short_id(p_cs.raw_id),
106 h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}</span></span>
106 h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}</span></span>
107 </div>
107 </div>
108 %endfor
108 %endfor
109 %else:
109 %else:
110 <div class="parent">${_('No parents')}</div>
110 <div class="parent">${_('No parents')}</div>
111 %endif
111 %endif
112
112
113 <span class="logtags">
113 <span class="logtags">
114 %if len(cs.parents)>1:
114 %if len(cs.parents)>1:
115 <span class="merge">${_('merge')}</span>
115 <span class="merge">${_('merge')}</span>
116 %endif
116 %endif
117 %if cs.branch:
117 %if cs.branch:
118 <span class="branchtag" title="${'%s %s' % (_('branch'),cs.branch)}">
118 <span class="branchtag" title="${'%s %s' % (_('branch'),cs.branch)}">
119 ${h.link_to(h.shorter(cs.branch),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
119 ${h.link_to(h.shorter(cs.branch),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
120 </span>
120 </span>
121 %endif
121 %endif
122 %if h.is_hg(c.rhodecode_repo):
122 %if h.is_hg(c.rhodecode_repo):
123 %for book in cs.bookmarks:
123 %for book in cs.bookmarks:
124 <span class="bookbook" title="${'%s %s' % (_('bookmark'),book)}">
124 <span class="bookbook" title="${'%s %s' % (_('bookmark'),book)}">
125 ${h.link_to(h.shorter(book),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
125 ${h.link_to(h.shorter(book),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
126 </span>
126 </span>
127 %endfor
127 %endfor
128 %endif
128 %endif
129 %for tag in cs.tags:
129 %for tag in cs.tags:
130 <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}">
130 <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}">
131 ${h.link_to(h.shorter(tag),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span>
131 ${h.link_to(h.shorter(tag),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span>
132 %endfor
132 %endfor
133 </span>
133 </span>
134 </div>
134 </div>
135 </div>
135 </div>
136
136
137 %endfor
137 %endfor
138 <div class="pagination-wh pagination-left">
138 <div class="pagination-wh pagination-left">
139 ${c.pagination.pager('$link_previous ~2~ $link_next')}
139 ${c.pagination.pager('$link_previous ~2~ $link_next')}
140 </div>
140 </div>
141 </div>
141 </div>
142 </div>
142 </div>
143
143
144 <script type="text/javascript" src="${h.url('/js/graph.js')}"></script>
144 <script type="text/javascript" src="${h.url('/js/graph.js')}"></script>
145 <script type="text/javascript">
145 <script type="text/javascript">
146 YAHOO.util.Event.onDOMReady(function(){
146 YAHOO.util.Event.onDOMReady(function(){
147
147
148 //Monitor range checkboxes and build a link to changesets
148 //Monitor range checkboxes and build a link to changesets
149 //ranges
149 //ranges
150 var checkboxes = YUD.getElementsByClassName('changeset_range');
150 var checkboxes = YUD.getElementsByClassName('changeset_range');
151 var url_tmpl = "${h.url('changeset_home',repo_name=c.repo_name,revision='__REVRANGE__')}";
151 var url_tmpl = "${h.url('changeset_home',repo_name=c.repo_name,revision='__REVRANGE__')}";
152 YUE.on(checkboxes,'click',function(e){
152 YUE.on(checkboxes,'click',function(e){
153 var clicked_cb = e.currentTarget;
153 var clicked_cb = e.currentTarget;
154 var checked_checkboxes = [];
154 var checked_checkboxes = [];
155 for (pos in checkboxes){
155 for (pos in checkboxes){
156 if(checkboxes[pos].checked){
156 if(checkboxes[pos].checked){
157 checked_checkboxes.push(checkboxes[pos]);
157 checked_checkboxes.push(checkboxes[pos]);
158 }
158 }
159 }
159 }
160 if(YUD.get('open_new_pr')){
160 if(YUD.get('open_new_pr')){
161 if(checked_checkboxes.length>0){
161 if(checked_checkboxes.length>0){
162 // modify open pull request to show we have selected cs
162 // modify open pull request to show we have selected cs
163 YUD.get('open_new_pr').innerHTML = _TM['Open new pull request for selected changesets'];
163 YUD.get('open_new_pr').innerHTML = _TM['Open new pull request for selected changesets'];
164
164
165 }else{
165 }else{
166 YUD.get('open_new_pr').innerHTML = _TM['Open new pull request'];
166 YUD.get('open_new_pr').innerHTML = _TM['Open new pull request'];
167 }
167 }
168 }
168 }
169
169
170 if(checked_checkboxes.length>1){
170 if(checked_checkboxes.length>0){
171 var rev_end = checked_checkboxes[0].name;
171 var rev_end = checked_checkboxes[0].name;
172 var rev_start = checked_checkboxes[checked_checkboxes.length-1].name;
172 var rev_start = checked_checkboxes[checked_checkboxes.length-1].name;
173
173
174 // now select all checkboxes in the middle.
174 // now select all checkboxes in the middle.
175 var checked = false;
175 var checked = false;
176 for (var i=0; i<checkboxes.length; i++){
176 for (var i=0; i<checkboxes.length; i++){
177 var cb = checkboxes[i];
177 var cb = checkboxes[i];
178 var rev = cb.name;
178 var rev = cb.name;
179
179
180 if (rev == rev_end){
180 if (rev == rev_end){
181 checked = true;
181 checked = true;
182 }
182 }
183 if (checked){
183 if (checked){
184 cb.checked = true;
184 cb.checked = true;
185 }
185 }
186 else{
186 else{
187 cb.checked = false;
187 cb.checked = false;
188 }
188 }
189 if (rev == rev_start){
189 if (rev == rev_start){
190 checked = false;
190 checked = false;
191 }
191 }
192
192
193 }
193 }
194
194
195 var url = url_tmpl.replace('__REVRANGE__',
195 var url = url_tmpl.replace('__REVRANGE__',
196 rev_start+'...'+rev_end);
196 rev_start+'...'+rev_end);
197
197
198 var link = _TM['Show selected changes __S -> __E'];
198 var link = _TM['Show selected changes __S -> __E'];
199 link = link.replace('__S',rev_start.substr(0,6));
199 link = link.replace('__S',rev_start.substr(0,6));
200 link = link.replace('__E',rev_end.substr(0,6));
200 link = link.replace('__E',rev_end.substr(0,6));
201 YUD.get('rev_range_container').href = url;
201 YUD.get('rev_range_container').href = url;
202 YUD.get('rev_range_container').innerHTML = link;
202 YUD.get('rev_range_container').innerHTML = link;
203 YUD.setStyle('rev_range_container','display','');
203 YUD.setStyle('rev_range_container','display','');
204 YUD.setStyle('rev_range_clear','display','');
204 YUD.setStyle('rev_range_clear','display','');
205
205
206 YUD.get('open_new_pr').href += '?rev_start={0}&rev_end={1}'.format(rev_start,rev_end);
206 YUD.get('open_new_pr').href += '?rev_start={0}&rev_end={1}'.format(rev_start,rev_end);
207
207
208 }
208 }
209 else{
209 else{
210 YUD.setStyle('rev_range_container','display','none');
210 YUD.setStyle('rev_range_container','display','none');
211 YUD.setStyle('rev_range_clear','display','none');
211 YUD.setStyle('rev_range_clear','display','none');
212 }
212 }
213 });
213 });
214 YUE.on('rev_range_clear','click',function(e){
214 YUE.on('rev_range_clear','click',function(e){
215 for (var i=0; i<checkboxes.length; i++){
215 for (var i=0; i<checkboxes.length; i++){
216 var cb = checkboxes[i];
216 var cb = checkboxes[i];
217 cb.checked = false;
217 cb.checked = false;
218 }
218 }
219 YUE.preventDefault(e);
219 YUE.preventDefault(e);
220 })
220 })
221 var msgs = YUQ('.message');
221 var msgs = YUQ('.message');
222 // get first element height
222 // get first element height
223 var el = YUQ('#graph_content .container')[0];
223 var el = YUQ('#graph_content .container')[0];
224 var row_h = el.clientHeight;
224 var row_h = el.clientHeight;
225 for(var i=0;i<msgs.length;i++){
225 for(var i=0;i<msgs.length;i++){
226 var m = msgs[i];
226 var m = msgs[i];
227
227
228 var h = m.clientHeight;
228 var h = m.clientHeight;
229 var pad = YUD.getStyle(m,'padding');
229 var pad = YUD.getStyle(m,'padding');
230 if(h > row_h){
230 if(h > row_h){
231 var offset = row_h - (h+12);
231 var offset = row_h - (h+12);
232 YUD.setStyle(m.nextElementSibling,'display','block');
232 YUD.setStyle(m.nextElementSibling,'display','block');
233 YUD.setStyle(m.nextElementSibling,'margin-top',offset+'px');
233 YUD.setStyle(m.nextElementSibling,'margin-top',offset+'px');
234 };
234 };
235 }
235 }
236 YUE.on(YUQ('.expand'),'click',function(e){
236 YUE.on(YUQ('.expand'),'click',function(e){
237 var elem = e.currentTarget.parentNode.parentNode;
237 var elem = e.currentTarget.parentNode.parentNode;
238 YUD.setStyle(e.currentTarget,'display','none');
238 YUD.setStyle(e.currentTarget,'display','none');
239 YUD.setStyle(elem,'height','auto');
239 YUD.setStyle(elem,'height','auto');
240
240
241 //redraw the graph, line_count and jsdata are global vars
241 //redraw the graph, line_count and jsdata are global vars
242 set_canvas(100);
242 set_canvas(100);
243
243
244 var r = new BranchRenderer();
244 var r = new BranchRenderer();
245 r.render(jsdata,100,line_count);
245 r.render(jsdata,100,line_count);
246
246
247 })
247 })
248
248
249 // Fetch changeset details
249 // Fetch changeset details
250 YUE.on(YUD.getElementsByClassName('changed_total'),'click',function(e){
250 YUE.on(YUD.getElementsByClassName('changed_total'),'click',function(e){
251 var id = e.currentTarget.id;
251 var id = e.currentTarget.id;
252 var url = "${h.url('changelog_details',repo_name=c.repo_name,cs='__CS__')}";
252 var url = "${h.url('changelog_details',repo_name=c.repo_name,cs='__CS__')}";
253 var url = url.replace('__CS__',id.replace('changed_total_',''));
253 var url = url.replace('__CS__',id.replace('changed_total_',''));
254 ypjax(url,id,function(){tooltip_activate()});
254 ypjax(url,id,function(){tooltip_activate()});
255 });
255 });
256
256
257 // change branch filter
257 // change branch filter
258 YUE.on(YUD.get('branch_filter'),'change',function(e){
258 YUE.on(YUD.get('branch_filter'),'change',function(e){
259 var selected_branch = e.currentTarget.options[e.currentTarget.selectedIndex].value;
259 var selected_branch = e.currentTarget.options[e.currentTarget.selectedIndex].value;
260 var url_main = "${h.url('changelog_home',repo_name=c.repo_name)}";
260 var url_main = "${h.url('changelog_home',repo_name=c.repo_name)}";
261 var url = "${h.url('changelog_home',repo_name=c.repo_name,branch='__BRANCH__')}";
261 var url = "${h.url('changelog_home',repo_name=c.repo_name,branch='__BRANCH__')}";
262 var url = url.replace('__BRANCH__',selected_branch);
262 var url = url.replace('__BRANCH__',selected_branch);
263 if(selected_branch != ''){
263 if(selected_branch != ''){
264 window.location = url;
264 window.location = url;
265 }else{
265 }else{
266 window.location = url_main;
266 window.location = url_main;
267 }
267 }
268
268
269 });
269 });
270
270
271 function set_canvas(width) {
271 function set_canvas(width) {
272 var c = document.getElementById('graph_nodes');
272 var c = document.getElementById('graph_nodes');
273 var t = document.getElementById('graph_content');
273 var t = document.getElementById('graph_content');
274 canvas = document.getElementById('graph_canvas');
274 canvas = document.getElementById('graph_canvas');
275 var div_h = t.clientHeight;
275 var div_h = t.clientHeight;
276 c.style.height=div_h+'px';
276 c.style.height=div_h+'px';
277 canvas.setAttribute('height',div_h);
277 canvas.setAttribute('height',div_h);
278 c.style.height=width+'px';
278 c.style.height=width+'px';
279 canvas.setAttribute('width',width);
279 canvas.setAttribute('width',width);
280 };
280 };
281 var heads = 1;
281 var heads = 1;
282 var line_count = 0;
282 var line_count = 0;
283 var jsdata = ${c.jsdata|n};
283 var jsdata = ${c.jsdata|n};
284
284
285 for (var i=0;i<jsdata.length;i++) {
285 for (var i=0;i<jsdata.length;i++) {
286 var in_l = jsdata[i][2];
286 var in_l = jsdata[i][2];
287 for (var j in in_l) {
287 for (var j in in_l) {
288 var m = in_l[j][1];
288 var m = in_l[j][1];
289 if (m > line_count)
289 if (m > line_count)
290 line_count = m;
290 line_count = m;
291 }
291 }
292 }
292 }
293 set_canvas(100);
293 set_canvas(100);
294
294
295 var r = new BranchRenderer();
295 var r = new BranchRenderer();
296 r.render(jsdata,100,line_count);
296 r.render(jsdata,100,line_count);
297
297
298 });
298 });
299 </script>
299 </script>
300 %else:
300 %else:
301 ${_('There are no changes yet')}
301 ${_('There are no changes yet')}
302 %endif
302 %endif
303 </div>
303 </div>
304 </div>
304 </div>
305 </%def>
305 </%def>
General Comments 0
You need to be logged in to leave comments. Login now