Merge lp:~stevenk/launchpad/destroy-private-projects-feature-flags into lp:launchpad
- destroy-private-projects-feature-flags
- Merge into devel
Proposed by
Steve Kowalik
Status: | Merged |
---|---|
Merged at revision: | 16483 |
Proposed branch: | lp:~stevenk/launchpad/destroy-private-projects-feature-flags |
Merge into: | lp:launchpad |
Diff against target: |
940 lines (+91/-278) 13 files modified
lib/lp/blueprints/browser/specification.py (+11/-35) lib/lp/blueprints/browser/tests/test_specification.py (+0/-49) lib/lp/blueprints/templates/specification-index.pt (+1/-1) lib/lp/registry/browser/pillar.py (+3/-6) lib/lp/registry/browser/product.py (+26/-46) lib/lp/registry/browser/tests/project-add-views.txt (+3/-0) lib/lp/registry/browser/tests/test_pillar_sharing.py (+3/-17) lib/lp/registry/browser/tests/test_product.py (+41/-67) lib/lp/registry/browser/tests/test_projectgroup.py (+1/-8) lib/lp/registry/browser/tests/test_sourcepackage_views.py (+1/-4) lib/lp/registry/model/product.py (+0/-3) lib/lp/registry/tests/test_product.py (+0/-23) lib/lp/services/features/flags.py (+1/-19) |
To merge this branch: | bzr merge lp:~stevenk/launchpad/destroy-private-projects-feature-flags |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
William Grant | code | Approve | |
Review via email: mp+147022@code.launchpad.net |
Commit message
Description of the change
Destroy the three private project feature flags.
To post a comment you must log in.
Revision history for this message
William Grant (wgrant) : | # |
review:
Approve
(code)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'lib/lp/blueprints/browser/specification.py' |
2 | --- lib/lp/blueprints/browser/specification.py 2013-01-30 05:31:20 +0000 |
3 | +++ lib/lp/blueprints/browser/specification.py 2013-02-07 06:17:24 +0000 |
4 | @@ -125,7 +125,6 @@ |
5 | from lp.registry.interfaces.product import IProduct |
6 | from lp.registry.interfaces.productseries import IProductSeries |
7 | from lp.services.config import config |
8 | -from lp.services.features import getFeatureFlag |
9 | from lp.services.fields import WorkItemsText |
10 | from lp.services.propertycache import cachedproperty |
11 | from lp.services.webapp import ( |
12 | @@ -144,21 +143,12 @@ |
13 | ) |
14 | |
15 | |
16 | -INFORMATION_TYPE_FLAG = 'blueprints.information_type.enabled' |
17 | - |
18 | - |
19 | class INewSpecification(Interface): |
20 | """A schema for a new specification.""" |
21 | |
22 | use_template(ISpecification, include=[ |
23 | - 'name', |
24 | - 'title', |
25 | - 'specurl', |
26 | - 'summary', |
27 | - 'assignee', |
28 | - 'drafter', |
29 | - 'approver', |
30 | - ]) |
31 | + 'name', 'title', 'specurl', 'summary', 'assignee', 'drafter', |
32 | + 'approver']) |
33 | |
34 | definition_status = Choice( |
35 | title=_('Definition Status'), |
36 | @@ -225,8 +215,6 @@ |
37 | Does nothing if the user cannot select different information types or |
38 | the feature flag is not enabled. |
39 | """ |
40 | - if not getFeatureFlag(INFORMATION_TYPE_FLAG): |
41 | - return fields |
42 | if len(self.info_types) < 2: |
43 | return fields |
44 | info_type_field = copy_field(ISpecification['information_type'], |
45 | @@ -318,10 +306,6 @@ |
46 | def validate(self, data): |
47 | """See `LaunchpadFormView`.`""" |
48 | super(NewSpecificationView, self).validate(data) |
49 | - self.validate_information_type(data) |
50 | - |
51 | - def validate_information_type(self, data): |
52 | - """Validate the information type is allowed for this context.""" |
53 | information_type = data.get('information_type', None) |
54 | if information_type is None: |
55 | # We rely on the model to set the correct default value. |
56 | @@ -519,14 +503,11 @@ |
57 | class SpecificationContextMenu(ContextMenu, SpecificationEditLinksMixin): |
58 | |
59 | usedfor = ISpecification |
60 | - links = ['edit', 'people', 'status', 'priority', |
61 | - 'whiteboard', 'proposegoal', 'workitems', |
62 | - 'milestone', 'subscription', |
63 | - 'addsubscriber', |
64 | - 'linkbug', 'unlinkbug', 'linkbranch', |
65 | - 'adddependency', 'removedependency', |
66 | - 'dependencytree', 'linksprint', 'supersede', |
67 | - 'retarget', 'information_type'] |
68 | + links = ['edit', 'people', 'status', 'priority', 'whiteboard', |
69 | + 'proposegoal', 'workitems', 'milestone', 'subscription', |
70 | + 'addsubscriber', 'linkbug', 'unlinkbug', 'linkbranch', |
71 | + 'adddependency', 'removedependency', 'dependencytree', |
72 | + 'linksprint', 'supersede', 'retarget', 'information_type'] |
73 | |
74 | @enabled_with_permission('launchpad.Edit') |
75 | def milestone(self): |
76 | @@ -1537,16 +1518,13 @@ |
77 | |
78 | @action(_('Continue'), name='continue') |
79 | def continue_action(self, action, data): |
80 | - self.context.linkBranch(branch=data['branch'], |
81 | - registrant=self.user) |
82 | + self.context.linkBranch(branch=data['branch'], registrant=self.user) |
83 | |
84 | @property |
85 | def next_url(self): |
86 | return canonical_url(self.context) |
87 | |
88 | - @property |
89 | - def cancel_url(self): |
90 | - return canonical_url(self.context) |
91 | + cancel_url = next_url |
92 | |
93 | |
94 | class SpecificationSetView(AppFrontPageSearchView, HasSpecificationsView): |
95 | @@ -1600,8 +1578,7 @@ |
96 | if starter is None: |
97 | return '' |
98 | date_formatter = DateTimeFormatterAPI(context.date_started) |
99 | - return "%s %s" % ( |
100 | - format_link(starter), date_formatter.displaydate()) |
101 | + return "%s %s" % (format_link(starter), date_formatter.displaydate()) |
102 | return render |
103 | |
104 | |
105 | @@ -1615,6 +1592,5 @@ |
106 | if completer is None: |
107 | return '' |
108 | date_formatter = DateTimeFormatterAPI(context.date_completed) |
109 | - return "%s %s" % ( |
110 | - format_link(completer), date_formatter.displaydate()) |
111 | + return "%s %s" % (format_link(completer), date_formatter.displaydate()) |
112 | return render |
113 | |
114 | === modified file 'lib/lp/blueprints/browser/tests/test_specification.py' |
115 | --- lib/lp/blueprints/browser/tests/test_specification.py 2013-01-31 05:34:42 +0000 |
116 | +++ lib/lp/blueprints/browser/tests/test_specification.py 2013-02-07 06:17:24 +0000 |
117 | @@ -27,7 +27,6 @@ |
118 | from lp.app.enums import InformationType |
119 | from lp.app.interfaces.services import IService |
120 | from lp.blueprints.browser import specification |
121 | -from lp.blueprints.browser.specification import INFORMATION_TYPE_FLAG |
122 | from lp.blueprints.enums import SpecificationImplementationStatus |
123 | from lp.blueprints.interfaces.specification import ( |
124 | ISpecification, |
125 | @@ -36,7 +35,6 @@ |
126 | from lp.registry.enums import SpecificationSharingPolicy |
127 | from lp.registry.interfaces.person import PersonVisibility |
128 | from lp.registry.interfaces.product import IProductSeries |
129 | -from lp.services.features.testing import FeatureFixture |
130 | from lp.services.webapp.escaping import html_escape |
131 | from lp.services.webapp.interaction import ANONYMOUS |
132 | from lp.services.webapp.interfaces import BrowserNotificationLevel |
133 | @@ -219,12 +217,6 @@ |
134 | self.assertIn(spec_name, view.contents) |
135 | |
136 | |
137 | -def set_blueprint_information_type(test_case, enabled): |
138 | - value = 'true' if enabled else '' |
139 | - fixture = FeatureFixture({INFORMATION_TYPE_FLAG: value}) |
140 | - test_case.useFixture(fixture) |
141 | - |
142 | - |
143 | class TestSpecificationSet(BrowserTestCase): |
144 | |
145 | layer = DatabaseFunctionalLayer |
146 | @@ -268,10 +260,6 @@ |
147 | portlet_tag = soupmatchers.Tag( |
148 | 'info-type-portlet', True, attrs=dict(id='information-type-summary')) |
149 | |
150 | - def setUp(self): |
151 | - super(TestSpecificationInformationType, self).setUp() |
152 | - set_blueprint_information_type(self, True) |
153 | - |
154 | def assertBrowserMatches(self, matcher): |
155 | browser = self.getViewBrowser(self.factory.makeSpecification()) |
156 | self.assertThat(browser.contents, matcher) |
157 | @@ -279,11 +267,6 @@ |
158 | def test_has_privacy_portlet(self): |
159 | self.assertBrowserMatches(soupmatchers.HTMLContains(self.portlet_tag)) |
160 | |
161 | - def test_privacy_portlet_requires_flag(self): |
162 | - set_blueprint_information_type(self, False) |
163 | - self.assertBrowserMatches( |
164 | - Not(soupmatchers.HTMLContains(self.portlet_tag))) |
165 | - |
166 | def test_has_privacy_banner(self): |
167 | owner = self.factory.makePerson() |
168 | policy = SpecificationSharingPolicy.PUBLIC_OR_PROPRIETARY |
169 | @@ -433,7 +416,6 @@ |
170 | |
171 | def test_allowed_info_type_validated(self): |
172 | """information_type must be validated against context""" |
173 | - set_blueprint_information_type(self, True) |
174 | context = getUtility(ISpecificationSet) |
175 | product = self.factory.makeProduct() |
176 | form = self._create_form_data(product.name) |
177 | @@ -454,7 +436,6 @@ |
178 | |
179 | def test_allowed_info_type_validated(self): |
180 | """information_type must be validated against context""" |
181 | - set_blueprint_information_type(self, True) |
182 | sprint = self.factory.makeSprint() |
183 | product = self.factory.makeProduct(owner=sprint.owner) |
184 | form = self._create_form_data(product.name) |
185 | @@ -474,7 +455,6 @@ |
186 | |
187 | def test_allowed_info_type_validated(self): |
188 | """information_type must be validated against context""" |
189 | - set_blueprint_information_type(self, True) |
190 | project = self.factory.makeProject() |
191 | product = self.factory.makeProduct(project=project) |
192 | form = self._create_form_data(product.name) |
193 | @@ -522,7 +502,6 @@ |
194 | |
195 | def setUp(self): |
196 | super(TestNewSpecificationInformationType, self).setUp() |
197 | - set_blueprint_information_type(self, True) |
198 | it_field = soupmatchers.Tag( |
199 | 'it-field', True, attrs=dict(name='field.information_type')) |
200 | self.match_it = soupmatchers.HTMLContains(it_field) |
201 | @@ -532,25 +511,12 @@ |
202 | browser = self.getUserBrowser(NEW_SPEC_FROM_ROOT_URL) |
203 | self.assertThat(browser.contents, self.match_it) |
204 | |
205 | - def test_from_root_no_flag(self): |
206 | - """Information_type is excluded with no flag.""" |
207 | - set_blueprint_information_type(self, False) |
208 | - browser = self.getUserBrowser(NEW_SPEC_FROM_ROOT_URL) |
209 | - self.assertThat(browser.contents, Not(self.match_it)) |
210 | - |
211 | def test_from_sprint(self): |
212 | """Information_type is included creating from a sprint.""" |
213 | sprint = self.factory.makeSprint() |
214 | browser = self.getViewBrowser(sprint, view_name='+addspec') |
215 | self.assertThat(browser.contents, self.match_it) |
216 | |
217 | - def test_from_sprint_no_flag(self): |
218 | - """Information_type is excluded with no flag.""" |
219 | - set_blueprint_information_type(self, False) |
220 | - sprint = self.factory.makeSprint() |
221 | - browser = self.getViewBrowser(sprint, view_name='+addspec') |
222 | - self.assertThat(browser.contents, Not(self.match_it)) |
223 | - |
224 | def submitSpec(self, browser): |
225 | """Submit a Specification via a browser.""" |
226 | name = self.factory.getUniqueString() |
227 | @@ -592,13 +558,6 @@ |
228 | SpecificationSharingPolicy.EMBARGOED_OR_PROPRIETARY) |
229 | self.assertEqual(InformationType.EMBARGOED, spec.information_type) |
230 | |
231 | - def test_from_product_no_flag(self): |
232 | - """information_type is excluded with no flag.""" |
233 | - set_blueprint_information_type(self, False) |
234 | - product = self.factory.makeProduct() |
235 | - browser = self.getViewBrowser(product, view_name='+addspec') |
236 | - self.assertThat(browser.contents, Not(self.match_it)) |
237 | - |
238 | def test_from_productseries(self): |
239 | """Information_type is included creating from productseries.""" |
240 | policy = SpecificationSharingPolicy.PUBLIC_OR_PROPRIETARY |
241 | @@ -608,13 +567,6 @@ |
242 | browser = self.getViewBrowser(series, view_name='+addspec') |
243 | self.assertThat(browser.contents, self.match_it) |
244 | |
245 | - def test_from_productseries_no_flag(self): |
246 | - """information_type is excluded with no flag.""" |
247 | - set_blueprint_information_type(self, False) |
248 | - series = self.factory.makeProductSeries() |
249 | - browser = self.getViewBrowser(series, view_name='+addspec') |
250 | - self.assertThat(browser.contents, Not(self.match_it)) |
251 | - |
252 | def test_from_distribution(self): |
253 | """information_type is excluded creating from distro.""" |
254 | distro = self.factory.makeDistribution() |
255 | @@ -633,7 +585,6 @@ |
256 | layer = DatabaseFunctionalLayer |
257 | |
258 | def _setUp(self): |
259 | - set_blueprint_information_type(self, True) |
260 | it_field = soupmatchers.Tag( |
261 | 'it-field', True, attrs=dict(name='field.information_type')) |
262 | self.match_it = soupmatchers.HTMLContains(it_field) |
263 | |
264 | === modified file 'lib/lp/blueprints/templates/specification-index.pt' |
265 | --- lib/lp/blueprints/templates/specification-index.pt 2012-10-15 16:01:38 +0000 |
266 | +++ lib/lp/blueprints/templates/specification-index.pt 2013-02-07 06:17:24 +0000 |
267 | @@ -386,7 +386,7 @@ |
268 | |
269 | <tal:side metal:fill-slot="side"> |
270 | <tal:menu replace="structure context/@@+global-actions" /> |
271 | - <tal:privacy replace="structure context/@@+portlet-privacy" condition="features/blueprints.information_type.enabled" /> |
272 | + <tal:privacy replace="structure context/@@+portlet-privacy" /> |
273 | <div tal:replace="structure context/@@+portlet-subscribers" /> |
274 | </tal:side> |
275 | </body> |
276 | |
277 | === modified file 'lib/lp/registry/browser/pillar.py' |
278 | --- lib/lp/registry/browser/pillar.py 2012-12-18 16:41:18 +0000 |
279 | +++ lib/lp/registry/browser/pillar.py 2013-02-07 06:17:24 +0000 |
280 | @@ -1,4 +1,4 @@ |
281 | -# Copyright 2009-2012 Canonical Ltd. This software is licensed under the |
282 | +# Copyright 2009-2013 Canonical Ltd. This software is licensed under the |
283 | # GNU Affero General Public License version 3 (see the file LICENSE). |
284 | |
285 | """Common views for objects that implement `IPillar`.""" |
286 | @@ -56,7 +56,6 @@ |
287 | from lp.registry.interfaces.projectgroup import IProjectGroup |
288 | from lp.registry.model.pillar import PillarPerson |
289 | from lp.services.config import config |
290 | -from lp.services.features import getFeatureFlag |
291 | from lp.services.propertycache import cachedproperty |
292 | from lp.services.webapp.authorization import check_permission |
293 | from lp.services.webapp.batching import ( |
294 | @@ -294,10 +293,8 @@ |
295 | |
296 | @property |
297 | def specification_sharing_policies(self): |
298 | - if getFeatureFlag('blueprints.information_type.enabled'): |
299 | - return self._getSharingService().getSpecificationSharingPolicies( |
300 | - self.context) |
301 | - return None |
302 | + return self._getSharingService().getSpecificationSharingPolicies( |
303 | + self.context) |
304 | |
305 | @property |
306 | def sharing_permissions(self): |
307 | |
308 | === modified file 'lib/lp/registry/browser/product.py' |
309 | --- lib/lp/registry/browser/product.py 2012-11-28 21:26:06 +0000 |
310 | +++ lib/lp/registry/browser/product.py 2013-02-07 06:17:24 +0000 |
311 | @@ -1,4 +1,4 @@ |
312 | -# Copyright 2009-2012 Canonical Ltd. This software is licensed under the |
313 | +# Copyright 2009-2013 Canonical Ltd. This software is licensed under the |
314 | # GNU Affero General Public License version 3 (see the file LICENSE). |
315 | |
316 | """Browser views for products.""" |
317 | @@ -174,7 +174,6 @@ |
318 | from lp.registry.interfaces.sourcepackagename import ISourcePackageNameSet |
319 | from lp.services.config import config |
320 | from lp.services.database.decoratedresultset import DecoratedResultSet |
321 | -from lp.services.features import getFeatureFlag |
322 | from lp.services.feeds.browser import FeedsMixin |
323 | from lp.services.fields import ( |
324 | PillarAliases, |
325 | @@ -209,7 +208,6 @@ |
326 | |
327 | OR = ' OR ' |
328 | SPACE = ' ' |
329 | -PRIVATE_PROJECTS_FLAG = 'disclosure.private_projects.enabled' |
330 | |
331 | |
332 | class ProductNavigation( |
333 | @@ -1397,8 +1395,7 @@ |
334 | custom_widget('licenses', LicenseWidget) |
335 | custom_widget('license_info', GhostWidget) |
336 | custom_widget( |
337 | - 'information_type', |
338 | - LaunchpadRadioWidgetWithDescription, |
339 | + 'information_type', LaunchpadRadioWidgetWithDescription, |
340 | vocabulary=InformationTypeVocabulary( |
341 | types=PUBLIC_PROPRIETARY_INFORMATION_TYPES)) |
342 | |
343 | @@ -1424,19 +1421,10 @@ |
344 | # the form is rendered during LaunchpadFormView's initialize() |
345 | # when an action is invoked. |
346 | cache = IJSONRequestCache(self.request) |
347 | - json_dump_information_types(cache, |
348 | - PUBLIC_PROPRIETARY_INFORMATION_TYPES) |
349 | + json_dump_information_types( |
350 | + cache, PUBLIC_PROPRIETARY_INFORMATION_TYPES) |
351 | super(ProductEditView, self).initialize() |
352 | |
353 | - def setUpFields(self): |
354 | - """See `LaunchpadFormView`.""" |
355 | - super(ProductEditView, self).setUpFields() |
356 | - |
357 | - private_projects_flag = 'disclosure.private_projects.enabled' |
358 | - private_projects = bool(getFeatureFlag(private_projects_flag)) |
359 | - if not private_projects: |
360 | - self.form_fields = self.form_fields.omit('information_type') |
361 | - |
362 | def validate(self, data): |
363 | """Validate 'licenses' and 'license_info'. |
364 | |
365 | @@ -1447,10 +1435,11 @@ |
366 | or "Other/Open Source" is checked. |
367 | """ |
368 | super(ProductEditView, self).validate(data) |
369 | - info_type = data.get('information_type') |
370 | - if info_type is not None: |
371 | - errors = [str(e) for e in |
372 | - self.context.checkInformationType(info_type)] |
373 | + information_type = data.get('information_type') |
374 | + if information_type: |
375 | + errors = [ |
376 | + str(e) for e in self.context.checkInformationType( |
377 | + information_type)] |
378 | if len(errors) > 0: |
379 | self.setFieldError('information_type', ' '.join(errors)) |
380 | |
381 | @@ -1881,9 +1870,7 @@ |
382 | def setUpFields(self): |
383 | """See `LaunchpadFormView`.""" |
384 | super(ProjectAddStepOne, self).setUpFields() |
385 | - self.form_fields = ( |
386 | - self.form_fields + |
387 | - create_source_package_fields()) |
388 | + self.form_fields = (self.form_fields + create_source_package_fields()) |
389 | |
390 | def setUpWidgets(self): |
391 | """See `LaunchpadFormView`.""" |
392 | @@ -1925,8 +1912,7 @@ |
393 | |
394 | _field_names = ['displayname', 'name', 'title', 'summary', 'description', |
395 | 'homepageurl', 'information_type', 'licenses', |
396 | - 'license_info', 'driver', 'bug_supervisor', 'owner', |
397 | - ] |
398 | + 'license_info', 'driver', 'bug_supervisor', 'owner'] |
399 | schema = IProduct |
400 | step_name = 'projectaddstep2' |
401 | template = ViewPageTemplateFile('../templates/product-new.pt') |
402 | @@ -1962,8 +1948,8 @@ |
403 | # the form is rendered during LaunchpadFormView's initialize() |
404 | # when an action is invoked. |
405 | cache = IJSONRequestCache(self.request) |
406 | - json_dump_information_types(cache, |
407 | - PUBLIC_PROPRIETARY_INFORMATION_TYPES) |
408 | + json_dump_information_types( |
409 | + cache, PUBLIC_PROPRIETARY_INFORMATION_TYPES) |
410 | super(ProjectAddStepTwo, self).initialize() |
411 | |
412 | @property |
413 | @@ -1972,8 +1958,7 @@ |
414 | return u'Complete Registration' |
415 | else: |
416 | return u'Complete registration and link to %s package' % ( |
417 | - self.source_package_name.name, |
418 | - ) |
419 | + self.source_package_name.name) |
420 | |
421 | @property |
422 | def _return_url(self): |
423 | @@ -2003,8 +1988,7 @@ |
424 | |
425 | @property |
426 | def enable_information_type(self): |
427 | - private_projects = bool(getFeatureFlag(PRIVATE_PROJECTS_FLAG)) |
428 | - return private_projects and not self.source_package_name |
429 | + return not self.source_package_name |
430 | |
431 | def setUpFields(self): |
432 | """See `LaunchpadFormView`.""" |
433 | @@ -2013,14 +1997,13 @@ |
434 | hidden_fields = self.form_fields.select(*hidden_names) |
435 | |
436 | if not self.enable_information_type: |
437 | - hidden_names.extend([ |
438 | - 'information_type', 'bug_supervisor', 'driver']) |
439 | + hidden_names.extend( |
440 | + ['information_type', 'bug_supervisor', 'driver']) |
441 | |
442 | visible_fields = self.form_fields.omit(*hidden_names) |
443 | - self.form_fields = (visible_fields + |
444 | - self._createDisclaimMaintainerField() + |
445 | - create_source_package_fields() + |
446 | - hidden_fields) |
447 | + self.form_fields = ( |
448 | + visible_fields + self._createDisclaimMaintainerField() + |
449 | + create_source_package_fields() + hidden_fields) |
450 | |
451 | def _createDisclaimMaintainerField(self): |
452 | """Return a Bool field for disclaiming maintainer. |
453 | @@ -2048,8 +2031,8 @@ |
454 | self.widgets['name'].read_only = True |
455 | # The "hint" is really more of an explanation at this point, but the |
456 | # phrasing is different. |
457 | - self.widgets['name'].hint = ('When published, ' |
458 | - "this will be the project's URL.") |
459 | + self.widgets['name'].hint = ( |
460 | + "When published, this will be the project's URL.") |
461 | self.widgets['displayname'].visible = False |
462 | self.widgets['source_package_name'].visible = False |
463 | self.widgets['distroseries'].visible = False |
464 | @@ -2100,14 +2083,13 @@ |
465 | """ |
466 | # XXX BarryWarsaw 16-Apr-2009 do we need batching and should we return |
467 | # more than 7 hits? |
468 | - pillar_set = getUtility(IPillarNameSet) |
469 | - return pillar_set.search(self._search_string, 7) |
470 | + return getUtility(IPillarNameSet).search(self._search_string, 7) |
471 | |
472 | @cachedproperty |
473 | def search_results_count(self): |
474 | """Return the count of matching `IPillar`s.""" |
475 | - pillar_set = getUtility(IPillarNameSet) |
476 | - return pillar_set.count_search_matches(self._search_string) |
477 | + return getUtility(IPillarNameSet).count_search_matches( |
478 | + self._search_string) |
479 | |
480 | # StepView requires that its validate() method not be overridden, so make |
481 | # sure this calls the right method. validateStep() will call the licence |
482 | @@ -2130,8 +2112,7 @@ |
483 | for required_field in ('bug_supervisor', 'driver'): |
484 | if data.get(required_field) is None: |
485 | self.setFieldError( |
486 | - required_field, |
487 | - 'Select a user or team.') |
488 | + required_field, 'Select a user or team.') |
489 | |
490 | @property |
491 | def label(self): |
492 | @@ -2194,7 +2175,6 @@ |
493 | """The controlling view for product/+new.""" |
494 | |
495 | page_title = ProjectAddStepOne.page_title |
496 | - related_features = (PRIVATE_PROJECTS_FLAG,) |
497 | total_steps = 2 |
498 | |
499 | @property |
500 | |
501 | === modified file 'lib/lp/registry/browser/tests/project-add-views.txt' |
502 | --- lib/lp/registry/browser/tests/project-add-views.txt 2012-07-30 20:02:26 +0000 |
503 | +++ lib/lp/registry/browser/tests/project-add-views.txt 2013-02-07 06:17:24 +0000 |
504 | @@ -130,6 +130,7 @@ |
505 | ... print error |
506 | You must select at least one licence. If you select Other/Proprietary |
507 | or Other/OpenSource you must include a description of the licence. |
508 | + ... |
509 | |
510 | When an open source licence is selected, the project is created. |
511 | |
512 | @@ -144,6 +145,8 @@ |
513 | ... 'field.licenses': ['PYTHON'], |
514 | ... 'field.license_info': '', |
515 | ... 'field.owner': registrant.name, |
516 | + ... 'field.driver': registrant.name, |
517 | + ... 'field.bug_supervisor': registrant.name, |
518 | ... 'field.__visited_steps__': '%s|%s' % ( |
519 | ... ProjectAddStepOne.step_name, ProjectAddStepTwo.step_name), |
520 | ... 'field.actions.continue': 'Continue', |
521 | |
522 | === modified file 'lib/lp/registry/browser/tests/test_pillar_sharing.py' |
523 | --- lib/lp/registry/browser/tests/test_pillar_sharing.py 2012-12-20 14:53:10 +0000 |
524 | +++ lib/lp/registry/browser/tests/test_pillar_sharing.py 2013-02-07 06:17:24 +0000 |
525 | @@ -1,4 +1,4 @@ |
526 | -# Copyright 2012 Canonical Ltd. This software is licensed under the |
527 | +# Copyright 2012-2013 Canonical Ltd. This software is licensed under the |
528 | # GNU Affero General Public License version 3 (see the file LICENSE). |
529 | |
530 | """Test views that manage sharing.""" |
531 | @@ -29,7 +29,6 @@ |
532 | from lp.registry.model.pillar import PillarPerson |
533 | from lp.services.config import config |
534 | from lp.services.database.lpstorm import IStore |
535 | -from lp.services.features.testing import FeatureFixture |
536 | from lp.services.webapp.interfaces import StormRangeFactoryError |
537 | from lp.services.webapp.publisher import canonical_url |
538 | from lp.testing import ( |
539 | @@ -270,9 +269,8 @@ |
540 | self.assertIsNotNone(cache.objects.get('branch_sharing_policies')) |
541 | self.assertIsNotNone(cache.objects.get('bug_sharing_policies')) |
542 | self.assertIsNotNone(cache.objects.get('sharing_permissions')) |
543 | - # Ensure we don't set specification_sharing_policies without the |
544 | - # feature flag enabled. |
545 | - self.assertIsNone(cache.objects.get('specification_sharing_policies')) |
546 | + self.assertIsNotNone( |
547 | + cache.objects.get('specification_sharing_policies')) |
548 | batch_size = config.launchpad.default_batch_size |
549 | apgfs = getUtility(IAccessPolicyGrantFlatSource) |
550 | grantees = apgfs.findGranteePermissionsByPolicy( |
551 | @@ -282,18 +280,6 @@ |
552 | self.assertContentEqual( |
553 | grantee_data, cache.objects.get('grantee_data')) |
554 | |
555 | - def test_view_date_model_adds_specification(self): |
556 | - # This test can move up to the above test when not feature flagged, |
557 | - # but for now, ensure specification_sharing_policies is added to |
558 | - # the cache if the flag is set. |
559 | - feature_flag = { |
560 | - 'blueprints.information_type.enabled': 'on'} |
561 | - with FeatureFixture(feature_flag): |
562 | - view = create_initialized_view(self.pillar, name='+sharing') |
563 | - cache = IJSONRequestCache(view.request) |
564 | - self.assertIsNotNone( |
565 | - cache.objects.get('specification_sharing_policies')) |
566 | - |
567 | def test_view_batch_data(self): |
568 | # Test the expected batching data is in the json request cache. |
569 | view = create_initialized_view(self.pillar, name='+sharing') |
570 | |
571 | === modified file 'lib/lp/registry/browser/tests/test_product.py' |
572 | --- lib/lp/registry/browser/tests/test_product.py 2012-11-26 21:01:54 +0000 |
573 | +++ lib/lp/registry/browser/tests/test_product.py 2013-02-07 06:17:24 +0000 |
574 | @@ -1,4 +1,4 @@ |
575 | -# Copyright 2010-2012 Canonical Ltd. This software is licensed under the |
576 | +# Copyright 2010-2013 Canonical Ltd. This software is licensed under the |
577 | # GNU Affero General Public License version 3 (see the file LICENSE). |
578 | |
579 | """Tests for product views.""" |
580 | @@ -28,7 +28,6 @@ |
581 | ServiceUsage, |
582 | ) |
583 | from lp.registry.browser.product import ( |
584 | - PRIVATE_PROJECTS_FLAG, |
585 | ProjectAddStepOne, |
586 | ProjectAddStepTwo, |
587 | ) |
588 | @@ -43,7 +42,6 @@ |
589 | from lp.registry.model.product import Product |
590 | from lp.services.config import config |
591 | from lp.services.database.lpstorm import IStore |
592 | -from lp.services.features.testing import FeatureFixture |
593 | from lp.services.webapp.publisher import canonical_url |
594 | from lp.testing import ( |
595 | BrowserTestCase, |
596 | @@ -151,7 +149,7 @@ |
597 | form['field.licenses'] = License.OTHER_PROPRIETARY.title |
598 | form['field.license_info'] = 'Commercial Subscription' |
599 | else: |
600 | - form['field.information_type'] = 0 |
601 | + form['field.information_type'] = 'PUBLIC' |
602 | form['field.owner'] = '' |
603 | form['field.licenses'] = ['MIT'] |
604 | form['field.license_info'] = '' |
605 | @@ -178,7 +176,6 @@ |
606 | self.assertContentEqual( |
607 | team_membership_policy_data, |
608 | cache.objects['team_membership_policy_data']) |
609 | - self.assertIn(PRIVATE_PROJECTS_FLAG, cache.objects['related_features']) |
610 | |
611 | def test_staging_message_is_not_demo(self): |
612 | view = create_initialized_view(self.product_set, '+new') |
613 | @@ -214,7 +211,8 @@ |
614 | view.view.field_names) |
615 | self.assertEqual( |
616 | ['displayname', 'name', 'title', 'summary', 'description', |
617 | - 'homepageurl', 'licenses', 'owner', 'disclaim_maintainer', |
618 | + 'homepageurl', 'information_type', 'licenses', 'driver', |
619 | + 'bug_supervisor', 'owner', 'disclaim_maintainer', |
620 | 'source_package_name', 'distroseries', '__visited_steps__', |
621 | 'license_info'], |
622 | [f.__name__ for f in view.view.form_fields]) |
623 | @@ -266,36 +264,25 @@ |
624 | form = make_product_form(action=2) |
625 | form['field.owner'] = '' |
626 | form['field.disclaim_maintainer'] = 'on' |
627 | + form['field.information_type'] = 'PUBLIC' |
628 | view = create_initialized_view(self.product_set, '+new', form=form) |
629 | self.assertEqual(0, len(view.view.errors)) |
630 | product = self.product_set.getByName('fnord') |
631 | self.assertEqual('registry', product.owner.name) |
632 | |
633 | - def test_information_type_saved_new_product_default(self): |
634 | - # information_type should be PUBLIC by default for new projects. |
635 | - # if the private projects feature flag is not enabled. |
636 | - registrant = self.factory.makePerson() |
637 | - login_person(registrant) |
638 | - form = make_product_form(registrant, action=2, proprietary=True) |
639 | - view = create_initialized_view(self.product_set, '+new', form=form) |
640 | - self.assertEqual(0, len(view.view.errors)) |
641 | - product = self.product_set.getByName('fnord') |
642 | - self.assertEqual(InformationType.PUBLIC, product.information_type) |
643 | - |
644 | def test_information_type_saved_new_product_updated(self): |
645 | # information_type will be updated if passed in via form data, |
646 | # if the private projects feature flag is enabled. |
647 | - with FeatureFixture({u'disclosure.private_projects.enabled': u'on'}): |
648 | - registrant = self.factory.makePerson() |
649 | - login_person(registrant) |
650 | - form = make_product_form(registrant, action=2, proprietary=True) |
651 | - form['field.maintainer'] = registrant.name |
652 | - view = create_initialized_view( |
653 | - self.product_set, '+new', form=form) |
654 | - self.assertEqual(0, len(view.view.errors)) |
655 | - product = self.product_set.getByName('fnord') |
656 | - self.assertEqual( |
657 | - InformationType.PROPRIETARY, product.information_type) |
658 | + registrant = self.factory.makePerson() |
659 | + login_person(registrant) |
660 | + form = make_product_form(registrant, action=2, proprietary=True) |
661 | + form['field.maintainer'] = registrant.name |
662 | + view = create_initialized_view( |
663 | + self.product_set, '+new', form=form) |
664 | + self.assertEqual(0, len(view.view.errors)) |
665 | + product = self.product_set.getByName('fnord') |
666 | + self.assertEqual( |
667 | + InformationType.PROPRIETARY, product.information_type) |
668 | |
669 | |
670 | class TestProductView(BrowserTestCase): |
671 | @@ -488,37 +475,30 @@ |
672 | def test_limited_information_types_allowed(self): |
673 | """Products can only be PUBLIC_PROPRIETARY_INFORMATION_TYPES""" |
674 | product = self.factory.makeProduct() |
675 | - with FeatureFixture({u'disclosure.private_projects.enabled': u'on'}): |
676 | - login_person(product.owner) |
677 | - view = create_initialized_view( |
678 | - product, |
679 | - '+edit', |
680 | - principal=product.owner) |
681 | - vocabulary = view.widgets['information_type'].vocabulary |
682 | - info_types = [t.name for t in vocabulary] |
683 | - expected = ['PUBLIC', 'PROPRIETARY', 'EMBARGOED'] |
684 | - self.assertEqual(expected, info_types) |
685 | + login_person(product.owner) |
686 | + view = create_initialized_view( |
687 | + product, '+edit', principal=product.owner) |
688 | + vocabulary = view.widgets['information_type'].vocabulary |
689 | + info_types = [t.name for t in vocabulary] |
690 | + expected = ['PUBLIC', 'PROPRIETARY', 'EMBARGOED'] |
691 | + self.assertEqual(expected, info_types) |
692 | |
693 | def test_change_information_type_proprietary(self): |
694 | product = self.factory.makeProduct(name='fnord') |
695 | - with FeatureFixture({u'disclosure.private_projects.enabled': u'on'}): |
696 | - login_person(product.owner) |
697 | - form = self._make_product_edit_form(product, proprietary=True) |
698 | - view = create_initialized_view(product, '+edit', form=form) |
699 | - self.assertEqual(0, len(view.errors)) |
700 | + login_person(product.owner) |
701 | + form = self._make_product_edit_form(product, proprietary=True) |
702 | + view = create_initialized_view(product, '+edit', form=form) |
703 | + self.assertEqual(0, len(view.errors)) |
704 | |
705 | - product_set = getUtility(IProductSet) |
706 | - updated_product = product_set.getByName('fnord') |
707 | - self.assertEqual( |
708 | - InformationType.PROPRIETARY, updated_product.information_type) |
709 | - # A complimentary commercial subscription is auto generated for |
710 | - # the product when the information type is changed. |
711 | - self.assertIsNotNone(updated_product.commercial_subscription) |
712 | + updated_product = getUtility(IProductSet).getByName('fnord') |
713 | + self.assertEqual( |
714 | + InformationType.PROPRIETARY, updated_product.information_type) |
715 | + # A complimentary commercial subscription is auto generated for |
716 | + # the product when the information type is changed. |
717 | + self.assertIsNotNone(updated_product.commercial_subscription) |
718 | |
719 | def test_change_information_type_proprietary_packaged(self): |
720 | # It should be an error to make a Product private if it is packaged. |
721 | - self.useFixture(FeatureFixture( |
722 | - {u'disclosure.private_projects.enabled': u'on'})) |
723 | product = self.factory.makeProduct() |
724 | sourcepackage = self.factory.makeSourcePackage() |
725 | sourcepackage.setPackaging(product.development_focus, product.owner) |
726 | @@ -537,8 +517,6 @@ |
727 | product = self.factory.makeProduct() |
728 | self.factory.makeBranch(product=product) |
729 | self.factory.makeSpecification(product=product) |
730 | - self.useFixture(FeatureFixture( |
731 | - {u'disclosure.private_projects.enabled': u'on'})) |
732 | browser = self.getViewBrowser(product, '+edit', user=product.owner) |
733 | info_type = browser.getControl(name='field.information_type') |
734 | info_type.value = ['PROPRIETARY'] |
735 | @@ -552,20 +530,16 @@ |
736 | def test_change_information_type_public(self): |
737 | owner = self.factory.makePerson(name='pting') |
738 | product = self.factory.makeProduct( |
739 | - name='fnord', |
740 | - information_type=InformationType.PROPRIETARY, |
741 | - owner=owner, |
742 | - ) |
743 | - with FeatureFixture({u'disclosure.private_projects.enabled': u'on'}): |
744 | - login_person(owner) |
745 | - form = self._make_product_edit_form(product) |
746 | - view = create_initialized_view(product, '+edit', form=form) |
747 | - self.assertEqual(0, len(view.errors)) |
748 | + name='fnord', information_type=InformationType.PROPRIETARY, |
749 | + owner=owner) |
750 | + login_person(owner) |
751 | + form = self._make_product_edit_form(product) |
752 | + view = create_initialized_view(product, '+edit', form=form) |
753 | + self.assertEqual(0, len(view.errors)) |
754 | |
755 | - product_set = getUtility(IProductSet) |
756 | - updated_product = product_set.getByName('fnord') |
757 | - self.assertEqual( |
758 | - InformationType.PUBLIC, updated_product.information_type) |
759 | + updated_product = getUtility(IProductSet).getByName('fnord') |
760 | + self.assertEqual( |
761 | + InformationType.PUBLIC, updated_product.information_type) |
762 | |
763 | |
764 | class ProductSetReviewLicensesViewTestCase(TestCaseWithFactory): |
765 | |
766 | === modified file 'lib/lp/registry/browser/tests/test_projectgroup.py' |
767 | --- lib/lp/registry/browser/tests/test_projectgroup.py 2012-11-20 20:53:20 +0000 |
768 | +++ lib/lp/registry/browser/tests/test_projectgroup.py 2013-02-07 06:17:24 +0000 |
769 | @@ -1,4 +1,4 @@ |
770 | -# Copyright 2010-2012 Canonical Ltd. This software is licensed under the |
771 | +# Copyright 2010-2013 Canonical Ltd. This software is licensed under the |
772 | # GNU Affero General Public License version 3 (see the file LICENSE). |
773 | |
774 | """Tests for project group views.""" |
775 | @@ -21,7 +21,6 @@ |
776 | ) |
777 | from lp.registry.interfaces.person import IPersonSet |
778 | from lp.registry.interfaces.product import IProductSet |
779 | -from lp.services.features.testing import FeatureFixture |
780 | from lp.services.webapp import canonical_url |
781 | from lp.services.webapp.interfaces import ILaunchBag |
782 | from lp.testing import ( |
783 | @@ -102,8 +101,6 @@ |
784 | def test_mixed_product_projectgroup_milestone(self): |
785 | # If a milestone is mixed between public and proprietary products, |
786 | # only the public is shown to people without access. |
787 | - self.useFixture( |
788 | - FeatureFixture({u'disclosure.private_projects.enabled': u'on'})) |
789 | owner = self.factory.makePerson() |
790 | teammember = self.factory.makePerson() |
791 | owning_team = self.factory.makeTeam(owner=owner, |
792 | @@ -205,8 +202,6 @@ |
793 | def test_information_type(self): |
794 | # Information type controls are provided when creating a project via a |
795 | # project group. |
796 | - self.useFixture( |
797 | - FeatureFixture({u'disclosure.private_projects.enabled': u'on'})) |
798 | form = make_product_form(action=1) |
799 | project = self.factory.makeProject() |
800 | with person_logged_in(project.owner): |
801 | @@ -217,8 +212,6 @@ |
802 | |
803 | def test_information_type_saved(self): |
804 | # Setting information_type to PROPRIETARY via form actually works. |
805 | - self.useFixture( |
806 | - FeatureFixture({u'disclosure.private_projects.enabled': u'on'})) |
807 | project = self.factory.makeProject() |
808 | form = make_product_form(project.owner, action=2, proprietary=True) |
809 | with person_logged_in(project.owner): |
810 | |
811 | === modified file 'lib/lp/registry/browser/tests/test_sourcepackage_views.py' |
812 | --- lib/lp/registry/browser/tests/test_sourcepackage_views.py 2012-11-12 22:27:55 +0000 |
813 | +++ lib/lp/registry/browser/tests/test_sourcepackage_views.py 2013-02-07 06:17:24 +0000 |
814 | @@ -1,4 +1,4 @@ |
815 | -# Copyright 2010-2012 Canonical Ltd. This software is licensed under the |
816 | +# Copyright 2010-2013 Canonical Ltd. This software is licensed under the |
817 | # GNU Affero General Public License version 3 (see the file LICENSE). |
818 | |
819 | """Tests for SourcePackage view code.""" |
820 | @@ -30,7 +30,6 @@ |
821 | IDistroSeriesSet, |
822 | ) |
823 | from lp.registry.interfaces.sourcepackage import ISourcePackage |
824 | -from lp.services.features.testing import FeatureFixture |
825 | from lp.soyuz.tests.test_publishing import SoyuzTestPublisher |
826 | from lp.testing import ( |
827 | BrowserTestCase, |
828 | @@ -165,8 +164,6 @@ |
829 | |
830 | def test_register_upstream_forbids_proprietary(self): |
831 | # Cannot specify information_type if registering for sourcepackage. |
832 | - self.useFixture(FeatureFixture({'disclosure.private_projects.enabled': |
833 | - 'on'})) |
834 | sourcepackage = self.factory.makeSourcePackage() |
835 | browser = self.getViewBrowser(sourcepackage) |
836 | browser.getControl("Register the upstream project").click() |
837 | |
838 | === modified file 'lib/lp/registry/model/product.py' |
839 | --- lib/lp/registry/model/product.py 2013-01-22 05:07:31 +0000 |
840 | +++ lib/lp/registry/model/product.py 2013-02-07 06:17:24 +0000 |
841 | @@ -200,7 +200,6 @@ |
842 | SQLBase, |
843 | sqlvalues, |
844 | ) |
845 | -from lp.services.features import getFeatureFlag |
846 | from lp.services.propertycache import ( |
847 | cachedproperty, |
848 | get_property_cache, |
849 | @@ -1562,8 +1561,6 @@ |
850 | |
851 | def userCanView(self, user): |
852 | """See `IProductPublic`.""" |
853 | - if getFeatureFlag('disclosure.private_project.traversal_override'): |
854 | - return True |
855 | if self.information_type in PUBLIC_INFORMATION_TYPES: |
856 | return True |
857 | if user is None: |
858 | |
859 | === modified file 'lib/lp/registry/tests/test_product.py' |
860 | --- lib/lp/registry/tests/test_product.py 2013-01-09 04:53:17 +0000 |
861 | +++ lib/lp/registry/tests/test_product.py 2013-02-07 06:17:24 +0000 |
862 | @@ -92,7 +92,6 @@ |
863 | ) |
864 | from lp.registry.model.productlicense import ProductLicense |
865 | from lp.services.database.lpstorm import IStore |
866 | -from lp.services.features.testing import FeatureFixture |
867 | from lp.services.webapp.authorization import check_permission |
868 | from lp.services.webapp.escaping import html_escape |
869 | from lp.testing import ( |
870 | @@ -1196,28 +1195,6 @@ |
871 | product.userCanView(user) |
872 | product.userCanView(IPersonRoles(user)) |
873 | |
874 | - def test_userCanView_override(self): |
875 | - # userCanView is overridden by the traversal override. |
876 | - product = self.factory.makeProduct( |
877 | - information_type=InformationType.PROPRIETARY) |
878 | - unprivileged = self.factory.makePerson() |
879 | - with person_logged_in(unprivileged): |
880 | - with FeatureFixture( |
881 | - {'disclosure.private_project.traversal_override': 'on'}): |
882 | - self.assertTrue(product.userCanView(unprivileged)) |
883 | - self.assertFalse(product.userCanView(unprivileged)) |
884 | - |
885 | - def test_anonymous_traversal_override(self): |
886 | - # The traversal override affects the permissions granted to anonymous |
887 | - # users. |
888 | - product = self.factory.makeProduct( |
889 | - information_type=InformationType.PROPRIETARY) |
890 | - with person_logged_in(None): |
891 | - with FeatureFixture( |
892 | - {'disclosure.private_project.traversal_override': 'on'}): |
893 | - self.assertTrue(check_permission('launchpad.View', product)) |
894 | - self.assertFalse(check_permission('launchpad.View', product)) |
895 | - |
896 | def test_information_type_prevents_pruning(self): |
897 | # Access policies for Product.information_type are not pruned. |
898 | owner = self.factory.makePerson() |
899 | |
900 | === modified file 'lib/lp/services/features/flags.py' |
901 | --- lib/lp/services/features/flags.py 2012-11-19 05:54:50 +0000 |
902 | +++ lib/lp/services/features/flags.py 2013-02-07 06:17:24 +0000 |
903 | @@ -1,4 +1,4 @@ |
904 | -# Copyright 2010-2012 Canonical Ltd. This software is licensed under the |
905 | +# Copyright 2010-2013 Canonical Ltd. This software is licensed under the |
906 | # GNU Affero General Public License version 3 (see the file LICENSE). |
907 | |
908 | __all__ = [ |
909 | @@ -57,12 +57,6 @@ |
910 | '', |
911 | '', |
912 | ''), |
913 | - ('blueprints.information_type.enabled', |
914 | - 'boolean', |
915 | - 'Enable UI for information_type on Blueprints.', |
916 | - 'Disable UI', |
917 | - 'Blueprint information_type UI', |
918 | - 'https://dev.launchpad.net/LEP/PrivateProjects'), |
919 | ('bugs.affected_count_includes_dupes.disabled', |
920 | 'boolean', |
921 | ("Disable adding up affected users across all duplicate bugs."), |
922 | @@ -226,18 +220,6 @@ |
923 | '', |
924 | '', |
925 | ''), |
926 | - ('disclosure.private_projects.enabled', |
927 | - 'boolean', |
928 | - 'If true, enabled access to private project registration features.', |
929 | - 'disabled', |
930 | - 'Allow registering a non-public project.', |
931 | - 'http://blog.launchpad.net/general/private-projects-beta'), |
932 | - ('disclosure.private_project.traversal_override', |
933 | - 'boolean', |
934 | - 'If set, allow all users to traverse to private projects.', |
935 | - 'Traversal to private projects requires special access.', |
936 | - 'Override traveral checks.', |
937 | - 'https://dev.launchpad.net/LEP/PrivateProjects'), |
938 | ]) |
939 | |
940 | # The set of all flag names that are documented. |