Merge lp:~stevenk/launchpad/sanity-check-bugwatch-bug-id into lp:launchpad

Proposed by Steve Kowalik
Status: Merged
Approved by: Steve Kowalik
Approved revision: no longer in the source branch.
Merged at revision: 16116
Proposed branch: lp:~stevenk/launchpad/sanity-check-bugwatch-bug-id
Merge into: lp:launchpad
Diff against target: 186 lines (+31/-19)
4 files modified
lib/lp/bugs/interfaces/bugtracker.py (+1/-3)
lib/lp/bugs/interfaces/bugwatch.py (+1/-3)
lib/lp/bugs/model/bugwatch.py (+15/-12)
lib/lp/bugs/tests/test_bugwatch.py (+14/-1)
To merge this branch: bzr merge lp:~stevenk/launchpad/sanity-check-bugwatch-bug-id
Reviewer Review Type Date Requested Status
Ian Booth (community) Approve
Review via email: mp+128625@code.launchpad.net

Commit message

Change the parsing methods that check if a remote URL for a bugwatch is valid to only accept bug numbers that are all digits.

Description of the change

Change the parsing methods that check if a remote URL for a bugwatch is valid. From what I can see, before I started this branch, only debbugs actually gave an error if the bug id supplied is not all digits, and the Trac and RoundUp parsers did something *awesome* and truncated the URL at the first non-digit character.

I think I've sorted it out so all parsers (except the e-mail address parser for obvious reasons) will croak when the remote bug id is not all digits. The LoC count can come off my something like -1000 count, but I have removed the pylint garbage and a comment that didn't add value in the slightest.

To post a comment you must log in.
Revision history for this message
Ian Booth (wallyworld) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/bugs/interfaces/bugtracker.py'
--- lib/lp/bugs/interfaces/bugtracker.py 2012-01-01 02:58:52 +0000
+++ lib/lp/bugs/interfaces/bugtracker.py 2012-10-09 06:00:12 +0000
@@ -1,8 +1,6 @@
1# Copyright 2009-2011 Canonical Ltd. This software is licensed under the1# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4# pylint: disable-msg=E0211,E0213
5
6"""Bug tracker interfaces."""4"""Bug tracker interfaces."""
75
8__metaclass__ = type6__metaclass__ = type
97
=== modified file 'lib/lp/bugs/interfaces/bugwatch.py'
--- lib/lp/bugs/interfaces/bugwatch.py 2012-01-01 02:58:52 +0000
+++ lib/lp/bugs/interfaces/bugwatch.py 2012-10-09 06:00:12 +0000
@@ -1,8 +1,6 @@
1# Copyright 2009-2011 Canonical Ltd. This software is licensed under the1# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4# pylint: disable-msg=E0211,E0213
5
6"""Bug watch interfaces."""4"""Bug watch interfaces."""
75
8__metaclass__ = type6__metaclass__ = type
97
=== modified file 'lib/lp/bugs/model/bugwatch.py'
--- lib/lp/bugs/model/bugwatch.py 2012-06-29 08:40:05 +0000
+++ lib/lp/bugs/model/bugwatch.py 2012-10-09 06:00:12 +0000
@@ -1,8 +1,6 @@
1# Copyright 2009-2012 Canonical Ltd. This software is licensed under the1# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4# pylint: disable-msg=E0611,W0212
5
6__metaclass__ = type4__metaclass__ = type
7__all__ = [5__all__ = [
8 'BugWatch',6 'BugWatch',
@@ -20,7 +18,6 @@
20from lazr.lifecycle.snapshot import Snapshot18from lazr.lifecycle.snapshot import Snapshot
21from lazr.uri import find_uris_in_text19from lazr.uri import find_uris_in_text
22from pytz import utc20from pytz import utc
23# SQL imports
24from sqlobject import (21from sqlobject import (
25 ForeignKey,22 ForeignKey,
26 SQLObjectNotFound,23 SQLObjectNotFound,
@@ -495,6 +492,8 @@
495 remote_bug = query['issue']492 remote_bug = query['issue']
496 else:493 else:
497 return None494 return None
495 if remote_bug is None or not remote_bug.isdigit():
496 return None
498 base_path = path[:-len(bug_page)]497 base_path = path[:-len(bug_page)]
499 base_url = urlunsplit((scheme, host, base_path, '', ''))498 base_url = urlunsplit((scheme, host, base_path, '', ''))
500 return base_url, remote_bug499 return base_url, remote_bug
@@ -504,9 +503,8 @@
504 bug_page = 'view.php'503 bug_page = 'view.php'
505 if not path.endswith(bug_page):504 if not path.endswith(bug_page):
506 return None505 return None
507 if query.get('id'):506 remote_bug = query.get('id')
508 remote_bug = query['id']507 if remote_bug is None or not remote_bug.isdigit():
509 else:
510 return None508 return None
511 base_path = path[:-len(bug_page)]509 base_path = path[:-len(bug_page)]
512 base_url = urlunsplit((scheme, host, base_path, '', ''))510 base_url = urlunsplit((scheme, host, base_path, '', ''))
@@ -539,7 +537,7 @@
539537
540 def parseRoundupURL(self, scheme, host, path, query):538 def parseRoundupURL(self, scheme, host, path, query):
541 """Extract the RoundUp base URL and bug ID."""539 """Extract the RoundUp base URL and bug ID."""
542 match = re.match(r'(.*/)issue(\d+)', path)540 match = re.match(r'(.*/)issue(\d+)$', path)
543 if not match:541 if not match:
544 return None542 return None
545 base_path = match.group(1)543 base_path = match.group(1)
@@ -569,13 +567,15 @@
569567
570 base_path = match.group(1)568 base_path = match.group(1)
571 remote_bug = query['id']569 remote_bug = query['id']
570 if remote_bug is None or not remote_bug.isdigit():
571 return None
572572
573 base_url = urlunsplit((scheme, host, base_path, '', ''))573 base_url = urlunsplit((scheme, host, base_path, '', ''))
574 return base_url, remote_bug574 return base_url, remote_bug
575575
576 def parseTracURL(self, scheme, host, path, query):576 def parseTracURL(self, scheme, host, path, query):
577 """Extract the Trac base URL and bug ID."""577 """Extract the Trac base URL and bug ID."""
578 match = re.match(r'(.*/)ticket/(\d+)', path)578 match = re.match(r'(.*/)ticket/(\d+)$', path)
579 if not match:579 if not match:
580 return None580 return None
581 base_path = match.group(1)581 base_path = match.group(1)
@@ -605,6 +605,8 @@
605 return None605 return None
606606
607 remote_bug = query['aid']607 remote_bug = query['aid']
608 if remote_bug is None or not remote_bug.isdigit():
609 return None
608610
609 # There's only one global SF instance registered in Launchpad,611 # There's only one global SF instance registered in Launchpad,
610 # so we return that if the hostnames match.612 # so we return that if the hostnames match.
@@ -638,6 +640,8 @@
638 # a value, so we simply use the first and only key we come640 # a value, so we simply use the first and only key we come
639 # across as a best-effort guess.641 # across as a best-effort guess.
640 remote_bug = query.popitem()[0]642 remote_bug = query.popitem()[0]
643 if remote_bug is None or not remote_bug.isdigit():
644 return None
641645
642 if host in savannah_hosts:646 if host in savannah_hosts:
643 return savannah_tracker.baseurl, remote_bug647 return savannah_tracker.baseurl, remote_bug
@@ -669,7 +673,7 @@
669 if path != '/bug.php' or len(query) != 1:673 if path != '/bug.php' or len(query) != 1:
670 return None674 return None
671 remote_bug = query.get('id')675 remote_bug = query.get('id')
672 if remote_bug is None:676 if remote_bug is None or not remote_bug.isdigit():
673 return None677 return None
674 base_url = urlunsplit((scheme, host, '/', '', ''))678 base_url = urlunsplit((scheme, host, '/', '', ''))
675 return base_url, remote_bug679 return base_url, remote_bug
@@ -687,7 +691,7 @@
687 return None691 return None
688692
689 remote_bug = query.get('id')693 remote_bug = query.get('id')
690 if remote_bug is None:694 if remote_bug is None or not remote_bug.isdigit():
691 return None695 return None
692696
693 tracker_path = path_match.groupdict()['base_path']697 tracker_path = path_match.groupdict()['base_path']
@@ -708,9 +712,8 @@
708 if not bugtracker_data:712 if not bugtracker_data:
709 continue713 continue
710 base_url, remote_bug = bugtracker_data714 base_url, remote_bug = bugtracker_data
711 bugtrackerset = getUtility(IBugTrackerSet)
712 # Check whether we have a registered bug tracker already.715 # Check whether we have a registered bug tracker already.
713 bugtracker = bugtrackerset.queryByBaseURL(base_url)716 bugtracker = getUtility(IBugTrackerSet).queryByBaseURL(base_url)
714717
715 if bugtracker is not None:718 if bugtracker is not None:
716 return bugtracker, remote_bug719 return bugtracker, remote_bug
717720
=== modified file 'lib/lp/bugs/tests/test_bugwatch.py'
--- lib/lp/bugs/tests/test_bugwatch.py 2012-08-08 07:23:58 +0000
+++ lib/lp/bugs/tests/test_bugwatch.py 2012-10-09 06:00:12 +0000
@@ -1,4 +1,4 @@
1# Copyright 2009-2010 Canonical Ltd. This software is licensed under the1# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Tests for BugWatchSet."""4"""Tests for BugWatchSet."""
@@ -9,6 +9,7 @@
9 datetime,9 datetime,
10 timedelta,10 timedelta,
11 )11 )
12import re
12import unittest13import unittest
13from urlparse import urlunsplit14from urlparse import urlunsplit
1415
@@ -122,6 +123,14 @@
122 self.fail(123 self.fail(
123 "NoBugTrackerFound wasn't raised by extractBugTrackerAndBug")124 "NoBugTrackerFound wasn't raised by extractBugTrackerAndBug")
124125
126 def test_invalid_bug_number(self):
127 # Replace the second digit of the remote bug id with an E, which all
128 # parsers will reject as invalid.
129 invalid_url = re.sub(r'(\d)\d', r'\1E', self.bug_url, count=1)
130 self.assertRaises(
131 UnrecognizedBugTrackerURL,
132 self.bugwatch_set.extractBugTrackerAndBug, invalid_url)
133
125134
126class MantisExtractBugTrackerAndBugTest(135class MantisExtractBugTrackerAndBugTest(
127 ExtractBugTrackerAndBugTestBase, unittest.TestCase):136 ExtractBugTrackerAndBugTestBase, unittest.TestCase):
@@ -339,6 +348,10 @@
339 self.bugwatch_set.extractBugTrackerAndBug,348 self.bugwatch_set.extractBugTrackerAndBug,
340 url='this\.is@@a.bad.email.address')349 url='this\.is@@a.bad.email.address')
341350
351 def test_invalid_bug_number(self):
352 # Test does not make sense for email addresses.
353 pass
354
342355
343class PHPProjectBugTrackerExtractBugTrackerAndBugTest(356class PHPProjectBugTrackerExtractBugTrackerAndBugTest(
344 ExtractBugTrackerAndBugTestBase, unittest.TestCase):357 ExtractBugTrackerAndBugTestBase, unittest.TestCase):