1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
|
# Copyright 2009 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
# pylint: disable-msg=E0211,E0213
"""Milestone interfaces."""
__metaclass__ = type
__all__ = [
'ICanGetMilestonesDirectly',
'IHasMilestones',
'IMilestone',
'IMilestoneSet',
'IProjectGroupMilestone',
]
from lazr.lifecycle.snapshot import doNotSnapshot
from lazr.restful.declarations import (
call_with,
export_as_webservice_entry,
export_destructor_operation,
export_factory_operation,
export_operation_as,
export_read_operation,
exported,
operation_for_version,
operation_parameters,
operation_returns_entry,
rename_parameters_as,
REQUEST_USER,
)
from lazr.restful.fields import (
CollectionField,
Reference,
)
from zope.interface import (
Attribute,
Interface,
)
from zope.schema import (
Bool,
Choice,
Int,
TextLine,
)
from lp import _
from lp.services.webservice.apihelpers import (
patch_plain_parameter_type,
)
from lp.app.validators.name import name_validator
from lp.bugs.interfaces.bugtarget import (
IHasBugs,
IHasOfficialBugTags,
)
from lp.bugs.interfaces.bugtask import IBugTask
from lp.bugs.interfaces.structuralsubscription import (
IStructuralSubscriptionTarget,
)
from lp.registry.interfaces.productrelease import IProductRelease
from lp.services.fields import (
ContentNameField,
FormattableDate,
NoneableDescription,
NoneableTextLine,
)
class MilestoneNameField(ContentNameField):
"""A field that can get the milestone from different contexts."""
@property
def _content_iface(self):
"""The interface this field manages."""
return IMilestone
def _getByName(self, name):
"""Return the named milestone from the context."""
# IProductSeries and IDistroSeries are imported here to
# avoid an import loop.
from lp.registry.interfaces.productseries import (
IProductSeries)
from lp.registry.interfaces.distroseries import IDistroSeries
if IMilestone.providedBy(self.context):
milestone = self.context.target.getMilestone(name)
elif IProductSeries.providedBy(self.context):
milestone = self.context.product.getMilestone(name)
elif IDistroSeries.providedBy(self.context):
milestone = self.context.distribution.getMilestone(name)
else:
raise AssertionError(
'Editing a milestone in an unexpected context: %r'
% self.context)
if milestone is not None:
self.errormessage = _(
"The name %%s is already used by a milestone in %s."
% milestone.target.displayname)
return milestone
class IMilestone(IHasBugs, IStructuralSubscriptionTarget,
IHasOfficialBugTags):
"""A milestone, or a targeting point for bugs and other
release-management items that need coordination.
"""
export_as_webservice_entry()
id = Int(title=_("Id"))
name = exported(
MilestoneNameField(
title=_("Name"),
description=_(
"Only letters, numbers, and simple punctuation are allowed."),
constraint=name_validator))
code_name = exported(
NoneableTextLine(
title=u'Code name', required=False,
description=_('An alternative name for the milestone.')))
product = Choice(
title=_("Project"),
description=_("The project to which this milestone is associated"),
vocabulary="Product")
distribution = Choice(title=_("Distribution"),
description=_("The distribution to which this milestone belongs."),
vocabulary="Distribution")
productseries = Choice(
title=_("Product Series"),
description=_("The product series for which this is a milestone."),
vocabulary="FilteredProductSeries",
required=False) # for now
distroseries = Choice(
title=_("Distro Series"),
description=_(
"The distribution series for which this is a milestone."),
vocabulary="FilteredDistroSeries",
required=False) # for now
dateexpected = exported(
FormattableDate(title=_("Date Targeted"), required=False,
description=_("Example: 2005-11-24")),
exported_as='date_targeted')
active = exported(
Bool(
title=_("Active"),
description=_("Whether or not this milestone should be shown "
"in web forms for bug targeting.")),
exported_as='is_active')
summary = exported(
NoneableDescription(
title=_("Summary"),
required=False,
description=_(
"A summary of the features and status of this milestone.")))
target = exported(
Reference(
schema=Interface, # IHasMilestones
title=_("The product or distribution of this milestone."),
required=False))
series_target = exported(
Reference(
schema=Interface, # IHasMilestones
title=_("The productseries or distroseries of this milestone."),
required=False))
displayname = Attribute("A displayname for this milestone, constructed "
"from the milestone name.")
title = exported(
TextLine(title=_("A milestone context title for pages."),
readonly=True))
specifications = Attribute("A list of the specifications targeted to "
"this milestone.")
product_release = exported(
Reference(
schema=IProductRelease,
title=_("The release for this milestone."),
required=False,
readonly=True),
exported_as='release')
@call_with(owner=REQUEST_USER)
@rename_parameters_as(datereleased='date_released')
@export_factory_operation(
IProductRelease,
['datereleased', 'changelog', 'release_notes'])
@operation_for_version('beta')
def createProductRelease(owner, datereleased,
changelog=None, release_notes=None):
"""Create a new ProductRelease.
:param owner: `IPerson` object who manages the release.
:param datereleased: Date of the product release.
:param changelog: Detailed changes in each version.
:param release_notes: Overview of changes in each version.
:returns: `IProductRelease` object.
"""
def closeBugsAndBlueprints(user):
"""Close completed bugs and blueprints.
Bugs that are fix committed status are updated to fix released.
Blueprints that are in deployment status are updated to implemented
status.
XXX sinzui 2010-01-27 bug=341687: blueprints not yet implemented.
"""
@export_destructor_operation()
@export_operation_as('delete')
@operation_for_version('beta')
def destroySelf():
"""Delete this milestone.
This method must not be used if this milestone has a product
release.
"""
# Avoid circular imports
IBugTask['milestone'].schema = IMilestone
patch_plain_parameter_type(
IBugTask, 'transitionToMilestone', 'new_milestone', IMilestone)
class IMilestoneSet(Interface):
"""An set provides access `IMilestone`s."""
def __iter__():
"""Return an iterator over all the milestones for a thing."""
def get(milestoneid):
"""Get a milestone by its id.
If the milestone with that ID is not found, a
NotFoundError will be raised.
"""
def getByIds(milestoneids):
"""Get the milestones for milestoneids."""
def getByNameAndProduct(name, product, default=None):
"""Get a milestone by its name and product.
If no milestone is found, default will be returned.
"""
def getByNameAndDistribution(name, distribution, default=None):
"""Get a milestone by its name and distribution.
If no milestone is found, default will be returned.
"""
def getVisibleMilestones():
"""Return all visible milestones."""
class IProjectGroupMilestone(IMilestone):
"""A marker interface for milestones related to a project"""
class IHasMilestones(Interface):
"""An interface for classes providing milestones."""
export_as_webservice_entry()
has_milestones = Bool(title=_("Whether the object has any milestones."))
milestones = exported(doNotSnapshot(
CollectionField(
title=_("The visible and active milestones associated with this "
"object, ordered by date expected."),
value_type=Reference(schema=IMilestone))),
exported_as='active_milestones')
all_milestones = exported(doNotSnapshot(
CollectionField(
title=_("All milestones associated with this object, ordered by "
"date expected."),
value_type=Reference(schema=IMilestone))))
class ICanGetMilestonesDirectly(Interface):
""" An interface for classes providing getMilestone(name)."""
@operation_parameters(
name=TextLine(title=_("Name"), required=True))
@operation_returns_entry(IMilestone)
@export_read_operation()
@operation_for_version('beta')
def getMilestone(name):
"""Return a milestone with the given name for this object, or None."""
# Fix cyclic references.
IMilestone['target'].schema = IHasMilestones
IMilestone['series_target'].schema = IHasMilestones
IProductRelease['milestone'].schema = IMilestone
|