9404.1.2
by Jonathan Lange
start hacking on autoland. |
1 |
"""Land an approved merge proposal."""
|
2 |
||
10430.2.1
by Brad Crittenden
Fixed comparison between launchpad._root_uri and *_SERVICE_ROOT to account for the fact the former has a version tacked onto it now. |
3 |
from launchpadlib.launchpad import Launchpad |
4 |
from launchpadlib.uris import ( |
|
5 |
DEV_SERVICE_ROOT, EDGE_SERVICE_ROOT, LPNET_SERVICE_ROOT, |
|
6 |
STAGING_SERVICE_ROOT) |
|
9404.1.2
by Jonathan Lange
start hacking on autoland. |
7 |
from lazr.uri import URI |
9644.4.1
by Brad Crittenden
Make ec2 land figure out the merge proposal based on the current branch. |
8 |
from bzrlib.errors import BzrCommandError |
9 |
||
9404.1.2
by Jonathan Lange
start hacking on autoland. |
10 |
|
9404.1.29
by Jonathan Lange
Handle the case when there are no reviewers. |
11 |
class MissingReviewError(Exception): |
12 |
"""Raised when we try to get a review message without enough reviewers."""
|
|
9404.1.2
by Jonathan Lange
start hacking on autoland. |
13 |
|
14 |
||
11079.1.1
by Ursula Junque (Ursinha)
Added the no_qa parameter and how to deal with it in the get_commit_message method. Added an exception class to describe this error: MissingBugsError. |
15 |
class MissingBugsError(Exception): |
11079.1.15
by Ursula Junque (Ursinha)
changed all variables and options from incr to incremental, more self explainable; raising MissingBugs exceptions without a message |
16 |
"""Merge proposal has no linked bugs and no [no-qa] tag."""
|
17 |
||
18 |
||
19 |
class MissingBugsIncrementalError(Exception): |
|
20 |
"""Merge proposal has the [incr] tag but no linked bugs."""
|
|
11079.1.6
by Ursula Junque (Ursinha)
Adding MissingBugsIncrError exception and incr commit tag to the check_qa_clauses method, now changed to check both tags, no-qa and incr. |
21 |
|
22 |
||
9404.1.2
by Jonathan Lange
start hacking on autoland. |
23 |
class LaunchpadBranchLander: |
24 |
||
25 |
name = 'launchpad-branch-lander' |
|
26 |
||
27 |
def __init__(self, launchpad): |
|
28 |
self._launchpad = launchpad |
|
29 |
||
30 |
@classmethod
|
|
11677.3.3
by Robert Collins
More edge removal. |
31 |
def load(cls, service_root='production'): |
9404.1.25
by Jonathan Lange
Compliant XXXs |
32 |
# XXX: JonathanLange 2009-09-24: No unit tests.
|
33 |
# XXX: JonathanLange 2009-09-24 bug=435813: If cached data invalid,
|
|
34 |
# there's no easy way to delete it and try again.
|
|
12143.3.2
by Leonard Richardson
Updated to support the new Launchpad constructor and the return of login_with. |
35 |
launchpad = Launchpad.login_with(cls.name, service_root) |
9404.1.2
by Jonathan Lange
start hacking on autoland. |
36 |
return cls(launchpad) |
37 |
||
38 |
def load_merge_proposal(self, mp_url): |
|
39 |
"""Get the merge proposal object for the 'mp_url'."""
|
|
9404.1.25
by Jonathan Lange
Compliant XXXs |
40 |
# XXX: JonathanLange 2009-09-24: No unit tests.
|
9404.1.2
by Jonathan Lange
start hacking on autoland. |
41 |
web_mp_uri = URI(mp_url) |
42 |
api_mp_uri = self._launchpad._root_uri.append( |
|
43 |
web_mp_uri.path.lstrip('/')) |
|
9404.1.14
by Jonathan Lange
Extract a merge proposal wrapper class out of the functions. |
44 |
return MergeProposal(self._launchpad.load(str(api_mp_uri))) |
45 |
||
9644.4.4
by Brad Crittenden
Changes from code review. Fixed get_reviewer_clause to account for multiple review types and mentored reviews. |
46 |
def get_lp_branch(self, branch): |
47 |
"""Get the launchpadlib branch based on a bzr branch."""
|
|
48 |
# First try the public branch.
|
|
49 |
branch_url = branch.get_public_branch() |
|
50 |
if branch_url: |
|
51 |
lp_branch = self._launchpad.branches.getByUrl( |
|
52 |
url=branch_url) |
|
53 |
if lp_branch is not None: |
|
54 |
return lp_branch |
|
55 |
# If that didn't work try the push location.
|
|
56 |
branch_url = branch.get_push_location() |
|
57 |
if branch_url: |
|
58 |
lp_branch = self._launchpad.branches.getByUrl( |
|
59 |
url=branch_url) |
|
60 |
if lp_branch is not None: |
|
61 |
return lp_branch |
|
62 |
raise BzrCommandError( |
|
63 |
"No public branch could be found. Please re-run and specify "
|
|
64 |
"the URL for the merge proposal.") |
|
65 |
||
9644.4.1
by Brad Crittenden
Make ec2 land figure out the merge proposal based on the current branch. |
66 |
def get_merge_proposal_from_branch(self, branch): |
67 |
"""Get the merge proposal from the branch."""
|
|
9644.4.4
by Brad Crittenden
Changes from code review. Fixed get_reviewer_clause to account for multiple review types and mentored reviews. |
68 |
|
69 |
lp_branch = self.get_lp_branch(branch) |
|
12708.2.6
by Jonathan Lange
Only consider needs-review or approved merge proposals. |
70 |
proposals = [ |
71 |
mp for mp in lp_branch.landing_targets |
|
72 |
if mp.queue_status in ('Needs review', 'Approved')] |
|
9644.4.2
by Brad Crittenden
Fixed error handling for the case when there are no merge proposals. |
73 |
if len(proposals) == 0: |
74 |
raise BzrCommandError( |
|
12708.2.6
by Jonathan Lange
Only consider needs-review or approved merge proposals. |
75 |
"The public branch has no open source merge proposals. "
|
9644.4.2
by Brad Crittenden
Fixed error handling for the case when there are no merge proposals. |
76 |
"You must have a merge proposal before attempting to "
|
77 |
"land the branch.") |
|
78 |
elif len(proposals) > 1: |
|
9644.4.1
by Brad Crittenden
Make ec2 land figure out the merge proposal based on the current branch. |
79 |
raise BzrCommandError( |
12708.2.6
by Jonathan Lange
Only consider needs-review or approved merge proposals. |
80 |
"The public branch has multiple open source merge "
|
81 |
"proposals. You must provide the URL to the one you wish "
|
|
82 |
"to use.") |
|
9644.4.1
by Brad Crittenden
Make ec2 land figure out the merge proposal based on the current branch. |
83 |
return MergeProposal(proposals[0]) |
84 |
||
9404.1.14
by Jonathan Lange
Extract a merge proposal wrapper class out of the functions. |
85 |
|
86 |
class MergeProposal: |
|
9404.1.15
by Jonathan Lange
Docstrings. |
87 |
"""Wrapper around launchpadlib `IBranchMergeProposal` for landing."""
|
9404.1.14
by Jonathan Lange
Extract a merge proposal wrapper class out of the functions. |
88 |
|
89 |
def __init__(self, mp): |
|
9404.1.15
by Jonathan Lange
Docstrings. |
90 |
"""Construct a merge proposal.
|
91 |
||
92 |
:param mp: A launchpadlib `IBranchMergeProposal`.
|
|
93 |
"""
|
|
9404.1.14
by Jonathan Lange
Extract a merge proposal wrapper class out of the functions. |
94 |
self._mp = mp |
95 |
self._launchpad = mp._root |
|
96 |
||
97 |
@property
|
|
98 |
def source_branch(self): |
|
9404.1.15
by Jonathan Lange
Docstrings. |
99 |
"""The push URL of the source branch."""
|
9404.1.14
by Jonathan Lange
Extract a merge proposal wrapper class out of the functions. |
100 |
return str(self._get_push_url(self._mp.source_branch)) |
101 |
||
102 |
@property
|
|
103 |
def target_branch(self): |
|
9404.1.15
by Jonathan Lange
Docstrings. |
104 |
"""The push URL of the target branch."""
|
9404.1.35
by Jonathan Lange
Make target_branch better. |
105 |
return str(self._get_push_url(self._mp.target_branch)) |
9404.1.14
by Jonathan Lange
Extract a merge proposal wrapper class out of the functions. |
106 |
|
9404.1.27
by Jonathan Lange
Use EDGE, fix up commit message API. |
107 |
@property
|
108 |
def commit_message(self): |
|
109 |
"""The commit message specified on the merge proposal."""
|
|
110 |
return self._mp.commit_message |
|
111 |
||
9404.1.28
by Jonathan Lange
Check that the merge proposal is approved before landing it. |
112 |
@property
|
113 |
def is_approved(self): |
|
114 |
"""Is this merge proposal approved for landing."""
|
|
115 |
return self._mp.queue_status == 'Approved' |
|
116 |
||
9404.1.14
by Jonathan Lange
Extract a merge proposal wrapper class out of the functions. |
117 |
def get_stakeholder_emails(self): |
118 |
"""Return a collection of people who should know about branch landing.
|
|
119 |
||
120 |
Used to determine who to email with the ec2 test results.
|
|
121 |
||
122 |
:return: A set of `IPerson`s.
|
|
123 |
"""
|
|
9404.1.25
by Jonathan Lange
Compliant XXXs |
124 |
# XXX: JonathanLange 2009-09-24: No unit tests.
|
9404.1.30
by Jonathan Lange
Don't specify duplicate email addresses. |
125 |
return set( |
9644.4.5
by Brad Crittenden
Assume no review type is a code review. |
126 |
map(get_email, |
127 |
[self._mp.source_branch.owner, self._launchpad.me])) |
|
9404.1.14
by Jonathan Lange
Extract a merge proposal wrapper class out of the functions. |
128 |
|
129 |
def get_reviews(self): |
|
130 |
"""Return a dictionary of all Approved reviews.
|
|
131 |
||
132 |
Used to determine who has actually approved a branch for landing. The
|
|
133 |
key of the dictionary is the type of review, and the value is the list
|
|
134 |
of people who have voted Approve with that type.
|
|
135 |
||
136 |
Common types include 'code', 'db', 'ui' and of course `None`.
|
|
137 |
"""
|
|
138 |
reviews = {} |
|
139 |
for vote in self._mp.votes: |
|
140 |
comment = vote.comment |
|
141 |
if comment is None or comment.vote != "Approve": |
|
142 |
continue
|
|
143 |
reviewers = reviews.setdefault(vote.review_type, []) |
|
144 |
reviewers.append(vote.reviewer) |
|
12708.2.7
by Jonathan Lange
I think that this fixes bug 607434 |
145 |
if self.is_approved and not reviews: |
146 |
reviews[None] = [self._mp.reviewer] |
|
9404.1.14
by Jonathan Lange
Extract a merge proposal wrapper class out of the functions. |
147 |
return reviews |
148 |
||
149 |
def get_bugs(self): |
|
9404.1.15
by Jonathan Lange
Docstrings. |
150 |
"""Return a collection of bugs linked to the source branch."""
|
9404.1.14
by Jonathan Lange
Extract a merge proposal wrapper class out of the functions. |
151 |
return self._mp.source_branch.linked_bugs |
152 |
||
153 |
def _get_push_url(self, branch): |
|
9404.1.9
by Jonathan Lange
Make get_push_url work and use it a little. |
154 |
"""Return the push URL for 'branch'.
|
155 |
||
156 |
This function is a work-around for Launchpad's lack of exposing the
|
|
157 |
branch's push URL.
|
|
158 |
||
159 |
:param branch: A launchpadlib `IBranch`.
|
|
160 |
"""
|
|
9404.1.25
by Jonathan Lange
Compliant XXXs |
161 |
# XXX: JonathanLange 2009-09-24: No unit tests.
|
9404.1.9
by Jonathan Lange
Make get_push_url work and use it a little. |
162 |
host = get_bazaar_host(str(self._launchpad._root_uri)) |
9404.1.24
by Jonathan Lange
Substantial amount of comment cleanup. |
163 |
# XXX: JonathanLange 2009-09-24 bug=435790: lazr.uri allows a path
|
164 |
# without a leading '/' and then doesn't insert a '/' in the final
|
|
165 |
# URL. Do it ourselves.
|
|
9404.1.9
by Jonathan Lange
Make get_push_url work and use it a little. |
166 |
return URI(scheme='bzr+ssh', host=host, path='/' + branch.unique_name) |
9404.1.2
by Jonathan Lange
start hacking on autoland. |
167 |
|
11869.5.2
by Diogo Matsubara
change get_commit_message to build_commit_message since that's what the method is actually doing. |
168 |
def build_commit_message(self, commit_text, testfix=False, no_qa=False, |
11490.1.2
by Diogo Matsubara
implement the rollback option and add more tests for the no-qa and incr options |
169 |
incremental=False, rollback=None): |
9404.1.14
by Jonathan Lange
Extract a merge proposal wrapper class out of the functions. |
170 |
"""Get the Launchpad-style commit message for a merge proposal."""
|
171 |
reviews = self.get_reviews() |
|
172 |
bugs = self.get_bugs() |
|
11079.1.12
by Ursula Junque (Ursinha)
applied changes suggested by jtv: strip the string handling and trying to use tags, inside get_commit_message now I just join the clauses and create the commit msg. |
173 |
|
11869.5.3
by Diogo Matsubara
add code to remove duplicate tags from commit message |
174 |
tags = [ |
11079.1.19
by Ursula Junque (Ursinha)
changes suggested by jtv: how to generate clauses string and some elifs |
175 |
get_testfix_clause(testfix), |
176 |
get_reviewer_clause(reviews), |
|
177 |
get_bugs_clause(bugs), |
|
178 |
get_qa_clause(bugs, no_qa, |
|
11490.1.2
by Diogo Matsubara
implement the rollback option and add more tests for the no-qa and incr options |
179 |
incremental, rollback=rollback), |
11869.5.3
by Diogo Matsubara
add code to remove duplicate tags from commit message |
180 |
]
|
181 |
||
182 |
# Make sure we don't add duplicated tags to commit_text.
|
|
183 |
commit_tags = tags[:] |
|
184 |
for tag in tags: |
|
185 |
if tag in commit_text: |
|
186 |
commit_tags.remove(tag) |
|
187 |
||
188 |
if commit_tags: |
|
189 |
return '%s %s' % (''.join(commit_tags), commit_text) |
|
190 |
else: |
|
191 |
return commit_text |
|
11079.1.12
by Ursula Junque (Ursinha)
applied changes suggested by jtv: strip the string handling and trying to use tags, inside get_commit_message now I just join the clauses and create the commit msg. |
192 |
|
11869.5.1
by Diogo Matsubara
set the commit message in the merge proposal from the built commit message. |
193 |
def set_commit_message(self, commit_message): |
194 |
"""Set the Launchpad-style commit message for a merge proposal."""
|
|
195 |
self._mp.commit_message = commit_message |
|
196 |
self._mp.lp_save() |
|
197 |
||
11079.1.12
by Ursula Junque (Ursinha)
applied changes suggested by jtv: strip the string handling and trying to use tags, inside get_commit_message now I just join the clauses and create the commit msg. |
198 |
|
199 |
def get_testfix_clause(testfix=False): |
|
200 |
"""Get the testfix clause."""
|
|
11079.1.19
by Ursula Junque (Ursinha)
changes suggested by jtv: how to generate clauses string and some elifs |
201 |
if testfix: |
202 |
testfix_clause = '[testfix]' |
|
203 |
else: |
|
204 |
testfix_clause = '' |
|
11079.1.12
by Ursula Junque (Ursinha)
applied changes suggested by jtv: strip the string handling and trying to use tags, inside get_commit_message now I just join the clauses and create the commit msg. |
205 |
return testfix_clause |
206 |
||
207 |
||
11490.1.2
by Diogo Matsubara
implement the rollback option and add more tests for the no-qa and incr options |
208 |
def get_qa_clause(bugs, no_qa=False, incremental=False, rollback=None): |
11079.1.15
by Ursula Junque (Ursinha)
changed all variables and options from incr to incremental, more self explainable; raising MissingBugs exceptions without a message |
209 |
"""Check the no-qa and incremental options, getting the qa clause.
|
11079.1.12
by Ursula Junque (Ursinha)
applied changes suggested by jtv: strip the string handling and trying to use tags, inside get_commit_message now I just join the clauses and create the commit msg. |
210 |
|
11490.1.1
by Diogo Matsubara
implement the no-qa and incr use case in the autoland.py script |
211 |
The qa clause will always be or no-qa, or incremental, or no-qa and
|
11490.1.2
by Diogo Matsubara
implement the rollback option and add more tests for the no-qa and incr options |
212 |
incremental, or a revno for the rollback clause, or no tags.
|
213 |
||
214 |
See https://dev.launchpad.net/QAProcessContinuousRollouts for detailed
|
|
215 |
explanation of each clause.
|
|
11079.1.12
by Ursula Junque (Ursinha)
applied changes suggested by jtv: strip the string handling and trying to use tags, inside get_commit_message now I just join the clauses and create the commit msg. |
216 |
"""
|
217 |
qa_clause = "" |
|
11079.1.6
by Ursula Junque (Ursinha)
Adding MissingBugsIncrError exception and incr commit tag to the check_qa_clauses method, now changed to check both tags, no-qa and incr. |
218 |
|
11490.1.2
by Diogo Matsubara
implement the rollback option and add more tests for the no-qa and incr options |
219 |
if not bugs and not no_qa and not incremental and not rollback: |
11079.1.15
by Ursula Junque (Ursinha)
changed all variables and options from incr to incremental, more self explainable; raising MissingBugs exceptions without a message |
220 |
raise MissingBugsError |
221 |
||
222 |
if incremental and not bugs: |
|
223 |
raise MissingBugsIncrementalError |
|
224 |
||
11490.1.1
by Diogo Matsubara
implement the no-qa and incr use case in the autoland.py script |
225 |
if no_qa and incremental: |
226 |
qa_clause = '[no-qa][incr]' |
|
227 |
elif incremental: |
|
11079.1.19
by Ursula Junque (Ursinha)
changes suggested by jtv: how to generate clauses string and some elifs |
228 |
qa_clause = '[incr]' |
229 |
elif no_qa: |
|
230 |
qa_clause = '[no-qa]' |
|
11490.1.2
by Diogo Matsubara
implement the rollback option and add more tests for the no-qa and incr options |
231 |
elif rollback: |
232 |
qa_clause = '[rollback=%d]' % rollback |
|
11079.1.19
by Ursula Junque (Ursinha)
changes suggested by jtv: how to generate clauses string and some elifs |
233 |
else: |
234 |
qa_clause = '' |
|
11079.1.6
by Ursula Junque (Ursinha)
Adding MissingBugsIncrError exception and incr commit tag to the check_qa_clauses method, now changed to check both tags, no-qa and incr. |
235 |
|
11079.1.12
by Ursula Junque (Ursinha)
applied changes suggested by jtv: strip the string handling and trying to use tags, inside get_commit_message now I just join the clauses and create the commit msg. |
236 |
return qa_clause |
11079.1.3
by Ursula Junque (Ursinha)
created a separated method to take care of the no-qa tag, check_qa_clause |
237 |
|
238 |
||
9404.1.11
by Jonathan Lange
Tie everything together to make the default command line. |
239 |
def get_email(person): |
9404.1.17
by Jonathan Lange
More docstrings. |
240 |
"""Get the preferred email address for 'person'."""
|
9404.1.11
by Jonathan Lange
Tie everything together to make the default command line. |
241 |
email_object = person.preferred_email_address |
9404.1.24
by Jonathan Lange
Substantial amount of comment cleanup. |
242 |
# XXX: JonathanLange 2009-09-24 bug=319432: This raises a very obscure
|
243 |
# error when the email address isn't set. e.g. with name12 in the sample
|
|
244 |
# data. e.g. "httplib2.RelativeURIError: Only absolute URIs are allowed.
|
|
245 |
# uri = tag:launchpad.net:2008:redacted".
|
|
9404.1.11
by Jonathan Lange
Tie everything together to make the default command line. |
246 |
return email_object.email |
247 |
||
9404.1.2
by Jonathan Lange
start hacking on autoland. |
248 |
|
249 |
def get_bugs_clause(bugs): |
|
9404.1.4
by Jonathan Lange
More tests. |
250 |
"""Return the bugs clause of a commit message.
|
251 |
||
252 |
:param bugs: A collection of `IBug` objects.
|
|
253 |
:return: A string of the form "[bug=A,B,C]".
|
|
254 |
"""
|
|
9404.1.2
by Jonathan Lange
start hacking on autoland. |
255 |
if not bugs: |
256 |
return '' |
|
12708.2.5
by Jonathan Lange
Don't include bugs that have been fixed in Launchpad. |
257 |
bug_ids = [] |
258 |
for bug in bugs: |
|
259 |
for task in bug.bug_tasks: |
|
260 |
if (task.bug_target_name == 'launchpad' |
|
261 |
and task.status not in ['Fix Committed', 'Fix Released']): |
|
262 |
bug_ids.append(str(bug.id)) |
|
263 |
break
|
|
264 |
if not bug_ids: |
|
265 |
return '' |
|
266 |
return '[bug=%s]' % ','.join(bug_ids) |
|
9404.1.2
by Jonathan Lange
start hacking on autoland. |
267 |
|
268 |
||
9404.1.4
by Jonathan Lange
More tests. |
269 |
def get_reviewer_handle(reviewer): |
270 |
"""Get the handle for 'reviewer'.
|
|
271 |
||
272 |
The handles of reviewers are included in the commit message for Launchpad
|
|
273 |
changes. Historically, these handles have been the IRC nicks. Thus, if
|
|
274 |
'reviewer' has an IRC nickname for Freenode, we use that. Otherwise we use
|
|
275 |
their Launchpad username.
|
|
276 |
||
277 |
:param reviewer: A launchpadlib `IPerson` object.
|
|
9404.1.5
by Jonathan Lange
Get the reviewer string. |
278 |
:return: unicode text.
|
9404.1.4
by Jonathan Lange
More tests. |
279 |
"""
|
280 |
irc_handles = reviewer.irc_nicknames |
|
281 |
for handle in irc_handles: |
|
282 |
if handle.network == 'irc.freenode.net': |
|
283 |
return handle.nickname |
|
284 |
return reviewer.name |
|
285 |
||
286 |
||
9404.1.26
by Jonathan Lange
Release-critical support added. |
287 |
def _comma_separated_names(things): |
9644.4.7
by Brad Crittenden
Fixed test failures and added a test for mentored reviews. |
288 |
"""Return a string of comma-separated names of 'things'.
|
289 |
||
290 |
The list is sorted before being joined.
|
|
291 |
"""
|
|
292 |
return ','.join(sorted(thing.name for thing in things)) |
|
9404.1.26
by Jonathan Lange
Release-critical support added. |
293 |
|
294 |
||
9404.1.5
by Jonathan Lange
Get the reviewer string. |
295 |
def get_reviewer_clause(reviewers): |
296 |
"""Get the reviewer section of a commit message, given the reviewers.
|
|
297 |
||
298 |
:param reviewers: A dict mapping review types to lists of reviewers, as
|
|
299 |
returned by 'get_reviews'.
|
|
300 |
:return: A string like u'[r=foo,bar][ui=plop]'.
|
|
301 |
"""
|
|
9862.1.2
by Aaron Bentley
Handle the case where the reviewer field is ''. |
302 |
# If no review type is specified it is assumed to be a code review.
|
9644.4.5
by Brad Crittenden
Assume no review type is a code review. |
303 |
code_reviewers = reviewers.get(None, []) |
9644.4.4
by Brad Crittenden
Changes from code review. Fixed get_reviewer_clause to account for multiple review types and mentored reviews. |
304 |
ui_reviewers = [] |
305 |
rc_reviewers = [] |
|
306 |
for review_type, reviewer in reviewers.items(): |
|
9644.4.7
by Brad Crittenden
Fixed test failures and added a test for mentored reviews. |
307 |
if review_type is None: |
308 |
continue
|
|
9862.1.2
by Aaron Bentley
Handle the case where the reviewer field is ''. |
309 |
if review_type == '': |
310 |
code_reviewers.extend(reviewer) |
|
9644.4.7
by Brad Crittenden
Fixed test failures and added a test for mentored reviews. |
311 |
if 'code' in review_type or 'db' in review_type: |
9644.4.4
by Brad Crittenden
Changes from code review. Fixed get_reviewer_clause to account for multiple review types and mentored reviews. |
312 |
code_reviewers.extend(reviewer) |
313 |
if 'ui' in review_type: |
|
314 |
ui_reviewers.extend(reviewer) |
|
315 |
if 'release-critical' in review_type: |
|
316 |
rc_reviewers.extend(reviewer) |
|
9404.1.29
by Jonathan Lange
Handle the case when there are no reviewers. |
317 |
if not code_reviewers: |
318 |
raise MissingReviewError("Need approved votes in order to land.") |
|
9404.1.5
by Jonathan Lange
Get the reviewer string. |
319 |
if ui_reviewers: |
12289.3.1
by William Grant
Don't add [ui=none] if there are no UI reviewers. The PQM regexp no longer requires it. |
320 |
ui_clause = '[ui=%s]' % _comma_separated_names(ui_reviewers) |
9404.1.5
by Jonathan Lange
Get the reviewer string. |
321 |
else: |
12289.3.1
by William Grant
Don't add [ui=none] if there are no UI reviewers. The PQM regexp no longer requires it. |
322 |
ui_clause = '' |
9404.1.26
by Jonathan Lange
Release-critical support added. |
323 |
if rc_reviewers: |
324 |
rc_clause = ( |
|
325 |
'[release-critical=%s]' % _comma_separated_names(rc_reviewers)) |
|
326 |
else: |
|
327 |
rc_clause = '' |
|
12289.3.1
by William Grant
Don't add [ui=none] if there are no UI reviewers. The PQM regexp no longer requires it. |
328 |
return '%s[r=%s]%s' % ( |
9404.1.26
by Jonathan Lange
Release-critical support added. |
329 |
rc_clause, _comma_separated_names(code_reviewers), ui_clause) |
9404.1.5
by Jonathan Lange
Get the reviewer string. |
330 |
|
331 |
||
9404.1.7
by Jonathan Lange
Add a function that will return the bazaar host given an API root. |
332 |
def get_bazaar_host(api_root): |
333 |
"""Get the Bazaar service for the given API root."""
|
|
9404.1.24
by Jonathan Lange
Substantial amount of comment cleanup. |
334 |
# XXX: JonathanLange 2009-09-24 bug=435803: This is only needed because
|
335 |
# Launchpad doesn't expose the push URL for branches.
|
|
10430.2.1
by Brad Crittenden
Fixed comparison between launchpad._root_uri and *_SERVICE_ROOT to account for the fact the former has a version tacked onto it now. |
336 |
if api_root.startswith(EDGE_SERVICE_ROOT): |
9404.1.7
by Jonathan Lange
Add a function that will return the bazaar host given an API root. |
337 |
return 'bazaar.launchpad.net' |
10430.2.1
by Brad Crittenden
Fixed comparison between launchpad._root_uri and *_SERVICE_ROOT to account for the fact the former has a version tacked onto it now. |
338 |
elif api_root.startswith(DEV_SERVICE_ROOT): |
9404.1.7
by Jonathan Lange
Add a function that will return the bazaar host given an API root. |
339 |
return 'bazaar.launchpad.dev' |
10430.2.1
by Brad Crittenden
Fixed comparison between launchpad._root_uri and *_SERVICE_ROOT to account for the fact the former has a version tacked onto it now. |
340 |
elif api_root.startswith(STAGING_SERVICE_ROOT): |
9404.1.7
by Jonathan Lange
Add a function that will return the bazaar host given an API root. |
341 |
return 'bazaar.staging.launchpad.net' |
10430.2.1
by Brad Crittenden
Fixed comparison between launchpad._root_uri and *_SERVICE_ROOT to account for the fact the former has a version tacked onto it now. |
342 |
elif api_root.startswith(LPNET_SERVICE_ROOT): |
9404.1.7
by Jonathan Lange
Add a function that will return the bazaar host given an API root. |
343 |
return 'bazaar.launchpad.net' |
344 |
else: |
|
345 |
raise ValueError( |
|
346 |
'Cannot determine Bazaar host. "%s" not a recognized Launchpad ' |
|
347 |
'API root.' % (api_root,)) |