Merge lp:~cjwatson/launchpad/git-recipe-model into lp:launchpad
- git-recipe-model
- Merge into devel
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 17893 | ||||
Proposed branch: | lp:~cjwatson/launchpad/git-recipe-model | ||||
Merge into: | lp:launchpad | ||||
Prerequisite: | lp:~cjwatson/launchpad/minimal-recipe-text-bzr | ||||
Diff against target: |
1518 lines (+472/-211) 8 files modified
lib/lp/code/errors.py (+14/-3) lib/lp/code/interfaces/sourcepackagerecipe.py (+16/-1) lib/lp/code/model/sourcepackagerecipe.py (+21/-1) lib/lp/code/model/sourcepackagerecipebuild.py (+1/-1) lib/lp/code/model/sourcepackagerecipedata.py (+133/-41) lib/lp/code/model/tests/test_sourcepackagerecipe.py (+264/-157) lib/lp/code/model/tests/test_sourcepackagerecipebuild.py (+4/-4) lib/lp/testing/factory.py (+19/-3) |
||||
To merge this branch: | bzr merge lp:~cjwatson/launchpad/git-recipe-model | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
William Grant | code | Approve | |
Review via email: mp+282248@code.launchpad.net |
Commit message
Add basic model for Git recipes.
Description of the change
Add basic model for Git recipes.
This is long, but it's mostly tests, and I couldn't get it much shorter while still testing it properly.
While the database model has git_repository plus a revspec, and there are certainly cases where one might wish to pin a recipe to a particular tag or commit rather than a moving branch (so that should be possible), the common case is going to be to create a recipe based on a branch; this is therefore optimised for that workflow, so you can point the recipe construction code at an IGitRef and it will set the revspec to the branch name. The browser code will let you create and list recipes from either a GitRef or a GitRepository (and if you don't fill in a revspec manually in the latter case, git-build-recipe will use HEAD, which matches "git clone" and is often what people will want in practice). I think this approach is least likely to result in confused users unable to find the link.
Other bits like repository deletion handling, staleness handling, and browser code will follow in later branches.
William Grant (wgrant) : | # |
Preview Diff
1 | === modified file 'lib/lp/code/errors.py' | |||
2 | --- lib/lp/code/errors.py 2015-06-13 01:45:19 +0000 | |||
3 | +++ lib/lp/code/errors.py 2016-01-12 17:27:35 +0000 | |||
4 | @@ -1,4 +1,4 @@ | |||
6 | 1 | # Copyright 2009-2015 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2016 Canonical Ltd. This software is licensed under the |
7 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
8 | 3 | 3 | ||
9 | 4 | """Errors used in the lp/code modules.""" | 4 | """Errors used in the lp/code modules.""" |
10 | @@ -46,6 +46,7 @@ | |||
11 | 46 | 'NoSuchGitReference', | 46 | 'NoSuchGitReference', |
12 | 47 | 'NoSuchGitRepository', | 47 | 'NoSuchGitRepository', |
13 | 48 | 'PrivateBranchRecipe', | 48 | 'PrivateBranchRecipe', |
14 | 49 | 'PrivateGitRepositoryRecipe', | ||
15 | 49 | 'ReviewNotPending', | 50 | 'ReviewNotPending', |
16 | 50 | 'StaleLastMirrored', | 51 | 'StaleLastMirrored', |
17 | 51 | 'TooNewRecipeFormat', | 52 | 'TooNewRecipeFormat', |
18 | @@ -298,12 +299,22 @@ | |||
19 | 298 | 299 | ||
20 | 299 | def __init__(self, branch): | 300 | def __init__(self, branch): |
21 | 300 | message = ( | 301 | message = ( |
24 | 301 | 'Recipe may not refer to private branch: %s' % | 302 | 'Recipe may not refer to private branch: %s' % branch.identity) |
23 | 302 | branch.bzr_identity) | ||
25 | 303 | self.branch = branch | 303 | self.branch = branch |
26 | 304 | Exception.__init__(self, message) | 304 | Exception.__init__(self, message) |
27 | 305 | 305 | ||
28 | 306 | 306 | ||
29 | 307 | @error_status(httplib.BAD_REQUEST) | ||
30 | 308 | class PrivateGitRepositoryRecipe(Exception): | ||
31 | 309 | |||
32 | 310 | def __init__(self, repository): | ||
33 | 311 | message = ( | ||
34 | 312 | 'Recipe may not refer to private repository: %s' % | ||
35 | 313 | repository.identity) | ||
36 | 314 | self.repository = repository | ||
37 | 315 | Exception.__init__(self, message) | ||
38 | 316 | |||
39 | 317 | |||
40 | 307 | class ReviewNotPending(Exception): | 318 | class ReviewNotPending(Exception): |
41 | 308 | """The requested review is not in a pending state.""" | 319 | """The requested review is not in a pending state.""" |
42 | 309 | 320 | ||
43 | 310 | 321 | ||
44 | === modified file 'lib/lp/code/interfaces/sourcepackagerecipe.py' | |||
45 | --- lib/lp/code/interfaces/sourcepackagerecipe.py 2016-01-11 21:11:27 +0000 | |||
46 | +++ lib/lp/code/interfaces/sourcepackagerecipe.py 2016-01-12 17:27:35 +0000 | |||
47 | @@ -14,6 +14,7 @@ | |||
48 | 14 | 'ISourcePackageRecipeDataSource', | 14 | 'ISourcePackageRecipeDataSource', |
49 | 15 | 'ISourcePackageRecipeSource', | 15 | 'ISourcePackageRecipeSource', |
50 | 16 | 'MINIMAL_RECIPE_TEXT_BZR', | 16 | 'MINIMAL_RECIPE_TEXT_BZR', |
51 | 17 | 'MINIMAL_RECIPE_TEXT_GIT', | ||
52 | 17 | ] | 18 | ] |
53 | 18 | 19 | ||
54 | 19 | 20 | ||
55 | @@ -55,6 +56,7 @@ | |||
56 | 55 | from lp import _ | 56 | from lp import _ |
57 | 56 | from lp.app.validators.name import name_validator | 57 | from lp.app.validators.name import name_validator |
58 | 57 | from lp.code.interfaces.branch import IBranch | 58 | from lp.code.interfaces.branch import IBranch |
59 | 59 | from lp.code.interfaces.gitrepository import IGitRepository | ||
60 | 58 | from lp.registry.interfaces.distroseries import IDistroSeries | 60 | from lp.registry.interfaces.distroseries import IDistroSeries |
61 | 59 | from lp.registry.interfaces.pocket import PackagePublishingPocket | 61 | from lp.registry.interfaces.pocket import PackagePublishingPocket |
62 | 60 | from lp.registry.interfaces.role import IHasOwner | 62 | from lp.registry.interfaces.role import IHasOwner |
63 | @@ -72,13 +74,26 @@ | |||
64 | 72 | ''') | 74 | ''') |
65 | 73 | 75 | ||
66 | 74 | 76 | ||
67 | 77 | MINIMAL_RECIPE_TEXT_GIT = dedent(u'''\ | ||
68 | 78 | # git-build-recipe format 0.4 deb-version {debupstream}-0~{revtime} | ||
69 | 79 | %s %s | ||
70 | 80 | ''') | ||
71 | 81 | |||
72 | 82 | |||
73 | 75 | class ISourcePackageRecipeData(Interface): | 83 | class ISourcePackageRecipeData(Interface): |
74 | 76 | """A recipe as database data, not text.""" | 84 | """A recipe as database data, not text.""" |
75 | 77 | 85 | ||
76 | 78 | base_branch = exported( | 86 | base_branch = exported( |
77 | 79 | Reference( | 87 | Reference( |
78 | 80 | IBranch, title=_("The base branch used by this recipe."), | 88 | IBranch, title=_("The base branch used by this recipe."), |
80 | 81 | required=True, readonly=True)) | 89 | required=False, readonly=True)) |
81 | 90 | base_git_repository = exported( | ||
82 | 91 | Reference( | ||
83 | 92 | IGitRepository, | ||
84 | 93 | title=_("The base Git repository used by this recipe."), | ||
85 | 94 | required=False, readonly=True)) | ||
86 | 95 | base = Attribute( | ||
87 | 96 | "The base branch/repository used by this recipe (VCS-agnostic).") | ||
88 | 82 | 97 | ||
89 | 83 | deb_version_template = exported( | 98 | deb_version_template = exported( |
90 | 84 | TextLine( | 99 | TextLine( |
91 | 85 | 100 | ||
92 | === modified file 'lib/lp/code/model/sourcepackagerecipe.py' | |||
93 | --- lib/lp/code/model/sourcepackagerecipe.py 2016-01-11 19:16:04 +0000 | |||
94 | +++ lib/lp/code/model/sourcepackagerecipe.py 2016-01-12 17:27:35 +0000 | |||
95 | @@ -13,6 +13,7 @@ | |||
96 | 13 | timedelta, | 13 | timedelta, |
97 | 14 | ) | 14 | ) |
98 | 15 | from operator import attrgetter | 15 | from operator import attrgetter |
99 | 16 | import re | ||
100 | 16 | 17 | ||
101 | 17 | from lazr.delegates import delegate_to | 18 | from lazr.delegates import delegate_to |
102 | 18 | from pytz import utc | 19 | from pytz import utc |
103 | @@ -151,6 +152,18 @@ | |||
104 | 151 | def base_branch(self): | 152 | def base_branch(self): |
105 | 152 | return self._recipe_data.base_branch | 153 | return self._recipe_data.base_branch |
106 | 153 | 154 | ||
107 | 155 | @property | ||
108 | 156 | def base_git_repository(self): | ||
109 | 157 | return self._recipe_data.base_git_repository | ||
110 | 158 | |||
111 | 159 | @property | ||
112 | 160 | def base(self): | ||
113 | 161 | if self.base_branch is not None: | ||
114 | 162 | return self.base_branch | ||
115 | 163 | else: | ||
116 | 164 | assert self.base_git_repository is not None | ||
117 | 165 | return self.base_git_repository | ||
118 | 166 | |||
119 | 154 | @staticmethod | 167 | @staticmethod |
120 | 155 | def preLoadDataForSourcePackageRecipes(sourcepackagerecipes): | 168 | def preLoadDataForSourcePackageRecipes(sourcepackagerecipes): |
121 | 156 | # Load the referencing SourcePackageRecipeData. | 169 | # Load the referencing SourcePackageRecipeData. |
122 | @@ -173,7 +186,14 @@ | |||
123 | 173 | 186 | ||
124 | 174 | @property | 187 | @property |
125 | 175 | def recipe_text(self): | 188 | def recipe_text(self): |
127 | 176 | return self.builder_recipe.get_recipe_text() | 189 | recipe_text = self.builder_recipe.get_recipe_text() |
128 | 190 | # For git-based recipes, mangle the header line to say | ||
129 | 191 | # "git-build-recipe" to reduce confusion; bzr-builder's recipe | ||
130 | 192 | # parser will always round-trip this to "bzr-builder". | ||
131 | 193 | if self.base_git_repository is not None: | ||
132 | 194 | recipe_text = re.sub( | ||
133 | 195 | r"^(#\s*)bzr-builder", r"\1git-build-recipe", recipe_text) | ||
134 | 196 | return recipe_text | ||
135 | 177 | 197 | ||
136 | 178 | def updateSeries(self, distroseries): | 198 | def updateSeries(self, distroseries): |
137 | 179 | if distroseries != self.distroseries: | 199 | if distroseries != self.distroseries: |
138 | 180 | 200 | ||
139 | === modified file 'lib/lp/code/model/sourcepackagerecipebuild.py' | |||
140 | --- lib/lp/code/model/sourcepackagerecipebuild.py 2016-01-11 19:16:04 +0000 | |||
141 | +++ lib/lp/code/model/sourcepackagerecipebuild.py 2016-01-12 17:27:35 +0000 | |||
142 | @@ -183,7 +183,7 @@ | |||
143 | 183 | if self.recipe is None: | 183 | if self.recipe is None: |
144 | 184 | branch_name = 'deleted' | 184 | branch_name = 'deleted' |
145 | 185 | else: | 185 | else: |
147 | 186 | branch_name = self.recipe.base_branch.unique_name | 186 | branch_name = self.recipe.base.unique_name |
148 | 187 | return '%s recipe build in %s %s' % ( | 187 | return '%s recipe build in %s %s' % ( |
149 | 188 | branch_name, self.distribution.name, self.distroseries.name) | 188 | branch_name, self.distribution.name, self.distroseries.name) |
150 | 189 | 189 | ||
151 | 190 | 190 | ||
152 | === modified file 'lib/lp/code/model/sourcepackagerecipedata.py' | |||
153 | --- lib/lp/code/model/sourcepackagerecipedata.py 2016-01-11 19:16:04 +0000 | |||
154 | +++ lib/lp/code/model/sourcepackagerecipedata.py 2016-01-12 17:27:35 +0000 | |||
155 | @@ -11,7 +11,7 @@ | |||
156 | 11 | __metaclass__ = type | 11 | __metaclass__ = type |
157 | 12 | __all__ = ['SourcePackageRecipeData'] | 12 | __all__ = ['SourcePackageRecipeData'] |
158 | 13 | 13 | ||
160 | 14 | from itertools import groupby | 14 | import re |
161 | 15 | 15 | ||
162 | 16 | from bzrlib.plugins.builder.recipe import ( | 16 | from bzrlib.plugins.builder.recipe import ( |
163 | 17 | BaseRecipeBranch, | 17 | BaseRecipeBranch, |
164 | @@ -45,16 +45,23 @@ | |||
165 | 45 | 45 | ||
166 | 46 | from lp.code.errors import ( | 46 | from lp.code.errors import ( |
167 | 47 | NoSuchBranch, | 47 | NoSuchBranch, |
168 | 48 | NoSuchGitRepository, | ||
169 | 48 | PrivateBranchRecipe, | 49 | PrivateBranchRecipe, |
170 | 50 | PrivateGitRepositoryRecipe, | ||
171 | 49 | TooNewRecipeFormat, | 51 | TooNewRecipeFormat, |
172 | 50 | ) | 52 | ) |
173 | 53 | from lp.code.interfaces.branch import IBranch | ||
174 | 51 | from lp.code.interfaces.branchlookup import IBranchLookup | 54 | from lp.code.interfaces.branchlookup import IBranchLookup |
175 | 55 | from lp.code.interfaces.gitlookup import IGitLookup | ||
176 | 56 | from lp.code.interfaces.gitref import IGitRef | ||
177 | 57 | from lp.code.interfaces.gitrepository import IGitRepository | ||
178 | 52 | from lp.code.interfaces.sourcepackagerecipe import ( | 58 | from lp.code.interfaces.sourcepackagerecipe import ( |
179 | 53 | IRecipeBranchSource, | 59 | IRecipeBranchSource, |
180 | 54 | ISourcePackageRecipeData, | 60 | ISourcePackageRecipeData, |
181 | 55 | ISourcePackageRecipeDataSource, | 61 | ISourcePackageRecipeDataSource, |
182 | 56 | ) | 62 | ) |
183 | 57 | from lp.code.model.branch import Branch | 63 | from lp.code.model.branch import Branch |
184 | 64 | from lp.code.model.gitrepository import GitRepository | ||
185 | 58 | from lp.services.database.bulk import ( | 65 | from lp.services.database.bulk import ( |
186 | 59 | load_referencing, | 66 | load_referencing, |
187 | 60 | load_related, | 67 | load_related, |
188 | @@ -92,15 +99,25 @@ | |||
189 | 92 | 99 | ||
190 | 93 | __storm_table__ = "SourcePackageRecipeDataInstruction" | 100 | __storm_table__ = "SourcePackageRecipeDataInstruction" |
191 | 94 | 101 | ||
194 | 95 | def __init__(self, name, type, comment, line_number, branch, revspec, | 102 | def __init__(self, name, type, comment, line_number, branch_or_repository, |
195 | 96 | directory, recipe_data, parent_instruction, | 103 | revspec, directory, recipe_data, parent_instruction, |
196 | 97 | source_directory): | 104 | source_directory): |
197 | 98 | super(_SourcePackageRecipeDataInstruction, self).__init__() | 105 | super(_SourcePackageRecipeDataInstruction, self).__init__() |
198 | 99 | self.name = unicode(name) | 106 | self.name = unicode(name) |
199 | 100 | self.type = type | 107 | self.type = type |
200 | 101 | self.comment = comment | 108 | self.comment = comment |
201 | 102 | self.line_number = line_number | 109 | self.line_number = line_number |
203 | 103 | self.branch = branch | 110 | if IGitRepository.providedBy(branch_or_repository): |
204 | 111 | self.git_repository = branch_or_repository | ||
205 | 112 | elif IGitRef.providedBy(branch_or_repository): | ||
206 | 113 | self.git_repository = branch_or_repository | ||
207 | 114 | if revspec is None: | ||
208 | 115 | revspec = branch_or_repository.name | ||
209 | 116 | elif IBranch.providedBy(branch_or_repository): | ||
210 | 117 | self.branch = branch_or_repository | ||
211 | 118 | else: | ||
212 | 119 | raise AssertionError( | ||
213 | 120 | "Unsupported source: %r" % (branch_or_repository,)) | ||
214 | 104 | if revspec is not None: | 121 | if revspec is not None: |
215 | 105 | revspec = unicode(revspec) | 122 | revspec = unicode(revspec) |
216 | 106 | self.revspec = revspec | 123 | self.revspec = revspec |
217 | @@ -118,8 +135,10 @@ | |||
218 | 118 | comment = Unicode(allow_none=True) | 135 | comment = Unicode(allow_none=True) |
219 | 119 | line_number = Int(allow_none=False) | 136 | line_number = Int(allow_none=False) |
220 | 120 | 137 | ||
222 | 121 | branch_id = Int(name='branch', allow_none=False) | 138 | branch_id = Int(name='branch', allow_none=True) |
223 | 122 | branch = Reference(branch_id, 'Branch.id') | 139 | branch = Reference(branch_id, 'Branch.id') |
224 | 140 | git_repository_id = Int(name='git_repository', allow_none=True) | ||
225 | 141 | git_repository = Reference(git_repository_id, 'GitRepository.id') | ||
226 | 123 | 142 | ||
227 | 124 | revspec = Unicode(allow_none=True) | 143 | revspec = Unicode(allow_none=True) |
228 | 125 | directory = Unicode(allow_none=True) | 144 | directory = Unicode(allow_none=True) |
229 | @@ -134,8 +153,12 @@ | |||
230 | 134 | 153 | ||
231 | 135 | def appendToRecipe(self, recipe_branch): | 154 | def appendToRecipe(self, recipe_branch): |
232 | 136 | """Append a bzr-builder instruction to the recipe_branch object.""" | 155 | """Append a bzr-builder instruction to the recipe_branch object.""" |
235 | 137 | branch = RecipeBranch( | 156 | if self.branch is not None: |
236 | 138 | self.name, self.branch.bzr_identity, self.revspec) | 157 | identity = self.branch.identity |
237 | 158 | else: | ||
238 | 159 | assert self.git_repository is not None | ||
239 | 160 | identity = self.git_repository.identity | ||
240 | 161 | branch = RecipeBranch(self.name, identity, self.revspec) | ||
241 | 139 | if self.type == InstructionType.MERGE: | 162 | if self.type == InstructionType.MERGE: |
242 | 140 | recipe_branch.merge_branch(branch) | 163 | recipe_branch.merge_branch(branch) |
243 | 141 | elif self.type == InstructionType.NEST: | 164 | elif self.type == InstructionType.NEST: |
244 | @@ -165,8 +188,29 @@ | |||
245 | 165 | 188 | ||
246 | 166 | id = Int(primary=True) | 189 | id = Int(primary=True) |
247 | 167 | 190 | ||
249 | 168 | base_branch_id = Int(name='base_branch', allow_none=False) | 191 | base_branch_id = Int(name='base_branch', allow_none=True) |
250 | 169 | base_branch = Reference(base_branch_id, 'Branch.id') | 192 | base_branch = Reference(base_branch_id, 'Branch.id') |
251 | 193 | base_git_repository_id = Int(name='base_git_repository', allow_none=True) | ||
252 | 194 | base_git_repository = Reference(base_git_repository_id, 'GitRepository.id') | ||
253 | 195 | |||
254 | 196 | @property | ||
255 | 197 | def base(self): | ||
256 | 198 | if self.base_branch is not None: | ||
257 | 199 | return self.base_branch | ||
258 | 200 | else: | ||
259 | 201 | assert self.base_git_repository is not None | ||
260 | 202 | return self.base_git_repository | ||
261 | 203 | |||
262 | 204 | @base.setter | ||
263 | 205 | def base(self, value): | ||
264 | 206 | if IGitRepository.providedBy(value): | ||
265 | 207 | self.base_git_repository = value | ||
266 | 208 | self.base_branch = None | ||
267 | 209 | elif IBranch.providedBy(value): | ||
268 | 210 | self.base_branch = value | ||
269 | 211 | self.base_git_repository = None | ||
270 | 212 | else: | ||
271 | 213 | raise AssertionError("Unsupported base: %r" % (value,)) | ||
272 | 170 | 214 | ||
273 | 171 | recipe_format = Unicode(allow_none=False) | 215 | recipe_format = Unicode(allow_none=False) |
274 | 172 | deb_version_template = Unicode(allow_none=True) | 216 | deb_version_template = Unicode(allow_none=True) |
275 | @@ -189,6 +233,12 @@ | |||
276 | 189 | @staticmethod | 233 | @staticmethod |
277 | 190 | def getParsedRecipe(recipe_text): | 234 | def getParsedRecipe(recipe_text): |
278 | 191 | """See `IRecipeBranchSource`.""" | 235 | """See `IRecipeBranchSource`.""" |
279 | 236 | # We're using bzr-builder to parse the recipe text. While the | ||
280 | 237 | # formats are mostly compatible, the header line must say | ||
281 | 238 | # "bzr-builder" even though git-build-recipe also supports its own | ||
282 | 239 | # name there. | ||
283 | 240 | recipe_text = re.sub( | ||
284 | 241 | r"^(#\s*)git-build-recipe", r"\1bzr-builder", recipe_text) | ||
285 | 192 | parser = RecipeParser(recipe_text) | 242 | parser = RecipeParser(recipe_text) |
286 | 193 | return parser.parse(permitted_instructions=SAFE_INSTRUCTIONS) | 243 | return parser.parse(permitted_instructions=SAFE_INSTRUCTIONS) |
287 | 194 | 244 | ||
288 | @@ -222,7 +272,7 @@ | |||
289 | 222 | def getRecipe(self): | 272 | def getRecipe(self): |
290 | 223 | """The BaseRecipeBranch version of the recipe.""" | 273 | """The BaseRecipeBranch version of the recipe.""" |
291 | 224 | base_branch = BaseRecipeBranch( | 274 | base_branch = BaseRecipeBranch( |
293 | 225 | self.base_branch.bzr_identity, self.deb_version_template, | 275 | self.base.identity, self.deb_version_template, |
294 | 226 | self.recipe_format, self.revspec) | 276 | self.recipe_format, self.revspec) |
295 | 227 | insn_stack = [] | 277 | insn_stack = [] |
296 | 228 | for insn in self.instructions: | 278 | for insn in self.instructions: |
297 | @@ -238,7 +288,7 @@ | |||
298 | 238 | dict(insn=insn, recipe_branch=recipe_branch)) | 288 | dict(insn=insn, recipe_branch=recipe_branch)) |
299 | 239 | return base_branch | 289 | return base_branch |
300 | 240 | 290 | ||
302 | 241 | def _scanInstructions(self, recipe_branch): | 291 | def _scanInstructions(self, base, recipe_branch): |
303 | 242 | """Check the recipe_branch doesn't use 'run' and look up the branches. | 292 | """Check the recipe_branch doesn't use 'run' and look up the branches. |
304 | 243 | 293 | ||
305 | 244 | We do all the lookups before we start constructing database objects to | 294 | We do all the lookups before we start constructing database objects to |
306 | @@ -247,15 +297,22 @@ | |||
307 | 247 | :return: A map ``{branch_url: db_branch}``. | 297 | :return: A map ``{branch_url: db_branch}``. |
308 | 248 | """ | 298 | """ |
309 | 249 | r = {} | 299 | r = {} |
310 | 300 | if IGitRepository.providedBy(base): | ||
311 | 301 | lookup = getUtility(IGitLookup) | ||
312 | 302 | missing_error = NoSuchGitRepository | ||
313 | 303 | private_error = PrivateGitRepositoryRecipe | ||
314 | 304 | else: | ||
315 | 305 | lookup = getUtility(IBranchLookup) | ||
316 | 306 | missing_error = NoSuchBranch | ||
317 | 307 | private_error = PrivateBranchRecipe | ||
318 | 250 | for instruction in recipe_branch.child_branches: | 308 | for instruction in recipe_branch.child_branches: |
321 | 251 | db_branch = getUtility(IBranchLookup).getByUrl( | 309 | db_branch = lookup.getByUrl(instruction.recipe_branch.url) |
320 | 252 | instruction.recipe_branch.url) | ||
322 | 253 | if db_branch is None: | 310 | if db_branch is None: |
324 | 254 | raise NoSuchBranch(instruction.recipe_branch.url) | 311 | raise missing_error(instruction.recipe_branch.url) |
325 | 255 | if db_branch.private: | 312 | if db_branch.private: |
327 | 256 | raise PrivateBranchRecipe(db_branch) | 313 | raise private_error(db_branch) |
328 | 257 | r[instruction.recipe_branch.url] = db_branch | 314 | r[instruction.recipe_branch.url] = db_branch |
330 | 258 | r.update(self._scanInstructions(instruction.recipe_branch)) | 315 | r.update(self._scanInstructions(base, instruction.recipe_branch)) |
331 | 259 | return r | 316 | return r |
332 | 260 | 317 | ||
333 | 261 | def _recordInstructions(self, recipe_branch, parent_insn, branch_map, | 318 | def _recordInstructions(self, recipe_branch, parent_insn, branch_map, |
334 | @@ -280,10 +337,11 @@ | |||
335 | 280 | "Unsupported instruction %r" % instruction) | 337 | "Unsupported instruction %r" % instruction) |
336 | 281 | line_number += 1 | 338 | line_number += 1 |
337 | 282 | comment = None | 339 | comment = None |
339 | 283 | db_branch = branch_map[instruction.recipe_branch.url] | 340 | db_branch_or_repository = branch_map[instruction.recipe_branch.url] |
340 | 284 | insn = _SourcePackageRecipeDataInstruction( | 341 | insn = _SourcePackageRecipeDataInstruction( |
341 | 285 | instruction.recipe_branch.name, type, comment, | 342 | instruction.recipe_branch.name, type, comment, |
343 | 286 | line_number, db_branch, instruction.recipe_branch.revspec, | 343 | line_number, db_branch_or_repository, |
344 | 344 | instruction.recipe_branch.revspec, | ||
345 | 287 | nest_path, self, parent_insn, source_directory) | 345 | nest_path, self, parent_insn, source_directory) |
346 | 288 | line_number = self._recordInstructions( | 346 | line_number = self._recordInstructions( |
347 | 289 | instruction.recipe_branch, insn, branch_map, line_number) | 347 | instruction.recipe_branch, insn, branch_map, line_number) |
348 | @@ -294,24 +352,33 @@ | |||
349 | 294 | clear_property_cache(self) | 352 | clear_property_cache(self) |
350 | 295 | if builder_recipe.format > MAX_RECIPE_FORMAT: | 353 | if builder_recipe.format > MAX_RECIPE_FORMAT: |
351 | 296 | raise TooNewRecipeFormat(builder_recipe.format, MAX_RECIPE_FORMAT) | 354 | raise TooNewRecipeFormat(builder_recipe.format, MAX_RECIPE_FORMAT) |
353 | 297 | branch_map = self._scanInstructions(builder_recipe) | 355 | base = getUtility(IBranchLookup).getByUrl(builder_recipe.url) |
354 | 356 | if base is None: | ||
355 | 357 | base = getUtility(IGitLookup).getByUrl(builder_recipe.url) | ||
356 | 358 | if base is None: | ||
357 | 359 | # If possible, try to raise an exception consistent with | ||
358 | 360 | # whether the current recipe is Bazaar-based or Git-based, | ||
359 | 361 | # so that error messages make more sense. | ||
360 | 362 | if self.base_git_repository is not None: | ||
361 | 363 | raise NoSuchGitRepository(builder_recipe.url) | ||
362 | 364 | else: | ||
363 | 365 | raise NoSuchBranch(builder_recipe.url) | ||
364 | 366 | elif base.private: | ||
365 | 367 | raise PrivateGitRepositoryRecipe(base) | ||
366 | 368 | elif base.private: | ||
367 | 369 | raise PrivateBranchRecipe(base) | ||
368 | 370 | branch_map = self._scanInstructions(base, builder_recipe) | ||
369 | 298 | # If this object hasn't been added to a store yet, there can't be any | 371 | # If this object hasn't been added to a store yet, there can't be any |
370 | 299 | # instructions linking to us yet. | 372 | # instructions linking to us yet. |
371 | 300 | if Store.of(self) is not None: | 373 | if Store.of(self) is not None: |
372 | 301 | self.instructions.find().remove() | 374 | self.instructions.find().remove() |
373 | 302 | branch_lookup = getUtility(IBranchLookup) | ||
374 | 303 | base_branch = branch_lookup.getByUrl(builder_recipe.url) | ||
375 | 304 | if base_branch is None: | ||
376 | 305 | raise NoSuchBranch(builder_recipe.url) | ||
377 | 306 | if base_branch.private: | ||
378 | 307 | raise PrivateBranchRecipe(base_branch) | ||
379 | 308 | if builder_recipe.revspec is not None: | 375 | if builder_recipe.revspec is not None: |
380 | 309 | self.revspec = unicode(builder_recipe.revspec) | 376 | self.revspec = unicode(builder_recipe.revspec) |
381 | 310 | else: | 377 | else: |
382 | 311 | self.revspec = None | 378 | self.revspec = None |
383 | 312 | self._recordInstructions( | 379 | self._recordInstructions( |
384 | 313 | builder_recipe, parent_insn=None, branch_map=branch_map) | 380 | builder_recipe, parent_insn=None, branch_map=branch_map) |
386 | 314 | self.base_branch = base_branch | 381 | self.base = base |
387 | 315 | if builder_recipe.deb_version is None: | 382 | if builder_recipe.deb_version is None: |
388 | 316 | self.deb_version_template = None | 383 | self.deb_version_template = None |
389 | 317 | else: | 384 | else: |
390 | @@ -329,44 +396,69 @@ | |||
391 | 329 | 396 | ||
392 | 330 | @staticmethod | 397 | @staticmethod |
393 | 331 | def preLoadReferencedBranches(sourcepackagerecipedatas): | 398 | def preLoadReferencedBranches(sourcepackagerecipedatas): |
395 | 332 | # Circular import. | 399 | # Circular imports. |
396 | 333 | from lp.code.model.branchcollection import GenericBranchCollection | 400 | from lp.code.model.branchcollection import GenericBranchCollection |
397 | 401 | from lp.code.model.gitcollection import GenericGitCollection | ||
398 | 334 | # Load the related Branch, _SourcePackageRecipeDataInstruction. | 402 | # Load the related Branch, _SourcePackageRecipeDataInstruction. |
399 | 335 | base_branches = load_related( | 403 | base_branches = load_related( |
400 | 336 | Branch, sourcepackagerecipedatas, ['base_branch_id']) | 404 | Branch, sourcepackagerecipedatas, ['base_branch_id']) |
401 | 405 | base_repositories = load_related( | ||
402 | 406 | GitRepository, sourcepackagerecipedatas, | ||
403 | 407 | ['base_git_repository_id']) | ||
404 | 337 | sprd_instructions = load_referencing( | 408 | sprd_instructions = load_referencing( |
405 | 338 | _SourcePackageRecipeDataInstruction, | 409 | _SourcePackageRecipeDataInstruction, |
406 | 339 | sourcepackagerecipedatas, ['recipe_data_id']) | 410 | sourcepackagerecipedatas, ['recipe_data_id']) |
407 | 340 | sub_branches = load_related( | 411 | sub_branches = load_related( |
408 | 341 | Branch, sprd_instructions, ['branch_id']) | 412 | Branch, sprd_instructions, ['branch_id']) |
409 | 413 | sub_repositories = load_related( | ||
410 | 414 | GitRepository, sprd_instructions, ['git_repository_id']) | ||
411 | 342 | all_branches = base_branches + sub_branches | 415 | all_branches = base_branches + sub_branches |
414 | 343 | # Pre-load branches' data. | 416 | all_repositories = base_repositories + sub_repositories |
415 | 344 | GenericBranchCollection.preloadDataForBranches(all_branches) | 417 | # Pre-load branches'/repositories' data. |
416 | 418 | if all_branches: | ||
417 | 419 | GenericBranchCollection.preloadDataForBranches(all_branches) | ||
418 | 420 | if all_repositories: | ||
419 | 421 | GenericGitCollection.preloadDataForRepositories(all_repositories) | ||
420 | 345 | # Store the pre-fetched objects on the sourcepackagerecipedatas | 422 | # Store the pre-fetched objects on the sourcepackagerecipedatas |
421 | 346 | # objects. | 423 | # objects. |
433 | 347 | branch_to_recipe_data = dict([ | 424 | branch_to_recipe_data = { |
434 | 348 | (instr.branch_id, instr.recipe_data_id) | 425 | instr.branch_id: instr.recipe_data_id |
435 | 349 | for instr in sprd_instructions]) | 426 | for instr in sprd_instructions |
436 | 350 | caches = dict((sprd.id, [sprd, get_property_cache(sprd)]) | 427 | if instr.branch_id is not None} |
437 | 351 | for sprd in sourcepackagerecipedatas) | 428 | repository_to_recipe_data = { |
438 | 352 | for unused, [sprd, cache] in caches.items(): | 429 | instr.git_repository_id: instr.recipe_data_id |
439 | 353 | cache._referenced_branches = [sprd.base_branch] | 430 | for instr in sprd_instructions |
440 | 354 | for recipe_data_id, branches in groupby( | 431 | if instr.git_repository_id is not None} |
441 | 355 | sub_branches, lambda branch: branch_to_recipe_data[branch.id]): | 432 | caches = { |
442 | 356 | cache = caches[recipe_data_id][1] | 433 | sprd.id: [sprd, get_property_cache(sprd)] |
443 | 357 | cache._referenced_branches.extend(list(branches)) | 434 | for sprd in sourcepackagerecipedatas} |
444 | 435 | for _, [sprd, cache] in caches.items(): | ||
445 | 436 | cache._referenced_branches = [sprd.base] | ||
446 | 437 | for branch in sub_branches: | ||
447 | 438 | cache = caches[branch_to_recipe_data[branch.id]][1] | ||
448 | 439 | cache._referenced_branches.append(branch) | ||
449 | 440 | for repository in sub_repositories: | ||
450 | 441 | cache = caches[repository_to_recipe_data[repository.id]][1] | ||
451 | 442 | cache._referenced_branches.append(repository) | ||
452 | 358 | 443 | ||
453 | 359 | def getReferencedBranches(self): | 444 | def getReferencedBranches(self): |
455 | 360 | """Return an iterator of the Branch objects referenced by this recipe. | 445 | """Return an iterator of the Branch/GitRepository objects referenced |
456 | 446 | by this recipe. | ||
457 | 361 | """ | 447 | """ |
458 | 362 | return self._referenced_branches | 448 | return self._referenced_branches |
459 | 363 | 449 | ||
460 | 364 | @cachedproperty | 450 | @cachedproperty |
461 | 365 | def _referenced_branches(self): | 451 | def _referenced_branches(self): |
463 | 366 | referenced_branches = [self.base_branch] | 452 | referenced_branches = [self.base] |
464 | 367 | sub_branches = IStore(self).find( | 453 | sub_branches = IStore(self).find( |
465 | 368 | Branch, | 454 | Branch, |
466 | 369 | _SourcePackageRecipeDataInstruction.recipe_data == self, | 455 | _SourcePackageRecipeDataInstruction.recipe_data == self, |
467 | 370 | Branch.id == _SourcePackageRecipeDataInstruction.branch_id) | 456 | Branch.id == _SourcePackageRecipeDataInstruction.branch_id) |
468 | 371 | referenced_branches.extend(sub_branches) | 457 | referenced_branches.extend(sub_branches) |
469 | 458 | sub_repositories = IStore(self).find( | ||
470 | 459 | GitRepository, | ||
471 | 460 | _SourcePackageRecipeDataInstruction.recipe_data == self, | ||
472 | 461 | GitRepository.id == | ||
473 | 462 | _SourcePackageRecipeDataInstruction.git_repository_id) | ||
474 | 463 | referenced_branches.extend(sub_repositories) | ||
475 | 372 | return referenced_branches | 464 | return referenced_branches |
476 | 373 | 465 | ||
477 | === modified file 'lib/lp/code/model/tests/test_sourcepackagerecipe.py' | |||
478 | --- lib/lp/code/model/tests/test_sourcepackagerecipe.py 2016-01-11 21:11:27 +0000 | |||
479 | +++ lib/lp/code/model/tests/test_sourcepackagerecipe.py 2016-01-12 17:27:35 +0000 | |||
480 | @@ -32,6 +32,7 @@ | |||
481 | 32 | from lp.code.errors import ( | 32 | from lp.code.errors import ( |
482 | 33 | BuildAlreadyPending, | 33 | BuildAlreadyPending, |
483 | 34 | PrivateBranchRecipe, | 34 | PrivateBranchRecipe, |
484 | 35 | PrivateGitRepositoryRecipe, | ||
485 | 35 | TooNewRecipeFormat, | 36 | TooNewRecipeFormat, |
486 | 36 | ) | 37 | ) |
487 | 37 | from lp.code.interfaces.sourcepackagerecipe import ( | 38 | from lp.code.interfaces.sourcepackagerecipe import ( |
488 | @@ -39,6 +40,7 @@ | |||
489 | 39 | ISourcePackageRecipeSource, | 40 | ISourcePackageRecipeSource, |
490 | 40 | ISourcePackageRecipeView, | 41 | ISourcePackageRecipeView, |
491 | 41 | MINIMAL_RECIPE_TEXT_BZR, | 42 | MINIMAL_RECIPE_TEXT_BZR, |
492 | 43 | MINIMAL_RECIPE_TEXT_GIT, | ||
493 | 42 | ) | 44 | ) |
494 | 43 | from lp.code.interfaces.sourcepackagerecipebuild import ( | 45 | from lp.code.interfaces.sourcepackagerecipebuild import ( |
495 | 44 | ISourcePackageRecipeBuild, | 46 | ISourcePackageRecipeBuild, |
496 | @@ -86,14 +88,76 @@ | |||
497 | 86 | from lp.testing.pages import webservice_for_person | 88 | from lp.testing.pages import webservice_for_person |
498 | 87 | 89 | ||
499 | 88 | 90 | ||
501 | 89 | class TestSourcePackageRecipe(TestCaseWithFactory): | 91 | class BzrMixin: |
502 | 92 | """Mixin for Bazaar-based recipe tests.""" | ||
503 | 93 | |||
504 | 94 | private_error = PrivateBranchRecipe | ||
505 | 95 | branch_type = "branch" | ||
506 | 96 | recipe_id = "bzr-builder" | ||
507 | 97 | |||
508 | 98 | def makeBranch(self, **kwargs): | ||
509 | 99 | return self.factory.makeAnyBranch(**kwargs) | ||
510 | 100 | |||
511 | 101 | @staticmethod | ||
512 | 102 | def getRepository(branch): | ||
513 | 103 | return branch | ||
514 | 104 | |||
515 | 105 | @staticmethod | ||
516 | 106 | def getBranchRecipeText(branch): | ||
517 | 107 | return branch.identity | ||
518 | 108 | |||
519 | 109 | @staticmethod | ||
520 | 110 | def setInformationType(branch, information_type): | ||
521 | 111 | removeSecurityProxy(branch).information_type = information_type | ||
522 | 112 | |||
523 | 113 | def makeRecipeText(self): | ||
524 | 114 | branch = self.makeBranch() | ||
525 | 115 | return MINIMAL_RECIPE_TEXT_BZR % branch.identity | ||
526 | 116 | |||
527 | 117 | |||
528 | 118 | class GitMixin: | ||
529 | 119 | """Mixin for Git-based recipe tests.""" | ||
530 | 120 | |||
531 | 121 | private_error = PrivateGitRepositoryRecipe | ||
532 | 122 | branch_type = "repository" | ||
533 | 123 | recipe_id = "git-build-recipe" | ||
534 | 124 | |||
535 | 125 | def makeBranch(self, **kwargs): | ||
536 | 126 | return self.factory.makeGitRefs(**kwargs)[0] | ||
537 | 127 | |||
538 | 128 | @staticmethod | ||
539 | 129 | def getRepository(branch): | ||
540 | 130 | return branch.repository | ||
541 | 131 | |||
542 | 132 | @staticmethod | ||
543 | 133 | def getBranchRecipeText(branch): | ||
544 | 134 | return branch.identity | ||
545 | 135 | |||
546 | 136 | @staticmethod | ||
547 | 137 | def setInformationType(branch, information_type): | ||
548 | 138 | removeSecurityProxy(branch.repository).information_type = ( | ||
549 | 139 | information_type) | ||
550 | 140 | |||
551 | 141 | def makeRecipeText(self): | ||
552 | 142 | branch = self.makeBranch() | ||
553 | 143 | return MINIMAL_RECIPE_TEXT_GIT % ( | ||
554 | 144 | branch.repository.identity, branch.name) | ||
555 | 145 | |||
556 | 146 | |||
557 | 147 | class TestSourcePackageRecipeMixin: | ||
558 | 90 | """Tests for `SourcePackageRecipe` objects.""" | 148 | """Tests for `SourcePackageRecipe` objects.""" |
559 | 91 | 149 | ||
560 | 92 | layer = DatabaseFunctionalLayer | 150 | layer = DatabaseFunctionalLayer |
561 | 93 | 151 | ||
562 | 152 | def makeSourcePackageRecipe(self, branches=(), recipe=None, **kwargs): | ||
563 | 153 | if recipe is None and len(branches) == 0: | ||
564 | 154 | branches = [self.makeBranch()] | ||
565 | 155 | return self.factory.makeSourcePackageRecipe( | ||
566 | 156 | branches=branches, recipe=recipe, **kwargs) | ||
567 | 157 | |||
568 | 94 | def test_implements_interface(self): | 158 | def test_implements_interface(self): |
569 | 95 | """SourcePackageRecipe implements ISourcePackageRecipe.""" | 159 | """SourcePackageRecipe implements ISourcePackageRecipe.""" |
571 | 96 | recipe = self.factory.makeSourcePackageRecipe() | 160 | recipe = self.makeSourcePackageRecipe() |
572 | 97 | verifyObject(ISourcePackageRecipe, recipe) | 161 | verifyObject(ISourcePackageRecipe, recipe) |
573 | 98 | 162 | ||
574 | 99 | def test_avoids_problematic_snapshots(self): | 163 | def test_avoids_problematic_snapshots(self): |
575 | @@ -103,7 +167,7 @@ | |||
576 | 103 | 'pending_builds', | 167 | 'pending_builds', |
577 | 104 | ] | 168 | ] |
578 | 105 | self.assertThat( | 169 | self.assertThat( |
580 | 106 | self.factory.makeSourcePackageRecipe(), | 170 | self.makeSourcePackageRecipe(), |
581 | 107 | DoesNotSnapshot(problematic_properties, ISourcePackageRecipeView)) | 171 | DoesNotSnapshot(problematic_properties, ISourcePackageRecipeView)) |
582 | 108 | 172 | ||
583 | 109 | def makeRecipeComponents(self, branches=()): | 173 | def makeRecipeComponents(self, branches=()): |
584 | @@ -128,7 +192,7 @@ | |||
585 | 128 | components = self.makeRecipeComponents() | 192 | components = self.makeRecipeComponents() |
586 | 129 | recipe = getUtility(ISourcePackageRecipeSource).new(**components) | 193 | recipe = getUtility(ISourcePackageRecipeSource).new(**components) |
587 | 130 | transaction.commit() | 194 | transaction.commit() |
589 | 131 | self.assertEquals( | 195 | self.assertEqual( |
590 | 132 | (components['registrant'], components['owner'], | 196 | (components['registrant'], components['owner'], |
591 | 133 | set(components['distroseries']), components['name']), | 197 | set(components['distroseries']), components['name']), |
592 | 134 | (recipe.registrant, recipe.owner, set(recipe.distroseries), | 198 | (recipe.registrant, recipe.owner, set(recipe.distroseries), |
593 | @@ -139,35 +203,38 @@ | |||
594 | 139 | """An exception should be raised if the base branch is private.""" | 203 | """An exception should be raised if the base branch is private.""" |
595 | 140 | owner = self.factory.makePerson() | 204 | owner = self.factory.makePerson() |
596 | 141 | with person_logged_in(owner): | 205 | with person_logged_in(owner): |
598 | 142 | branch = self.factory.makeAnyBranch( | 206 | branch = self.makeBranch( |
599 | 143 | owner=owner, information_type=InformationType.USERDATA) | 207 | owner=owner, information_type=InformationType.USERDATA) |
600 | 144 | components = self.makeRecipeComponents(branches=[branch]) | 208 | components = self.makeRecipeComponents(branches=[branch]) |
601 | 145 | recipe_source = getUtility(ISourcePackageRecipeSource) | 209 | recipe_source = getUtility(ISourcePackageRecipeSource) |
602 | 146 | e = self.assertRaises( | 210 | e = self.assertRaises( |
604 | 147 | PrivateBranchRecipe, recipe_source.new, **components) | 211 | self.private_error, recipe_source.new, **components) |
605 | 148 | self.assertEqual( | 212 | self.assertEqual( |
608 | 149 | 'Recipe may not refer to private branch: %s' % | 213 | 'Recipe may not refer to private %s: %s' % |
609 | 150 | branch.bzr_identity, str(e)) | 214 | (self.branch_type, self.getRepository(branch).identity), |
610 | 215 | str(e)) | ||
611 | 151 | 216 | ||
612 | 152 | def test_creation_private_referenced_branch(self): | 217 | def test_creation_private_referenced_branch(self): |
613 | 153 | """An exception should be raised if a referenced branch is private.""" | 218 | """An exception should be raised if a referenced branch is private.""" |
614 | 154 | owner = self.factory.makePerson() | 219 | owner = self.factory.makePerson() |
615 | 155 | with person_logged_in(owner): | 220 | with person_logged_in(owner): |
618 | 156 | base_branch = self.factory.makeAnyBranch(owner=owner) | 221 | base_branch = self.makeBranch(owner=owner) |
619 | 157 | referenced_branch = self.factory.makeAnyBranch( | 222 | referenced_branch = self.makeBranch( |
620 | 158 | owner=owner, information_type=InformationType.USERDATA) | 223 | owner=owner, information_type=InformationType.USERDATA) |
621 | 159 | branches = [base_branch, referenced_branch] | 224 | branches = [base_branch, referenced_branch] |
622 | 160 | components = self.makeRecipeComponents(branches=branches) | 225 | components = self.makeRecipeComponents(branches=branches) |
623 | 161 | recipe_source = getUtility(ISourcePackageRecipeSource) | 226 | recipe_source = getUtility(ISourcePackageRecipeSource) |
624 | 162 | e = self.assertRaises( | 227 | e = self.assertRaises( |
626 | 163 | PrivateBranchRecipe, recipe_source.new, **components) | 228 | self.private_error, recipe_source.new, **components) |
627 | 164 | self.assertEqual( | 229 | self.assertEqual( |
630 | 165 | 'Recipe may not refer to private branch: %s' % | 230 | 'Recipe may not refer to private %s: %s' % ( |
631 | 166 | referenced_branch.bzr_identity, str(e)) | 231 | self.branch_type, |
632 | 232 | self.getRepository(referenced_branch).identity), | ||
633 | 233 | str(e)) | ||
634 | 167 | 234 | ||
635 | 168 | def test_exists(self): | 235 | def test_exists(self): |
636 | 169 | # Test ISourcePackageRecipeSource.exists | 236 | # Test ISourcePackageRecipeSource.exists |
638 | 170 | recipe = self.factory.makeSourcePackageRecipe() | 237 | recipe = self.makeSourcePackageRecipe() |
639 | 171 | 238 | ||
640 | 172 | self.assertTrue( | 239 | self.assertTrue( |
641 | 173 | getUtility(ISourcePackageRecipeSource).exists( | 240 | getUtility(ISourcePackageRecipeSource).exists( |
642 | @@ -185,32 +252,33 @@ | |||
643 | 185 | 252 | ||
644 | 186 | def test_recipe_implements_interface(self): | 253 | def test_recipe_implements_interface(self): |
645 | 187 | # SourcePackageRecipe objects implement ISourcePackageRecipe. | 254 | # SourcePackageRecipe objects implement ISourcePackageRecipe. |
647 | 188 | recipe = self.factory.makeSourcePackageRecipe() | 255 | recipe = self.makeSourcePackageRecipe() |
648 | 189 | transaction.commit() | 256 | transaction.commit() |
649 | 190 | with person_logged_in(recipe.owner): | 257 | with person_logged_in(recipe.owner): |
650 | 191 | self.assertProvides(recipe, ISourcePackageRecipe) | 258 | self.assertProvides(recipe, ISourcePackageRecipe) |
651 | 192 | 259 | ||
652 | 193 | def test_base_branch(self): | 260 | def test_base_branch(self): |
653 | 194 | # When a recipe is created, we can access its base branch. | 261 | # When a recipe is created, we can access its base branch. |
656 | 195 | branch = self.factory.makeAnyBranch() | 262 | branch = self.makeBranch() |
657 | 196 | sp_recipe = self.factory.makeSourcePackageRecipe(branches=[branch]) | 263 | sp_recipe = self.makeSourcePackageRecipe(branches=[branch]) |
658 | 197 | transaction.commit() | 264 | transaction.commit() |
660 | 198 | self.assertEquals(branch, sp_recipe.base_branch) | 265 | self.assertEqual(self.getRepository(branch), sp_recipe.base) |
661 | 199 | 266 | ||
662 | 200 | def test_branch_links_created(self): | 267 | def test_branch_links_created(self): |
663 | 201 | # When a recipe is created, we can query it for links to the branch | 268 | # When a recipe is created, we can query it for links to the branch |
664 | 202 | # it references. | 269 | # it references. |
668 | 203 | branch = self.factory.makeAnyBranch() | 270 | branch = self.makeBranch() |
669 | 204 | sp_recipe = self.factory.makeSourcePackageRecipe( | 271 | sp_recipe = self.makeSourcePackageRecipe(branches=[branch]) |
667 | 205 | branches=[branch]) | ||
670 | 206 | transaction.commit() | 272 | transaction.commit() |
672 | 207 | self.assertEquals([branch], list(sp_recipe.getReferencedBranches())) | 273 | self.assertEqual( |
673 | 274 | [self.getRepository(branch)], | ||
674 | 275 | list(sp_recipe.getReferencedBranches())) | ||
675 | 208 | 276 | ||
676 | 209 | def createSourcePackageRecipe(self, number_of_branches=2): | 277 | def createSourcePackageRecipe(self, number_of_branches=2): |
677 | 210 | branches = [] | 278 | branches = [] |
678 | 211 | for i in range(number_of_branches): | 279 | for i in range(number_of_branches): |
681 | 212 | branches.append(self.factory.makeAnyBranch()) | 280 | branches.append(self.makeBranch()) |
682 | 213 | sp_recipe = self.factory.makeSourcePackageRecipe(branches=branches) | 281 | sp_recipe = self.makeSourcePackageRecipe(branches=branches) |
683 | 214 | transaction.commit() | 282 | transaction.commit() |
684 | 215 | return sp_recipe, branches | 283 | return sp_recipe, branches |
685 | 216 | 284 | ||
686 | @@ -218,8 +286,8 @@ | |||
687 | 218 | # If a recipe links to more than one branch, getReferencedBranches() | 286 | # If a recipe links to more than one branch, getReferencedBranches() |
688 | 219 | # returns all of them. | 287 | # returns all of them. |
689 | 220 | sp_recipe, [branch1, branch2] = self.createSourcePackageRecipe() | 288 | sp_recipe, [branch1, branch2] = self.createSourcePackageRecipe() |
692 | 221 | self.assertEquals( | 289 | self.assertEqual( |
693 | 222 | sorted([branch1, branch2]), | 290 | sorted([self.getRepository(branch1), self.getRepository(branch2)]), |
694 | 223 | sorted(sp_recipe.getReferencedBranches())) | 291 | sorted(sp_recipe.getReferencedBranches())) |
695 | 224 | 292 | ||
696 | 225 | def test_preLoadReferencedBranches(self): | 293 | def test_preLoadReferencedBranches(self): |
697 | @@ -230,16 +298,15 @@ | |||
698 | 230 | referenced_branches = sp_recipe.getReferencedBranches() | 298 | referenced_branches = sp_recipe.getReferencedBranches() |
699 | 231 | clear_property_cache(recipe_data) | 299 | clear_property_cache(recipe_data) |
700 | 232 | SourcePackageRecipeData.preLoadReferencedBranches([recipe_data]) | 300 | SourcePackageRecipeData.preLoadReferencedBranches([recipe_data]) |
702 | 233 | self.assertEquals( | 301 | self.assertEqual( |
703 | 234 | sorted(referenced_branches), | 302 | sorted(referenced_branches), |
704 | 235 | sorted(sp_recipe.getReferencedBranches())) | 303 | sorted(sp_recipe.getReferencedBranches())) |
705 | 236 | 304 | ||
706 | 237 | def test_random_user_cant_edit(self): | 305 | def test_random_user_cant_edit(self): |
707 | 238 | # An arbitrary user can't set attributes. | 306 | # An arbitrary user can't set attributes. |
709 | 239 | branch1 = self.factory.makeAnyBranch() | 307 | branch1 = self.makeBranch() |
710 | 240 | recipe_1 = self.factory.makeRecipeText(branch1) | 308 | recipe_1 = self.factory.makeRecipeText(branch1) |
713 | 241 | sp_recipe = self.factory.makeSourcePackageRecipe( | 309 | sp_recipe = self.makeSourcePackageRecipe(recipe=recipe_1) |
712 | 242 | recipe=recipe_1) | ||
714 | 243 | login_person(self.factory.makePerson()) | 310 | login_person(self.factory.makePerson()) |
715 | 244 | self.assertRaises( | 311 | self.assertRaises( |
716 | 245 | Unauthorized, getattr, sp_recipe, 'setRecipeText') | 312 | Unauthorized, getattr, sp_recipe, 'setRecipeText') |
717 | @@ -247,71 +314,78 @@ | |||
718 | 247 | def test_set_recipe_text_resets_branch_references(self): | 314 | def test_set_recipe_text_resets_branch_references(self): |
719 | 248 | # When the recipe_text is replaced, getReferencedBranches returns | 315 | # When the recipe_text is replaced, getReferencedBranches returns |
720 | 249 | # (only) the branches referenced by the new recipe. | 316 | # (only) the branches referenced by the new recipe. |
725 | 250 | branch1 = self.factory.makeAnyBranch() | 317 | branch1 = self.makeBranch() |
726 | 251 | sp_recipe = self.factory.makeSourcePackageRecipe( | 318 | sp_recipe = self.makeSourcePackageRecipe(branches=[branch1]) |
727 | 252 | branches=[branch1]) | 319 | branch2 = self.makeBranch() |
724 | 253 | branch2 = self.factory.makeAnyBranch() | ||
728 | 254 | new_recipe = self.factory.makeRecipeText(branch2) | 320 | new_recipe = self.factory.makeRecipeText(branch2) |
729 | 255 | with person_logged_in(sp_recipe.owner): | 321 | with person_logged_in(sp_recipe.owner): |
730 | 256 | sp_recipe.setRecipeText(new_recipe) | 322 | sp_recipe.setRecipeText(new_recipe) |
732 | 257 | self.assertEquals([branch2], list(sp_recipe.getReferencedBranches())) | 323 | self.assertEqual( |
733 | 324 | [self.getRepository(branch2)], | ||
734 | 325 | list(sp_recipe.getReferencedBranches())) | ||
735 | 258 | 326 | ||
736 | 259 | def test_rejects_run_command(self): | 327 | def test_rejects_run_command(self): |
737 | 260 | recipe_text = '''\ | 328 | recipe_text = '''\ |
739 | 261 | # bzr-builder format 0.3 deb-version 0.1-{revno} | 329 | # %(recipe_id)s format 0.3 deb-version 0.1-{revno} |
740 | 262 | %(base)s | 330 | %(base)s |
741 | 263 | run touch test | 331 | run touch test |
743 | 264 | ''' % dict(base=self.factory.makeAnyBranch().bzr_identity) | 332 | ''' % dict(recipe_id=self.recipe_id, |
744 | 333 | base=self.getBranchRecipeText(self.makeBranch())) | ||
745 | 265 | recipe_text = textwrap.dedent(recipe_text) | 334 | recipe_text = textwrap.dedent(recipe_text) |
746 | 266 | self.assertRaises( | 335 | self.assertRaises( |
748 | 267 | ForbiddenInstructionError, self.factory.makeSourcePackageRecipe, | 336 | ForbiddenInstructionError, self.makeSourcePackageRecipe, |
749 | 268 | recipe=recipe_text) | 337 | recipe=recipe_text) |
750 | 269 | 338 | ||
751 | 270 | def test_run_rejected_without_mangling_recipe(self): | 339 | def test_run_rejected_without_mangling_recipe(self): |
753 | 271 | sp_recipe = self.factory.makeSourcePackageRecipe() | 340 | sp_recipe = self.makeSourcePackageRecipe() |
754 | 272 | old_branches = list(sp_recipe.getReferencedBranches()) | 341 | old_branches = list(sp_recipe.getReferencedBranches()) |
755 | 273 | recipe_text = '''\ | 342 | recipe_text = '''\ |
757 | 274 | # bzr-builder format 0.3 deb-version 0.1-{revno} | 343 | # %(recipe_id)s format 0.3 deb-version 0.1-{revno} |
758 | 275 | %(base)s | 344 | %(base)s |
759 | 276 | run touch test | 345 | run touch test |
761 | 277 | ''' % dict(base=self.factory.makeAnyBranch().bzr_identity) | 346 | ''' % dict(recipe_id=self.recipe_id, |
762 | 347 | base=self.getBranchRecipeText(self.makeBranch())) | ||
763 | 278 | recipe_text = textwrap.dedent(recipe_text) | 348 | recipe_text = textwrap.dedent(recipe_text) |
764 | 279 | with person_logged_in(sp_recipe.owner): | 349 | with person_logged_in(sp_recipe.owner): |
765 | 280 | self.assertRaises( | 350 | self.assertRaises( |
766 | 281 | ForbiddenInstructionError, sp_recipe.setRecipeText, | 351 | ForbiddenInstructionError, sp_recipe.setRecipeText, |
767 | 282 | recipe_text) | 352 | recipe_text) |
769 | 283 | self.assertEquals( | 353 | self.assertEqual( |
770 | 284 | old_branches, list(sp_recipe.getReferencedBranches())) | 354 | old_branches, list(sp_recipe.getReferencedBranches())) |
771 | 285 | 355 | ||
772 | 286 | def test_nest_part(self): | 356 | def test_nest_part(self): |
773 | 287 | """nest-part instruction can be round-tripped.""" | 357 | """nest-part instruction can be round-tripped.""" |
776 | 288 | base = self.factory.makeBranch() | 358 | base = self.makeBranch() |
777 | 289 | nested = self.factory.makeBranch() | 359 | nested = self.makeBranch() |
778 | 290 | recipe_text = ( | 360 | recipe_text = ( |
780 | 291 | "# bzr-builder format 0.3 deb-version 1\n" | 361 | "# %s format 0.3 deb-version 1\n" |
781 | 292 | "%s revid:base_revid\n" | 362 | "%s revid:base_revid\n" |
782 | 293 | "nest-part nested1 %s foo bar tag:foo\n" % | 363 | "nest-part nested1 %s foo bar tag:foo\n" % |
785 | 294 | (base.bzr_identity, nested.bzr_identity)) | 364 | (self.recipe_id, |
786 | 295 | recipe = self.factory.makeSourcePackageRecipe(recipe=recipe_text) | 365 | self.getRepository(base).identity, |
787 | 366 | self.getRepository(nested).identity)) | ||
788 | 367 | recipe = self.makeSourcePackageRecipe(recipe=recipe_text) | ||
789 | 296 | self.assertEqual(recipe_text, recipe.recipe_text) | 368 | self.assertEqual(recipe_text, recipe.recipe_text) |
790 | 297 | 369 | ||
791 | 298 | def test_nest_part_no_target(self): | 370 | def test_nest_part_no_target(self): |
792 | 299 | """nest-part instruction with no target-dir can be round-tripped.""" | 371 | """nest-part instruction with no target-dir can be round-tripped.""" |
795 | 300 | base = self.factory.makeBranch() | 372 | base = self.makeBranch() |
796 | 301 | nested = self.factory.makeBranch() | 373 | nested = self.makeBranch() |
797 | 302 | recipe_text = ( | 374 | recipe_text = ( |
799 | 303 | "# bzr-builder format 0.3 deb-version 1\n" | 375 | "# %s format 0.3 deb-version 1\n" |
800 | 304 | "%s revid:base_revid\n" | 376 | "%s revid:base_revid\n" |
801 | 305 | "nest-part nested1 %s foo\n" % | 377 | "nest-part nested1 %s foo\n" % |
804 | 306 | (base.bzr_identity, nested.bzr_identity)) | 378 | (self.recipe_id, |
805 | 307 | recipe = self.factory.makeSourcePackageRecipe(recipe=recipe_text) | 379 | self.getRepository(base).identity, |
806 | 380 | self.getRepository(nested).identity)) | ||
807 | 381 | recipe = self.makeSourcePackageRecipe(recipe=recipe_text) | ||
808 | 308 | self.assertEqual(recipe_text, recipe.recipe_text) | 382 | self.assertEqual(recipe_text, recipe.recipe_text) |
809 | 309 | 383 | ||
810 | 310 | def test_accept_format_0_3(self): | 384 | def test_accept_format_0_3(self): |
811 | 311 | """Recipe format 0.3 is accepted.""" | 385 | """Recipe format 0.3 is accepted.""" |
812 | 312 | builder_recipe = self.factory.makeRecipe() | 386 | builder_recipe = self.factory.makeRecipe() |
813 | 313 | builder_recipe.format = 0.3 | 387 | builder_recipe.format = 0.3 |
815 | 314 | self.factory.makeSourcePackageRecipe(recipe=str(builder_recipe)) | 388 | self.makeSourcePackageRecipe(recipe=str(builder_recipe)) |
816 | 315 | 389 | ||
817 | 316 | def test_reject_newer_formats(self): | 390 | def test_reject_newer_formats(self): |
818 | 317 | with recipe_parser_newest_version(145.115): | 391 | with recipe_parser_newest_version(145.115): |
819 | @@ -319,11 +393,11 @@ | |||
820 | 319 | builder_recipe.format = 145.115 | 393 | builder_recipe.format = 145.115 |
821 | 320 | self.assertRaises( | 394 | self.assertRaises( |
822 | 321 | TooNewRecipeFormat, | 395 | TooNewRecipeFormat, |
824 | 322 | self.factory.makeSourcePackageRecipe, | 396 | self.makeSourcePackageRecipe, |
825 | 323 | recipe=str(builder_recipe)) | 397 | recipe=str(builder_recipe)) |
826 | 324 | 398 | ||
827 | 325 | def test_requestBuild(self): | 399 | def test_requestBuild(self): |
829 | 326 | recipe = self.factory.makeSourcePackageRecipe() | 400 | recipe = self.makeSourcePackageRecipe() |
830 | 327 | (distroseries,) = list(recipe.distroseries) | 401 | (distroseries,) = list(recipe.distroseries) |
831 | 328 | ppa = self.factory.makeArchive() | 402 | ppa = self.factory.makeArchive() |
832 | 329 | build = recipe.requestBuild(ppa, ppa.owner, distroseries, | 403 | build = recipe.requestBuild(ppa, ppa.owner, distroseries, |
833 | @@ -342,17 +416,17 @@ | |||
834 | 342 | removeSecurityProxy(build).build_farm_job_id).one() | 416 | removeSecurityProxy(build).build_farm_job_id).one() |
835 | 343 | self.assertProvides(build_queue, IBuildQueue) | 417 | self.assertProvides(build_queue, IBuildQueue) |
836 | 344 | self.assertTrue(build_queue.virtualized) | 418 | self.assertTrue(build_queue.virtualized) |
838 | 345 | self.assertEquals(build_queue.status, BuildQueueStatus.WAITING) | 419 | self.assertEqual(build_queue.status, BuildQueueStatus.WAITING) |
839 | 346 | 420 | ||
840 | 347 | def test_requestBuildRejectsNotPPA(self): | 421 | def test_requestBuildRejectsNotPPA(self): |
842 | 348 | recipe = self.factory.makeSourcePackageRecipe() | 422 | recipe = self.makeSourcePackageRecipe() |
843 | 349 | not_ppa = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY) | 423 | not_ppa = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY) |
844 | 350 | (distroseries,) = list(recipe.distroseries) | 424 | (distroseries,) = list(recipe.distroseries) |
845 | 351 | self.assertRaises(NonPPABuildRequest, recipe.requestBuild, not_ppa, | 425 | self.assertRaises(NonPPABuildRequest, recipe.requestBuild, not_ppa, |
846 | 352 | not_ppa.owner, distroseries, PackagePublishingPocket.RELEASE) | 426 | not_ppa.owner, distroseries, PackagePublishingPocket.RELEASE) |
847 | 353 | 427 | ||
848 | 354 | def test_requestBuildRejectsNoPermission(self): | 428 | def test_requestBuildRejectsNoPermission(self): |
850 | 355 | recipe = self.factory.makeSourcePackageRecipe() | 429 | recipe = self.makeSourcePackageRecipe() |
851 | 356 | ppa = self.factory.makeArchive() | 430 | ppa = self.factory.makeArchive() |
852 | 357 | requester = self.factory.makePerson() | 431 | requester = self.factory.makePerson() |
853 | 358 | (distroseries,) = list(recipe.distroseries) | 432 | (distroseries,) = list(recipe.distroseries) |
854 | @@ -360,14 +434,14 @@ | |||
855 | 360 | requester, distroseries, PackagePublishingPocket.RELEASE) | 434 | requester, distroseries, PackagePublishingPocket.RELEASE) |
856 | 361 | 435 | ||
857 | 362 | def test_requestBuildRejectsInvalidPocket(self): | 436 | def test_requestBuildRejectsInvalidPocket(self): |
859 | 363 | recipe = self.factory.makeSourcePackageRecipe() | 437 | recipe = self.makeSourcePackageRecipe() |
860 | 364 | ppa = self.factory.makeArchive() | 438 | ppa = self.factory.makeArchive() |
861 | 365 | (distroseries,) = list(recipe.distroseries) | 439 | (distroseries,) = list(recipe.distroseries) |
862 | 366 | self.assertRaises(InvalidPocketForPPA, recipe.requestBuild, ppa, | 440 | self.assertRaises(InvalidPocketForPPA, recipe.requestBuild, ppa, |
863 | 367 | ppa.owner, distroseries, PackagePublishingPocket.BACKPORTS) | 441 | ppa.owner, distroseries, PackagePublishingPocket.BACKPORTS) |
864 | 368 | 442 | ||
865 | 369 | def test_requestBuildRejectsDisabledArchive(self): | 443 | def test_requestBuildRejectsDisabledArchive(self): |
867 | 370 | recipe = self.factory.makeSourcePackageRecipe() | 444 | recipe = self.makeSourcePackageRecipe() |
868 | 371 | ppa = self.factory.makeArchive() | 445 | ppa = self.factory.makeArchive() |
869 | 372 | removeSecurityProxy(ppa).disable() | 446 | removeSecurityProxy(ppa).disable() |
870 | 373 | (distroseries,) = list(recipe.distroseries) | 447 | (distroseries,) = list(recipe.distroseries) |
871 | @@ -377,7 +451,7 @@ | |||
872 | 377 | 451 | ||
873 | 378 | def test_requestBuildScore(self): | 452 | def test_requestBuildScore(self): |
874 | 379 | """Normal build requests have a relatively low queue score (2505).""" | 453 | """Normal build requests have a relatively low queue score (2505).""" |
876 | 380 | recipe = self.factory.makeSourcePackageRecipe() | 454 | recipe = self.makeSourcePackageRecipe() |
877 | 381 | build = recipe.requestBuild(recipe.daily_build_archive, | 455 | build = recipe.requestBuild(recipe.daily_build_archive, |
878 | 382 | recipe.owner, list(recipe.distroseries)[0], | 456 | recipe.owner, list(recipe.distroseries)[0], |
879 | 383 | PackagePublishingPocket.RELEASE) | 457 | PackagePublishingPocket.RELEASE) |
880 | @@ -387,7 +461,7 @@ | |||
881 | 387 | 461 | ||
882 | 388 | def test_requestBuildManualScore(self): | 462 | def test_requestBuildManualScore(self): |
883 | 389 | """Manual build requests have a score equivalent to binary builds.""" | 463 | """Manual build requests have a score equivalent to binary builds.""" |
885 | 390 | recipe = self.factory.makeSourcePackageRecipe() | 464 | recipe = self.makeSourcePackageRecipe() |
886 | 391 | build = recipe.requestBuild(recipe.daily_build_archive, | 465 | build = recipe.requestBuild(recipe.daily_build_archive, |
887 | 392 | recipe.owner, list(recipe.distroseries)[0], | 466 | recipe.owner, list(recipe.distroseries)[0], |
888 | 393 | PackagePublishingPocket.RELEASE, manual=True) | 467 | PackagePublishingPocket.RELEASE, manual=True) |
889 | @@ -397,7 +471,7 @@ | |||
890 | 397 | 471 | ||
891 | 398 | def test_requestBuild_relative_build_score(self): | 472 | def test_requestBuild_relative_build_score(self): |
892 | 399 | """Offsets for archives are respected.""" | 473 | """Offsets for archives are respected.""" |
894 | 400 | recipe = self.factory.makeSourcePackageRecipe() | 474 | recipe = self.makeSourcePackageRecipe() |
895 | 401 | archive = recipe.daily_build_archive | 475 | archive = recipe.daily_build_archive |
896 | 402 | removeSecurityProxy(archive).relative_build_score = 100 | 476 | removeSecurityProxy(archive).relative_build_score = 100 |
897 | 403 | build = recipe.requestBuild( | 477 | build = recipe.requestBuild( |
898 | @@ -409,7 +483,7 @@ | |||
899 | 409 | 483 | ||
900 | 410 | def test_requestBuildRejectRepeats(self): | 484 | def test_requestBuildRejectRepeats(self): |
901 | 411 | """Reject build requests that are identical to pending builds.""" | 485 | """Reject build requests that are identical to pending builds.""" |
903 | 412 | recipe = self.factory.makeSourcePackageRecipe() | 486 | recipe = self.makeSourcePackageRecipe() |
904 | 413 | series = list(recipe.distroseries)[0] | 487 | series = list(recipe.distroseries)[0] |
905 | 414 | archive = self.factory.makeArchive(owner=recipe.owner) | 488 | archive = self.factory.makeArchive(owner=recipe.owner) |
906 | 415 | old_build = recipe.requestBuild(archive, recipe.owner, series, | 489 | old_build = recipe.requestBuild(archive, recipe.owner, series, |
907 | @@ -447,7 +521,7 @@ | |||
908 | 447 | private=True) | 521 | private=True) |
909 | 448 | 522 | ||
910 | 449 | # Create a recipe with the team P3A as the build destination. | 523 | # Create a recipe with the team P3A as the build destination. |
912 | 450 | recipe = self.factory.makeSourcePackageRecipe() | 524 | recipe = self.makeSourcePackageRecipe() |
913 | 451 | 525 | ||
914 | 452 | # Add upload component rights for the non-team person. | 526 | # Add upload component rights for the non-team person. |
915 | 453 | with person_logged_in(team_owner): | 527 | with person_logged_in(team_owner): |
916 | @@ -467,13 +541,13 @@ | |||
917 | 467 | def test_sourcepackagerecipe_description(self): | 541 | def test_sourcepackagerecipe_description(self): |
918 | 468 | """Ensure that the SourcePackageRecipe has a proper description.""" | 542 | """Ensure that the SourcePackageRecipe has a proper description.""" |
919 | 469 | description = u'The whoozits and whatzits.' | 543 | description = u'The whoozits and whatzits.' |
921 | 470 | source_package_recipe = self.factory.makeSourcePackageRecipe( | 544 | source_package_recipe = self.makeSourcePackageRecipe( |
922 | 471 | description=description) | 545 | description=description) |
923 | 472 | self.assertEqual(description, source_package_recipe.description) | 546 | self.assertEqual(description, source_package_recipe.description) |
924 | 473 | 547 | ||
925 | 474 | def test_distroseries(self): | 548 | def test_distroseries(self): |
926 | 475 | """Test that the distroseries behaves as a set.""" | 549 | """Test that the distroseries behaves as a set.""" |
928 | 476 | recipe = self.factory.makeSourcePackageRecipe() | 550 | recipe = self.makeSourcePackageRecipe() |
929 | 477 | distroseries = self.factory.makeDistroSeries() | 551 | distroseries = self.factory.makeDistroSeries() |
930 | 478 | (old_distroseries,) = recipe.distroseries | 552 | (old_distroseries,) = recipe.distroseries |
931 | 479 | recipe.distroseries.add(distroseries) | 553 | recipe.distroseries.add(distroseries) |
932 | @@ -486,7 +560,7 @@ | |||
933 | 486 | 560 | ||
934 | 487 | def test_build_daily(self): | 561 | def test_build_daily(self): |
935 | 488 | """Test that build_daily behaves as a bool.""" | 562 | """Test that build_daily behaves as a bool.""" |
937 | 489 | recipe = self.factory.makeSourcePackageRecipe() | 563 | recipe = self.makeSourcePackageRecipe() |
938 | 490 | self.assertFalse(recipe.build_daily) | 564 | self.assertFalse(recipe.build_daily) |
939 | 491 | login_person(recipe.owner) | 565 | login_person(recipe.owner) |
940 | 492 | recipe.build_daily = True | 566 | recipe.build_daily = True |
941 | @@ -495,9 +569,9 @@ | |||
942 | 495 | def test_view_public(self): | 569 | def test_view_public(self): |
943 | 496 | """Anyone can view a recipe with public branches.""" | 570 | """Anyone can view a recipe with public branches.""" |
944 | 497 | owner = self.factory.makePerson() | 571 | owner = self.factory.makePerson() |
946 | 498 | branch = self.factory.makeAnyBranch(owner=owner) | 572 | branch = self.makeBranch(owner=owner) |
947 | 499 | with person_logged_in(owner): | 573 | with person_logged_in(owner): |
949 | 500 | recipe = self.factory.makeSourcePackageRecipe(branches=[branch]) | 574 | recipe = self.makeSourcePackageRecipe(branches=[branch]) |
950 | 501 | self.assertTrue(check_permission('launchpad.View', recipe)) | 575 | self.assertTrue(check_permission('launchpad.View', recipe)) |
951 | 502 | with person_logged_in(self.factory.makePerson()): | 576 | with person_logged_in(self.factory.makePerson()): |
952 | 503 | self.assertTrue(check_permission('launchpad.View', recipe)) | 577 | self.assertTrue(check_permission('launchpad.View', recipe)) |
953 | @@ -506,19 +580,18 @@ | |||
954 | 506 | def test_view_private(self): | 580 | def test_view_private(self): |
955 | 507 | """Recipes with private branches are restricted.""" | 581 | """Recipes with private branches are restricted.""" |
956 | 508 | owner = self.factory.makePerson() | 582 | owner = self.factory.makePerson() |
958 | 509 | branch = self.factory.makeAnyBranch(owner=owner) | 583 | branch = self.makeBranch(owner=owner) |
959 | 510 | with person_logged_in(owner): | 584 | with person_logged_in(owner): |
961 | 511 | recipe = self.factory.makeSourcePackageRecipe(branches=[branch]) | 585 | recipe = self.makeSourcePackageRecipe(branches=[branch]) |
962 | 512 | self.assertTrue(check_permission('launchpad.View', recipe)) | 586 | self.assertTrue(check_permission('launchpad.View', recipe)) |
965 | 513 | removeSecurityProxy(branch).information_type = ( | 587 | self.setInformationType(branch, InformationType.USERDATA) |
964 | 514 | InformationType.USERDATA) | ||
966 | 515 | with person_logged_in(self.factory.makePerson()): | 588 | with person_logged_in(self.factory.makePerson()): |
967 | 516 | self.assertFalse(check_permission('launchpad.View', recipe)) | 589 | self.assertFalse(check_permission('launchpad.View', recipe)) |
968 | 517 | self.assertFalse(check_permission('launchpad.View', recipe)) | 590 | self.assertFalse(check_permission('launchpad.View', recipe)) |
969 | 518 | 591 | ||
970 | 519 | def test_edit(self): | 592 | def test_edit(self): |
971 | 520 | """Only the owner can edit a sourcepackagerecipe.""" | 593 | """Only the owner can edit a sourcepackagerecipe.""" |
973 | 521 | recipe = self.factory.makeSourcePackageRecipe() | 594 | recipe = self.makeSourcePackageRecipe() |
974 | 522 | self.assertFalse(check_permission('launchpad.Edit', recipe)) | 595 | self.assertFalse(check_permission('launchpad.Edit', recipe)) |
975 | 523 | with person_logged_in(self.factory.makePerson()): | 596 | with person_logged_in(self.factory.makePerson()): |
976 | 524 | self.assertFalse(check_permission('launchpad.Edit', recipe)) | 597 | self.assertFalse(check_permission('launchpad.Edit', recipe)) |
977 | @@ -528,8 +601,8 @@ | |||
978 | 528 | def test_destroySelf(self): | 601 | def test_destroySelf(self): |
979 | 529 | """Should destroy associated builds, distroseries, etc.""" | 602 | """Should destroy associated builds, distroseries, etc.""" |
980 | 530 | # Recipe should have at least one datainstruction. | 603 | # Recipe should have at least one datainstruction. |
983 | 531 | branches = [self.factory.makeBranch() for count in range(2)] | 604 | branches = [self.makeBranch() for count in range(2)] |
984 | 532 | recipe = self.factory.makeSourcePackageRecipe(branches=branches) | 605 | recipe = self.makeSourcePackageRecipe(branches=branches) |
985 | 533 | pending_build = self.factory.makeSourcePackageRecipeBuild( | 606 | pending_build = self.factory.makeSourcePackageRecipeBuild( |
986 | 534 | recipe=recipe) | 607 | recipe=recipe) |
987 | 535 | pending_build.queueBuild() | 608 | pending_build.queueBuild() |
988 | @@ -545,7 +618,7 @@ | |||
989 | 545 | def test_destroySelf_preserves_release(self): | 618 | def test_destroySelf_preserves_release(self): |
990 | 546 | # Destroying a sourcepackagerecipe removes references to its builds | 619 | # Destroying a sourcepackagerecipe removes references to its builds |
991 | 547 | # from their releases. | 620 | # from their releases. |
993 | 548 | recipe = self.factory.makeSourcePackageRecipe() | 621 | recipe = self.makeSourcePackageRecipe() |
994 | 549 | build = self.factory.makeSourcePackageRecipeBuild(recipe=recipe) | 622 | build = self.factory.makeSourcePackageRecipeBuild(recipe=recipe) |
995 | 550 | release = self.factory.makeSourcePackageRelease( | 623 | release = self.factory.makeSourcePackageRelease( |
996 | 551 | source_package_recipe_build=build) | 624 | source_package_recipe_build=build) |
997 | @@ -557,7 +630,7 @@ | |||
998 | 557 | def test_destroySelf_retains_build(self): | 630 | def test_destroySelf_retains_build(self): |
999 | 558 | # Destroying a sourcepackagerecipe removes references to its builds | 631 | # Destroying a sourcepackagerecipe removes references to its builds |
1000 | 559 | # from their releases. | 632 | # from their releases. |
1002 | 560 | recipe = self.factory.makeSourcePackageRecipe() | 633 | recipe = self.makeSourcePackageRecipe() |
1003 | 561 | build = self.factory.makeSourcePackageRecipeBuild(recipe=recipe) | 634 | build = self.factory.makeSourcePackageRecipeBuild(recipe=recipe) |
1004 | 562 | store = Store.of(build) | 635 | store = Store.of(build) |
1005 | 563 | store.flush() | 636 | store.flush() |
1006 | @@ -578,12 +651,11 @@ | |||
1007 | 578 | 651 | ||
1008 | 579 | def test_findStaleDailyBuilds(self): | 652 | def test_findStaleDailyBuilds(self): |
1009 | 580 | # Stale recipe not built daily. | 653 | # Stale recipe not built daily. |
1011 | 581 | self.factory.makeSourcePackageRecipe() | 654 | self.makeSourcePackageRecipe() |
1012 | 582 | # Daily build recipe not stale. | 655 | # Daily build recipe not stale. |
1015 | 583 | self.factory.makeSourcePackageRecipe( | 656 | self.makeSourcePackageRecipe(build_daily=True, is_stale=False) |
1014 | 584 | build_daily=True, is_stale=False) | ||
1016 | 585 | # Stale daily build. | 657 | # Stale daily build. |
1018 | 586 | stale_daily = self.factory.makeSourcePackageRecipe( | 658 | stale_daily = self.makeSourcePackageRecipe( |
1019 | 587 | build_daily=True, is_stale=True) | 659 | build_daily=True, is_stale=True) |
1020 | 588 | self.assertContentEqual([stale_daily], | 660 | self.assertContentEqual([stale_daily], |
1021 | 589 | SourcePackageRecipe.findStaleDailyBuilds()) | 661 | SourcePackageRecipe.findStaleDailyBuilds()) |
1022 | @@ -591,8 +663,7 @@ | |||
1023 | 591 | def test_findStaleDailyBuildsDistinct(self): | 663 | def test_findStaleDailyBuildsDistinct(self): |
1024 | 592 | # If a recipe has 2 builds due to 2 distroseries, it only returns | 664 | # If a recipe has 2 builds due to 2 distroseries, it only returns |
1025 | 593 | # one recipe. | 665 | # one recipe. |
1028 | 594 | recipe = self.factory.makeSourcePackageRecipe( | 666 | recipe = self.makeSourcePackageRecipe(build_daily=True, is_stale=True) |
1027 | 595 | build_daily=True, is_stale=True) | ||
1029 | 596 | hoary = self.factory.makeSourcePackageRecipeDistroseries("hoary") | 667 | hoary = self.factory.makeSourcePackageRecipeDistroseries("hoary") |
1030 | 597 | recipe.distroseries.add(hoary) | 668 | recipe.distroseries.add(hoary) |
1031 | 598 | for series in recipe.distroseries: | 669 | for series in recipe.distroseries: |
1032 | @@ -613,7 +684,7 @@ | |||
1033 | 613 | build.updateStatus( | 684 | build.updateStatus( |
1034 | 614 | BuildStatus.FULLYBUILT, | 685 | BuildStatus.FULLYBUILT, |
1035 | 615 | date_finished=build.date_started + duration) | 686 | date_finished=build.date_started + duration) |
1037 | 616 | recipe = removeSecurityProxy(self.factory.makeSourcePackageRecipe()) | 687 | recipe = removeSecurityProxy(self.makeSourcePackageRecipe()) |
1038 | 617 | self.assertIs(None, recipe.getMedianBuildDuration()) | 688 | self.assertIs(None, recipe.getMedianBuildDuration()) |
1039 | 618 | build = self.factory.makeSourcePackageRecipeBuild(recipe=recipe) | 689 | build = self.factory.makeSourcePackageRecipeBuild(recipe=recipe) |
1040 | 619 | set_duration(build, 10) | 690 | set_duration(build, 10) |
1041 | @@ -632,7 +703,7 @@ | |||
1042 | 632 | 703 | ||
1043 | 633 | def test_getBuilds(self): | 704 | def test_getBuilds(self): |
1044 | 634 | # Test the various getBuilds methods. | 705 | # Test the various getBuilds methods. |
1046 | 635 | recipe = self.factory.makeSourcePackageRecipe() | 706 | recipe = self.makeSourcePackageRecipe() |
1047 | 636 | builds = [ | 707 | builds = [ |
1048 | 637 | self.factory.makeSourcePackageRecipeBuild(recipe=recipe) | 708 | self.factory.makeSourcePackageRecipeBuild(recipe=recipe) |
1049 | 638 | for x in range(3)] | 709 | for x in range(3)] |
1050 | @@ -654,7 +725,7 @@ | |||
1051 | 654 | person = self.factory.makePerson() | 725 | person = self.factory.makePerson() |
1052 | 655 | archives = [self.factory.makeArchive(owner=person) for x in range(4)] | 726 | archives = [self.factory.makeArchive(owner=person) for x in range(4)] |
1053 | 656 | distroseries = self.factory.makeSourcePackageRecipeDistroseries() | 727 | distroseries = self.factory.makeSourcePackageRecipeDistroseries() |
1055 | 657 | recipe = self.factory.makeSourcePackageRecipe() | 728 | recipe = self.makeSourcePackageRecipe() |
1056 | 658 | 729 | ||
1057 | 659 | build_info = [] | 730 | build_info = [] |
1058 | 660 | for archive in archives: | 731 | for archive in archives: |
1059 | @@ -666,7 +737,7 @@ | |||
1060 | 666 | 737 | ||
1061 | 667 | def test_getBuilds_cancelled(self): | 738 | def test_getBuilds_cancelled(self): |
1062 | 668 | # Cancelled builds are not considered pending. | 739 | # Cancelled builds are not considered pending. |
1064 | 669 | recipe = self.factory.makeSourcePackageRecipe() | 740 | recipe = self.makeSourcePackageRecipe() |
1065 | 670 | build = self.factory.makeSourcePackageRecipeBuild(recipe=recipe) | 741 | build = self.factory.makeSourcePackageRecipeBuild(recipe=recipe) |
1066 | 671 | with admin_logged_in(): | 742 | with admin_logged_in(): |
1067 | 672 | build.queueBuild() | 743 | build.queueBuild() |
1068 | @@ -676,40 +747,42 @@ | |||
1069 | 676 | self.assertEqual([], list(recipe.pending_builds)) | 747 | self.assertEqual([], list(recipe.pending_builds)) |
1070 | 677 | 748 | ||
1071 | 678 | def test_setRecipeText_private_base_branch(self): | 749 | def test_setRecipeText_private_base_branch(self): |
1073 | 679 | source_package_recipe = self.factory.makeSourcePackageRecipe() | 750 | source_package_recipe = self.makeSourcePackageRecipe() |
1074 | 680 | with person_logged_in(source_package_recipe.owner): | 751 | with person_logged_in(source_package_recipe.owner): |
1076 | 681 | branch = self.factory.makeAnyBranch( | 752 | branch = self.makeBranch( |
1077 | 682 | owner=source_package_recipe.owner, | 753 | owner=source_package_recipe.owner, |
1078 | 683 | information_type=InformationType.USERDATA) | 754 | information_type=InformationType.USERDATA) |
1079 | 684 | recipe_text = self.factory.makeRecipeText(branch) | 755 | recipe_text = self.factory.makeRecipeText(branch) |
1080 | 685 | e = self.assertRaises( | 756 | e = self.assertRaises( |
1082 | 686 | PrivateBranchRecipe, source_package_recipe.setRecipeText, | 757 | self.private_error, source_package_recipe.setRecipeText, |
1083 | 687 | recipe_text) | 758 | recipe_text) |
1084 | 688 | self.assertEqual( | 759 | self.assertEqual( |
1087 | 689 | 'Recipe may not refer to private branch: %s' % | 760 | 'Recipe may not refer to private %s: %s' % |
1088 | 690 | branch.bzr_identity, str(e)) | 761 | (self.branch_type, self.getRepository(branch).identity), |
1089 | 762 | str(e)) | ||
1090 | 691 | 763 | ||
1091 | 692 | def test_setRecipeText_private_referenced_branch(self): | 764 | def test_setRecipeText_private_referenced_branch(self): |
1093 | 693 | source_package_recipe = self.factory.makeSourcePackageRecipe() | 765 | source_package_recipe = self.makeSourcePackageRecipe() |
1094 | 694 | with person_logged_in(source_package_recipe.owner): | 766 | with person_logged_in(source_package_recipe.owner): |
1098 | 695 | base_branch = self.factory.makeAnyBranch( | 767 | base_branch = self.makeBranch(owner=source_package_recipe.owner) |
1099 | 696 | owner=source_package_recipe.owner) | 768 | referenced_branch = self.makeBranch( |
1097 | 697 | referenced_branch = self.factory.makeAnyBranch( | ||
1100 | 698 | owner=source_package_recipe.owner, | 769 | owner=source_package_recipe.owner, |
1101 | 699 | information_type=InformationType.USERDATA) | 770 | information_type=InformationType.USERDATA) |
1102 | 700 | recipe_text = self.factory.makeRecipeText( | 771 | recipe_text = self.factory.makeRecipeText( |
1103 | 701 | base_branch, referenced_branch) | 772 | base_branch, referenced_branch) |
1104 | 702 | e = self.assertRaises( | 773 | e = self.assertRaises( |
1106 | 703 | PrivateBranchRecipe, source_package_recipe.setRecipeText, | 774 | self.private_error, source_package_recipe.setRecipeText, |
1107 | 704 | recipe_text) | 775 | recipe_text) |
1108 | 705 | self.assertEqual( | 776 | self.assertEqual( |
1111 | 706 | 'Recipe may not refer to private branch: %s' % | 777 | 'Recipe may not refer to private %s: %s' % |
1112 | 707 | referenced_branch.bzr_identity, str(e)) | 778 | (self.branch_type, |
1113 | 779 | self.getRepository(referenced_branch).identity), | ||
1114 | 780 | str(e)) | ||
1115 | 708 | 781 | ||
1116 | 709 | def test_getBuilds_ignores_disabled_archive(self): | 782 | def test_getBuilds_ignores_disabled_archive(self): |
1117 | 710 | # Builds into a disabled archive aren't returned. | 783 | # Builds into a disabled archive aren't returned. |
1118 | 711 | archive = self.factory.makeArchive() | 784 | archive = self.factory.makeArchive() |
1120 | 712 | recipe = self.factory.makeSourcePackageRecipe() | 785 | recipe = self.makeSourcePackageRecipe() |
1121 | 713 | self.factory.makeSourcePackageRecipeBuild( | 786 | self.factory.makeSourcePackageRecipeBuild( |
1122 | 714 | recipe=recipe, archive=archive) | 787 | recipe=recipe, archive=archive) |
1123 | 715 | with person_logged_in(archive.owner): | 788 | with person_logged_in(archive.owner): |
1124 | @@ -719,19 +792,19 @@ | |||
1125 | 719 | self.assertEqual([], list(recipe.pending_builds)) | 792 | self.assertEqual([], list(recipe.pending_builds)) |
1126 | 720 | 793 | ||
1127 | 721 | def test_containsUnbuildableSeries(self): | 794 | def test_containsUnbuildableSeries(self): |
1129 | 722 | recipe = self.factory.makeSourcePackageRecipe() | 795 | recipe = self.makeSourcePackageRecipe() |
1130 | 723 | self.assertFalse(recipe.containsUnbuildableSeries( | 796 | self.assertFalse(recipe.containsUnbuildableSeries( |
1131 | 724 | recipe.daily_build_archive)) | 797 | recipe.daily_build_archive)) |
1132 | 725 | 798 | ||
1133 | 726 | def test_containsUnbuildableSeries_with_obsolete_series(self): | 799 | def test_containsUnbuildableSeries_with_obsolete_series(self): |
1135 | 727 | recipe = self.factory.makeSourcePackageRecipe() | 800 | recipe = self.makeSourcePackageRecipe() |
1136 | 728 | warty = self.factory.makeSourcePackageRecipeDistroseries() | 801 | warty = self.factory.makeSourcePackageRecipeDistroseries() |
1137 | 729 | removeSecurityProxy(warty).status = SeriesStatus.OBSOLETE | 802 | removeSecurityProxy(warty).status = SeriesStatus.OBSOLETE |
1138 | 730 | self.assertTrue(recipe.containsUnbuildableSeries( | 803 | self.assertTrue(recipe.containsUnbuildableSeries( |
1139 | 731 | recipe.daily_build_archive)) | 804 | recipe.daily_build_archive)) |
1140 | 732 | 805 | ||
1141 | 733 | def test_performDailyBuild_filters_obsolete_series(self): | 806 | def test_performDailyBuild_filters_obsolete_series(self): |
1143 | 734 | recipe = self.factory.makeSourcePackageRecipe() | 807 | recipe = self.makeSourcePackageRecipe() |
1144 | 735 | warty = self.factory.makeSourcePackageRecipeDistroseries() | 808 | warty = self.factory.makeSourcePackageRecipeDistroseries() |
1145 | 736 | hoary = self.factory.makeSourcePackageRecipeDistroseries(name='hoary') | 809 | hoary = self.factory.makeSourcePackageRecipeDistroseries(name='hoary') |
1146 | 737 | with person_logged_in(recipe.owner): | 810 | with person_logged_in(recipe.owner): |
1147 | @@ -741,19 +814,30 @@ | |||
1148 | 741 | self.assertEqual([build.recipe for build in builds], [recipe]) | 814 | self.assertEqual([build.recipe for build in builds], [recipe]) |
1149 | 742 | 815 | ||
1150 | 743 | 816 | ||
1152 | 744 | class TestRecipeBranchRoundTripping(TestCaseWithFactory): | 817 | class TestSourcePackageRecipeBzr( |
1153 | 818 | TestSourcePackageRecipeMixin, BzrMixin, TestCaseWithFactory): | ||
1154 | 819 | """Test `SourcePackageRecipe` objects for Bazaar.""" | ||
1155 | 820 | |||
1156 | 821 | |||
1157 | 822 | class TestSourcePackageRecipeGit( | ||
1158 | 823 | TestSourcePackageRecipeMixin, GitMixin, TestCaseWithFactory): | ||
1159 | 824 | """Test `SourcePackageRecipe` objects for Git.""" | ||
1160 | 825 | |||
1161 | 826 | |||
1162 | 827 | class TestRecipeBranchRoundTrippingMixin: | ||
1163 | 745 | 828 | ||
1164 | 746 | layer = DatabaseFunctionalLayer | 829 | layer = DatabaseFunctionalLayer |
1165 | 747 | 830 | ||
1166 | 748 | def setUp(self): | 831 | def setUp(self): |
1171 | 749 | super(TestRecipeBranchRoundTripping, self).setUp() | 832 | super(TestRecipeBranchRoundTrippingMixin, self).setUp() |
1172 | 750 | self.base_branch = self.factory.makeAnyBranch() | 833 | self.base_branch = self.makeBranch() |
1173 | 751 | self.nested_branch = self.factory.makeAnyBranch() | 834 | self.nested_branch = self.makeBranch() |
1174 | 752 | self.merged_branch = self.factory.makeAnyBranch() | 835 | self.merged_branch = self.makeBranch() |
1175 | 753 | self.branch_identities = { | 836 | self.branch_identities = { |
1179 | 754 | 'base': self.base_branch.bzr_identity, | 837 | 'recipe_id': self.recipe_id, |
1180 | 755 | 'nested': self.nested_branch.bzr_identity, | 838 | 'base': self.getRepository(self.base_branch).identity, |
1181 | 756 | 'merged': self.merged_branch.bzr_identity, | 839 | 'nested': self.getRepository(self.nested_branch).identity, |
1182 | 840 | 'merged': self.getRepository(self.merged_branch).identity, | ||
1183 | 757 | } | 841 | } |
1184 | 758 | 842 | ||
1185 | 759 | def get_recipe(self, recipe_text): | 843 | def get_recipe(self, recipe_text): |
1186 | @@ -785,161 +869,173 @@ | |||
1187 | 785 | 869 | ||
1188 | 786 | def test_builds_simplest_recipe(self): | 870 | def test_builds_simplest_recipe(self): |
1189 | 787 | recipe_text = '''\ | 871 | recipe_text = '''\ |
1191 | 788 | # bzr-builder format 0.3 deb-version 0.1-{revno} | 872 | # %(recipe_id)s format 0.3 deb-version 0.1-{revno} |
1192 | 789 | %(base)s | 873 | %(base)s |
1193 | 790 | ''' % self.branch_identities | 874 | ''' % self.branch_identities |
1194 | 791 | base_branch = self.get_recipe(recipe_text).builder_recipe | 875 | base_branch = self.get_recipe(recipe_text).builder_recipe |
1195 | 792 | self.check_base_recipe_branch( | 876 | self.check_base_recipe_branch( |
1197 | 793 | base_branch, self.base_branch.bzr_identity, | 877 | base_branch, self.getRepository(self.base_branch).identity, |
1198 | 794 | deb_version='0.1-{revno}') | 878 | deb_version='0.1-{revno}') |
1199 | 795 | 879 | ||
1200 | 796 | def test_builds_recipe_with_merge(self): | 880 | def test_builds_recipe_with_merge(self): |
1201 | 797 | recipe_text = '''\ | 881 | recipe_text = '''\ |
1203 | 798 | # bzr-builder format 0.3 deb-version 0.1-{revno} | 882 | # %(recipe_id)s format 0.3 deb-version 0.1-{revno} |
1204 | 799 | %(base)s | 883 | %(base)s |
1205 | 800 | merge bar %(merged)s | 884 | merge bar %(merged)s |
1206 | 801 | ''' % self.branch_identities | 885 | ''' % self.branch_identities |
1207 | 802 | base_branch = self.get_recipe(recipe_text).builder_recipe | 886 | base_branch = self.get_recipe(recipe_text).builder_recipe |
1208 | 803 | self.check_base_recipe_branch( | 887 | self.check_base_recipe_branch( |
1211 | 804 | base_branch, self.base_branch.bzr_identity, num_child_branches=1, | 888 | base_branch, self.getRepository(self.base_branch).identity, |
1212 | 805 | deb_version='0.1-{revno}') | 889 | num_child_branches=1, deb_version='0.1-{revno}') |
1213 | 806 | child_branch, location = base_branch.child_branches[0].as_tuple() | 890 | child_branch, location = base_branch.child_branches[0].as_tuple() |
1214 | 807 | self.assertEqual(None, location) | 891 | self.assertEqual(None, location) |
1215 | 808 | self.check_recipe_branch( | 892 | self.check_recipe_branch( |
1217 | 809 | child_branch, "bar", self.merged_branch.bzr_identity) | 893 | child_branch, "bar", |
1218 | 894 | self.getRepository(self.merged_branch).identity) | ||
1219 | 810 | 895 | ||
1220 | 811 | def test_builds_recipe_with_nest(self): | 896 | def test_builds_recipe_with_nest(self): |
1221 | 812 | recipe_text = '''\ | 897 | recipe_text = '''\ |
1223 | 813 | # bzr-builder format 0.3 deb-version 0.1-{revno} | 898 | # %(recipe_id)s format 0.3 deb-version 0.1-{revno} |
1224 | 814 | %(base)s | 899 | %(base)s |
1225 | 815 | nest bar %(nested)s baz | 900 | nest bar %(nested)s baz |
1226 | 816 | ''' % self.branch_identities | 901 | ''' % self.branch_identities |
1227 | 817 | base_branch = self.get_recipe(recipe_text).builder_recipe | 902 | base_branch = self.get_recipe(recipe_text).builder_recipe |
1228 | 818 | self.check_base_recipe_branch( | 903 | self.check_base_recipe_branch( |
1231 | 819 | base_branch, self.base_branch.bzr_identity, num_child_branches=1, | 904 | base_branch, self.getRepository(self.base_branch).identity, |
1232 | 820 | deb_version='0.1-{revno}') | 905 | num_child_branches=1, deb_version='0.1-{revno}') |
1233 | 821 | child_branch, location = base_branch.child_branches[0].as_tuple() | 906 | child_branch, location = base_branch.child_branches[0].as_tuple() |
1234 | 822 | self.assertEqual("baz", location) | 907 | self.assertEqual("baz", location) |
1235 | 823 | self.check_recipe_branch( | 908 | self.check_recipe_branch( |
1237 | 824 | child_branch, "bar", self.nested_branch.bzr_identity) | 909 | child_branch, "bar", |
1238 | 910 | self.getRepository(self.nested_branch).identity) | ||
1239 | 825 | 911 | ||
1240 | 826 | def test_builds_recipe_with_nest_then_merge(self): | 912 | def test_builds_recipe_with_nest_then_merge(self): |
1241 | 827 | recipe_text = '''\ | 913 | recipe_text = '''\ |
1243 | 828 | # bzr-builder format 0.3 deb-version 0.1-{revno} | 914 | # %(recipe_id)s format 0.3 deb-version 0.1-{revno} |
1244 | 829 | %(base)s | 915 | %(base)s |
1245 | 830 | nest bar %(nested)s baz | 916 | nest bar %(nested)s baz |
1246 | 831 | merge zam %(merged)s | 917 | merge zam %(merged)s |
1247 | 832 | ''' % self.branch_identities | 918 | ''' % self.branch_identities |
1248 | 833 | base_branch = self.get_recipe(recipe_text).builder_recipe | 919 | base_branch = self.get_recipe(recipe_text).builder_recipe |
1249 | 834 | self.check_base_recipe_branch( | 920 | self.check_base_recipe_branch( |
1252 | 835 | base_branch, self.base_branch.bzr_identity, num_child_branches=2, | 921 | base_branch, self.getRepository(self.base_branch).identity, |
1253 | 836 | deb_version='0.1-{revno}') | 922 | num_child_branches=2, deb_version='0.1-{revno}') |
1254 | 837 | child_branch, location = base_branch.child_branches[0].as_tuple() | 923 | child_branch, location = base_branch.child_branches[0].as_tuple() |
1255 | 838 | self.assertEqual("baz", location) | 924 | self.assertEqual("baz", location) |
1256 | 839 | self.check_recipe_branch( | 925 | self.check_recipe_branch( |
1258 | 840 | child_branch, "bar", self.nested_branch.bzr_identity) | 926 | child_branch, "bar", |
1259 | 927 | self.getRepository(self.nested_branch).identity) | ||
1260 | 841 | child_branch, location = base_branch.child_branches[1].as_tuple() | 928 | child_branch, location = base_branch.child_branches[1].as_tuple() |
1261 | 842 | self.assertEqual(None, location) | 929 | self.assertEqual(None, location) |
1262 | 843 | self.check_recipe_branch( | 930 | self.check_recipe_branch( |
1264 | 844 | child_branch, "zam", self.merged_branch.bzr_identity) | 931 | child_branch, "zam", |
1265 | 932 | self.getRepository(self.merged_branch).identity) | ||
1266 | 845 | 933 | ||
1267 | 846 | def test_builds_recipe_with_merge_then_nest(self): | 934 | def test_builds_recipe_with_merge_then_nest(self): |
1268 | 847 | recipe_text = '''\ | 935 | recipe_text = '''\ |
1270 | 848 | # bzr-builder format 0.3 deb-version 0.1-{revno} | 936 | # %(recipe_id)s format 0.3 deb-version 0.1-{revno} |
1271 | 849 | %(base)s | 937 | %(base)s |
1272 | 850 | merge zam %(merged)s | 938 | merge zam %(merged)s |
1273 | 851 | nest bar %(nested)s baz | 939 | nest bar %(nested)s baz |
1274 | 852 | ''' % self.branch_identities | 940 | ''' % self.branch_identities |
1275 | 853 | base_branch = self.get_recipe(recipe_text).builder_recipe | 941 | base_branch = self.get_recipe(recipe_text).builder_recipe |
1276 | 854 | self.check_base_recipe_branch( | 942 | self.check_base_recipe_branch( |
1279 | 855 | base_branch, self.base_branch.bzr_identity, num_child_branches=2, | 943 | base_branch, self.getRepository(self.base_branch).identity, |
1280 | 856 | deb_version='0.1-{revno}') | 944 | num_child_branches=2, deb_version='0.1-{revno}') |
1281 | 857 | child_branch, location = base_branch.child_branches[0].as_tuple() | 945 | child_branch, location = base_branch.child_branches[0].as_tuple() |
1282 | 858 | self.assertEqual(None, location) | 946 | self.assertEqual(None, location) |
1283 | 859 | self.check_recipe_branch( | 947 | self.check_recipe_branch( |
1285 | 860 | child_branch, "zam", self.merged_branch.bzr_identity) | 948 | child_branch, "zam", |
1286 | 949 | self.getRepository(self.merged_branch).identity) | ||
1287 | 861 | child_branch, location = base_branch.child_branches[1].as_tuple() | 950 | child_branch, location = base_branch.child_branches[1].as_tuple() |
1288 | 862 | self.assertEqual("baz", location) | 951 | self.assertEqual("baz", location) |
1289 | 863 | self.check_recipe_branch( | 952 | self.check_recipe_branch( |
1291 | 864 | child_branch, "bar", self.nested_branch.bzr_identity) | 953 | child_branch, "bar", |
1292 | 954 | self.getRepository(self.nested_branch).identity) | ||
1293 | 865 | 955 | ||
1294 | 866 | def test_builds_a_merge_in_to_a_nest(self): | 956 | def test_builds_a_merge_in_to_a_nest(self): |
1295 | 867 | recipe_text = '''\ | 957 | recipe_text = '''\ |
1297 | 868 | # bzr-builder format 0.3 deb-version 0.1-{revno} | 958 | # %(recipe_id)s format 0.3 deb-version 0.1-{revno} |
1298 | 869 | %(base)s | 959 | %(base)s |
1299 | 870 | nest bar %(nested)s baz | 960 | nest bar %(nested)s baz |
1300 | 871 | merge zam %(merged)s | 961 | merge zam %(merged)s |
1301 | 872 | ''' % self.branch_identities | 962 | ''' % self.branch_identities |
1302 | 873 | base_branch = self.get_recipe(recipe_text).builder_recipe | 963 | base_branch = self.get_recipe(recipe_text).builder_recipe |
1303 | 874 | self.check_base_recipe_branch( | 964 | self.check_base_recipe_branch( |
1306 | 875 | base_branch, self.base_branch.bzr_identity, num_child_branches=1, | 965 | base_branch, self.getRepository(self.base_branch).identity, |
1307 | 876 | deb_version='0.1-{revno}') | 966 | num_child_branches=1, deb_version='0.1-{revno}') |
1308 | 877 | child_branch, location = base_branch.child_branches[0].as_tuple() | 967 | child_branch, location = base_branch.child_branches[0].as_tuple() |
1309 | 878 | self.assertEqual("baz", location) | 968 | self.assertEqual("baz", location) |
1310 | 879 | self.check_recipe_branch( | 969 | self.check_recipe_branch( |
1312 | 880 | child_branch, "bar", self.nested_branch.bzr_identity, | 970 | child_branch, "bar", |
1313 | 971 | self.getRepository(self.nested_branch).identity, | ||
1314 | 881 | num_child_branches=1) | 972 | num_child_branches=1) |
1315 | 882 | child_branch, location = child_branch.child_branches[0].as_tuple() | 973 | child_branch, location = child_branch.child_branches[0].as_tuple() |
1316 | 883 | self.assertEqual(None, location) | 974 | self.assertEqual(None, location) |
1317 | 884 | self.check_recipe_branch( | 975 | self.check_recipe_branch( |
1319 | 885 | child_branch, "zam", self.merged_branch.bzr_identity) | 976 | child_branch, "zam", |
1320 | 977 | self.getRepository(self.merged_branch).identity) | ||
1321 | 886 | 978 | ||
1322 | 887 | def tests_builds_nest_into_a_nest(self): | 979 | def tests_builds_nest_into_a_nest(self): |
1325 | 888 | nested2 = self.factory.makeAnyBranch() | 980 | nested2 = self.makeBranch() |
1326 | 889 | self.branch_identities['nested2'] = nested2.bzr_identity | 981 | self.branch_identities['nested2'] = ( |
1327 | 982 | self.getRepository(nested2).identity) | ||
1328 | 890 | recipe_text = '''\ | 983 | recipe_text = '''\ |
1330 | 891 | # bzr-builder format 0.3 deb-version 0.1-{revno} | 984 | # %(recipe_id)s format 0.3 deb-version 0.1-{revno} |
1331 | 892 | %(base)s | 985 | %(base)s |
1332 | 893 | nest bar %(nested)s baz | 986 | nest bar %(nested)s baz |
1333 | 894 | nest zam %(nested2)s zoo | 987 | nest zam %(nested2)s zoo |
1334 | 895 | ''' % self.branch_identities | 988 | ''' % self.branch_identities |
1335 | 896 | base_branch = self.get_recipe(recipe_text).builder_recipe | 989 | base_branch = self.get_recipe(recipe_text).builder_recipe |
1336 | 897 | self.check_base_recipe_branch( | 990 | self.check_base_recipe_branch( |
1339 | 898 | base_branch, self.base_branch.bzr_identity, num_child_branches=1, | 991 | base_branch, self.getRepository(self.base_branch).identity, |
1340 | 899 | deb_version='0.1-{revno}') | 992 | num_child_branches=1, deb_version='0.1-{revno}') |
1341 | 900 | child_branch, location = base_branch.child_branches[0].as_tuple() | 993 | child_branch, location = base_branch.child_branches[0].as_tuple() |
1342 | 901 | self.assertEqual("baz", location) | 994 | self.assertEqual("baz", location) |
1343 | 902 | self.check_recipe_branch( | 995 | self.check_recipe_branch( |
1345 | 903 | child_branch, "bar", self.nested_branch.bzr_identity, | 996 | child_branch, "bar", |
1346 | 997 | self.getRepository(self.nested_branch).identity, | ||
1347 | 904 | num_child_branches=1) | 998 | num_child_branches=1) |
1348 | 905 | child_branch, location = child_branch.child_branches[0].as_tuple() | 999 | child_branch, location = child_branch.child_branches[0].as_tuple() |
1349 | 906 | self.assertEqual("zoo", location) | 1000 | self.assertEqual("zoo", location) |
1351 | 907 | self.check_recipe_branch(child_branch, "zam", nested2.bzr_identity) | 1001 | self.check_recipe_branch( |
1352 | 1002 | child_branch, "zam", self.getRepository(nested2).identity) | ||
1353 | 908 | 1003 | ||
1354 | 909 | def tests_builds_recipe_with_revspecs(self): | 1004 | def tests_builds_recipe_with_revspecs(self): |
1355 | 910 | recipe_text = '''\ | 1005 | recipe_text = '''\ |
1357 | 911 | # bzr-builder format 0.3 deb-version 0.1-{revno} | 1006 | # %(recipe_id)s format 0.3 deb-version 0.1-{revno} |
1358 | 912 | %(base)s revid:a | 1007 | %(base)s revid:a |
1359 | 913 | nest bar %(nested)s baz tag:b | 1008 | nest bar %(nested)s baz tag:b |
1360 | 914 | merge zam %(merged)s 2 | 1009 | merge zam %(merged)s 2 |
1361 | 915 | ''' % self.branch_identities | 1010 | ''' % self.branch_identities |
1362 | 916 | base_branch = self.get_recipe(recipe_text).builder_recipe | 1011 | base_branch = self.get_recipe(recipe_text).builder_recipe |
1363 | 917 | self.check_base_recipe_branch( | 1012 | self.check_base_recipe_branch( |
1366 | 918 | base_branch, self.base_branch.bzr_identity, num_child_branches=2, | 1013 | base_branch, self.getRepository(self.base_branch).identity, |
1367 | 919 | revspec="revid:a", deb_version='0.1-{revno}') | 1014 | num_child_branches=2, revspec="revid:a", deb_version='0.1-{revno}') |
1368 | 920 | instruction = base_branch.child_branches[0] | 1015 | instruction = base_branch.child_branches[0] |
1369 | 921 | child_branch = instruction.recipe_branch | 1016 | child_branch = instruction.recipe_branch |
1370 | 922 | location = instruction.nest_path | 1017 | location = instruction.nest_path |
1371 | 923 | self.assertEqual("baz", location) | 1018 | self.assertEqual("baz", location) |
1372 | 924 | self.check_recipe_branch( | 1019 | self.check_recipe_branch( |
1375 | 925 | child_branch, "bar", self.nested_branch.bzr_identity, | 1020 | child_branch, "bar", |
1376 | 926 | revspec="tag:b") | 1021 | self.getRepository(self.nested_branch).identity, revspec="tag:b") |
1377 | 927 | child_branch, location = base_branch.child_branches[1].as_tuple() | 1022 | child_branch, location = base_branch.child_branches[1].as_tuple() |
1378 | 928 | self.assertEqual(None, location) | 1023 | self.assertEqual(None, location) |
1379 | 929 | self.check_recipe_branch( | 1024 | self.check_recipe_branch( |
1381 | 930 | child_branch, "zam", self.merged_branch.bzr_identity, revspec="2") | 1025 | child_branch, "zam", |
1382 | 1026 | self.getRepository(self.merged_branch).identity, revspec="2") | ||
1383 | 931 | 1027 | ||
1384 | 932 | def test_unsets_revspecs(self): | 1028 | def test_unsets_revspecs(self): |
1385 | 933 | # Changing a recipe's text to no longer include revspecs unsets | 1029 | # Changing a recipe's text to no longer include revspecs unsets |
1386 | 934 | # them from the stored copy. | 1030 | # them from the stored copy. |
1387 | 935 | revspec_text = '''\ | 1031 | revspec_text = '''\ |
1389 | 936 | # bzr-builder format 0.3 deb-version 0.1-{revno} | 1032 | # %(recipe_id)s format 0.3 deb-version 0.1-{revno} |
1390 | 937 | %(base)s revid:a | 1033 | %(base)s revid:a |
1391 | 938 | nest bar %(nested)s baz tag:b | 1034 | nest bar %(nested)s baz tag:b |
1392 | 939 | merge zam %(merged)s 2 | 1035 | merge zam %(merged)s 2 |
1393 | 940 | ''' % self.branch_identities | 1036 | ''' % self.branch_identities |
1394 | 941 | no_revspec_text = '''\ | 1037 | no_revspec_text = '''\ |
1396 | 942 | # bzr-builder format 0.3 deb-version 0.1-{revno} | 1038 | # %(recipe_id)s format 0.3 deb-version 0.1-{revno} |
1397 | 943 | %(base)s | 1039 | %(base)s |
1398 | 944 | nest bar %(nested)s baz | 1040 | nest bar %(nested)s baz |
1399 | 945 | merge zam %(merged)s | 1041 | merge zam %(merged)s |
1400 | @@ -952,18 +1048,29 @@ | |||
1401 | 952 | 1048 | ||
1402 | 953 | def test_builds_recipe_without_debversion(self): | 1049 | def test_builds_recipe_without_debversion(self): |
1403 | 954 | recipe_text = '''\ | 1050 | recipe_text = '''\ |
1405 | 955 | # bzr-builder format 0.4 | 1051 | # %(recipe_id)s format 0.4 |
1406 | 956 | %(base)s | 1052 | %(base)s |
1407 | 957 | nest bar %(nested)s baz | 1053 | nest bar %(nested)s baz |
1408 | 958 | ''' % self.branch_identities | 1054 | ''' % self.branch_identities |
1409 | 959 | base_branch = self.get_recipe(recipe_text).builder_recipe | 1055 | base_branch = self.get_recipe(recipe_text).builder_recipe |
1410 | 960 | self.check_base_recipe_branch( | 1056 | self.check_base_recipe_branch( |
1413 | 961 | base_branch, self.base_branch.bzr_identity, num_child_branches=1, | 1057 | base_branch, self.getRepository(self.base_branch).identity, |
1414 | 962 | deb_version=None) | 1058 | num_child_branches=1, deb_version=None) |
1415 | 963 | child_branch, location = base_branch.child_branches[0].as_tuple() | 1059 | child_branch, location = base_branch.child_branches[0].as_tuple() |
1416 | 964 | self.assertEqual("baz", location) | 1060 | self.assertEqual("baz", location) |
1417 | 965 | self.check_recipe_branch( | 1061 | self.check_recipe_branch( |
1419 | 966 | child_branch, "bar", self.nested_branch.bzr_identity) | 1062 | child_branch, "bar", |
1420 | 1063 | self.getRepository(self.nested_branch).identity) | ||
1421 | 1064 | |||
1422 | 1065 | |||
1423 | 1066 | class TestRecipeBranchRoundTrippingBzr( | ||
1424 | 1067 | TestRecipeBranchRoundTrippingMixin, BzrMixin, TestCaseWithFactory): | ||
1425 | 1068 | pass | ||
1426 | 1069 | |||
1427 | 1070 | |||
1428 | 1071 | class TestRecipeBranchRoundTrippingGit( | ||
1429 | 1072 | TestRecipeBranchRoundTrippingMixin, GitMixin, TestCaseWithFactory): | ||
1430 | 1073 | pass | ||
1431 | 967 | 1074 | ||
1432 | 968 | 1075 | ||
1433 | 969 | class RecipeDateLastModified(TestCaseWithFactory): | 1076 | class RecipeDateLastModified(TestCaseWithFactory): |
1434 | 970 | 1077 | ||
1435 | === modified file 'lib/lp/code/model/tests/test_sourcepackagerecipebuild.py' | |||
1436 | --- lib/lp/code/model/tests/test_sourcepackagerecipebuild.py 2015-10-19 10:56:16 +0000 | |||
1437 | +++ lib/lp/code/model/tests/test_sourcepackagerecipebuild.py 2016-01-12 17:27:35 +0000 | |||
1438 | @@ -1,4 +1,4 @@ | |||
1440 | 1 | # Copyright 2010-2013 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2010-2016 Canonical Ltd. This software is licensed under the |
1441 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
1442 | 3 | 3 | ||
1443 | 4 | """Tests for source package builds.""" | 4 | """Tests for source package builds.""" |
1444 | @@ -106,11 +106,11 @@ | |||
1445 | 106 | self.assertEqual(bq, spb.buildqueue_record) | 106 | self.assertEqual(bq, spb.buildqueue_record) |
1446 | 107 | 107 | ||
1447 | 108 | def test_title(self): | 108 | def test_title(self): |
1450 | 109 | # A recipe build's title currently consists of the base | 109 | # A recipe build's title currently consists of the base source |
1451 | 110 | # branch's unique name. | 110 | # location's unique name. |
1452 | 111 | spb = self.makeSourcePackageRecipeBuild() | 111 | spb = self.makeSourcePackageRecipeBuild() |
1453 | 112 | title = "%s recipe build in %s %s" % ( | 112 | title = "%s recipe build in %s %s" % ( |
1455 | 113 | spb.recipe.base_branch.unique_name, spb.distribution.name, | 113 | spb.recipe.base.unique_name, spb.distribution.name, |
1456 | 114 | spb.distroseries.name) | 114 | spb.distroseries.name) |
1457 | 115 | self.assertEqual(spb.title, title) | 115 | self.assertEqual(spb.title, title) |
1458 | 116 | 116 | ||
1459 | 117 | 117 | ||
1460 | === modified file 'lib/lp/testing/factory.py' | |||
1461 | --- lib/lp/testing/factory.py 2016-01-11 21:11:27 +0000 | |||
1462 | +++ lib/lp/testing/factory.py 2016-01-12 17:27:35 +0000 | |||
1463 | @@ -2,7 +2,7 @@ | |||
1464 | 2 | # NOTE: The first line above must stay first; do not move the copyright | 2 | # NOTE: The first line above must stay first; do not move the copyright |
1465 | 3 | # notice to the top. See http://www.python.org/dev/peps/pep-0263/. | 3 | # notice to the top. See http://www.python.org/dev/peps/pep-0263/. |
1466 | 4 | # | 4 | # |
1468 | 5 | # Copyright 2009-2015 Canonical Ltd. This software is licensed under the | 5 | # Copyright 2009-2016 Canonical Ltd. This software is licensed under the |
1469 | 6 | # GNU Affero General Public License version 3 (see the file LICENSE). | 6 | # GNU Affero General Public License version 3 (see the file LICENSE). |
1470 | 7 | 7 | ||
1471 | 8 | """Testing infrastructure for the Launchpad application. | 8 | """Testing infrastructure for the Launchpad application. |
1472 | @@ -112,6 +112,7 @@ | |||
1473 | 112 | RevisionControlSystems, | 112 | RevisionControlSystems, |
1474 | 113 | ) | 113 | ) |
1475 | 114 | from lp.code.errors import UnknownBranchTypeError | 114 | from lp.code.errors import UnknownBranchTypeError |
1476 | 115 | from lp.code.interfaces.branch import IBranch | ||
1477 | 115 | from lp.code.interfaces.branchnamespace import get_branch_namespace | 116 | from lp.code.interfaces.branchnamespace import get_branch_namespace |
1478 | 116 | from lp.code.interfaces.branchtarget import IBranchTarget | 117 | from lp.code.interfaces.branchtarget import IBranchTarget |
1479 | 117 | from lp.code.interfaces.codeimport import ICodeImportSet | 118 | from lp.code.interfaces.codeimport import ICodeImportSet |
1480 | @@ -119,11 +120,13 @@ | |||
1481 | 119 | from lp.code.interfaces.codeimportmachine import ICodeImportMachineSet | 120 | from lp.code.interfaces.codeimportmachine import ICodeImportMachineSet |
1482 | 120 | from lp.code.interfaces.codeimportresult import ICodeImportResultSet | 121 | from lp.code.interfaces.codeimportresult import ICodeImportResultSet |
1483 | 121 | from lp.code.interfaces.gitnamespace import get_git_namespace | 122 | from lp.code.interfaces.gitnamespace import get_git_namespace |
1484 | 123 | from lp.code.interfaces.gitref import IGitRef | ||
1485 | 122 | from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch | 124 | from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch |
1486 | 123 | from lp.code.interfaces.revision import IRevisionSet | 125 | from lp.code.interfaces.revision import IRevisionSet |
1487 | 124 | from lp.code.interfaces.sourcepackagerecipe import ( | 126 | from lp.code.interfaces.sourcepackagerecipe import ( |
1488 | 125 | ISourcePackageRecipeSource, | 127 | ISourcePackageRecipeSource, |
1489 | 126 | MINIMAL_RECIPE_TEXT_BZR, | 128 | MINIMAL_RECIPE_TEXT_BZR, |
1490 | 129 | MINIMAL_RECIPE_TEXT_GIT, | ||
1491 | 127 | ) | 130 | ) |
1492 | 128 | from lp.code.interfaces.sourcepackagerecipebuild import ( | 131 | from lp.code.interfaces.sourcepackagerecipebuild import ( |
1493 | 129 | ISourcePackageRecipeBuildSource, | 132 | ISourcePackageRecipeBuildSource, |
1494 | @@ -2897,9 +2900,22 @@ | |||
1495 | 2897 | branches = (self.makeAnyBranch(), ) | 2900 | branches = (self.makeAnyBranch(), ) |
1496 | 2898 | base_branch = branches[0] | 2901 | base_branch = branches[0] |
1497 | 2899 | other_branches = branches[1:] | 2902 | other_branches = branches[1:] |
1499 | 2900 | text = MINIMAL_RECIPE_TEXT_BZR % base_branch.bzr_identity | 2903 | if IBranch.providedBy(base_branch): |
1500 | 2904 | text = MINIMAL_RECIPE_TEXT_BZR % base_branch.identity | ||
1501 | 2905 | elif IGitRef.providedBy(base_branch): | ||
1502 | 2906 | text = MINIMAL_RECIPE_TEXT_GIT % ( | ||
1503 | 2907 | base_branch.repository.identity, base_branch.name) | ||
1504 | 2908 | else: | ||
1505 | 2909 | raise AssertionError( | ||
1506 | 2910 | "Unsupported base_branch: %r" % (base_branch,)) | ||
1507 | 2901 | for i, branch in enumerate(other_branches): | 2911 | for i, branch in enumerate(other_branches): |
1509 | 2902 | text += 'merge dummy-%s %s\n' % (i, branch.bzr_identity) | 2912 | if IBranch.providedBy(branch): |
1510 | 2913 | text += 'merge dummy-%s %s\n' % (i, branch.identity) | ||
1511 | 2914 | elif IGitRef.providedBy(branch): | ||
1512 | 2915 | text += 'merge dummy-%s %s %s\n' % ( | ||
1513 | 2916 | i, branch.repository.identity, branch.name) | ||
1514 | 2917 | else: | ||
1515 | 2918 | raise AssertionError("Unsupported branch: %r" % (branch,)) | ||
1516 | 2903 | return text | 2919 | return text |
1517 | 2904 | 2920 | ||
1518 | 2905 | def makeRecipe(self, *branches): | 2921 | def makeRecipe(self, *branches): |