/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/bugtracker.py

  • Committer: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2018-11-16 18:59:44 UTC
  • mfrom: (7143.15.15 more-cleanups)
  • Revision ID: breezy.the.bot@gmail.com-20181116185944-biefv1sub37qfybm
Sprinkle some PEP8iness.

Merged from https://code.launchpad.net/~jelmer/brz/more-cleanups/+merge/358611

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
from bzrlib import registry
18
 
from bzrlib.lazy_import import lazy_import
 
17
from __future__ import absolute_import
 
18
 
 
19
from . import (
 
20
    errors,
 
21
    registry,
 
22
    )
 
23
from .lazy_import import lazy_import
19
24
lazy_import(globals(), """
20
 
from bzrlib import errors, urlutils
 
25
from breezy import urlutils
21
26
""")
22
27
 
23
28
 
37
42
"""
38
43
 
39
44
 
40
 
_bugs_help = \
41
 
"""When making a commit, metadata about bugs fixed by that change can be
 
45
_bugs_help = """\
 
46
When making a commit, metadata about bugs fixed by that change can be
42
47
recorded by using the ``--fixes`` option. For each bug marked as fixed, an
43
48
entry is included in the 'bugs' revision property stating '<url> <status>'.
44
49
(The only ``status`` value currently supported is ``fixed.``)
48
53
 
49
54
    bzr commit --fixes <tracker>:<id>
50
55
 
 
56
or::
 
57
 
 
58
    bzr commit --fixes <id>
 
59
 
51
60
where "<tracker>" is an identifier for the bug tracker, and "<id>" is the
52
61
identifier for that bug within the bugtracker, usually the bug number.
 
62
If "<tracker>" is not specified the ``bugtracker`` set in the branch
 
63
or global configuration is used.
53
64
 
54
65
Bazaar knows about a few bug trackers that have many users. If
55
66
you use one of these bug trackers then there is no setup required to
73
84
 
74
85
If you use Bugzilla or Trac, then you only need to set a configuration
75
86
variable which contains the base URL of the bug tracker. These options
76
 
can go into ``bazaar.conf``, ``branch.conf`` or into a branch-specific
 
87
can go into ``breezy.conf``, ``branch.conf`` or into a branch-specific
77
88
configuration section in ``locations.conf``.  You can set up these values
78
89
for each of the projects you work on.
79
90
 
93
104
--fixes`` to mark bugs in that tracker as being fixed by that commit. For
94
105
example::
95
106
 
96
 
    bugzilla_squid_url = http://www.squid-cache.org/bugs
 
107
    bugzilla_squid_url = http://bugs.squid-cache.org
97
108
 
98
109
would allow ``bzr commit --fixes squid:1234`` to mark Squid's bug 1234 as
99
110
fixed.
127
138
 
128
139
    bugtracker_cpan_url = http://rt.cpan.org/Public/Bug/Display.html?id={id}
129
140
 
130
 
for CPAN's RT bug tracker.
 
141
would allow ``bzr commit --fixes cpan:1234`` to mark bug 1234 in CPAN's
 
142
RT bug tracker as fixed, or::
 
143
 
 
144
    bugtracker_hudson_url = http://issues.hudson-ci.org/browse/{id}
 
145
 
 
146
would allow ``bzr commit --fixes hudson:HUDSON-1234`` to mark bug HUDSON-1234
 
147
in Hudson's JIRA bug tracker as fixed.
131
148
"""
132
149
 
133
150
 
 
151
class MalformedBugIdentifier(errors.BzrError):
 
152
 
 
153
    _fmt = ('Did not understand bug identifier %(bug_id)s: %(reason)s. '
 
154
            'See "brz help bugs" for more information on this feature.')
 
155
 
 
156
    def __init__(self, bug_id, reason):
 
157
        self.bug_id = bug_id
 
158
        self.reason = reason
 
159
 
 
160
 
 
161
class InvalidBugTrackerURL(errors.BzrError):
 
162
 
 
163
    _fmt = ("The URL for bug tracker \"%(abbreviation)s\" doesn't "
 
164
            "contain {id}: %(url)s")
 
165
 
 
166
    def __init__(self, abbreviation, url):
 
167
        self.abbreviation = abbreviation
 
168
        self.url = url
 
169
 
 
170
 
 
171
class UnknownBugTrackerAbbreviation(errors.BzrError):
 
172
 
 
173
    _fmt = ("Cannot find registered bug tracker called %(abbreviation)s "
 
174
            "on %(branch)s")
 
175
 
 
176
    def __init__(self, abbreviation, branch):
 
177
        self.abbreviation = abbreviation
 
178
        self.branch = branch
 
179
 
 
180
 
 
181
class InvalidLineInBugsProperty(errors.BzrError):
 
182
 
 
183
    _fmt = ("Invalid line in bugs property: '%(line)s'")
 
184
 
 
185
    def __init__(self, line):
 
186
        self.line = line
 
187
 
 
188
 
 
189
class InvalidBugStatus(errors.BzrError):
 
190
 
 
191
    _fmt = ("Invalid bug status: '%(status)s'")
 
192
 
 
193
    def __init__(self, status):
 
194
        self.status = status
 
195
 
 
196
 
134
197
def get_bug_url(abbreviated_bugtracker_name, branch, bug_id):
135
198
    """Return a URL pointing to the canonical web page of the bug identified by
136
199
    'bug_id'.
153
216
            tracker = tracker_type.get(abbreviated_bugtracker_name, branch)
154
217
            if tracker is not None:
155
218
                return tracker
156
 
        raise errors.UnknownBugTrackerAbbreviation(abbreviated_bugtracker_name,
157
 
                                                   branch)
 
219
        raise UnknownBugTrackerAbbreviation(
 
220
            abbreviated_bugtracker_name, branch)
158
221
 
159
222
    def help_topic(self, topic):
160
223
        return _bugs_help
189
252
        try:
190
253
            int(bug_id)
191
254
        except ValueError:
192
 
            raise errors.MalformedBugIdentifier(bug_id, "Must be an integer")
 
255
            raise MalformedBugIdentifier(bug_id, "Must be an integer")
193
256
 
194
257
 
195
258
class UniqueIntegerBugTracker(IntegerBugTracker):
205
268
        self.base_url = base_url
206
269
 
207
270
    def get(self, abbreviated_bugtracker_name, branch):
208
 
        """Returns the tracker if the abbreviation matches. Returns None
209
 
        otherwise."""
210
 
        if abbreviated_bugtracker_name != self.abbreviation:
211
 
            return None
212
 
        return self
213
 
 
214
 
    def _get_bug_url(self, bug_id):
215
 
        """Return the URL for bug_id."""
216
 
        return self.base_url + bug_id
 
271
        """Returns the tracker if the abbreviation matches, otherwise ``None``.
 
272
        """
 
273
        if abbreviated_bugtracker_name != self.abbreviation:
 
274
            return None
 
275
        return self
 
276
 
 
277
    def _get_bug_url(self, bug_id):
 
278
        """Return the URL for bug_id."""
 
279
        return self.base_url + str(bug_id)
 
280
 
 
281
 
 
282
class ProjectIntegerBugTracker(IntegerBugTracker):
 
283
    """A bug tracker that exists in one place only with per-project ids.
 
284
 
 
285
    If you have one of these trackers then register an instance passing in an
 
286
    abbreviated name for the bug tracker and a base URL. The bug ids are
 
287
    appended directly to the URL.
 
288
    """
 
289
 
 
290
    def __init__(self, abbreviated_bugtracker_name, base_url):
 
291
        self.abbreviation = abbreviated_bugtracker_name
 
292
        self._base_url = base_url
 
293
 
 
294
    def get(self, abbreviated_bugtracker_name, branch):
 
295
        """Returns the tracker if the abbreviation matches, otherwise ``None``.
 
296
        """
 
297
        if abbreviated_bugtracker_name != self.abbreviation:
 
298
            return None
 
299
        return self
 
300
 
 
301
    def check_bug_id(self, bug_id):
 
302
        try:
 
303
            (project, bug_id) = bug_id.rsplit('/', 1)
 
304
        except ValueError:
 
305
            raise MalformedBugIdentifier(bug_id, "Expected format: project/id")
 
306
        try:
 
307
            int(bug_id)
 
308
        except ValueError:
 
309
            raise MalformedBugIdentifier(bug_id, "Bug id must be an integer")
 
310
 
 
311
    def _get_bug_url(self, bug_id):
 
312
        (project, bug_id) = bug_id.rsplit('/', 1)
 
313
        """Return the URL for bug_id."""
 
314
        if '{id}' not in self._base_url:
 
315
            raise InvalidBugTrackerURL(self._abbreviation, self._base_url)
 
316
        if '{project}' not in self._base_url:
 
317
            raise InvalidBugTrackerURL(self._abbreviation, self._base_url)
 
318
        return self._base_url.replace(
 
319
            '{project}', project).replace('{id}', str(bug_id))
217
320
 
218
321
 
219
322
tracker_registry.register(
224
327
    'debian', UniqueIntegerBugTracker('deb', 'http://bugs.debian.org/'))
225
328
 
226
329
 
227
 
tracker_registry.register('gnome',
228
 
    UniqueIntegerBugTracker('gnome', 'http://bugzilla.gnome.org/show_bug.cgi?id='))
229
 
 
230
 
 
231
 
class URLParametrizedIntegerBugTracker(IntegerBugTracker):
 
330
tracker_registry.register(
 
331
    'gnome', UniqueIntegerBugTracker(
 
332
        'gnome', 'http://bugzilla.gnome.org/show_bug.cgi?id='))
 
333
 
 
334
 
 
335
tracker_registry.register(
 
336
    'github', ProjectIntegerBugTracker(
 
337
        'github', 'https://github.com/{project}/issues/{id}'))
 
338
 
 
339
 
 
340
class URLParametrizedBugTracker(BugTracker):
232
341
    """A type of bug tracker that can be found on a variety of different sites,
233
342
    and thus needs to have the base URL configured.
234
343
 
235
344
    Looks for a config setting in the form '<type_name>_<abbreviation>_url'.
236
 
    `type_name` is the name of the type of tracker (e.g. 'bugzilla' or 'trac')
237
 
    and `abbreviation` is a short name for the particular instance (e.g.
238
 
    'squid' or 'apache').
 
345
    `type_name` is the name of the type of tracker and `abbreviation`
 
346
    is a short name for the particular instance.
239
347
    """
240
348
 
241
349
    def get(self, abbreviation, branch):
242
350
        config = branch.get_config()
243
351
        url = config.get_user_option(
244
 
            "%s_%s_url" % (self.type_name, abbreviation))
 
352
            "%s_%s_url" % (self.type_name, abbreviation), expand=False)
245
353
        if url is None:
246
354
            return None
247
355
        self._base_url = url
256
364
        return urlutils.join(self._base_url, self._bug_area) + str(bug_id)
257
365
 
258
366
 
 
367
class URLParametrizedIntegerBugTracker(IntegerBugTracker,
 
368
                                       URLParametrizedBugTracker):
 
369
    """A type of bug tracker that  only allows integer bug IDs.
 
370
 
 
371
    This can be found on a variety of different sites, and thus needs to have
 
372
    the base URL configured.
 
373
 
 
374
    Looks for a config setting in the form '<type_name>_<abbreviation>_url'.
 
375
    `type_name` is the name of the type of tracker (e.g. 'bugzilla' or 'trac')
 
376
    and `abbreviation` is a short name for the particular instance (e.g.
 
377
    'squid' or 'apache').
 
378
    """
 
379
 
 
380
 
259
381
tracker_registry.register(
260
382
    'trac', URLParametrizedIntegerBugTracker('trac', 'ticket/'))
261
383
 
264
386
    URLParametrizedIntegerBugTracker('bugzilla', 'show_bug.cgi?id='))
265
387
 
266
388
 
267
 
class GenericBugTracker(URLParametrizedIntegerBugTracker):
 
389
class GenericBugTracker(URLParametrizedBugTracker):
268
390
    """Generic bug tracker specified by an URL template."""
269
391
 
270
392
    def __init__(self):
277
399
    def _get_bug_url(self, bug_id):
278
400
        """Given a validated bug_id, return the bug's web page's URL."""
279
401
        if '{id}' not in self._base_url:
280
 
            raise errors.InvalidBugTrackerURL(self._abbreviation,
281
 
                                              self._base_url)
 
402
            raise InvalidBugTrackerURL(self._abbreviation, self._base_url)
282
403
        return self._base_url.replace('{id}', str(bug_id))
283
404
 
284
405
 
286
407
 
287
408
 
288
409
FIXED = 'fixed'
 
410
RELATED = 'related'
289
411
 
290
 
ALLOWED_BUG_STATUSES = set([FIXED])
 
412
ALLOWED_BUG_STATUSES = {FIXED, RELATED}
291
413
 
292
414
 
293
415
def encode_fixes_bug_urls(bug_urls):
294
416
    """Get the revision property value for a commit that fixes bugs.
295
417
 
296
 
    :param bug_urls: An iterable of escaped URLs to bugs. These normally
 
418
    :param bug_urls: An iterable of (escaped URL, tag) tuples. These normally
297
419
        come from `get_bug_url`.
298
420
    :return: A string that will be set as the 'bugs' property of a revision
299
421
        as part of a commit.
300
422
    """
301
 
    return '\n'.join(('%s %s' % (url, FIXED)) for url in bug_urls)
 
423
    return '\n'.join(('%s %s' % (url, tag)) for (url, tag) in bug_urls)