Merge lp:~dpb/tarmac/better-prereq-branches into lp:tarmac
- better-prereq-branches
- Merge into main
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | dobey | ||||||||
Approved revision: | 428 | ||||||||
Merged at revision: | 426 | ||||||||
Proposed branch: | lp:~dpb/tarmac/better-prereq-branches | ||||||||
Merge into: | lp:tarmac | ||||||||
Diff against target: |
347 lines (+162/-23) 5 files modified
.bzrignore (+1/-0) docs/introduction.txt (+15/-1) tarmac/bin/commands.py (+43/-13) tarmac/tests/__init__.py (+1/-0) tarmac/tests/test_commands.py (+102/-9) |
||||||||
To merge this branch: | bzr merge lp:~dpb/tarmac/better-prereq-branches | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
dobey | Approve | ||
Review via email: mp+197969@code.launchpad.net |
Commit message
Better prerequisite handling.
Description of the change
Tarmac understands the launchpad concept of prerequisite branches. The
following conditions are supported when evaluating a candidate merge
proposal (MP).
* Multiple prerequisite non-superseded MPs => error
* Prerequiste branch but no associated MP => error
* Exactly one prerequisite non-superseded unmerged MP => skip
* Exactly one prerequisite non-superseded *Merged* MP => proceed
Additionally, the tarmac queue is processed taking into account prerequisite
branches. That is, dependent branches are processed *after* their prerequisites.
- 426. By David Britton
-
remove renaming of 'branch3'
David Britton (dpb) wrote : | # |
> 32 + * Multiple prerequisite non-superseded MPs => error
>
> How does one declare multiple prerequisite branches in Launchpad?
>
I don't know, but I didn't change or add this code path. You can see it at line 231 of tarmac/
What would you like me to do?
> 161 +++ tarmac/
>
> Many of the changes in here seem unrelated to the prerequisite work, and seems
> to be just you changing some of the names for the third branch in several of
> the tests. How are these related?
>
I reverted since you asked. They were to help me track down which test was failing before adding the 'unique_name' property. The error message coming out of bzrlib was not helpful and just contained 'branch3' which made it hard to see which test failed.
> The bug you filed is a duplicate of
> https:/
> already. Changing the --fixes here too would be great, if possible.
OK, I'll hopefully add '--fixes' to this commit
> Also, you need to commit using an e-mail address that is associated with your
> Launchpad account. Your shortened canonical.com address does not appear to be
> associated to your account, and so Launchpad cannot link to your account, nor
> will tarmac be able to find you via the Launchpad API from the e-mail address
> in the commit.
I added it.
- 427. By David Britton
-
Adding lp:900731 to the list of fixes
dobey (dobey) wrote : | # |
> > 32 + * Multiple prerequisite non-superseded MPs => error
> >
> > How does one declare multiple prerequisite branches in Launchpad?
> >
>
> I don't know, but I didn't change or add this code path. You can see it at
> line 231 of tarmac/
> this condition was hit.
>
> What would you like me to do?
I think you've misunderstood the code. That code is to deal with the case when a prerequisite branch has multiple proposals (ie, if someone re-proposed the branch and there is a superseded proposal, and such). These are not multiple prerequisites. The comments and documentation need to be clear about what the code is actually doing.
David Britton (dpb) wrote : | # |
I'll copy it here again:
"Multiple prerequisite non-superseded MPs"
What is wrong with that statement? I didn't say multiple prerequisite
branches. I said multiple prerequisite MPs (merge proposals). What would
you like me to say to clarify it?
Also, there is no comment about this. It's just documentation in a Readme,
unless I'm missing something.
On Sun, Feb 9, 2014 at 12:27 PM, Rodney Dawes <email address hidden>wrote:
> > > 32 + * Multiple prerequisite non-superseded MPs => error
> > >
> > > How does one declare multiple prerequisite branches in Launchpad?
> > >
> >
> > I don't know, but I didn't change or add this code path. You can see it
> at
> > line 231 of tarmac/
> if
> > this condition was hit.
> >
> > What would you like me to do?
>
> I think you've misunderstood the code. That code is to deal with the case
> when a prerequisite branch has multiple proposals (ie, if someone
> re-proposed the branch and there is a superseded proposal, and such). These
> are not multiple prerequisites. The comments and documentation need to be
> clear about what the code is actually doing.
> --
>
> https:/
> You are the owner of lp:~davidpbritton/tarmac/better-prereq-branches.
>
--
David Britton <email address hidden>
- 428. By David Britton
-
Clean up wording around prerequisite branches
David Britton (dpb) wrote : | # |
I committed a rewording change, I hope it's more clear. I think calling an MP "prerequisite" was what was leading to the confusion. (hopefully)
dobey (dobey) : | # |
Preview Diff
1 | === modified file '.bzrignore' | |||
2 | --- .bzrignore 2010-07-24 13:04:41 +0000 | |||
3 | +++ .bzrignore 2014-02-09 23:07:13 +0000 | |||
4 | @@ -4,3 +4,4 @@ | |||
5 | 4 | dist | 4 | dist |
6 | 5 | TODO | 5 | TODO |
7 | 6 | debug* | 6 | debug* |
8 | 7 | tarmac.egg-info | ||
9 | 7 | 8 | ||
10 | === modified file 'docs/introduction.txt' | |||
11 | --- docs/introduction.txt 2013-11-06 19:35:08 +0000 | |||
12 | +++ docs/introduction.txt 2014-02-09 23:07:13 +0000 | |||
13 | @@ -6,7 +6,6 @@ | |||
14 | 6 | merge, it should really just magically be merged. That's what Tarmac does, and | 6 | merge, it should really just magically be merged. That's what Tarmac does, and |
15 | 7 | it does it well. | 7 | it does it well. |
16 | 8 | 8 | ||
17 | 9 | |||
18 | 10 | How it works | 9 | How it works |
19 | 11 | ============ | 10 | ============ |
20 | 12 | 11 | ||
21 | @@ -20,6 +19,21 @@ | |||
22 | 20 | branch has landed. This opens up all sorts of branch landing options that can | 19 | branch has landed. This opens up all sorts of branch landing options that can |
23 | 21 | happen behind the scenes, while you can safely do more exciting work. | 20 | happen behind the scenes, while you can safely do more exciting work. |
24 | 22 | 21 | ||
25 | 22 | Prerequisite Branches | ||
26 | 23 | ===================== | ||
27 | 24 | |||
28 | 25 | Tarmac understands the launchpad concept of prerequisite branches. The | ||
29 | 26 | following conditions are supported when evaluating a candidate merge | ||
30 | 27 | proposal (MP). | ||
31 | 28 | |||
32 | 29 | * Prerequisite branch without an associated MP => error | ||
33 | 30 | * Prerequisite branch with multiple non-superseded MPs => error | ||
34 | 31 | * Prerequisite branch with exactly one non-superseded unmerged MP => skip | ||
35 | 32 | * Prerequisite branch with exactly one non-superseded *Merged* MP => proceed | ||
36 | 33 | |||
37 | 34 | Additionally, the tarmac queue is processed taking into account prerequisite | ||
38 | 35 | branches. That is, dependent branches are processed *after* their | ||
39 | 36 | prerequisites. | ||
40 | 23 | 37 | ||
41 | 24 | Configuration | 38 | Configuration |
42 | 25 | ============= | 39 | ============= |
43 | 26 | 40 | ||
44 | === modified file 'tarmac/bin/commands.py' | |||
45 | --- tarmac/bin/commands.py 2013-11-07 17:28:53 +0000 | |||
46 | +++ tarmac/bin/commands.py 2014-02-09 23:07:13 +0000 | |||
47 | @@ -25,6 +25,17 @@ | |||
48 | 25 | from tarmac.utility import get_review_url | 25 | from tarmac.utility import get_review_url |
49 | 26 | 26 | ||
50 | 27 | 27 | ||
51 | 28 | def _compare_proposals(a, b): | ||
52 | 29 | """Helper to sort proposals based on a prerequisite branch""" | ||
53 | 30 | if a.prerequisite_branch is not None: | ||
54 | 31 | if a.prerequisite_branch.unique_name == b.source_branch.unique_name: | ||
55 | 32 | return 1 | ||
56 | 33 | if b.prerequisite_branch is not None: | ||
57 | 34 | if b.prerequisite_branch.unique_name == a.source_branch.unique_name: | ||
58 | 35 | return -1 | ||
59 | 36 | return 0 | ||
60 | 37 | |||
61 | 38 | |||
62 | 28 | class TarmacCommand(Command): | 39 | class TarmacCommand(Command): |
63 | 29 | '''A command class.''' | 40 | '''A command class.''' |
64 | 30 | 41 | ||
65 | @@ -210,9 +221,7 @@ | |||
66 | 210 | try: | 221 | try: |
67 | 211 | prerequisite = proposal.prerequisite_branch | 222 | prerequisite = proposal.prerequisite_branch |
68 | 212 | if prerequisite: | 223 | if prerequisite: |
72 | 213 | merges = [x for x in prerequisite.landing_targets | 224 | merges = self._get_prerequisite_proposals(proposal) |
70 | 214 | if x.target_branch == target.lp_branch and | ||
71 | 215 | x.queue_status != u'Superseded'] | ||
73 | 216 | if len(merges) == 0: | 225 | if len(merges) == 0: |
74 | 217 | raise TarmacMergeError( | 226 | raise TarmacMergeError( |
75 | 218 | u'No proposals of prerequisite branch.', | 227 | u'No proposals of prerequisite branch.', |
76 | @@ -227,14 +236,6 @@ | |||
77 | 227 | u'of %s into %s, which is not Superseded.' % ( | 236 | u'of %s into %s, which is not Superseded.' % ( |
78 | 228 | prerequisite.web_link, | 237 | prerequisite.web_link, |
79 | 229 | target.lp_branch.web_link)) | 238 | target.lp_branch.web_link)) |
80 | 230 | elif len(merges) == 1: | ||
81 | 231 | if merges[0].queue_status != u'Merged': | ||
82 | 232 | raise TarmacMergeError( | ||
83 | 233 | u'Prerequisite not yet merged.', | ||
84 | 234 | u'The prerequisite %s has not yet been ' | ||
85 | 235 | u'merged into %s.' % ( | ||
86 | 236 | prerequisite.web_link, | ||
87 | 237 | target.lp_branch.web_link)) | ||
88 | 238 | 239 | ||
89 | 239 | if not proposal.reviewed_revid: | 240 | if not proposal.reviewed_revid: |
90 | 240 | raise TarmacMergeError( | 241 | raise TarmacMergeError( |
91 | @@ -325,10 +326,16 @@ | |||
92 | 325 | target.cleanup() | 326 | target.cleanup() |
93 | 326 | 327 | ||
94 | 327 | def _get_mergable_proposals_for_branch(self, lp_branch): | 328 | def _get_mergable_proposals_for_branch(self, lp_branch): |
96 | 328 | """Return a list of the mergable proposals for the given branch.""" | 329 | """ |
97 | 330 | Return a list of the mergable proposals for the given branch. The | ||
98 | 331 | list returned will be in the order that they should be processed. | ||
99 | 332 | """ | ||
100 | 329 | proposals = [] | 333 | proposals = [] |
102 | 330 | for entry in lp_branch.landing_candidates: | 334 | sorted_proposals = sorted( |
103 | 335 | lp_branch.landing_candidates, cmp=_compare_proposals) | ||
104 | 336 | for entry in sorted_proposals: | ||
105 | 331 | self.logger.debug("Considering merge proposal: {0}".format(entry.web_link)) | 337 | self.logger.debug("Considering merge proposal: {0}".format(entry.web_link)) |
106 | 338 | prereqs = self._get_prerequisite_proposals(entry) | ||
107 | 332 | 339 | ||
108 | 333 | if entry.queue_status != u'Approved': | 340 | if entry.queue_status != u'Approved': |
109 | 334 | self.logger.debug( | 341 | self.logger.debug( |
110 | @@ -342,9 +349,31 @@ | |||
111 | 342 | " Skipping proposal: proposal has no commit message") | 349 | " Skipping proposal: proposal has no commit message") |
112 | 343 | continue | 350 | continue |
113 | 344 | 351 | ||
114 | 352 | if len(prereqs) == 1 and prereqs[0].queue_status != u'Merged': | ||
115 | 353 | # N.B.: The case of a MP with more than one prereq MP open | ||
116 | 354 | # will be caught as a merge error. | ||
117 | 355 | self.logger.debug( | ||
118 | 356 | " Skipping proposal: prerequisite not yet merged") | ||
119 | 357 | continue | ||
120 | 358 | |||
121 | 345 | proposals.append(entry) | 359 | proposals.append(entry) |
122 | 346 | return proposals | 360 | return proposals |
123 | 347 | 361 | ||
124 | 362 | def _get_prerequisite_proposals(self, proposal): | ||
125 | 363 | """ | ||
126 | 364 | Given a proposal, return all prerequisite | ||
127 | 365 | proposals that are not in the superseded state. There ideally | ||
128 | 366 | should be one and only one here (or zero), but sometimes there | ||
129 | 367 | are not, depending on developer habits | ||
130 | 368 | """ | ||
131 | 369 | prerequisite = proposal.prerequisite_branch | ||
132 | 370 | target_branch = proposal.target_branch | ||
133 | 371 | if not prerequisite or not prerequisite.landing_targets: | ||
134 | 372 | return [] | ||
135 | 373 | return [x for x in prerequisite.landing_targets | ||
136 | 374 | if x.target_branch.unique_name == target_branch.unique_name and | ||
137 | 375 | x.queue_status != u'Superseded'] | ||
138 | 376 | |||
139 | 348 | def _get_reviews(self, proposal): | 377 | def _get_reviews(self, proposal): |
140 | 349 | """Get the set of reviews from the proposal.""" | 378 | """Get the set of reviews from the proposal.""" |
141 | 350 | reviews = [] | 379 | reviews = [] |
142 | @@ -405,3 +434,4 @@ | |||
143 | 405 | 'An error occurred trying to merge %s: %s', | 434 | 'An error occurred trying to merge %s: %s', |
144 | 406 | branch, error) | 435 | branch, error) |
145 | 407 | raise | 436 | raise |
146 | 437 | |||
147 | 408 | 438 | ||
148 | === modified file 'tarmac/tests/__init__.py' | |||
149 | --- tarmac/tests/__init__.py 2013-10-31 19:09:08 +0000 | |||
150 | +++ tarmac/tests/__init__.py 2014-02-09 23:07:13 +0000 | |||
151 | @@ -56,6 +56,7 @@ | |||
152 | 56 | self.revision_count = 0 | 56 | self.revision_count = 0 |
153 | 57 | self.bzr_identity = 'lp:%s' % os.path.basename(self.tree_dir) | 57 | self.bzr_identity = 'lp:%s' % os.path.basename(self.tree_dir) |
154 | 58 | self.web_link = self.bzr_identity | 58 | self.web_link = self.bzr_identity |
155 | 59 | self.unique_name = self.bzr_identity | ||
156 | 59 | self.project = MockLPProject() | 60 | self.project = MockLPProject() |
157 | 60 | 61 | ||
158 | 61 | 62 | ||
159 | 62 | 63 | ||
160 | === modified file 'tarmac/tests/test_commands.py' | |||
161 | --- tarmac/tests/test_commands.py 2013-11-07 17:28:53 +0000 | |||
162 | +++ tarmac/tests/test_commands.py 2014-02-09 23:07:13 +0000 | |||
163 | @@ -128,13 +128,16 @@ | |||
164 | 128 | display_name=self.branch2.lp_branch.bzr_identity, | 128 | display_name=self.branch2.lp_branch.bzr_identity, |
165 | 129 | web_link=self.branch2.lp_branch.bzr_identity, | 129 | web_link=self.branch2.lp_branch.bzr_identity, |
166 | 130 | name='source', | 130 | name='source', |
167 | 131 | unique_name='source', | ||
168 | 131 | revision_count=self.branch2.lp_branch.revision_count, | 132 | revision_count=self.branch2.lp_branch.revision_count, |
170 | 132 | landing_candidates=[]), | 133 | landing_candidates=[], |
171 | 134 | landing_targets=[]), | ||
172 | 133 | Thing( | 135 | Thing( |
173 | 134 | bzr_identity=self.branch1.lp_branch.bzr_identity, | 136 | bzr_identity=self.branch1.lp_branch.bzr_identity, |
174 | 135 | display_name=self.branch1.lp_branch.bzr_identity, | 137 | display_name=self.branch1.lp_branch.bzr_identity, |
175 | 136 | web_link=self.branch1.lp_branch.bzr_identity, | 138 | web_link=self.branch1.lp_branch.bzr_identity, |
176 | 137 | name='target', | 139 | name='target', |
177 | 140 | unique_name='target', | ||
178 | 138 | revision_count=self.branch1.lp_branch.revision_count, | 141 | revision_count=self.branch1.lp_branch.revision_count, |
179 | 139 | landing_candidates=None)] | 142 | landing_candidates=None)] |
180 | 140 | self.proposals = [Thing( | 143 | self.proposals = [Thing( |
181 | @@ -171,6 +174,8 @@ | |||
182 | 171 | comment=Thing(vote=u'Abstain'), | 174 | comment=Thing(vote=u'Abstain'), |
183 | 172 | reviewer=Thing(display_name=u'Reviewer2'))])] | 175 | reviewer=Thing(display_name=u'Reviewer2'))])] |
184 | 173 | self.branches[1].landing_candidates = self.proposals | 176 | self.branches[1].landing_candidates = self.proposals |
185 | 177 | self.branches[0].landing_targets = [ | ||
186 | 178 | self.proposals[0], self.proposals[1]] | ||
187 | 174 | 179 | ||
188 | 175 | self.launchpad = Thing(branches=Thing(getByUrl=self.getBranchByUrl), | 180 | self.launchpad = Thing(branches=Thing(getByUrl=self.getBranchByUrl), |
189 | 176 | me=Thing(display_name='Tarmac')) | 181 | me=Thing(display_name='Tarmac')) |
190 | @@ -180,6 +185,42 @@ | |||
191 | 180 | 185 | ||
192 | 181 | self.command = registry._get_command(commands.cmd_merge, 'merge') | 186 | self.command = registry._get_command(commands.cmd_merge, 'merge') |
193 | 182 | 187 | ||
194 | 188 | def addProposal(self, name, prerequisite_branch=None): | ||
195 | 189 | """Create a 3rd branch with a proposal""" | ||
196 | 190 | # Create a 3rd branch we'll use to test with | ||
197 | 191 | branch3_dir = os.path.join(self.TEST_ROOT, name) | ||
198 | 192 | mock3 = MockLPBranch(branch3_dir, source_branch=self.branch1.lp_branch) | ||
199 | 193 | branch3 = Branch.create(mock3, self.config, create_tree=True, | ||
200 | 194 | target=self.branch1) | ||
201 | 195 | branch3.commit('Prerequisite commit.') | ||
202 | 196 | branch3.lp_branch.revision_count += 1 | ||
203 | 197 | |||
204 | 198 | # Set up an approved proposal for the branch (prereq on branches[0]) | ||
205 | 199 | branch3.lp_branch.display_name = branch3.lp_branch.bzr_identity | ||
206 | 200 | branch3.lp_branch.name = name | ||
207 | 201 | branch3.lp_branch.unique_name = '~user/branch/' + name | ||
208 | 202 | branch3.lp_branch.landing_candidates = [] | ||
209 | 203 | b3_proposal = Thing( | ||
210 | 204 | self_link=u'http://api.edge.launchpad.net/devel/proposal3', | ||
211 | 205 | web_link=u'http://edge.launchpad.net/proposal3', | ||
212 | 206 | queue_status=u'Approved', | ||
213 | 207 | commit_message=u'Commitable.', | ||
214 | 208 | source_branch=branch3.lp_branch, | ||
215 | 209 | target_branch=self.branches[1], | ||
216 | 210 | prerequisite_branch=prerequisite_branch, | ||
217 | 211 | createComment=self.createComment, | ||
218 | 212 | setStatus=self.lp_save, | ||
219 | 213 | lp_save=self.lp_save, | ||
220 | 214 | reviewed_revid=None, | ||
221 | 215 | votes=[Thing( | ||
222 | 216 | comment=Thing(vote=u'Approve'), | ||
223 | 217 | reviewer=Thing(display_name=u'Reviewer'))]) | ||
224 | 218 | |||
225 | 219 | branch3.lp_branch.landing_targets = [b3_proposal] | ||
226 | 220 | self.proposals.append(b3_proposal) | ||
227 | 221 | self.branches.append(branch3.lp_branch) | ||
228 | 222 | |||
229 | 223 | |||
230 | 183 | def lp_save(self, *args, **kwargs): | 224 | def lp_save(self, *args, **kwargs): |
231 | 184 | """Do nothing here.""" | 225 | """Do nothing here.""" |
232 | 185 | pass | 226 | pass |
233 | @@ -248,8 +289,8 @@ | |||
234 | 248 | self.assertEqual(last_rev.properties.get('merge_url', None), | 289 | self.assertEqual(last_rev.properties.get('merge_url', None), |
235 | 249 | u'http://code.launchpad.net/proposal0') | 290 | u'http://code.launchpad.net/proposal0') |
236 | 250 | 291 | ||
239 | 251 | def test_run_merge_with_unmerged_prerequisite_fails(self): | 292 | def test_run_merge_with_unmerged_prerequisite_skips(self): |
240 | 252 | """Test that mereging a branch with an unmerged prerequisite fails.""" | 293 | """Test that mereging a branch with an unmerged prerequisite skips.""" |
241 | 253 | # Create a 3rd prerequisite branch we'll use to test with | 294 | # Create a 3rd prerequisite branch we'll use to test with |
242 | 254 | branch3_dir = os.path.join(self.TEST_ROOT, 'branch3') | 295 | branch3_dir = os.path.join(self.TEST_ROOT, 'branch3') |
243 | 255 | mock3 = MockLPBranch(branch3_dir, source_branch=self.branch1.lp_branch) | 296 | mock3 = MockLPBranch(branch3_dir, source_branch=self.branch1.lp_branch) |
244 | @@ -267,6 +308,7 @@ | |||
245 | 267 | # Set up an unapproved proposal for the prerequisite | 308 | # Set up an unapproved proposal for the prerequisite |
246 | 268 | branch3.lp_branch.display_name = branch3.lp_branch.bzr_identity | 309 | branch3.lp_branch.display_name = branch3.lp_branch.bzr_identity |
247 | 269 | branch3.lp_branch.name = 'branch3' | 310 | branch3.lp_branch.name = 'branch3' |
248 | 311 | branch3.unique_name = 'branch3' | ||
249 | 270 | branch3.lp_branch.landing_candidates = [] | 312 | branch3.lp_branch.landing_candidates = [] |
250 | 271 | b3_proposal = Thing( | 313 | b3_proposal = Thing( |
251 | 272 | self_link=u'http://api.edge.launchpad.net/devel/proposal3', | 314 | self_link=u'http://api.edge.launchpad.net/devel/proposal3', |
252 | @@ -290,11 +332,8 @@ | |||
253 | 290 | self.proposals[1].prerequisite_branch = branch3.lp_branch | 332 | self.proposals[1].prerequisite_branch = branch3.lp_branch |
254 | 291 | self.proposals[1].reviewed_revid = \ | 333 | self.proposals[1].reviewed_revid = \ |
255 | 292 | self.branch2.bzr_branch.last_revision() | 334 | self.branch2.bzr_branch.last_revision() |
257 | 293 | self.command.run(launchpad=self.launchpad) | 335 | self.assertEqual(self.command.run(launchpad=self.launchpad), None) |
258 | 294 | shutil.rmtree(branch3_dir) | 336 | shutil.rmtree(branch3_dir) |
259 | 295 | self.assertEqual(self.error.comment, | ||
260 | 296 | u'The prerequisite lp:branch3 has not yet been ' | ||
261 | 297 | u'merged into lp:branch1.') | ||
262 | 298 | 337 | ||
263 | 299 | def test_run_merge_with_unproposed_prerequisite_fails(self): | 338 | def test_run_merge_with_unproposed_prerequisite_fails(self): |
264 | 300 | """Test that mereging a branch with an unmerged prerequisite fails.""" | 339 | """Test that mereging a branch with an unmerged prerequisite fails.""" |
265 | @@ -315,6 +354,7 @@ | |||
266 | 315 | # Set up an unapproved proposal for the prerequisite | 354 | # Set up an unapproved proposal for the prerequisite |
267 | 316 | branch3.lp_branch.display_name = branch3.lp_branch.bzr_identity | 355 | branch3.lp_branch.display_name = branch3.lp_branch.bzr_identity |
268 | 317 | branch3.lp_branch.name = 'branch3' | 356 | branch3.lp_branch.name = 'branch3' |
269 | 357 | branch3.lp_branch.unique_name = 'branch3' | ||
270 | 318 | branch3.lp_branch.landing_candidates = [] | 358 | branch3.lp_branch.landing_candidates = [] |
271 | 319 | b3_proposal = Thing( | 359 | b3_proposal = Thing( |
272 | 320 | self_link=u'http://api.edge.launchpad.net/devel/proposal3', | 360 | self_link=u'http://api.edge.launchpad.net/devel/proposal3', |
273 | @@ -363,6 +403,7 @@ | |||
274 | 363 | # Set up an unapproved proposal for the prerequisite | 403 | # Set up an unapproved proposal for the prerequisite |
275 | 364 | branch3.lp_branch.display_name = branch3.lp_branch.bzr_identity | 404 | branch3.lp_branch.display_name = branch3.lp_branch.bzr_identity |
276 | 365 | branch3.lp_branch.name = 'branch3' | 405 | branch3.lp_branch.name = 'branch3' |
277 | 406 | branch3.lp_branch.unique_name = 'branch3' | ||
278 | 366 | branch3.lp_branch.landing_candidates = [] | 407 | branch3.lp_branch.landing_candidates = [] |
279 | 367 | b3_proposal = Thing( | 408 | b3_proposal = Thing( |
280 | 368 | self_link=u'http://api.edge.launchpad.net/devel/proposal3', | 409 | self_link=u'http://api.edge.launchpad.net/devel/proposal3', |
281 | @@ -394,8 +435,8 @@ | |||
282 | 394 | shutil.rmtree(branch3_dir) | 435 | shutil.rmtree(branch3_dir) |
283 | 395 | self.assertEqual(self.error.comment, | 436 | self.assertEqual(self.error.comment, |
284 | 396 | u'More than one proposal found for merge of ' | 437 | u'More than one proposal found for merge of ' |
287 | 397 | u'lp:branch3 into lp:branch1, which is not ' | 438 | u'lp:branch3 into lp:branch1, ' |
288 | 398 | u'Superseded.') | 439 | u'which is not Superseded.') |
289 | 399 | 440 | ||
290 | 400 | @patch('bzrlib.workingtree.WorkingTree.open') | 441 | @patch('bzrlib.workingtree.WorkingTree.open') |
291 | 401 | def test_run_merge_with_invalid_workingtree(self, mocked): | 442 | def test_run_merge_with_invalid_workingtree(self, mocked): |
292 | @@ -407,3 +448,55 @@ | |||
293 | 407 | self.command.run(launchpad=self.launchpad) | 448 | self.command.run(launchpad=self.launchpad) |
294 | 408 | self.assertEqual(self.error.comment, | 449 | self.assertEqual(self.error.comment, |
295 | 409 | invalid_tree_comment) | 450 | invalid_tree_comment) |
296 | 451 | |||
297 | 452 | def test__compare_proposals(self): | ||
298 | 453 | """ | ||
299 | 454 | _compare_proposals is meant to be a sort routine comparison function | ||
300 | 455 | """ | ||
301 | 456 | self.addProposal("compare_proposals", self.branches[0]) | ||
302 | 457 | self.assertEqual( | ||
303 | 458 | commands._compare_proposals(self.proposals[0], self.proposals[1]), | ||
304 | 459 | 0) | ||
305 | 460 | self.assertEqual( | ||
306 | 461 | commands._compare_proposals(self.proposals[0], self.proposals[2]), | ||
307 | 462 | -1) | ||
308 | 463 | self.assertEqual( | ||
309 | 464 | commands._compare_proposals(self.proposals[2], self.proposals[0]), | ||
310 | 465 | 1) | ||
311 | 466 | |||
312 | 467 | def test__get_mergable_proposals_for_branch_are_sorted(self): | ||
313 | 468 | """ | ||
314 | 469 | Mergable proposals should be in sorted order (prereqs should come | ||
315 | 470 | first in the list) | ||
316 | 471 | """ | ||
317 | 472 | self.addProposal("sorted_test", self.branches[0]) | ||
318 | 473 | proposals = self.command._get_mergable_proposals_for_branch( | ||
319 | 474 | self.branches[1]) | ||
320 | 475 | self.assertEqual(len(proposals), 2) | ||
321 | 476 | self.assertTrue(proposals[1].source_branch.name == "sorted_test") | ||
322 | 477 | |||
323 | 478 | def test__get_mergable_proposals_for_branch_prereq_unmerged(self): | ||
324 | 479 | """ | ||
325 | 480 | skip mergable proposals that have specified a prereq, | ||
326 | 481 | but that prereq is not merged yet. This is edge-casey, since | ||
327 | 482 | we now process the queue in an order that makes sense for | ||
328 | 483 | prereqs | ||
329 | 484 | """ | ||
330 | 485 | self.addProposal("unmerged") | ||
331 | 486 | self.proposals[0].prerequisite_branch = self.branches[2] | ||
332 | 487 | self.proposals[1].prerequisite_branch = self.branches[2] | ||
333 | 488 | proposals = self.command._get_mergable_proposals_for_branch( | ||
334 | 489 | self.branches[1]) | ||
335 | 490 | self.assertEqual(len(proposals), 1) | ||
336 | 491 | self.assertEqual(proposals[0].source_branch.name, "unmerged") | ||
337 | 492 | |||
338 | 493 | def test__get_prerequisite_proposals_no_prerequisites(self): | ||
339 | 494 | """proposals[0] does not have a prerequisite branch listed""" | ||
340 | 495 | proposals = self.command._get_prerequisite_proposals(self.proposals[0]) | ||
341 | 496 | self.assertEqual(len(proposals), 0) | ||
342 | 497 | |||
343 | 498 | def test__get_prerequisite_proposals_one_prerequisite(self): | ||
344 | 499 | """Branches[0] (source) has two open MPs against it""" | ||
345 | 500 | self.addProposal("one_prerequisite", self.branches[0]) | ||
346 | 501 | proposals = self.command._get_prerequisite_proposals(self.proposals[2]) | ||
347 | 502 | self.assertEqual(len(proposals), 2) |
32 + * Multiple prerequisite non-superseded MPs => error
How does one declare multiple prerequisite branches in Launchpad?
161 +++ tarmac/ tests/test_ commands. py 2013-12-05 22:45:14 +0000
Many of the changes in here seem unrelated to the prerequisite work, and seems to be just you changing some of the names for the third branch in several of the tests. How are these related?
The bug you filed is a duplicate of https:/ /bugs.launchpad .net/tarmac/ +bug/900731 and I've marked it as such already. Changing the --fixes here too would be great, if possible.
Also, you need to commit using an e-mail address that is associated with your Launchpad account. Your shortened canonical.com address does not appear to be associated to your account, and so Launchpad cannot link to your account, nor will tarmac be able to find you via the Launchpad API from the e-mail address in the commit.