/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): Colin Watson
  • Date: 2020-11-16 21:47:08 UTC
  • mfrom: (7521.1.1 remove-lp-workaround)
  • Revision ID: breezy.the.bot@gmail.com-20201116214708-jos209mgxi41oy15
Remove breezy.git workaround for bazaar.launchpad.net.

Merged from https://code.launchpad.net/~cjwatson/brz/remove-lp-workaround/+merge/393710

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 __future__ import absolute_import
18
 
 
19
 
from bzrlib import registry
20
 
from bzrlib.lazy_import import lazy_import
 
17
from . import (
 
18
    errors,
 
19
    registry,
 
20
    )
 
21
from .lazy_import import lazy_import
21
22
lazy_import(globals(), """
22
 
from bzrlib import errors, urlutils
 
23
from breezy import urlutils
23
24
""")
24
25
 
25
26
 
39
40
"""
40
41
 
41
42
 
42
 
_bugs_help = \
43
 
"""When making a commit, metadata about bugs fixed by that change can be
 
43
_bugs_help = """\
 
44
When making a commit, metadata about bugs fixed by that change can be
44
45
recorded by using the ``--fixes`` option. For each bug marked as fixed, an
45
46
entry is included in the 'bugs' revision property stating '<url> <status>'.
46
47
(The only ``status`` value currently supported is ``fixed.``)
81
82
 
82
83
If you use Bugzilla or Trac, then you only need to set a configuration
83
84
variable which contains the base URL of the bug tracker. These options
84
 
can go into ``bazaar.conf``, ``branch.conf`` or into a branch-specific
 
85
can go into ``breezy.conf``, ``branch.conf`` or into a branch-specific
85
86
configuration section in ``locations.conf``.  You can set up these values
86
87
for each of the projects you work on.
87
88
 
145
146
"""
146
147
 
147
148
 
 
149
class MalformedBugIdentifier(errors.BzrError):
 
150
 
 
151
    _fmt = ('Did not understand bug identifier %(bug_id)s: %(reason)s. '
 
152
            'See "brz help bugs" for more information on this feature.')
 
153
 
 
154
    def __init__(self, bug_id, reason):
 
155
        self.bug_id = bug_id
 
156
        self.reason = reason
 
157
 
 
158
 
 
159
class InvalidBugTrackerURL(errors.BzrError):
 
160
 
 
161
    _fmt = ("The URL for bug tracker \"%(abbreviation)s\" doesn't "
 
162
            "contain {id}: %(url)s")
 
163
 
 
164
    def __init__(self, abbreviation, url):
 
165
        self.abbreviation = abbreviation
 
166
        self.url = url
 
167
 
 
168
 
 
169
class UnknownBugTrackerAbbreviation(errors.BzrError):
 
170
 
 
171
    _fmt = ("Cannot find registered bug tracker called %(abbreviation)s "
 
172
            "on %(branch)s")
 
173
 
 
174
    def __init__(self, abbreviation, branch):
 
175
        self.abbreviation = abbreviation
 
176
        self.branch = branch
 
177
 
 
178
 
 
179
class InvalidLineInBugsProperty(errors.BzrError):
 
180
 
 
181
    _fmt = ("Invalid line in bugs property: '%(line)s'")
 
182
 
 
183
    def __init__(self, line):
 
184
        self.line = line
 
185
 
 
186
 
 
187
class InvalidBugUrl(errors.BzrError):
 
188
 
 
189
    _fmt = "Invalid bug URL: %(url)s"
 
190
 
 
191
    def __init__(self, url):
 
192
        self.url = url
 
193
 
 
194
 
 
195
class InvalidBugStatus(errors.BzrError):
 
196
 
 
197
    _fmt = ("Invalid bug status: '%(status)s'")
 
198
 
 
199
    def __init__(self, status):
 
200
        self.status = status
 
201
 
 
202
 
148
203
def get_bug_url(abbreviated_bugtracker_name, branch, bug_id):
149
204
    """Return a URL pointing to the canonical web page of the bug identified by
150
205
    'bug_id'.
167
222
            tracker = tracker_type.get(abbreviated_bugtracker_name, branch)
168
223
            if tracker is not None:
169
224
                return tracker
170
 
        raise errors.UnknownBugTrackerAbbreviation(abbreviated_bugtracker_name,
171
 
                                                   branch)
 
225
        raise UnknownBugTrackerAbbreviation(
 
226
            abbreviated_bugtracker_name, branch)
172
227
 
173
228
    def help_topic(self, topic):
174
229
        return _bugs_help
203
258
        try:
204
259
            int(bug_id)
205
260
        except ValueError:
206
 
            raise errors.MalformedBugIdentifier(bug_id, "Must be an integer")
 
261
            raise MalformedBugIdentifier(bug_id, "Must be an integer")
207
262
 
208
263
 
209
264
class UniqueIntegerBugTracker(IntegerBugTracker):
219
274
        self.base_url = base_url
220
275
 
221
276
    def get(self, abbreviated_bugtracker_name, branch):
222
 
        """Returns the tracker if the abbreviation matches. Returns None
223
 
        otherwise."""
224
 
        if abbreviated_bugtracker_name != self.abbreviation:
225
 
            return None
226
 
        return self
227
 
 
228
 
    def _get_bug_url(self, bug_id):
229
 
        """Return the URL for bug_id."""
230
 
        return self.base_url + bug_id
 
277
        """Returns the tracker if the abbreviation matches, otherwise ``None``.
 
278
        """
 
279
        if abbreviated_bugtracker_name != self.abbreviation:
 
280
            return None
 
281
        return self
 
282
 
 
283
    def _get_bug_url(self, bug_id):
 
284
        """Return the URL for bug_id."""
 
285
        return self.base_url + str(bug_id)
 
286
 
 
287
 
 
288
class ProjectIntegerBugTracker(IntegerBugTracker):
 
289
    """A bug tracker that exists in one place only with per-project ids.
 
290
 
 
291
    If you have one of these trackers then register an instance passing in an
 
292
    abbreviated name for the bug tracker and a base URL. The bug ids are
 
293
    appended directly to the URL.
 
294
    """
 
295
 
 
296
    def __init__(self, abbreviated_bugtracker_name, base_url):
 
297
        self.abbreviation = abbreviated_bugtracker_name
 
298
        self._base_url = base_url
 
299
 
 
300
    def get(self, abbreviated_bugtracker_name, branch):
 
301
        """Returns the tracker if the abbreviation matches, otherwise ``None``.
 
302
        """
 
303
        if abbreviated_bugtracker_name != self.abbreviation:
 
304
            return None
 
305
        return self
 
306
 
 
307
    def check_bug_id(self, bug_id):
 
308
        try:
 
309
            (project, bug_id) = bug_id.rsplit('/', 1)
 
310
        except ValueError:
 
311
            raise MalformedBugIdentifier(bug_id, "Expected format: project/id")
 
312
        try:
 
313
            int(bug_id)
 
314
        except ValueError:
 
315
            raise MalformedBugIdentifier(bug_id, "Bug id must be an integer")
 
316
 
 
317
    def _get_bug_url(self, bug_id):
 
318
        (project, bug_id) = bug_id.rsplit('/', 1)
 
319
        """Return the URL for bug_id."""
 
320
        if '{id}' not in self._base_url:
 
321
            raise InvalidBugTrackerURL(self._abbreviation, self._base_url)
 
322
        if '{project}' not in self._base_url:
 
323
            raise InvalidBugTrackerURL(self._abbreviation, self._base_url)
 
324
        return self._base_url.replace(
 
325
            '{project}', project).replace('{id}', str(bug_id))
231
326
 
232
327
 
233
328
tracker_registry.register(
238
333
    'debian', UniqueIntegerBugTracker('deb', 'http://bugs.debian.org/'))
239
334
 
240
335
 
241
 
tracker_registry.register('gnome',
242
 
    UniqueIntegerBugTracker('gnome',
243
 
                            'http://bugzilla.gnome.org/show_bug.cgi?id='))
 
336
tracker_registry.register(
 
337
    'gnome', UniqueIntegerBugTracker(
 
338
        'gnome', 'http://bugzilla.gnome.org/show_bug.cgi?id='))
 
339
 
 
340
 
 
341
tracker_registry.register(
 
342
    'github', ProjectIntegerBugTracker(
 
343
        'github', 'https://github.com/{project}/issues/{id}'))
244
344
 
245
345
 
246
346
class URLParametrizedBugTracker(BugTracker):
283
383
    'squid' or 'apache').
284
384
    """
285
385
 
 
386
 
286
387
tracker_registry.register(
287
388
    'trac', URLParametrizedIntegerBugTracker('trac', 'ticket/'))
288
389
 
304
405
    def _get_bug_url(self, bug_id):
305
406
        """Given a validated bug_id, return the bug's web page's URL."""
306
407
        if '{id}' not in self._base_url:
307
 
            raise errors.InvalidBugTrackerURL(self._abbreviation,
308
 
                                              self._base_url)
 
408
            raise InvalidBugTrackerURL(self._abbreviation, self._base_url)
309
409
        return self._base_url.replace('{id}', str(bug_id))
310
410
 
311
411
 
313
413
 
314
414
 
315
415
FIXED = 'fixed'
 
416
RELATED = 'related'
316
417
 
317
 
ALLOWED_BUG_STATUSES = set([FIXED])
 
418
ALLOWED_BUG_STATUSES = {FIXED, RELATED}
318
419
 
319
420
 
320
421
def encode_fixes_bug_urls(bug_urls):
321
422
    """Get the revision property value for a commit that fixes bugs.
322
423
 
323
 
    :param bug_urls: An iterable of escaped URLs to bugs. These normally
 
424
    :param bug_urls: An iterable of (escaped URL, tag) tuples. These normally
324
425
        come from `get_bug_url`.
325
426
    :return: A string that will be set as the 'bugs' property of a revision
326
427
        as part of a commit.
327
428
    """
328
 
    return '\n'.join(('%s %s' % (url, FIXED)) for url in bug_urls)
 
429
    lines = []
 
430
    for (url, tag) in bug_urls:
 
431
        if ' ' in url:
 
432
            raise InvalidBugUrl(url)
 
433
        lines.append('%s %s' % (url, tag))
 
434
    return '\n'.join(lines)
 
435
 
 
436
 
 
437
def decode_bug_urls(bug_text):
 
438
    """Decode a bug property text.
 
439
 
 
440
    :param bug_text: Contents of a bugs property
 
441
    :return: iterator over (url, status) tuples
 
442
    """
 
443
    for line in bug_text.splitlines():
 
444
        try:
 
445
            url, status = line.split(None, 2)
 
446
        except ValueError:
 
447
            raise InvalidLineInBugsProperty(line)
 
448
        if status not in ALLOWED_BUG_STATUSES:
 
449
            raise InvalidBugStatus(status)
 
450
        yield url, status