~launchpad-pqm/launchpad/devel

7675.429.3 by Tim Penhey
Move merge proposal errors to lp.code.errors.
1
# Copyright 2009 Canonical Ltd.  This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
3
4
"""Errors used in the lp/code modules."""
5
6
__metaclass__ = type
7
__all__ = [
8
    'BadBranchMergeProposalSearchContext',
9
    'BadStateTransition',
11270.2.1 by Tim Penhey
Move branch errors.
10
    'BranchCannotBePrivate',
11
    'BranchCannotBePublic',
12
    'BranchCreationException',
13
    'BranchCreationForbidden',
14
    'BranchCreatorNotMemberOfOwnerTeam',
15
    'BranchCreatorNotOwner',
16
    'BranchExists',
17
    'BranchTargetError',
18
    'BranchTypeError',
7675.729.1 by Aaron Bentley
Raise an exception for duplicate builds.
19
    'BuildAlreadyPending',
11151.1.7 by Paul Hummer
Added new exception to __all__
20
    'BuildNotAllowedForDistro',
7675.429.3 by Tim Penhey
Move merge proposal errors to lp.code.errors.
21
    'BranchMergeProposalExists',
11270.2.1 by Tim Penhey
Move branch errors.
22
    'CannotDeleteBranch',
11270.2.10 by Tim Penhey
Move errors from lp.code.interfaces.linkedbranch to lp.code.errors.
23
    'CannotHaveLinkedBranch',
10454.12.3 by James Westby
Add a way to get an exception if the import has already been requested.
24
    'CodeImportAlreadyRequested',
10454.12.1 by James Westby
Add ICodeImport and associated tests.
25
    'CodeImportAlreadyRunning',
26
    'CodeImportNotInReviewedState',
7675.430.3 by Tim Penhey
Move the claimReview method to the CodeReviewVoteReference.
27
    'ClaimReviewFailed',
7675.429.3 by Tim Penhey
Move merge proposal errors to lp.code.errors.
28
    'InvalidBranchMergeProposal',
7675.887.21 by Paul Hummer
Added IBranch.setMergeQueueConfig with accompanying tests
29
    'InvalidMergeQueueConfig',
11270.2.11 by Tim Penhey
Move InvalidNamespace from lp.code.interfaces.branchnamespace to lp.code.errors
30
    'InvalidNamespace',
11270.2.10 by Tim Penhey
Move errors from lp.code.interfaces.linkedbranch to lp.code.errors.
31
    'NoLinkedBranch',
11270.2.1 by Tim Penhey
Move branch errors.
32
    'NoSuchBranch',
11236.1.1 by Aaron Bentley
Attempting to use a private branch in a SourcePackageRecipe errors.
33
    'PrivateBranchRecipe',
7675.429.12 by Tim Penhey
Allow the deletion of pending reviews.
34
    'ReviewNotPending',
13084.5.2 by Aaron Bentley
Raise StaleLastMirrored as needed.
35
    'StaleLastMirrored',
10979.1.10 by Paul Hummer
Moved TooManyBuilds to lp.code.errors
36
    'TooManyBuilds',
10979.1.8 by Paul Hummer
Fixed import error
37
    'TooNewRecipeFormat',
10379.2.3 by Michael Hudson
acquireBranchToPull changes
38
    'UnknownBranchTypeError',
7675.429.16 by Tim Penhey
Move validation out into separate methods.
39
    'UserHasExistingReview',
7675.429.3 by Tim Penhey
Move merge proposal errors to lp.code.errors.
40
    'UserNotBranchReviewer',
41
    'WrongBranchMergeProposal',
42
]
43
12252.1.1 by j.c.sackett
Added webservice error and tests for CannotDeleteBranch
44
import httplib
45
12261.2.3 by Tim Penhey
Start hacking.
46
from bzrlib.plugins.builder.recipe import RecipeParseError
13228.3.9 by Francis J. Lacoste
Convert all webservice_error into error_status and use httplib constants.
47
from lazr.restful.declarations import error_status
10466.1.5 by Paul Hummer
Better solution!
48
11270.2.1 by Tim Penhey
Move branch errors.
49
from lp.app.errors import NameLookupFailed
50
12261.2.3 by Tim Penhey
Start hacking.
51
# Annotate the RecipeParseError's with a 400 webservice status.
13228.3.11 by Francis J. Lacoste
More constants conversion.
52
error_status(httplib.BAD_REQUEST)(RecipeParseError)
12261.2.3 by Tim Penhey
Start hacking.
53
7675.429.3 by Tim Penhey
Move merge proposal errors to lp.code.errors.
54
55
class BadBranchMergeProposalSearchContext(Exception):
56
    """The context is not valid for a branch merge proposal search."""
57
58
59
class BadStateTransition(Exception):
60
    """The user requested a state transition that is not possible."""
61
62
11270.2.1 by Tim Penhey
Move branch errors.
63
class BranchCreationException(Exception):
64
    """Base class for branch creation exceptions."""
65
66
13228.3.9 by Francis J. Lacoste
Convert all webservice_error into error_status and use httplib constants.
67
@error_status(httplib.CONFLICT)
11270.2.1 by Tim Penhey
Move branch errors.
68
class BranchExists(BranchCreationException):
69
    """Raised when creating a branch that already exists."""
70
71
    def __init__(self, existing_branch):
72
        # XXX: TimPenhey 2009-07-12 bug=405214: This error
73
        # message logic is incorrect, but the exact text is being tested
74
        # in branch-xmlrpc.txt.
75
        params = {'name': existing_branch.name}
76
        if existing_branch.product is None:
77
            params['maybe_junk'] = 'junk '
78
            params['context'] = existing_branch.owner.name
79
        else:
80
            params['maybe_junk'] = ''
81
            params['context'] = '%s in %s' % (
82
                existing_branch.owner.name, existing_branch.product.name)
83
        message = (
84
            'A %(maybe_junk)sbranch with the name "%(name)s" already exists '
85
            'for %(context)s.' % params)
86
        self.existing_branch = existing_branch
87
        BranchCreationException.__init__(self, message)
88
89
90
class BranchTargetError(Exception):
91
    """Raised when there is an error determining a branch target."""
92
93
13228.3.9 by Francis J. Lacoste
Convert all webservice_error into error_status and use httplib constants.
94
@error_status(httplib.BAD_REQUEST)
11270.2.1 by Tim Penhey
Move branch errors.
95
class CannotDeleteBranch(Exception):
96
    """The branch cannot be deleted at this time."""
97
98
99
class BranchCreationForbidden(BranchCreationException):
100
    """A Branch visibility policy forbids branch creation.
101
102
    The exception is raised if the policy for the product does not allow
103
    the creator of the branch to create a branch for that product.
104
    """
105
106
13228.3.9 by Francis J. Lacoste
Convert all webservice_error into error_status and use httplib constants.
107
@error_status(httplib.BAD_REQUEST)
11270.2.1 by Tim Penhey
Move branch errors.
108
class BranchCreatorNotMemberOfOwnerTeam(BranchCreationException):
109
    """Branch creator is not a member of the owner team.
110
111
    Raised when a user is attempting to create a branch and set the owner of
112
    the branch to a team that they are not a member of.
113
    """
114
13228.3.9 by Francis J. Lacoste
Convert all webservice_error into error_status and use httplib constants.
115
116
@error_status(httplib.BAD_REQUEST)
11270.2.1 by Tim Penhey
Move branch errors.
117
class BranchCreatorNotOwner(BranchCreationException):
118
    """A user cannot create a branch belonging to another user.
119
120
    Raised when a user is attempting to create a branch and set the owner of
121
    the branch to another user.
122
    """
123
124
125
class BranchTypeError(Exception):
126
    """An operation cannot be performed for a particular branch type.
127
128
    Some branch operations are only valid for certain types of branches.  The
129
    BranchTypeError exception is raised if one of these operations is called
130
    with a branch of the wrong type.
131
    """
132
133
134
class BranchCannotBePublic(Exception):
135
    """The branch cannot be made public."""
136
137
138
class BranchCannotBePrivate(Exception):
139
    """The branch cannot be made private."""
140
141
11912.2.1 by Ian Booth
Add back good changes after testfix revert
142
class InvalidBranchException(Exception):
143
    """Base exception for an error resolving a branch for a component.
144
145
    Subclasses should set _msg_template to match their required display
146
    message.
147
    """
148
149
    _msg_template = "Invalid branch for: %s"
150
151
    def __init__(self, component):
152
        self.component = component
153
        # It's expected that components have a name attribute,
154
        # so let's assume they will and deal with any error if it occurs.
155
        try:
156
            component_name = component.name
157
        except AttributeError:
158
            component_name = str(component)
159
        # The display_message contains something readable for the user.
160
        self.display_message = self._msg_template % component_name
161
        Exception.__init__(self, self._msg_template % (repr(component),))
162
163
164
class CannotHaveLinkedBranch(InvalidBranchException):
11270.2.10 by Tim Penhey
Move errors from lp.code.interfaces.linkedbranch to lp.code.errors.
165
    """Raised when we try to get the linked branch for a thing that can't."""
11270.2.1 by Tim Penhey
Move branch errors.
166
11912.2.1 by Ian Booth
Add back good changes after testfix revert
167
    _msg_template = "%s cannot have linked branches."
11270.2.1 by Tim Penhey
Move branch errors.
168
169
7675.430.3 by Tim Penhey
Move the claimReview method to the CodeReviewVoteReference.
170
class ClaimReviewFailed(Exception):
171
    """The user cannot claim the pending review."""
7675.429.3 by Tim Penhey
Move merge proposal errors to lp.code.errors.
172
173
174
class InvalidBranchMergeProposal(Exception):
175
    """Raised during the creation of a new branch merge proposal.
176
177
    The text of the exception is the rule violation.
178
    """
179
180
13228.3.9 by Francis J. Lacoste
Convert all webservice_error into error_status and use httplib constants.
181
@error_status(httplib.BAD_REQUEST)
7675.429.3 by Tim Penhey
Move merge proposal errors to lp.code.errors.
182
class BranchMergeProposalExists(InvalidBranchMergeProposal):
183
    """Raised if there is already a matching BranchMergeProposal."""
10454.10.13 by James Westby
Various fixes from Aarons review, thanks.
184
13278.2.2 by Aaron Bentley
Ensure error text is consistent.
185
    def __init__(self, existing_proposal):
186
        super(BranchMergeProposalExists, self).__init__(
187
                'There is already a branch merge proposal registered for '
188
                'branch %s to land on %s that is still active.' %
189
                (existing_proposal.source_branch.displayname,
190
                 existing_proposal.target_branch.displayname))
191
        self.existing_proposal = existing_proposal
192
7675.429.3 by Tim Penhey
Move merge proposal errors to lp.code.errors.
193
11270.2.11 by Tim Penhey
Move InvalidNamespace from lp.code.interfaces.branchnamespace to lp.code.errors
194
class InvalidNamespace(Exception):
195
    """Raised when someone tries to lookup a namespace with a bad name.
196
12221.1.7 by Jeroen Vermeulen
s/Unparseable/Unparsable/g, plus lint.
197
    By 'bad', we mean that the name is unparsable. It might be too short, too
11270.2.11 by Tim Penhey
Move InvalidNamespace from lp.code.interfaces.branchnamespace to lp.code.errors
198
    long or malformed in some other way.
199
    """
200
201
    def __init__(self, name):
202
        self.name = name
203
        Exception.__init__(
204
            self, "Cannot understand namespace name: '%s'" % (name,))
205
206
11912.2.1 by Ian Booth
Add back good changes after testfix revert
207
class NoLinkedBranch(InvalidBranchException):
11270.2.10 by Tim Penhey
Move errors from lp.code.interfaces.linkedbranch to lp.code.errors.
208
    """Raised when there's no linked branch for a thing."""
209
11912.2.1 by Ian Booth
Add back good changes after testfix revert
210
    _msg_template = "%s has no linked branch."
11270.2.10 by Tim Penhey
Move errors from lp.code.interfaces.linkedbranch to lp.code.errors.
211
212
213
class NoSuchBranch(NameLookupFailed):
214
    """Raised when we try to load a branch that does not exist."""
215
216
    _message_prefix = "No such branch"
217
218
13084.5.2 by Aaron Bentley
Raise StaleLastMirrored as needed.
219
class StaleLastMirrored(Exception):
220
    """Raised when last_mirrored_id is out of date with on-disk value."""
221
222
    def __init__(self, db_branch, info):
223
        """Constructor.
224
225
        :param db_branch: The database branch.
226
        :param info: A dict of information about the branch, as produced by
227
            lp.codehosting.bzrutils.get_branch_info
228
        """
229
        self.db_branch = db_branch
230
        self.info = info
231
        Exception.__init__(
232
            self,
233
            'Database last_mirrored_id %s does not match on-disk value %s' %
234
            (db_branch.last_mirrored_id, self.info['last_revision_id']))
235
236
13228.3.9 by Francis J. Lacoste
Convert all webservice_error into error_status and use httplib constants.
237
@error_status(httplib.BAD_REQUEST)
11236.1.1 by Aaron Bentley
Attempting to use a private branch in a SourcePackageRecipe errors.
238
class PrivateBranchRecipe(Exception):
239
240
    def __init__(self, branch):
241
        message = (
242
            'Recipe may not refer to private branch: %s' %
243
            branch.bzr_identity)
244
        self.branch = branch
245
        Exception.__init__(self, message)
246
247
7675.429.12 by Tim Penhey
Allow the deletion of pending reviews.
248
class ReviewNotPending(Exception):
249
    """The requested review is not in a pending state."""
250
251
7675.429.16 by Tim Penhey
Move validation out into separate methods.
252
class UserHasExistingReview(Exception):
253
    """The user has an existing review."""
254
255
7675.429.3 by Tim Penhey
Move merge proposal errors to lp.code.errors.
256
class UserNotBranchReviewer(Exception):
257
    """The user who attempted to review the merge proposal isn't a reviewer.
258
259
    A specific reviewer may be set on a branch.  If a specific reviewer
260
    isn't set then any user in the team of the owner of the branch is
261
    considered a reviewer.
262
    """
263
264
265
class WrongBranchMergeProposal(Exception):
266
    """The comment requested is not associated with this merge proposal."""
10379.2.3 by Michael Hudson
acquireBranchToPull changes
267
268
269
class UnknownBranchTypeError(Exception):
270
    """Raised when the user specifies an unrecognized branch type."""
10454.12.1 by James Westby
Add ICodeImport and associated tests.
271
272
13228.3.9 by Francis J. Lacoste
Convert all webservice_error into error_status and use httplib constants.
273
@error_status(httplib.BAD_REQUEST)
10454.12.1 by James Westby
Add ICodeImport and associated tests.
274
class CodeImportNotInReviewedState(Exception):
275
    """Raised when the user requests an import of a non-automatic import."""
10454.12.7 by James Westby
Fix formatting of error classes.
276
10454.12.3 by James Westby
Add a way to get an exception if the import has already been requested.
277
278
class CodeImportAlreadyRequested(Exception):
279
    """Raised when the user requests an import that is already requested."""
280
10454.12.4 by James Westby
Use the new method from the existing browser code.
281
    def __init__(self, msg, requesting_user):
282
        super(CodeImportAlreadyRequested, self).__init__(msg)
283
        self.requesting_user = requesting_user
284
10454.12.3 by James Westby
Add a way to get an exception if the import has already been requested.
285
13228.3.9 by Francis J. Lacoste
Convert all webservice_error into error_status and use httplib constants.
286
@error_status(httplib.BAD_REQUEST)
10454.12.1 by James Westby
Add ICodeImport and associated tests.
287
class CodeImportAlreadyRunning(Exception):
288
    """Raised when the user requests an import that is already running."""
10454.12.7 by James Westby
Fix formatting of error classes.
289
13228.3.9 by Francis J. Lacoste
Convert all webservice_error into error_status and use httplib constants.
290
291
@error_status(httplib.BAD_REQUEST)
10979.1.6 by Paul Hummer
Fixed lint, moved the exception
292
class TooNewRecipeFormat(Exception):
293
    """The format of the recipe supplied was too new."""
294
295
    def __init__(self, supplied_format, newest_supported):
296
        super(TooNewRecipeFormat, self).__init__()
297
        self.supplied_format = supplied_format
298
        self.newest_supported = newest_supported
10979.1.10 by Paul Hummer
Moved TooManyBuilds to lp.code.errors
299
300
13228.3.9 by Francis J. Lacoste
Convert all webservice_error into error_status and use httplib constants.
301
@error_status(httplib.BAD_REQUEST)
7675.729.1 by Aaron Bentley
Raise an exception for duplicate builds.
302
class RecipeBuildException(Exception):
10979.1.10 by Paul Hummer
Moved TooManyBuilds to lp.code.errors
303
7675.729.1 by Aaron Bentley
Raise an exception for duplicate builds.
304
    def __init__(self, recipe, distroseries, template):
10979.1.10 by Paul Hummer
Moved TooManyBuilds to lp.code.errors
305
        self.recipe = recipe
306
        self.distroseries = distroseries
7675.729.1 by Aaron Bentley
Raise an exception for duplicate builds.
307
        msg = template % {'recipe': recipe, 'distroseries': distroseries}
10979.1.10 by Paul Hummer
Moved TooManyBuilds to lp.code.errors
308
        Exception.__init__(self, msg)
7675.729.1 by Aaron Bentley
Raise an exception for duplicate builds.
309
310
311
class TooManyBuilds(RecipeBuildException):
312
    """A build was requested that exceeded the quota."""
313
314
    def __init__(self, recipe, distroseries):
315
        RecipeBuildException.__init__(
316
            self, recipe, distroseries,
317
            'You have exceeded your quota for recipe %(recipe)s for'
318
            ' distroseries %(distroseries)s')
319
320
321
class BuildAlreadyPending(RecipeBuildException):
322
    """A build was requested when an identical build was already pending."""
323
324
    def __init__(self, recipe, distroseries):
325
        RecipeBuildException.__init__(
326
            self, recipe, distroseries,
327
            'An identical build of this recipe is already pending.')
11151.1.6 by Paul Hummer
Added specific instruction
328
329
330
class BuildNotAllowedForDistro(RecipeBuildException):
11151.1.12 by Paul Hummer
Better docstring in lp.code.errors
331
    """A build was requested against an unsupported distroseries."""
11151.1.6 by Paul Hummer
Added specific instruction
332
333
    def __init__(self, recipe, distroseries):
334
        RecipeBuildException.__init__(
335
            self, recipe, distroseries,
336
            'A build against this distro is not allowed.')
7675.887.21 by Paul Hummer
Added IBranch.setMergeQueueConfig with accompanying tests
337
7675.887.29 by Paul Hummer
Extra line for PEP 8
338
13228.3.9 by Francis J. Lacoste
Convert all webservice_error into error_status and use httplib constants.
339
@error_status(httplib.BAD_REQUEST)
7675.887.21 by Paul Hummer
Added IBranch.setMergeQueueConfig with accompanying tests
340
class InvalidMergeQueueConfig(Exception):
341
    """The config specified is not a valid JSON string."""
342
343
    def __init__(self):
344
        message = ('The configuration specified is not a valid JSON string.')
345
        Exception.__init__(self, message)