6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
1 |
= ProductSeries = |
2879.1.1
by Diogo Matsubara
Fixes https://launchpad.net/products/launchpad/+bug/1543 Filing duplicate source details raises an integrityerror instead of a nice error |
2 |
|
3614.1.68
by Brad Bollenbach
reapply MaloneReleaseManagement |
3 |
A Launchpad Product models a single piece of software. However for |
4 |
release management purposes, a Product often has to be split in several |
|
5 |
discrete entities which must be considered separately for packaging, |
|
6 |
translations, version control, etc. We call these entities |
|
7 |
ProductSeries. |
|
2840.1.7
by David Allouche
[merge conflict] rocketfuel |
8 |
|
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
9 |
>>> from zope.component import getUtility |
14600.2.2
by Curtis Hovey
Moved webapp to lp.services. |
10 |
>>> from lp.services.webapp.testing import verifyObject |
11716.1.6
by Curtis Hovey
Converted glob imports in doctests to import for the true module. |
11 |
>>> from lp.registry.interfaces.person import IPersonSet |
11716.1.12
by Curtis Hovey
Sorted imports in doctests. |
12 |
>>> from lp.registry.interfaces.product import IProductSet |
11716.1.6
by Curtis Hovey
Converted glob imports in doctests to import for the true module. |
13 |
>>> from lp.registry.interfaces.productseries import IProductSeries |
11818.3.1
by Jeroen Vermeulen
Split out lp.translations.enums and lp.translations.interfaces.hastranslationimports. |
14 |
>>> from lp.translations.interfaces.hastranslationimports import ( |
8751.1.21
by Danilo Šegan
Fix up interface imports for a few external tests. |
15 |
... IHasTranslationImports) |
14606.3.1
by William Grant
Merge canonical.database into lp.services.database. |
16 |
>>> from lp.services.database.sqlbase import flush_database_updates |
2840.1.7
by David Allouche
[merge conflict] rocketfuel |
17 |
|
18 |
First, get a product that has some ProductSeries in the sample data. |
|
19 |
||
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
20 |
>>> productset = getUtility(IProductSet) |
21 |
>>> firefox = productset['firefox'] |
|
2840.1.7
by David Allouche
[merge conflict] rocketfuel |
22 |
|
3614.1.68
by Brad Bollenbach
reapply MaloneReleaseManagement |
23 |
A ProductSeries can be retrieved using the associated product and the |
24 |
series name. |
|
2840.1.7
by David Allouche
[merge conflict] rocketfuel |
25 |
|
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
26 |
>>> trunk = firefox.getSeries('trunk') |
2840.1.7
by David Allouche
[merge conflict] rocketfuel |
27 |
|
28 |
Verify that the resulting object correctly implements the IProductSeries |
|
29 |
interface. |
|
30 |
||
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
31 |
>>> verifyObject(IProductSeries, trunk) |
32 |
True |
|
33 |
>>> IProductSeries.providedBy(trunk) |
|
34 |
True |
|
2840.1.7
by David Allouche
[merge conflict] rocketfuel |
35 |
|
4268.3.20
by Carlos Perello Marin
All objects that implemente IHasTranslationImports check it now |
36 |
and IHasTranslationImports. |
37 |
||
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
38 |
>>> verifyObject(IHasTranslationImports, trunk) |
39 |
True |
|
40 |
>>> IHasTranslationImports.providedBy(trunk) |
|
41 |
True |
|
4268.3.20
by Carlos Perello Marin
All objects that implemente IHasTranslationImports check it now |
42 |
|
2840.1.7
by David Allouche
[merge conflict] rocketfuel |
43 |
And verify that it looks like the series we think it should be. |
44 |
||
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
45 |
>>> trunk.product == firefox |
46 |
True |
|
8942.3.2
by Curtis Hovey
Revised the grammar and clarity of a pair of tests. |
47 |
>>> print trunk.name |
48 |
trunk |
|
2840.1.7
by David Allouche
[merge conflict] rocketfuel |
49 |
|
50 |
It's also possible to ask a product for all its associated series. |
|
51 |
||
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
52 |
>>> onedotzero = firefox.getSeries('1.0') |
9760.8.1
by Brad Crittenden
Change the non-English 'serieses' to 'series' throughout our codebase. |
53 |
>>> list(firefox.series) == [onedotzero, trunk] |
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
54 |
True |
2840.1.7
by David Allouche
[merge conflict] rocketfuel |
55 |
|
3614.1.68
by Brad Bollenbach
reapply MaloneReleaseManagement |
56 |
A ProductSeries can also be fetched with the IProductSeriesSet utility. |
57 |
||
11692.6.2
by Curtis Hovey
Use deglober to fixing simple glob imports in doctests. |
58 |
>>> from lp.registry.interfaces.productseries import IProductSeriesSet |
3614.1.68
by Brad Bollenbach
reapply MaloneReleaseManagement |
59 |
|
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
60 |
>>> firefox_1_0 = getUtility(IProductSeriesSet).get(2) |
61 |
>>> print firefox_1_0.product.name |
|
62 |
firefox |
|
63 |
>>> print firefox_1_0.name |
|
64 |
1.0 |
|
3614.1.68
by Brad Bollenbach
reapply MaloneReleaseManagement |
65 |
|
8322.10.1
by Curtis Hovey
Allow product drivers to create series. |
66 |
New ProductSeries are created using Product.newSeries(). Only the product |
67 |
owner or driver can call Product.newSeries(). |
|
2840.1.7
by David Allouche
[merge conflict] rocketfuel |
68 |
|
8322.10.1
by Curtis Hovey
Allow product drivers to create series. |
69 |
>>> series_driver = factory.makePerson(name="driver") |
70 |
>>> summary = "Port of Firefox to the Emacs operating system." |
|
71 |
>>> emacs = firefox.newSeries(series_driver , 'emacs', summary) |
|
6935.4.1
by Edwin Grubbs
Mostly working |
72 |
Traceback (most recent call last): |
73 |
... |
|
8322.10.1
by Curtis Hovey
Allow product drivers to create series. |
74 |
Unauthorized: (..., 'newSeries', 'launchpad.Driver') |
75 |
||
76 |
>>> login_person(firefox.owner) |
|
9899.1.1
by Curtis Hovey
Fixed Product.addSeries to support the releasefileglob argument. |
77 |
>>> emacs_series = firefox.newSeries( |
78 |
... firefox.owner , 'emacs', summary, |
|
79 |
... releasefileglob='ftp://gnu.org/emacs*.gz') |
|
80 |
>>> print emacs_series.name |
|
81 |
emacs |
|
82 |
||
83 |
>>> print emacs_series.summary |
|
84 |
Port of Firefox to the Emacs operating system. |
|
85 |
||
86 |
>>> print emacs_series.releasefileglob |
|
87 |
ftp://gnu.org/emacs*.gz |
|
8322.10.1
by Curtis Hovey
Allow product drivers to create series. |
88 |
|
9017.1.10
by Curtis Hovey
Pushed productseries driver rule into the model. |
89 |
When a driver creates a series, he is also the driver of the new series |
90 |
to make him the release manager. |
|
91 |
||
8322.10.1
by Curtis Hovey
Allow product drivers to create series. |
92 |
>>> firefox.driver = series_driver |
93 |
>>> login_person(series_driver) |
|
94 |
>>> emacs2 = firefox.newSeries(series_driver , 'emacs2', summary) |
|
9017.1.10
by Curtis Hovey
Pushed productseries driver rule into the model. |
95 |
>>> print emacs2.driver.name |
96 |
driver |
|
8322.10.1
by Curtis Hovey
Allow product drivers to create series. |
97 |
|
98 |
A newly created series is assumed to be in the development state. |
|
99 |
||
6935.4.1
by Edwin Grubbs
Mostly working |
100 |
>>> login(ANONYMOUS) |
8942.3.2
by Curtis Hovey
Revised the grammar and clarity of a pair of tests. |
101 |
>>> print emacs_series.status.title |
102 |
Active Development |
|
2840.1.7
by David Allouche
[merge conflict] rocketfuel |
103 |
|
104 |
Let's check that the new series is properly associated to its product. |
|
105 |
||
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
106 |
>>> flush_database_updates() |
8942.3.1
by Curtis Hovey
Allow release managers to edit ProductSeries, milestones, and releases. |
107 |
>>> firefox.getSeries('emacs') == emacs_series |
108 |
True |
|
109 |
||
110 |
||
111 |
= Drivers and release managers = |
|
112 |
||
10326.1.1
by Henning Eggers
Mechanically renamed IProject* to IProjectGroup*. |
113 |
A driver for an IProduct or IProjectGroup cannot modify a product series. |
8942.3.1
by Curtis Hovey
Allow release managers to edit ProductSeries, milestones, and releases. |
114 |
|
14600.2.2
by Curtis Hovey
Moved webapp to lp.services. |
115 |
>>> from lp.services.webapp.authorization import check_permission |
8942.3.1
by Curtis Hovey
Allow release managers to edit ProductSeries, milestones, and releases. |
116 |
|
117 |
>>> login_person(series_driver) |
|
118 |
>>> print emacs_series.owner.name |
|
119 |
name12 |
|
120 |
>>> print emacs_series.driver |
|
121 |
None |
|
122 |
>>> check_permission('launchpad.Edit', emacs_series) |
|
123 |
False |
|
124 |
||
125 |
A person appointed to the series driver has the release manager role and can |
|
126 |
edit a product series. |
|
127 |
||
128 |
>>> login_person(firefox.owner) |
|
129 |
>>> emacs_series.driver = series_driver |
|
130 |
>>> login_person(series_driver) |
|
131 |
>>> check_permission('launchpad.Edit', emacs_series) |
|
132 |
True |
|
133 |
||
134 |
>>> login(ANONYMOUS) |
|
2879.1.1
by Diogo Matsubara
Fixes https://launchpad.net/products/launchpad/+bug/1543 Filing duplicate source details raises an integrityerror instead of a nice error |
135 |
|
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
136 |
|
8848.3.3
by Curtis Hovey
Ensure a glob (*) is in the productseries.releassefileglob. |
137 |
== ProductSeries releassefileglob == |
138 |
||
139 |
Each ProductSeries may have a releassefileglob that describes the location |
|
140 |
of where release files are uploaded to. The product release finder process |
|
141 |
uses the releassefileglob to locate and retrieve files. The files are stored |
|
142 |
in the librarian. Each fill is associated with a release. If the series |
|
143 |
does not have a release for version in the file name, the finder will create |
|
144 |
it. The finder will also create the series milestone too if it does not |
|
145 |
exist. The success of product release finder to retrieve files, and create |
|
146 |
milestone and releases, is largely predicated on the quality of the |
|
147 |
releassefileglob. |
|
148 |
||
149 |
The field is constrained by the validate_release_glob() function. It verifies |
|
150 |
that the url uses one of the supported schemes (ftp, http, http). |
|
151 |
||
152 |
>>> from lp.registry.interfaces.productseries import ( |
|
153 |
... validate_release_glob) |
|
154 |
||
155 |
>>> validate_release_glob('ftp://ftp.gnu.org/gnu/emacs/emacs-21.*.gz') |
|
156 |
True |
|
157 |
>>> validate_release_glob('http://ftp.gnu.org/gnu/emacs/emacs-21.*.gz') |
|
158 |
True |
|
159 |
>>> validate_release_glob('https://ftp.gnu.org/gnu/emacs/emacs-21.*.gz') |
|
160 |
True |
|
161 |
||
162 |
Invalid URLs and unsupported schemes raise a LaunchpadValidationError. |
|
163 |
||
164 |
>>> validate_release_glob('ftp.gnu.org/gnu/emacs/emacs-21.*.gz') |
|
165 |
Traceback (most recent call last): |
|
166 |
... |
|
167 |
LaunchpadValidationError: ... |
|
168 |
||
169 |
>>> validate_release_glob('wais://ftp.gnu.org/gnu/emacs/emacs-21.*.gz') |
|
170 |
Traceback (most recent call last): |
|
171 |
... |
|
172 |
LaunchpadValidationError: ... |
|
173 |
||
174 |
The URL must contain a glob (*) or , and may contain more than one. |
|
175 |
||
176 |
>>> validate_release_glob('http://ftp.gnu.org/gnu/emacs/emacs-21.10.1.gz') |
|
177 |
Traceback (most recent call last): |
|
178 |
... |
|
179 |
LaunchpadValidationError: ... |
|
180 |
||
181 |
>>> validate_release_glob('http://ftp.gnu.org/gnu/*/emacs-21.*.gz') |
|
182 |
True |
|
183 |
||
184 |
||
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
185 |
== Specification Listings == |
3348.1.33
by Mark Shuttleworth
Additional tests along with better registry pages. |
186 |
|
187 |
We should be able to get lists of specifications in different states |
|
188 |
related to a productseries. |
|
189 |
||
3614.1.68
by Brad Bollenbach
reapply MaloneReleaseManagement |
190 |
Basically, we can filter by completeness, and by whether or not the spec |
191 |
is informational. |
|
3348.1.33
by Mark Shuttleworth
Additional tests along with better registry pages. |
192 |
|
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
193 |
>>> onezero = firefox.getSeries("1.0") |
11824.1.3
by Tim Penhey
Fix imports for SpecificationFilter. |
194 |
>>> from lp.blueprints.enums import SpecificationFilter |
3348.1.33
by Mark Shuttleworth
Additional tests along with better registry pages. |
195 |
|
3348.1.38
by Mark Shuttleworth
More sophisticated default filtering for specification lists |
196 |
We will create two specs for onezero and use them to demonstrate the |
197 |
filtering. |
|
198 |
||
14606.3.1
by William Grant
Merge canonical.database into lp.services.database. |
199 |
>>> from lp.services.database.constants import UTC_NOW |
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
200 |
>>> carlos = getUtility(IPersonSet).getByName('carlos') |
8971.22.1
by Guilherme Salgado
Remove all 'from lp.registry.model.<module> import *' lines from canonical.launchpad.database.__init__ |
201 |
>>> from lp.blueprints.model.specification import Specification |
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
202 |
>>> a = Specification(name='a', title='A', summary='AA', owner=carlos, |
203 |
... product=firefox, productseries=onezero, |
|
204 |
... specurl='http://wbc.com/two', goal_proposer=carlos, |
|
205 |
... date_goal_proposed=UTC_NOW) |
|
206 |
>>> b = Specification(name='b', title='b', summary='bb', owner=carlos, |
|
207 |
... product=firefox, productseries=onezero, |
|
208 |
... specurl='http://fds.com/adsf', goal_proposer=carlos, |
|
209 |
... date_goal_proposed=UTC_NOW) |
|
3348.1.38
by Mark Shuttleworth
More sophisticated default filtering for specification lists |
210 |
|
3614.1.68
by Brad Bollenbach
reapply MaloneReleaseManagement |
211 |
Now, we will make one of them accepted, the other declined, and both of |
212 |
them informational. |
|
3348.1.38
by Mark Shuttleworth
More sophisticated default filtering for specification lists |
213 |
|
11824.1.2
by Tim Penhey
Fix imports for SpecificationDefinitionStatus. |
214 |
>>> from lp.blueprints.enums import ( |
11716.1.12
by Curtis Hovey
Sorted imports in doctests. |
215 |
... SpecificationDefinitionStatus, |
216 |
... SpecificationImplementationStatus, |
|
217 |
... ) |
|
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
218 |
>>> a.definition_status = b.definition_status = SpecificationDefinitionStatus.APPROVED |
219 |
>>> a.implementation_status = SpecificationImplementationStatus.INFORMATIONAL |
|
220 |
>>> b.implementation_status = SpecificationImplementationStatus.INFORMATIONAL |
|
221 |
>>> a.acceptBy(a.owner) |
|
222 |
>>> shim = a.updateLifecycleStatus(a.owner) |
|
223 |
>>> b.declineBy(b.owner) |
|
224 |
>>> shim = b.updateLifecycleStatus(b.owner) |
|
3348.1.38
by Mark Shuttleworth
More sophisticated default filtering for specification lists |
225 |
|
14606.3.1
by William Grant
Merge canonical.database into lp.services.database. |
226 |
>>> from lp.services.database.sqlbase import flush_database_updates |
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
227 |
>>> flush_database_updates() |
3348.1.38
by Mark Shuttleworth
More sophisticated default filtering for specification lists |
228 |
|
229 |
If we ask for ALL specs we should see them both. |
|
230 |
||
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
231 |
>>> filter = [SpecificationFilter.ALL] |
232 |
>>> for s in onezero.specifications(filter=filter): |
|
233 |
... print s.name |
|
234 |
a |
|
235 |
b |
|
3348.1.38
by Mark Shuttleworth
More sophisticated default filtering for specification lists |
236 |
|
3614.1.68
by Brad Bollenbach
reapply MaloneReleaseManagement |
237 |
With a productseries, we can ask for ACCEPTED, PROPOSED and DECLINED |
238 |
specs: |
|
3348.1.38
by Mark Shuttleworth
More sophisticated default filtering for specification lists |
239 |
|
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
240 |
>>> filter=[SpecificationFilter.ACCEPTED] |
241 |
>>> for spec in onezero.specifications(filter=filter): |
|
242 |
... print spec.name, spec.goalstatus.title |
|
243 |
a Accepted |
|
244 |
||
245 |
>>> filter=[SpecificationFilter.PROPOSED] |
|
246 |
>>> onezero.specifications(filter=filter).count() |
|
247 |
0 |
|
248 |
||
249 |
>>> filter=[SpecificationFilter.DECLINED] |
|
250 |
>>> onezero.specifications(filter=filter).count() |
|
251 |
1 |
|
3614.1.68
by Brad Bollenbach
reapply MaloneReleaseManagement |
252 |
|
253 |
We should see one informational spec if we ask just for that, the |
|
254 |
accepted one. |
|
3348.1.33
by Mark Shuttleworth
Additional tests along with better registry pages. |
255 |
|
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
256 |
>>> filter = [SpecificationFilter.INFORMATIONAL] |
257 |
>>> for s in onezero.specifications(filter=filter): |
|
258 |
... print s.name |
|
259 |
a |
|
3348.1.38
by Mark Shuttleworth
More sophisticated default filtering for specification lists |
260 |
|
261 |
If we specifically ask for declined informational, we will get that: |
|
262 |
||
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
263 |
>>> filter = [ |
264 |
... SpecificationFilter.INFORMATIONAL, SpecificationFilter.DECLINED] |
|
265 |
>>> for s in onezero.specifications(filter=filter): |
|
266 |
... print s.name |
|
267 |
b |
|
3348.1.38
by Mark Shuttleworth
More sophisticated default filtering for specification lists |
268 |
|
269 |
There are is one completed, accepted spec for 1.0: |
|
3348.1.33
by Mark Shuttleworth
Additional tests along with better registry pages. |
270 |
|
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
271 |
>>> filter = [SpecificationFilter.COMPLETE] |
272 |
>>> for spec in onezero.specifications(filter=filter): |
|
273 |
... print spec.name, spec.is_complete, spec.goalstatus.title |
|
274 |
a True Accepted |
|
3348.1.38
by Mark Shuttleworth
More sophisticated default filtering for specification lists |
275 |
|
276 |
There is one completed, declined spec: |
|
277 |
||
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
278 |
>>> filter = [SpecificationFilter.COMPLETE, SpecificationFilter.DECLINED] |
279 |
>>> for spec in onezero.specifications(filter=filter): |
|
280 |
... print spec.name, spec.is_complete, spec.goalstatus.title |
|
281 |
b True Declined |
|
3348.1.38
by Mark Shuttleworth
More sophisticated default filtering for specification lists |
282 |
|
283 |
Now lets make b incomplete, but accepted. |
|
284 |
||
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
285 |
>>> b.implementation_status = SpecificationImplementationStatus.BETA |
286 |
>>> b.definition_status = SpecificationDefinitionStatus.NEW |
|
287 |
>>> shim = b.acceptBy(b.owner) |
|
288 |
>>> shim = b.updateLifecycleStatus(b.owner) |
|
289 |
>>> flush_database_updates() |
|
3348.1.38
by Mark Shuttleworth
More sophisticated default filtering for specification lists |
290 |
|
3614.1.68
by Brad Bollenbach
reapply MaloneReleaseManagement |
291 |
And if we ask just for specs, we get BOTH the incomplete and the |
292 |
complete ones that have been accepted. |
|
3348.1.38
by Mark Shuttleworth
More sophisticated default filtering for specification lists |
293 |
|
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
294 |
>>> for spec in onezero.specifications(): |
295 |
... print spec.name, spec.is_complete, spec.goalstatus.title |
|
296 |
a True Accepted |
|
297 |
b False Accepted |
|
3348.1.33
by Mark Shuttleworth
Additional tests along with better registry pages. |
298 |
|
3691.12.17
by Mark Shuttleworth
Reviewer feedback, and fix assumed globally unique names in name validation. |
299 |
We can search for text in specifications (in this case there are no |
300 |
matches): |
|
301 |
||
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
302 |
>>> print len(list(onezero.specifications(filter=['new']))) |
303 |
0 |
|
304 |
||
305 |
||
306 |
== Lifecycle Management == |
|
3691.73.11
by Mark Shuttleworth
Test fixes |
307 |
|
3691.74.1
by Mark Shuttleworth
Track spec starting times and people. |
308 |
In the example above, we use the acceptBy and updateLifecycleStatus methods on |
3691.73.11
by Mark Shuttleworth
Test fixes |
309 |
a specification. These help us keep the full record of who moved the spec |
310 |
through each relevant stage of its existence. |
|
311 |
||
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
312 |
>>> b.goal_decider is None |
313 |
False |
|
314 |
>>> b.goal_decider.name |
|
315 |
u'carlos' |
|
316 |
>>> b.date_completed is None |
|
317 |
True |
|
3691.73.11
by Mark Shuttleworth
Test fixes |
318 |
|
319 |
There's a method which will tell us if status changes we have just made will |
|
320 |
change the overall state of the spec to "completed". |
|
321 |
||
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
322 |
>>> jdub = getUtility(IPersonSet).getByName('jdub') |
323 |
>>> b.definition_status = SpecificationDefinitionStatus.APPROVED |
|
324 |
>>> b.implementation_status = SpecificationImplementationStatus.INFORMATIONAL |
|
325 |
>>> print b.updateLifecycleStatus(jdub).title |
|
326 |
Complete |
|
327 |
>>> b.completer.name |
|
328 |
u'jdub' |
|
329 |
>>> b.date_completed is None |
|
330 |
False |
|
331 |
||
332 |
||
333 |
== Drivers == |
|
3348.1.33
by Mark Shuttleworth
Additional tests along with better registry pages. |
334 |
|
3614.1.68
by Brad Bollenbach
reapply MaloneReleaseManagement |
335 |
Products, projects and product series have drivers, who are people that |
336 |
have permission to approve bugs and features for specific releases. The |
|
337 |
rules are that: |
|
3348.1.33
by Mark Shuttleworth
Additional tests along with better registry pages. |
338 |
|
10724.1.1
by Henning Eggers
First batch of Project -> ProjectGrpoup renamings. |
339 |
1. a "driver" can be set on either ProjectGroup, Product or ProductSeries |
3614.1.68
by Brad Bollenbach
reapply MaloneReleaseManagement |
340 |
|
341 |
2. drivers are only actually relevant on a ProductSeries, because thats |
|
342 |
the granularity at which we track spec/bug targeting |
|
343 |
||
3348.1.33
by Mark Shuttleworth
Additional tests along with better registry pages. |
344 |
3. the important attribute is ".drivers" on a productseries, it is |
345 |
calculated based on the combination of owners and drivers in the |
|
3614.1.68
by Brad Bollenbach
reapply MaloneReleaseManagement |
346 |
series, product and project. It is a LIST of drivers, which might be |
347 |
empty, or have one, two or three people/teams in it. |
|
348 |
||
349 |
4. the list includes the explicitly set drivers from series, product |
|
350 |
and project |
|
351 |
||
3348.1.33
by Mark Shuttleworth
Additional tests along with better registry pages. |
352 |
5. if there are no explicitly set drivers, then: |
353 |
- if there is a project, then the list is the project.owner |
|
3614.1.68
by Brad Bollenbach
reapply MaloneReleaseManagement |
354 |
- if there is no project, then the list is the product.owner in |
355 |
other words, we use the "highest" owner as the fallback, which is |
|
3348.1.33
by Mark Shuttleworth
Additional tests along with better registry pages. |
356 |
either the product owner or the project owner if there is a project. |
357 |
||
3614.1.68
by Brad Bollenbach
reapply MaloneReleaseManagement |
358 |
We test these rules below. We will create the project, product and |
359 |
series directly so that we don't have to deal with security permissions |
|
360 |
checks when setting and resetting the driver attributes. |
|
3348.1.33
by Mark Shuttleworth
Additional tests along with better registry pages. |
361 |
|
14606.3.1
by William Grant
Merge canonical.database into lp.services.database. |
362 |
>>> from lp.services.database.sqlbase import flush_database_updates |
6786.2.4
by Brad Crittenden
Added registrant to product and project and created ValidPersonVocabulary. |
363 |
>>> login('foo.bar@canonical.com') |
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
364 |
>>> carlos = getUtility(IPersonSet).getByName('carlos') |
9105.3.1
by Brad Crittenden
Changed sample data to remove sabdfl. |
365 |
>>> mark = getUtility(IPersonSet).getByName('mark') |
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
366 |
>>> jblack = getUtility(IPersonSet).getByName('jblack') |
6786.2.4
by Brad Crittenden
Added registrant to product and project and created ValidPersonVocabulary. |
367 |
|
368 |
>>> project = factory.makeProject(name='testproj', |
|
369 |
... displayname='Test Project', |
|
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
370 |
... title='Test Project Title', homepageurl='http://foo.com/url', |
6786.2.4
by Brad Crittenden
Added registrant to product and project and created ValidPersonVocabulary. |
371 |
... summary='summary', description='description', owner=carlos) |
9105.3.1
by Brad Crittenden
Changed sample data to remove sabdfl. |
372 |
>>> product = factory.makeProduct(owner=mark, name='testprod', |
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
373 |
... displayname='Test Product', title='Test product title', |
374 |
... summary='summary', project=project) |
|
6786.2.4
by Brad Crittenden
Added registrant to product and project and created ValidPersonVocabulary. |
375 |
>>> series = factory.makeProductSeries(owner=jblack, name='1.0', product=product, |
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
376 |
... summary='Series summary') |
3348.1.33
by Mark Shuttleworth
Additional tests along with better registry pages. |
377 |
|
6786.2.4
by Brad Crittenden
Added registrant to product and project and created ValidPersonVocabulary. |
378 |
|
3614.1.68
by Brad Bollenbach
reapply MaloneReleaseManagement |
379 |
First, lets see what we get for the series drivers before we have |
6786.2.4
by Brad Crittenden
Added registrant to product and project and created ValidPersonVocabulary. |
380 |
anything actually set. |
3348.1.33
by Mark Shuttleworth
Additional tests along with better registry pages. |
381 |
|
382 |
If there is a project on the product, we would expect the project owner: |
|
383 |
||
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
384 |
>>> print series.product.project.name |
385 |
testproj |
|
386 |
>>> for d in series.drivers: |
|
387 |
... print d.name |
|
388 |
carlos |
|
3348.1.33
by Mark Shuttleworth
Additional tests along with better registry pages. |
389 |
|
390 |
If there is NO project on the product, then we expect the product owner: |
|
391 |
||
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
392 |
>>> product.project = None |
393 |
>>> for d in series.drivers: |
|
394 |
... print d.name |
|
9105.3.1
by Brad Crittenden
Changed sample data to remove sabdfl. |
395 |
mark |
3348.1.33
by Mark Shuttleworth
Additional tests along with better registry pages. |
396 |
|
397 |
Now lets put the project back: |
|
398 |
||
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
399 |
>>> product.project = project.id |
400 |
>>> flush_database_updates() |
|
3348.1.33
by Mark Shuttleworth
Additional tests along with better registry pages. |
401 |
|
10427.23.18
by Henning Eggers
Reviewer comments and suggestions. |
402 |
Edgar and cprov will be the drivers. |
3348.1.33
by Mark Shuttleworth
Additional tests along with better registry pages. |
403 |
|
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
404 |
>>> cprov = getUtility(IPersonSet).getByName('cprov') |
405 |
>>> edgar = getUtility(IPersonSet).getByName('edgar') |
|
10427.23.14
by Henning Eggers
Added unit test for product series and moved some functional test into it. |
406 |
|
407 |
Edgar becomes the driver of the project group and thus also drives the |
|
408 |
series. |
|
409 |
||
410 |
>>> project.driver = edgar |
|
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
411 |
>>> for d in series.drivers: |
412 |
... print d.name |
|
413 |
edgar |
|
414 |
||
10427.23.14
by Henning Eggers
Added unit test for product series and moved some functional test into it. |
415 |
In addition cprov is made driver of the series. Both are drivers now. |
416 |
||
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
417 |
>>> series.driver = cprov |
418 |
>>> for d in series.drivers: |
|
419 |
... print d.name |
|
10427.23.14
by Henning Eggers
Added unit test for product series and moved some functional test into it. |
420 |
cprov |
421 |
edgar |
|
422 |
||
423 |
With just a driver on the series, the owner of the project group is reported |
|
424 |
as driver, too. |
|
425 |
||
426 |
>>> project.driver = None |
|
427 |
>>> for d in series.drivers: |
|
428 |
... print d.name |
|
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
429 |
carlos |
430 |
cprov |
|
3348.1.33
by Mark Shuttleworth
Additional tests along with better registry pages. |
431 |
|
10427.23.18
by Henning Eggers
Reviewer comments and suggestions. |
432 |
Without a project group, the driver role falls back to the product owner. |
3348.1.33
by Mark Shuttleworth
Additional tests along with better registry pages. |
433 |
|
10427.23.14
by Henning Eggers
Added unit test for product series and moved some functional test into it. |
434 |
>>> product.project = None |
6414.2.1
by Guilherme Salgado
Database/Interface code for ProductSeries.status. |
435 |
>>> for d in series.drivers: |
436 |
... print d.name |
|
437 |
cprov |
|
9105.3.1
by Brad Crittenden
Changed sample data to remove sabdfl. |
438 |
mark |