Merge lp:~abentley/bzr-pqm/fix-lp-land into lp:bzr-pqm
- fix-lp-land
- Merge into devel
Proposed by
Aaron Bentley
Status: | Merged |
---|---|
Merged at revision: | 85 |
Proposed branch: | lp:~abentley/bzr-pqm/fix-lp-land |
Merge into: | lp:bzr-pqm |
Diff against target: |
398 lines (+216/-47) 5 files modified
__init__.py (+3/-4) lpland.py (+42/-25) pqm_submit.py (+44/-9) tests/test_lpland.py (+119/-9) tests/test_pqm_submit.py (+8/-0) |
To merge this branch: | bzr merge lp:~abentley/bzr-pqm/fix-lp-land |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jelmer Vernooij (community) | Approve | ||
Review via email: mp+91318@code.launchpad.net |
Commit message
Fix lp-land.
Description of the change
Recent changes to config handling broke lp-land. This breakage was not detected because lp-land was not sufficiently tested.
This branch fixes the breakage by using an implementation of config.Stack as the input to pqm_email.
It increases the test coverage of lp-land to reduce the chance of similar problems in the future.
It changes the behaviour of ConfigStack.get so that it supports environment variables such as BZR_EMAIL and EMAIL.
It extracts get_stacked_config and get_mail_from to increase code re-use.
It moves most functionality out of Submitter.__init__ into the new from_cmdline factory method, to make testing easier.
It extracts Submitter.
To post a comment you must log in.
lp:~abentley/bzr-pqm/fix-lp-land
updated
- 89. By Aaron Bentley
-
Cleanup.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '__init__.py' | |||
2 | --- __init__.py 2011-12-19 11:04:03 +0000 | |||
3 | +++ __init__.py 2012-02-02 17:34:20 +0000 | |||
4 | @@ -150,11 +150,9 @@ | |||
5 | 150 | def run(self, location=None, dry_run=False, testfix=False, | 150 | def run(self, location=None, dry_run=False, testfix=False, |
6 | 151 | no_qa=False, incremental=False, rollback=None): | 151 | no_qa=False, incremental=False, rollback=None): |
7 | 152 | from bzrlib.plugins.pqm.lpland import Submitter | 152 | from bzrlib.plugins.pqm.lpland import Submitter |
8 | 153 | from bzrlib import branch as _mod_branch | ||
9 | 154 | from bzrlib.plugins.pqm.lpland import ( | 153 | from bzrlib.plugins.pqm.lpland import ( |
10 | 155 | MissingReviewError, MissingBugsError, MissingBugsIncrementalError) | 154 | MissingReviewError, MissingBugsError, MissingBugsIncrementalError) |
11 | 156 | 155 | ||
12 | 157 | branch = _mod_branch.Branch.open_containing('.')[0] | ||
13 | 158 | if dry_run: | 156 | if dry_run: |
14 | 159 | outf = self.outf | 157 | outf = self.outf |
15 | 160 | else: | 158 | else: |
16 | @@ -162,8 +160,9 @@ | |||
17 | 162 | if rollback and (no_qa or incremental): | 160 | if rollback and (no_qa or incremental): |
18 | 163 | print "--rollback option used. Ignoring --no-qa and --incremental." | 161 | print "--rollback option used. Ignoring --no-qa and --incremental." |
19 | 164 | try: | 162 | try: |
22 | 165 | submitter = Submitter(branch, location, testfix, no_qa, | 163 | submitter = Submitter.from_cmdline( |
23 | 166 | incremental, rollback=rollback).run(outf) | 164 | location, testfix, no_qa, incremental, |
24 | 165 | rollback=rollback).run(outf) | ||
25 | 167 | except MissingReviewError: | 166 | except MissingReviewError: |
26 | 168 | raise BzrCommandError( | 167 | raise BzrCommandError( |
27 | 169 | "Cannot land branches that haven't got approved code " | 168 | "Cannot land branches that haven't got approved code " |
28 | 170 | 169 | ||
29 | === modified file 'lpland.py' | |||
30 | --- lpland.py 2011-12-16 20:21:06 +0000 | |||
31 | +++ lpland.py 2012-02-02 17:34:20 +0000 | |||
32 | @@ -198,39 +198,57 @@ | |||
33 | 198 | 198 | ||
34 | 199 | 199 | ||
35 | 200 | class Submitter(object): | 200 | class Submitter(object): |
36 | 201 | """Class that submits a to PQM from a merge proposal.""" | ||
37 | 201 | 202 | ||
39 | 202 | def __init__(self, branch, location, testfix=False, no_qa=False, | 203 | def __init__(self, branch, mp, testfix=False, no_qa=False, |
40 | 203 | incremental=False, rollback=None): | 204 | incremental=False, rollback=None): |
41 | 204 | self.branch = branch | 205 | self.branch = branch |
42 | 206 | self.mp = mp | ||
43 | 205 | self.testfix = testfix | 207 | self.testfix = testfix |
44 | 206 | self.no_qa = no_qa | 208 | self.no_qa = no_qa |
45 | 207 | self.incremental = incremental | 209 | self.incremental = incremental |
46 | 208 | self.rollback = rollback | 210 | self.rollback = rollback |
55 | 209 | self.config = self.branch.get_config() | 211 | self.config = pqm_submit.get_stacked_config(self.branch, None) |
56 | 210 | self.mail_from = self.config.get_user_option('pqm_user_email') | 212 | self.mail_from = pqm_submit.get_mail_from(self.config) |
57 | 211 | if not self.mail_from: | 213 | |
58 | 212 | self.mail_from = self.config.username() | 214 | @classmethod |
59 | 213 | self.lander = LaunchpadBranchLander.load() | 215 | def from_cmdline(cls, location, testfix, no_qa, incremental, rollback): |
60 | 214 | self.location = location | 216 | """Factory that returns a Submitter from commandline arguments.""" |
61 | 215 | 217 | from bzrlib import branch as _mod_branch | |
62 | 216 | def submission(self, mp): | 218 | branch = _mod_branch.Branch.open_containing('.')[0] |
63 | 219 | lander = LaunchpadBranchLander.load() | ||
64 | 220 | if location is None: | ||
65 | 221 | mp = lander.get_merge_proposal_from_branch(branch) | ||
66 | 222 | else: | ||
67 | 223 | mp = lander.load_merge_proposal(location) | ||
68 | 224 | return cls(branch, mp, testfix, no_qa, incremental, rollback) | ||
69 | 225 | |||
70 | 226 | def submission(self): | ||
71 | 227 | """Create a PQMSubmission for this Submitter.""" | ||
72 | 217 | submission = pqm_submit.PQMSubmission(self.branch, | 228 | submission = pqm_submit.PQMSubmission(self.branch, |
74 | 218 | mp.source_branch, mp.target_branch, '') | 229 | self.mp.source_branch, self.mp.target_branch, '') |
75 | 219 | return submission | 230 | return submission |
76 | 220 | 231 | ||
77 | 221 | @staticmethod | 232 | @staticmethod |
78 | 222 | def check_submission(submission): | 233 | def check_submission(submission): |
79 | 234 | """Ensure the Submission is reasonable.""" | ||
80 | 223 | submission.check_tree() | 235 | submission.check_tree() |
81 | 224 | submission.check_public_branch() | 236 | submission.check_public_branch() |
82 | 225 | 237 | ||
88 | 226 | def set_message(self, submission, mp): | 238 | def set_message(self, submission): |
89 | 227 | pqm_command = ''.join(submission.to_lines()) | 239 | """Set the message of the Submission. |
90 | 228 | commit_message = mp.commit_message or '' | 240 | |
91 | 229 | start_message = mp.get_commit_message(commit_message, self.testfix, | 241 | This starts with automatic generation from merge proposal and branch |
92 | 230 | self.no_qa, self.incremental, rollback=self.rollback) | 242 | properties, then allows the user to edit the values. |
93 | 243 | """ | ||
94 | 244 | commit_message = self.mp.commit_message or '' | ||
95 | 245 | start_message = self.mp.get_commit_message(commit_message, | ||
96 | 246 | self.testfix, self.no_qa, self.incremental, | ||
97 | 247 | rollback=self.rollback) | ||
98 | 231 | prompt = ('Proposed commit message:\n%s\nEdit before sending' | 248 | prompt = ('Proposed commit message:\n%s\nEdit before sending' |
99 | 232 | % start_message) | 249 | % start_message) |
100 | 233 | if commit_message == '' or ui.ui_factory.get_boolean(prompt): | 250 | if commit_message == '' or ui.ui_factory.get_boolean(prompt): |
101 | 251 | pqm_command = ''.join(submission.to_lines()) | ||
102 | 234 | unicode_message = msgeditor.edit_commit_message( | 252 | unicode_message = msgeditor.edit_commit_message( |
103 | 235 | 'pqm command:\n%s' % pqm_command, | 253 | 'pqm command:\n%s' % pqm_command, |
104 | 236 | start_message=start_message).rstrip('\n') | 254 | start_message=start_message).rstrip('\n') |
105 | @@ -239,18 +257,17 @@ | |||
106 | 239 | message = start_message | 257 | message = start_message |
107 | 240 | submission.message = message | 258 | submission.message = message |
108 | 241 | 259 | ||
118 | 242 | def run(self, outf): | 260 | def make_submission_email(self, submission, sign=True): |
119 | 243 | if self.location is None: | 261 | mail_to = pqm_submit.pqm_email(self.config, self.mp.target_branch) |
111 | 244 | mp = self.lander.get_merge_proposal_from_branch(self.branch) | ||
112 | 245 | else: | ||
113 | 246 | mp = self.lander.load_merge_proposal(self.location) | ||
114 | 247 | submission = self.submission(mp) | ||
115 | 248 | self.check_submission(submission) | ||
116 | 249 | self.set_message(submission, mp) | ||
117 | 250 | mail_to = pqm_submit.pqm_email(self.config, mp.target_branch) | ||
120 | 251 | if not mail_to: | 262 | if not mail_to: |
121 | 252 | raise pqm_submit.NoPQMSubmissionAddress(self.branch) | 263 | raise pqm_submit.NoPQMSubmissionAddress(self.branch) |
123 | 253 | email = submission.to_email(self.mail_from, mail_to) | 264 | return submission.to_email(self.mail_from, mail_to, sign=sign) |
124 | 265 | |||
125 | 266 | def run(self, outf, sign=True): | ||
126 | 267 | submission = self.submission() | ||
127 | 268 | self.check_submission(submission) | ||
128 | 269 | self.set_message(submission) | ||
129 | 270 | email = self.make_submission_email(submission, sign=sign) | ||
130 | 254 | if outf is not None: | 271 | if outf is not None: |
131 | 255 | outf.write(email.as_string()) | 272 | outf.write(email.as_string()) |
132 | 256 | else: | 273 | else: |
133 | 257 | 274 | ||
134 | === modified file 'pqm_submit.py' | |||
135 | --- pqm_submit.py 2012-01-20 15:32:43 +0000 | |||
136 | +++ pqm_submit.py 2012-02-02 17:34:20 +0000 | |||
137 | @@ -219,7 +219,16 @@ | |||
138 | 219 | return value | 219 | return value |
139 | 220 | return None | 220 | return None |
140 | 221 | 221 | ||
142 | 222 | get = _get_user_option | 222 | def get(self, option_name): |
143 | 223 | """Return an option exactly as bzrlib.config.Stack would. | ||
144 | 224 | |||
145 | 225 | Since Stack allows the environment to override 'email', this uses the | ||
146 | 226 | same logic. | ||
147 | 227 | """ | ||
148 | 228 | if option_name == 'email': | ||
149 | 229 | return self.username() | ||
150 | 230 | else: | ||
151 | 231 | return self._get_user_option(option_name) | ||
152 | 223 | 232 | ||
153 | 224 | def _get_user_id(self): | 233 | def _get_user_id(self): |
154 | 225 | for source in self._sources: | 234 | for source in self._sources: |
155 | @@ -245,9 +254,20 @@ | |||
156 | 245 | return mail_to.encode('utf8') # same here | 254 | return mail_to.encode('utf8') # same here |
157 | 246 | 255 | ||
158 | 247 | 256 | ||
162 | 248 | def submit(branch, message, dry_run=False, public_location=None, | 257 | def get_stacked_config(branch=None, public_location=None): |
163 | 249 | submit_location=None, tree=None, ignore_local=False): | 258 | """Return the relevant stacked config. |
164 | 250 | """Submit the given branch to the pqm.""" | 259 | |
165 | 260 | If the branch is supplied, a branch stacked config is returned. | ||
166 | 261 | Otherwise, if the public location is supplied, a stacked location config | ||
167 | 262 | is returned. | ||
168 | 263 | Otherwise, a global config is returned. | ||
169 | 264 | |||
170 | 265 | For bzr versions earlier than 2.5, pqm_submit.StackedConfig is used. For | ||
171 | 266 | later versions, the standard stacked config is used. | ||
172 | 267 | |||
173 | 268 | :param branch: The branch to retrieve the config for. | ||
174 | 269 | :param public_location: The public location to retrieve the config for. | ||
175 | 270 | """ | ||
176 | 251 | if bzrlib_version < (2, 5): | 271 | if bzrlib_version < (2, 5): |
177 | 252 | config = StackedConfig() | 272 | config = StackedConfig() |
178 | 253 | if branch: | 273 | if branch: |
179 | @@ -263,16 +283,31 @@ | |||
180 | 263 | config = _mod_config.LocationStack(public_location) | 283 | config = _mod_config.LocationStack(public_location) |
181 | 264 | else: | 284 | else: |
182 | 265 | config = _mod_config.GlobalStack() | 285 | config = _mod_config.GlobalStack() |
184 | 266 | 286 | return config | |
185 | 287 | |||
186 | 288 | |||
187 | 289 | def get_mail_from(config): | ||
188 | 290 | """Return the email id that the email is from. | ||
189 | 291 | |||
190 | 292 | :param config: The config to use for determining the from address. | ||
191 | 293 | """ | ||
192 | 294 | mail_from = config.get('pqm_user_email') | ||
193 | 295 | if not mail_from: | ||
194 | 296 | mail_from = config.get('email') | ||
195 | 297 | mail_from = mail_from.encode('utf8') # Make sure this isn't unicode | ||
196 | 298 | return mail_from | ||
197 | 299 | |||
198 | 300 | |||
199 | 301 | def submit(branch, message, dry_run=False, public_location=None, | ||
200 | 302 | submit_location=None, tree=None, ignore_local=False): | ||
201 | 303 | """Submit the given branch to the pqm.""" | ||
202 | 304 | config = get_stacked_config(branch, public_location) | ||
203 | 267 | submission = PQMSubmission( | 305 | submission = PQMSubmission( |
204 | 268 | source_branch=branch, public_location=public_location, message=message, | 306 | source_branch=branch, public_location=public_location, message=message, |
205 | 269 | submit_location=submit_location, | 307 | submit_location=submit_location, |
206 | 270 | tree=tree) | 308 | tree=tree) |
207 | 271 | 309 | ||
212 | 272 | mail_from = config.get('pqm_user_email') | 310 | mail_from = get_mail_from(config) |
209 | 273 | if not mail_from: | ||
210 | 274 | mail_from = config.get('email') | ||
211 | 275 | mail_from = mail_from.encode('utf8') # Make sure this isn't unicode | ||
213 | 276 | mail_to = pqm_email(config, submit_location) | 311 | mail_to = pqm_email(config, submit_location) |
214 | 277 | if not mail_to: | 312 | if not mail_to: |
215 | 278 | raise NoPQMSubmissionAddress(branch) | 313 | raise NoPQMSubmissionAddress(branch) |
216 | 279 | 314 | ||
217 | === modified file 'tests/test_lpland.py' | |||
218 | --- tests/test_lpland.py 2011-02-16 00:01:50 +0000 | |||
219 | +++ tests/test_lpland.py 2012-02-02 17:34:20 +0000 | |||
220 | @@ -5,17 +5,27 @@ | |||
221 | 5 | 5 | ||
222 | 6 | __metaclass__ = type | 6 | __metaclass__ = type |
223 | 7 | 7 | ||
224 | 8 | from cStringIO import StringIO | ||
225 | 9 | from textwrap import dedent | ||
226 | 8 | import unittest | 10 | import unittest |
227 | 9 | 11 | ||
232 | 10 | from launchpadlib.uris import ( | 12 | from bzrlib import ( |
233 | 11 | DEV_SERVICE_ROOT, EDGE_SERVICE_ROOT, LPNET_SERVICE_ROOT, | 13 | errors, |
234 | 12 | STAGING_SERVICE_ROOT) | 14 | ui, |
235 | 13 | 15 | ) | |
236 | 14 | from bzrlib.plugins.pqm.lpland import ( | 16 | from bzrlib.plugins.pqm.lpland import ( |
241 | 15 | get_bugs_clause, get_reviewer_clause, | 17 | get_bugs_clause, |
242 | 16 | get_reviewer_handle, get_testfix_clause, get_qa_clause, | 18 | get_reviewer_clause, |
243 | 17 | MissingReviewError, MissingBugsError, MissingBugsIncrementalError, | 19 | get_reviewer_handle, |
244 | 18 | MergeProposal) | 20 | get_testfix_clause, |
245 | 21 | get_qa_clause, | ||
246 | 22 | MissingReviewError, | ||
247 | 23 | MissingBugsError, | ||
248 | 24 | MissingBugsIncrementalError, | ||
249 | 25 | MergeProposal, | ||
250 | 26 | Submitter, | ||
251 | 27 | ) | ||
252 | 28 | from bzrlib.tests import TestCaseWithTransport | ||
253 | 19 | 29 | ||
254 | 20 | from fakemethod import FakeMethod | 30 | from fakemethod import FakeMethod |
255 | 21 | 31 | ||
256 | @@ -36,7 +46,7 @@ | |||
257 | 36 | Only used for the purposes of testing. | 46 | Only used for the purposes of testing. |
258 | 37 | """ | 47 | """ |
259 | 38 | 48 | ||
261 | 39 | def __init__(self, name, irc_handles): | 49 | def __init__(self, name='jrandom', irc_handles=()): |
262 | 40 | self.name = name | 50 | self.name = name |
263 | 41 | self.irc_nicknames = list(irc_handles) | 51 | self.irc_nicknames = list(irc_handles) |
264 | 42 | 52 | ||
265 | @@ -52,6 +62,30 @@ | |||
266 | 52 | self.network = network | 62 | self.network = network |
267 | 53 | 63 | ||
268 | 54 | 64 | ||
269 | 65 | class FakeBranch: | ||
270 | 66 | |||
271 | 67 | def __init__(self, location): | ||
272 | 68 | self.location = location | ||
273 | 69 | self.linked_bugs = [FakeBug(5)] | ||
274 | 70 | |||
275 | 71 | def composePublicURL(self, scheme): | ||
276 | 72 | return self.location | ||
277 | 73 | |||
278 | 74 | |||
279 | 75 | class FakeComment: | ||
280 | 76 | |||
281 | 77 | def __init__(self): | ||
282 | 78 | self.vote = 'Approve' | ||
283 | 79 | |||
284 | 80 | |||
285 | 81 | class FakeVote: | ||
286 | 82 | |||
287 | 83 | def __init__(self): | ||
288 | 84 | self.comment = FakeComment() | ||
289 | 85 | self.review_type = None | ||
290 | 86 | self.reviewer = FakePerson() | ||
291 | 87 | |||
292 | 88 | |||
293 | 55 | class FakeLPMergeProposal: | 89 | class FakeLPMergeProposal: |
294 | 56 | """Fake launchpadlib MergeProposal object. | 90 | """Fake launchpadlib MergeProposal object. |
295 | 57 | 91 | ||
296 | @@ -60,6 +94,10 @@ | |||
297 | 60 | 94 | ||
298 | 61 | def __init__(self, root=None): | 95 | def __init__(self, root=None): |
299 | 62 | self._root = root | 96 | self._root = root |
300 | 97 | self.source_branch = FakeBranch('lp_source') | ||
301 | 98 | self.target_branch = FakeBranch('lp_target') | ||
302 | 99 | self.commit_message = 'Message1' | ||
303 | 100 | self.votes = [FakeVote()] | ||
304 | 63 | 101 | ||
305 | 64 | 102 | ||
306 | 65 | class TestBugsClaused(unittest.TestCase): | 103 | class TestBugsClaused(unittest.TestCase): |
307 | @@ -361,3 +399,75 @@ | |||
308 | 361 | # If the merge proposal hasn't been approved by anyone, we cannot | 399 | # If the merge proposal hasn't been approved by anyone, we cannot |
309 | 362 | # generate a valid clause. | 400 | # generate a valid clause. |
310 | 363 | self.assertRaises(MissingReviewError, self.get_reviewer_clause, {}) | 401 | self.assertRaises(MissingReviewError, self.get_reviewer_clause, {}) |
311 | 402 | |||
312 | 403 | |||
313 | 404 | class TestSubmitter(TestCaseWithTransport): | ||
314 | 405 | |||
315 | 406 | def make_submitter(self): | ||
316 | 407 | """Return a Submitter for testing.""" | ||
317 | 408 | b = self.make_branch('source') | ||
318 | 409 | b.get_config().set_user_option('pqm_email', 'PQM <pqm@example.com>') | ||
319 | 410 | lp_source = self.make_branch('lp_source') | ||
320 | 411 | mp = MergeProposal(FakeLPMergeProposal()) | ||
321 | 412 | return Submitter(b, mp) | ||
322 | 413 | |||
323 | 414 | def test_submission(self): | ||
324 | 415 | """Creating a submission produces the expected result.""" | ||
325 | 416 | submitter = self.make_submitter() | ||
326 | 417 | submission = submitter.submission() | ||
327 | 418 | self.assertEqual(submitter.branch, submission.source_branch) | ||
328 | 419 | self.assertEqual('lp_source', submission.public_location) | ||
329 | 420 | self.assertEqual('lp_target', submission.submit_location) | ||
330 | 421 | self.assertEqual('', submission.message) | ||
331 | 422 | |||
332 | 423 | def test_check_submission(self): | ||
333 | 424 | """Checking the submission returns in the comment case.""" | ||
334 | 425 | submitter = self.make_submitter() | ||
335 | 426 | submitter.check_submission(submitter.submission()) | ||
336 | 427 | |||
337 | 428 | def test_check_submission_public_branch(self): | ||
338 | 429 | """Checking the submission raises if the public branch is outdated.""" | ||
339 | 430 | submitter = self.make_submitter() | ||
340 | 431 | tree = submitter.branch.create_checkout('tree', lightweight=True) | ||
341 | 432 | tree.commit('message') | ||
342 | 433 | self.assertRaises(errors.PublicBranchOutOfDate, | ||
343 | 434 | submitter.check_submission, submitter.submission()) | ||
344 | 435 | |||
345 | 436 | def test_set_message(self): | ||
346 | 437 | """Setting the message produces one in the correct format.""" | ||
347 | 438 | submitter = self.make_submitter() | ||
348 | 439 | submission = submitter.submission() | ||
349 | 440 | ui.ui_factory = ui.CannedInputUIFactory([False]) | ||
350 | 441 | submitter.set_message(submission) | ||
351 | 442 | self.assertEqual('[r=jrandom][bug=5] Message1', submission.message) | ||
352 | 443 | |||
353 | 444 | def test_make_submission_email(self): | ||
354 | 445 | """Creating a submission email works.""" | ||
355 | 446 | submitter = self.make_submitter() | ||
356 | 447 | submission = submitter.submission() | ||
357 | 448 | submission.message = 'Hello!' | ||
358 | 449 | target = self.make_branch('lp_target') | ||
359 | 450 | email = submitter.make_submission_email(submission, sign=False) | ||
360 | 451 | self.assertEqual('PQM <pqm@example.com>', email['To']) | ||
361 | 452 | self.assertEqual('jrandom@example.com', email['From']) | ||
362 | 453 | self.assertEqual('Hello!', email['Subject']) | ||
363 | 454 | self.assertContainsRe(email['User-Agent'], '^Bazaar') | ||
364 | 455 | self.assertEqual('star-merge lp_source lp_target\n', email._body) | ||
365 | 456 | |||
366 | 457 | def test_run(self): | ||
367 | 458 | """End-to-end test of Submitter.run.""" | ||
368 | 459 | submitter = self.make_submitter() | ||
369 | 460 | ui.ui_factory = ui.CannedInputUIFactory([False]) | ||
370 | 461 | outf = StringIO() | ||
371 | 462 | submitter.run(outf, sign=False) | ||
372 | 463 | self.assertContainsRe(outf.getvalue(), dedent("""\ | ||
373 | 464 | MIME-Version: 1.0 | ||
374 | 465 | Content-Type: text/plain; charset="us-ascii" | ||
375 | 466 | Content-Transfer-Encoding: 7bit | ||
376 | 467 | From: jrandom@example.com | ||
377 | 468 | Subject: \[r=jrandom\]\[bug=5\] Message1 | ||
378 | 469 | To: PQM <pqm@example.com> | ||
379 | 470 | User-Agent: Bazaar (.*) | ||
380 | 471 | |||
381 | 472 | star-merge lp_source lp_target | ||
382 | 473 | """)) | ||
383 | 364 | 474 | ||
384 | === modified file 'tests/test_pqm_submit.py' | |||
385 | --- tests/test_pqm_submit.py 2010-08-06 16:52:30 +0000 | |||
386 | +++ tests/test_pqm_submit.py 2012-02-02 17:34:20 +0000 | |||
387 | @@ -471,3 +471,11 @@ | |||
388 | 471 | call[1:3]) | 471 | call[1:3]) |
389 | 472 | self.assertContainsRe(call[3], EMAIL) | 472 | self.assertContainsRe(call[3], EMAIL) |
390 | 473 | 473 | ||
391 | 474 | |||
392 | 475 | class TestConfig(TestCaseWithMemoryTransport): | ||
393 | 476 | |||
394 | 477 | def test_email_from_environ(self): | ||
395 | 478 | """The config can get the email from the environ.""" | ||
396 | 479 | branch = self.make_branch('foo') | ||
397 | 480 | config = pqm_submit.get_stacked_config(branch, None) | ||
398 | 481 | self.assertEqual('jrandom@example.com', config.get('email')) |
Not much to add, nice cleanup!