##// END OF EJS Templates
better handling of EmptyChangeset case in cherry pick pull request
marcink -
r3387:bd5420ea beta
parent child Browse files
Show More
@@ -1,192 +1,192 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.compare
3 rhodecode.controllers.compare
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 compare controller for pylons showing differences between two
6 compare controller for pylons showing differences between two
7 repos, branches, bookmarks or tips
7 repos, branches, bookmarks or tips
8
8
9 :created_on: May 6, 2012
9 :created_on: May 6, 2012
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
12 :license: GPLv3, see COPYING for more details.
13 """
13 """
14 # This program is free software: you can redistribute it and/or modify
14 # This program is free software: you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation, either version 3 of the License, or
16 # the Free Software Foundation, either version 3 of the License, or
17 # (at your option) any later version.
17 # (at your option) any later version.
18 #
18 #
19 # This program is distributed in the hope that it will be useful,
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
22 # GNU General Public License for more details.
23 #
23 #
24 # You should have received a copy of the GNU General Public License
24 # You should have received a copy of the GNU General Public License
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 import logging
26 import logging
27 import traceback
27 import traceback
28
28
29 from webob.exc import HTTPNotFound
29 from webob.exc import HTTPNotFound
30 from pylons import request, response, session, tmpl_context as c, url
30 from pylons import request, response, session, tmpl_context as c, url
31 from pylons.controllers.util import abort, redirect
31 from pylons.controllers.util import abort, redirect
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33
33
34 from rhodecode.lib.vcs.exceptions import EmptyRepositoryError, RepositoryError
34 from rhodecode.lib.vcs.exceptions import EmptyRepositoryError, RepositoryError
35 from rhodecode.lib import helpers as h
35 from rhodecode.lib import helpers as h
36 from rhodecode.lib.base import BaseRepoController, render
36 from rhodecode.lib.base import BaseRepoController, render
37 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
37 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
38 from rhodecode.lib import diffs
38 from rhodecode.lib import diffs
39
39
40 from rhodecode.model.db import Repository
40 from rhodecode.model.db import Repository
41 from rhodecode.model.pull_request import PullRequestModel
41 from rhodecode.model.pull_request import PullRequestModel
42 from webob.exc import HTTPBadRequest
42 from webob.exc import HTTPBadRequest
43 from rhodecode.lib.diffs import LimitedDiffContainer
43 from rhodecode.lib.diffs import LimitedDiffContainer
44 from rhodecode.lib.vcs.backends.base import EmptyChangeset
44 from rhodecode.lib.vcs.backends.base import EmptyChangeset
45
45
46 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
47
47
48
48
49 class CompareController(BaseRepoController):
49 class CompareController(BaseRepoController):
50
50
51 @LoginRequired()
51 @LoginRequired()
52 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
52 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
53 'repository.admin')
53 'repository.admin')
54 def __before__(self):
54 def __before__(self):
55 super(CompareController, self).__before__()
55 super(CompareController, self).__before__()
56
56
57 def __get_cs_or_redirect(self, rev, repo, redirect_after=True,
57 def __get_cs_or_redirect(self, rev, repo, redirect_after=True,
58 partial=False):
58 partial=False):
59 """
59 """
60 Safe way to get changeset if error occur it redirects to changeset with
60 Safe way to get changeset if error occur it redirects to changeset with
61 proper message. If partial is set then don't do redirect raise Exception
61 proper message. If partial is set then don't do redirect raise Exception
62 instead
62 instead
63
63
64 :param rev: revision to fetch
64 :param rev: revision to fetch
65 :param repo: repo instance
65 :param repo: repo instance
66 """
66 """
67
67
68 try:
68 try:
69 type_, rev = rev
69 type_, rev = rev
70 return repo.scm_instance.get_changeset(rev)
70 return repo.scm_instance.get_changeset(rev)
71 except EmptyRepositoryError, e:
71 except EmptyRepositoryError, e:
72 if not redirect_after:
72 if not redirect_after:
73 return None
73 return None
74 h.flash(h.literal(_('There are no changesets yet')),
74 h.flash(h.literal(_('There are no changesets yet')),
75 category='warning')
75 category='warning')
76 redirect(url('summary_home', repo_name=repo.repo_name))
76 redirect(url('summary_home', repo_name=repo.repo_name))
77
77
78 except RepositoryError, e:
78 except RepositoryError, e:
79 log.error(traceback.format_exc())
79 log.error(traceback.format_exc())
80 h.flash(str(e), category='warning')
80 h.flash(str(e), category='warning')
81 if not partial:
81 if not partial:
82 redirect(h.url('summary_home', repo_name=repo.repo_name))
82 redirect(h.url('summary_home', repo_name=repo.repo_name))
83 raise HTTPBadRequest()
83 raise HTTPBadRequest()
84
84
85 def index(self, org_ref_type, org_ref, other_ref_type, other_ref):
85 def index(self, org_ref_type, org_ref, other_ref_type, other_ref):
86
86
87 org_repo = c.rhodecode_db_repo.repo_name
87 org_repo = c.rhodecode_db_repo.repo_name
88 org_ref = (org_ref_type, org_ref)
88 org_ref = (org_ref_type, org_ref)
89 other_ref = (other_ref_type, other_ref)
89 other_ref = (other_ref_type, other_ref)
90 other_repo = request.GET.get('other_repo', org_repo)
90 other_repo = request.GET.get('other_repo', org_repo)
91 c.fulldiff = fulldiff = request.GET.get('fulldiff')
91 c.fulldiff = fulldiff = request.GET.get('fulldiff')
92 rev_start = request.GET.get('rev_start')
92 rev_start = request.GET.get('rev_start')
93 rev_end = request.GET.get('rev_end')
93 rev_end = request.GET.get('rev_end')
94
94
95 c.swap_url = h.url('compare_url', as_form=request.GET.get('as_form'),
95 c.swap_url = h.url('compare_url', as_form=request.GET.get('as_form'),
96 repo_name=other_repo,
96 repo_name=other_repo,
97 org_ref_type=other_ref[0], org_ref=other_ref[1],
97 org_ref_type=other_ref[0], org_ref=other_ref[1],
98 other_repo=org_repo,
98 other_repo=org_repo,
99 other_ref_type=org_ref[0], other_ref=org_ref[1])
99 other_ref_type=org_ref[0], other_ref=org_ref[1])
100
100
101 partial = request.environ.get('HTTP_X_PARTIAL_XHR')
101 partial = request.environ.get('HTTP_X_PARTIAL_XHR')
102
102
103 org_repo = Repository.get_by_repo_name(org_repo)
103 org_repo = Repository.get_by_repo_name(org_repo)
104 other_repo = Repository.get_by_repo_name(other_repo)
104 other_repo = Repository.get_by_repo_name(other_repo)
105
105
106 self.__get_cs_or_redirect(rev=org_ref, repo=org_repo, partial=partial)
106 self.__get_cs_or_redirect(rev=org_ref, repo=org_repo, partial=partial)
107 self.__get_cs_or_redirect(rev=other_ref, repo=other_repo, partial=partial)
107 self.__get_cs_or_redirect(rev=other_ref, repo=other_repo, partial=partial)
108
108
109 if org_repo is None:
109 if org_repo is None:
110 log.error('Could not find org repo %s' % org_repo)
110 log.error('Could not find org repo %s' % org_repo)
111 raise HTTPNotFound
111 raise HTTPNotFound
112 if other_repo is None:
112 if other_repo is None:
113 log.error('Could not find other repo %s' % other_repo)
113 log.error('Could not find other repo %s' % other_repo)
114 raise HTTPNotFound
114 raise HTTPNotFound
115
115
116 if org_repo != other_repo and h.is_git(org_repo):
116 if org_repo != other_repo and h.is_git(org_repo):
117 log.error('compare of two remote repos not available for GIT REPOS')
117 log.error('compare of two remote repos not available for GIT REPOS')
118 raise HTTPNotFound
118 raise HTTPNotFound
119
119
120 if org_repo.scm_instance.alias != other_repo.scm_instance.alias:
120 if org_repo.scm_instance.alias != other_repo.scm_instance.alias:
121 log.error('compare of two different kind of remote repos not available')
121 log.error('compare of two different kind of remote repos not available')
122 raise HTTPNotFound
122 raise HTTPNotFound
123
123
124 c.org_repo = org_repo
124 c.org_repo = org_repo
125 c.other_repo = other_repo
125 c.other_repo = other_repo
126 c.org_ref = org_ref[1]
126 c.org_ref = org_ref[1]
127 c.other_ref = other_ref[1]
127 c.other_ref = other_ref[1]
128 c.org_ref_type = org_ref[0]
128 c.org_ref_type = org_ref[0]
129 c.other_ref_type = other_ref[0]
129 c.other_ref_type = other_ref[0]
130
130
131 if rev_start and rev_end:
131 if rev_start and rev_end:
132 # swap revs with cherry picked ones, save them for display
132 # swap revs with cherry picked ones, save them for display
133 #org_ref = ('rev', rev_start)
133 #org_ref = ('rev', rev_start)
134 #other_ref = ('rev', rev_end)
134 #other_ref = ('rev', rev_end)
135 c.org_ref = rev_start[:12]
135 c.org_ref = rev_start[:12]
136 c.other_ref = rev_end[:12]
136 c.other_ref = rev_end[:12]
137 # get parent of
137 # get parent of
138 # rev start to include it in the diff
138 # rev start to include it in the diff
139 _cs = other_repo.scm_instance.get_changeset(rev_start)
139 _cs = other_repo.scm_instance.get_changeset(rev_start)
140 rev_start = _cs.parents[0].raw_id if _cs.parents else EmptyChangeset()
140 rev_start = _cs.parents[0].raw_id if _cs.parents else EmptyChangeset().raw_id
141 org_ref = ('rev', rev_start)
141 org_ref = ('rev', rev_start)
142 other_ref = ('rev', rev_end)
142 other_ref = ('rev', rev_end)
143 #if we cherry pick it's not remote, make the other_repo org_repo
143 #if we cherry pick it's not remote, make the other_repo org_repo
144 org_repo = other_repo
144 org_repo = other_repo
145
145
146 c.cs_ranges, ancestor = PullRequestModel().get_compare_data(
146 c.cs_ranges, ancestor = PullRequestModel().get_compare_data(
147 org_repo, org_ref, other_repo, other_ref)
147 org_repo, org_ref, other_repo, other_ref)
148
148
149 c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
149 c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
150 c.cs_ranges])
150 c.cs_ranges])
151 # defines that we need hidden inputs with changesets
151 # defines that we need hidden inputs with changesets
152 c.as_form = request.GET.get('as_form', False)
152 c.as_form = request.GET.get('as_form', False)
153 if partial:
153 if partial:
154 return render('compare/compare_cs.html')
154 return render('compare/compare_cs.html')
155
155
156 if ancestor and org_repo != other_repo:
156 if ancestor and org_repo != other_repo:
157 # case we want a simple diff without incoming changesets,
157 # case we want a simple diff without incoming changesets,
158 # previewing what will be merged.
158 # previewing what will be merged.
159 # Make the diff on the forked repo, with
159 # Make the diff on the forked repo, with
160 # revision that is common ancestor
160 # revision that is common ancestor
161 log.debug('Using ancestor %s as org_ref instead of %s'
161 log.debug('Using ancestor %s as org_ref instead of %s'
162 % (ancestor, org_ref))
162 % (ancestor, org_ref))
163 org_ref = ('rev', ancestor)
163 org_ref = ('rev', ancestor)
164 org_repo = other_repo
164 org_repo = other_repo
165
165
166 diff_limit = self.cut_off_limit if not fulldiff else None
166 diff_limit = self.cut_off_limit if not fulldiff else None
167
167
168 _diff = diffs.differ(org_repo, org_ref, other_repo, other_ref)
168 _diff = diffs.differ(org_repo, org_ref, other_repo, other_ref)
169
169
170 diff_processor = diffs.DiffProcessor(_diff or '', format='gitdiff',
170 diff_processor = diffs.DiffProcessor(_diff or '', format='gitdiff',
171 diff_limit=diff_limit)
171 diff_limit=diff_limit)
172 _parsed = diff_processor.prepare()
172 _parsed = diff_processor.prepare()
173
173
174 c.limited_diff = False
174 c.limited_diff = False
175 if isinstance(_parsed, LimitedDiffContainer):
175 if isinstance(_parsed, LimitedDiffContainer):
176 c.limited_diff = True
176 c.limited_diff = True
177
177
178 c.files = []
178 c.files = []
179 c.changes = {}
179 c.changes = {}
180 c.lines_added = 0
180 c.lines_added = 0
181 c.lines_deleted = 0
181 c.lines_deleted = 0
182 for f in _parsed:
182 for f in _parsed:
183 st = f['stats']
183 st = f['stats']
184 if st[0] != 'b':
184 if st[0] != 'b':
185 c.lines_added += st[0]
185 c.lines_added += st[0]
186 c.lines_deleted += st[1]
186 c.lines_deleted += st[1]
187 fid = h.FID('', f['filename'])
187 fid = h.FID('', f['filename'])
188 c.files.append([fid, f['operation'], f['filename'], f['stats']])
188 c.files.append([fid, f['operation'], f['filename'], f['stats']])
189 diff = diff_processor.as_html(enable_comments=False, parsed_lines=[f])
189 diff = diff_processor.as_html(enable_comments=False, parsed_lines=[f])
190 c.changes[fid] = [f['operation'], f['filename'], diff]
190 c.changes[fid] = [f['operation'], f['filename'], diff]
191
191
192 return render('compare/compare_diff.html')
192 return render('compare/compare_diff.html')
@@ -1,248 +1,257 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 datetime
27 import datetime
28 import re
28 import re
29
29
30 from pylons.i18n.translation import _
30 from pylons.i18n.translation import _
31
31
32 from rhodecode.model.meta import Session
32 from rhodecode.model.meta import Session
33 from rhodecode.lib import helpers as h, unionrepo
33 from rhodecode.lib import helpers as h, unionrepo
34 from rhodecode.model import BaseModel
34 from rhodecode.model import BaseModel
35 from rhodecode.model.db import PullRequest, PullRequestReviewers, Notification,\
35 from rhodecode.model.db import PullRequest, PullRequestReviewers, Notification,\
36 ChangesetStatus
36 ChangesetStatus
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 scmutil
40 from rhodecode.lib.vcs.utils.hgcompat import scmutil
41 from rhodecode.lib.vcs.utils import safe_str
41 from rhodecode.lib.vcs.utils import safe_str
42 from rhodecode.lib.vcs.backends.base import EmptyChangeset
42
43
43 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
44
45
45
46
46 class PullRequestModel(BaseModel):
47 class PullRequestModel(BaseModel):
47
48
48 cls = PullRequest
49 cls = PullRequest
49
50
50 def __get_pull_request(self, pull_request):
51 def __get_pull_request(self, pull_request):
51 return self._get_instance(PullRequest, pull_request)
52 return self._get_instance(PullRequest, pull_request)
52
53
53 def get_all(self, repo):
54 def get_all(self, repo):
54 repo = self._get_repo(repo)
55 repo = self._get_repo(repo)
55 return PullRequest.query()\
56 return PullRequest.query()\
56 .filter(PullRequest.other_repo == repo)\
57 .filter(PullRequest.other_repo == repo)\
57 .order_by(PullRequest.created_on)\
58 .order_by(PullRequest.created_on)\
58 .all()
59 .all()
59
60
60 def create(self, created_by, org_repo, org_ref, other_repo, other_ref,
61 def create(self, created_by, org_repo, org_ref, other_repo, other_ref,
61 revisions, reviewers, title, description=None):
62 revisions, reviewers, title, description=None):
62 from rhodecode.model.changeset_status import ChangesetStatusModel
63 from rhodecode.model.changeset_status import ChangesetStatusModel
63
64
64 created_by_user = self._get_user(created_by)
65 created_by_user = self._get_user(created_by)
65 org_repo = self._get_repo(org_repo)
66 org_repo = self._get_repo(org_repo)
66 other_repo = self._get_repo(other_repo)
67 other_repo = self._get_repo(other_repo)
67
68
68 new = PullRequest()
69 new = PullRequest()
69 new.org_repo = org_repo
70 new.org_repo = org_repo
70 new.org_ref = org_ref
71 new.org_ref = org_ref
71 new.other_repo = other_repo
72 new.other_repo = other_repo
72 new.other_ref = other_ref
73 new.other_ref = other_ref
73 new.revisions = revisions
74 new.revisions = revisions
74 new.title = title
75 new.title = title
75 new.description = description
76 new.description = description
76 new.author = created_by_user
77 new.author = created_by_user
77 self.sa.add(new)
78 self.sa.add(new)
78 Session().flush()
79 Session().flush()
79 #members
80 #members
80 for member in reviewers:
81 for member in reviewers:
81 _usr = self._get_user(member)
82 _usr = self._get_user(member)
82 reviewer = PullRequestReviewers(_usr, new)
83 reviewer = PullRequestReviewers(_usr, new)
83 self.sa.add(reviewer)
84 self.sa.add(reviewer)
84
85
85 #reset state to under-review
86 #reset state to under-review
86 ChangesetStatusModel().set_status(
87 ChangesetStatusModel().set_status(
87 repo=org_repo,
88 repo=org_repo,
88 status=ChangesetStatus.STATUS_UNDER_REVIEW,
89 status=ChangesetStatus.STATUS_UNDER_REVIEW,
89 user=created_by_user,
90 user=created_by_user,
90 pull_request=new
91 pull_request=new
91 )
92 )
92
93
93 #notification to reviewers
94 #notification to reviewers
94 notif = NotificationModel()
95 notif = NotificationModel()
95
96
96 pr_url = h.url('pullrequest_show', repo_name=other_repo.repo_name,
97 pr_url = h.url('pullrequest_show', repo_name=other_repo.repo_name,
97 pull_request_id=new.pull_request_id,
98 pull_request_id=new.pull_request_id,
98 qualified=True,
99 qualified=True,
99 )
100 )
100 subject = safe_unicode(
101 subject = safe_unicode(
101 h.link_to(
102 h.link_to(
102 _('%(user)s wants you to review pull request #%(pr_id)s: %(pr_title)s') % \
103 _('%(user)s wants you to review pull request #%(pr_id)s: %(pr_title)s') % \
103 {'user': created_by_user.username,
104 {'user': created_by_user.username,
104 'pr_title': new.title,
105 'pr_title': new.title,
105 'pr_id': new.pull_request_id},
106 'pr_id': new.pull_request_id},
106 pr_url
107 pr_url
107 )
108 )
108 )
109 )
109 body = description
110 body = description
110 kwargs = {
111 kwargs = {
111 'pr_title': title,
112 'pr_title': title,
112 'pr_user_created': h.person(created_by_user.email),
113 'pr_user_created': h.person(created_by_user.email),
113 'pr_repo_url': h.url('summary_home', repo_name=other_repo.repo_name,
114 'pr_repo_url': h.url('summary_home', repo_name=other_repo.repo_name,
114 qualified=True,),
115 qualified=True,),
115 'pr_url': pr_url,
116 'pr_url': pr_url,
116 'pr_revisions': revisions
117 'pr_revisions': revisions
117 }
118 }
118 notif.create(created_by=created_by_user, subject=subject, body=body,
119 notif.create(created_by=created_by_user, subject=subject, body=body,
119 recipients=reviewers,
120 recipients=reviewers,
120 type_=Notification.TYPE_PULL_REQUEST, email_kwargs=kwargs)
121 type_=Notification.TYPE_PULL_REQUEST, email_kwargs=kwargs)
121 return new
122 return new
122
123
123 def update_reviewers(self, pull_request, reviewers_ids):
124 def update_reviewers(self, pull_request, reviewers_ids):
124 reviewers_ids = set(reviewers_ids)
125 reviewers_ids = set(reviewers_ids)
125 pull_request = self.__get_pull_request(pull_request)
126 pull_request = self.__get_pull_request(pull_request)
126 current_reviewers = PullRequestReviewers.query()\
127 current_reviewers = PullRequestReviewers.query()\
127 .filter(PullRequestReviewers.pull_request==
128 .filter(PullRequestReviewers.pull_request==
128 pull_request)\
129 pull_request)\
129 .all()
130 .all()
130 current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
131 current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
131
132
132 to_add = reviewers_ids.difference(current_reviewers_ids)
133 to_add = reviewers_ids.difference(current_reviewers_ids)
133 to_remove = current_reviewers_ids.difference(reviewers_ids)
134 to_remove = current_reviewers_ids.difference(reviewers_ids)
134
135
135 log.debug("Adding %s reviewers" % to_add)
136 log.debug("Adding %s reviewers" % to_add)
136 log.debug("Removing %s reviewers" % to_remove)
137 log.debug("Removing %s reviewers" % to_remove)
137
138
138 for uid in to_add:
139 for uid in to_add:
139 _usr = self._get_user(uid)
140 _usr = self._get_user(uid)
140 reviewer = PullRequestReviewers(_usr, pull_request)
141 reviewer = PullRequestReviewers(_usr, pull_request)
141 self.sa.add(reviewer)
142 self.sa.add(reviewer)
142
143
143 for uid in to_remove:
144 for uid in to_remove:
144 reviewer = PullRequestReviewers.query()\
145 reviewer = PullRequestReviewers.query()\
145 .filter(PullRequestReviewers.user_id==uid,
146 .filter(PullRequestReviewers.user_id==uid,
146 PullRequestReviewers.pull_request==pull_request)\
147 PullRequestReviewers.pull_request==pull_request)\
147 .scalar()
148 .scalar()
148 if reviewer:
149 if reviewer:
149 self.sa.delete(reviewer)
150 self.sa.delete(reviewer)
150
151
151 def delete(self, pull_request):
152 def delete(self, pull_request):
152 pull_request = self.__get_pull_request(pull_request)
153 pull_request = self.__get_pull_request(pull_request)
153 Session().delete(pull_request)
154 Session().delete(pull_request)
154
155
155 def close_pull_request(self, pull_request):
156 def close_pull_request(self, pull_request):
156 pull_request = self.__get_pull_request(pull_request)
157 pull_request = self.__get_pull_request(pull_request)
157 pull_request.status = PullRequest.STATUS_CLOSED
158 pull_request.status = PullRequest.STATUS_CLOSED
158 pull_request.updated_on = datetime.datetime.now()
159 pull_request.updated_on = datetime.datetime.now()
159 self.sa.add(pull_request)
160 self.sa.add(pull_request)
160
161
161 def _get_changesets(self, alias, org_repo, org_ref, other_repo, other_ref):
162 def _get_changesets(self, alias, org_repo, org_ref, other_repo, other_ref):
162 """
163 """
163 Returns a list of changesets that can be merged from org_repo@org_ref
164 Returns a list of changesets that can be merged from org_repo@org_ref
164 to other_repo@other_ref ... and the ancestor that would be used for merge
165 to other_repo@other_ref ... and the ancestor that would be used for merge
165
166
166 :param org_repo:
167 :param org_repo:
167 :param org_ref:
168 :param org_ref:
168 :param other_repo:
169 :param other_repo:
169 :param other_ref:
170 :param other_ref:
170 :param tmp:
171 :param tmp:
171 """
172 """
172
173
173 ancestor = None
174 ancestor = None
174
175
175 if alias == 'hg':
176 if alias == 'hg':
176 # lookup up the exact node id
177 # lookup up the exact node id
177 _revset_predicates = {
178 _revset_predicates = {
178 'branch': 'branch',
179 'branch': 'branch',
179 'book': 'bookmark',
180 'book': 'bookmark',
180 'tag': 'tag',
181 'tag': 'tag',
181 'rev': 'id',
182 'rev': 'id',
182 }
183 }
184
183 org_rev_spec = "%s('%s')" % (_revset_predicates[org_ref[0]],
185 org_rev_spec = "%s('%s')" % (_revset_predicates[org_ref[0]],
184 safe_str(org_ref[1]))
186 safe_str(org_ref[1]))
185 org_rev = scmutil.revsingle(org_repo._repo,
187 if org_ref[1] == EmptyChangeset().raw_id:
186 org_rev_spec)
188 org_rev = org_ref[1]
189 else:
190 org_rev = org_repo._repo[scmutil.revrange(org_repo._repo,
191 [org_rev_spec])[-1]]
187 other_rev_spec = "%s('%s')" % (_revset_predicates[other_ref[0]],
192 other_rev_spec = "%s('%s')" % (_revset_predicates[other_ref[0]],
188 safe_str(other_ref[1]))
193 safe_str(other_ref[1]))
189 other_rev = scmutil.revsingle(other_repo._repo, other_rev_spec)
194 if other_ref[1] == EmptyChangeset().raw_id:
195 other_rev = other_ref[1]
196 else:
197 other_rev = other_repo._repo[scmutil.revrange(other_repo._repo,
198 [other_rev_spec])[-1]]
190
199
191 #case two independent repos
200 #case two independent repos
192 if org_repo != other_repo:
201 if org_repo != other_repo:
193 hgrepo = unionrepo.unionrepository(other_repo.baseui,
202 hgrepo = unionrepo.unionrepository(other_repo.baseui,
194 other_repo.path,
203 other_repo.path,
195 org_repo.path)
204 org_repo.path)
196 # all the changesets we are looking for will be in other_repo,
205 # all the changesets we are looking for will be in other_repo,
197 # so rev numbers from hgrepo can be used in other_repo
206 # so rev numbers from hgrepo can be used in other_repo
198
207
199 #no remote compare do it on the same repository
208 #no remote compare do it on the same repository
200 else:
209 else:
201 hgrepo = other_repo._repo
210 hgrepo = other_repo._repo
202
211
203 revs = ["ancestors(id('%s')) and not ancestors(id('%s'))" %
212 revs = ["ancestors(id('%s')) and not ancestors(id('%s'))" %
204 (other_rev, org_rev)]
213 (other_rev, org_rev)]
205 changesets = [other_repo.get_changeset(cs)
214 changesets = [other_repo.get_changeset(cs)
206 for cs in scmutil.revrange(hgrepo, revs)]
215 for cs in scmutil.revrange(hgrepo, revs)]
207
216
208 if org_repo != other_repo:
217 if org_repo != other_repo:
209 ancestors = scmutil.revrange(hgrepo,
218 ancestors = scmutil.revrange(hgrepo,
210 ["ancestor(id('%s'), id('%s'))" % (org_rev, other_rev)])
219 ["ancestor(id('%s'), id('%s'))" % (org_rev, other_rev)])
211 if len(ancestors) == 1:
220 if len(ancestors) == 1:
212 ancestor = hgrepo[ancestors[0]].hex()
221 ancestor = hgrepo[ancestors[0]].hex()
213
222
214 elif alias == 'git':
223 elif alias == 'git':
215 assert org_repo == other_repo, (org_repo, other_repo) # no git support for different repos
224 assert org_repo == other_repo, (org_repo, other_repo) # no git support for different repos
216 so, se = org_repo.run_git_command(
225 so, se = org_repo.run_git_command(
217 'log --reverse --pretty="format: %%H" -s -p %s..%s' % (org_ref[1],
226 'log --reverse --pretty="format: %%H" -s -p %s..%s' % (org_ref[1],
218 other_ref[1])
227 other_ref[1])
219 )
228 )
220 changesets = [org_repo.get_changeset(cs)
229 changesets = [org_repo.get_changeset(cs)
221 for cs in re.findall(r'[0-9a-fA-F]{40}', so)]
230 for cs in re.findall(r'[0-9a-fA-F]{40}', so)]
222
231
223 return changesets, ancestor
232 return changesets, ancestor
224
233
225 def get_compare_data(self, org_repo, org_ref, other_repo, other_ref):
234 def get_compare_data(self, org_repo, org_ref, other_repo, other_ref):
226 """
235 """
227 Returns incoming changesets for mercurial repositories
236 Returns incoming changesets for mercurial repositories
228
237
229 :param org_repo:
238 :param org_repo:
230 :param org_ref:
239 :param org_ref:
231 :param other_repo:
240 :param other_repo:
232 :param other_ref:
241 :param other_ref:
233 """
242 """
234
243
235 if len(org_ref) != 2 or not isinstance(org_ref, (list, tuple)):
244 if len(org_ref) != 2 or not isinstance(org_ref, (list, tuple)):
236 raise Exception('org_ref must be a two element list/tuple')
245 raise Exception('org_ref must be a two element list/tuple')
237
246
238 if len(other_ref) != 2 or not isinstance(org_ref, (list, tuple)):
247 if len(other_ref) != 2 or not isinstance(org_ref, (list, tuple)):
239 raise Exception('other_ref must be a two element list/tuple')
248 raise Exception('other_ref must be a two element list/tuple')
240
249
241 org_repo_scm = org_repo.scm_instance
250 org_repo_scm = org_repo.scm_instance
242 other_repo_scm = other_repo.scm_instance
251 other_repo_scm = other_repo.scm_instance
243
252
244 alias = org_repo.scm_instance.alias
253 alias = org_repo.scm_instance.alias
245 cs_ranges, ancestor = self._get_changesets(alias,
254 cs_ranges, ancestor = self._get_changesets(alias,
246 org_repo_scm, org_ref,
255 org_repo_scm, org_ref,
247 other_repo_scm, other_ref)
256 other_repo_scm, other_ref)
248 return cs_ranges, ancestor
257 return cs_ranges, ancestor
General Comments 0
You need to be logged in to leave comments. Login now