Changeset 52645 in webkit
- Timestamp:
- Dec 29, 2009 10:46:22 PM (14 years ago)
- Location:
- trunk/WebKitTools
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebKitTools/ChangeLog
r52644 r52645 1 2009-12-29 Eric Seidel <eric@webkit.org> 2 3 Reviewed by Adam Barth. 4 5 Split out BugzillaQueries class from Bugzilla 6 https://bugs.webkit.org/show_bug.cgi?id=33042 7 8 * Scripts/modules/bugzilla.py: 9 - Split out BugzillaQueries from Bugzilla. 10 - Try to isolate self.bugzilla usage into helper functions whenever possible. 11 - Add a bunch of FIXMEs. 12 - Rename fetch_bug_ids_from_needs_commit_list to fetch_bug_ids_from_pending_commit_list 13 * Scripts/modules/bugzilla_unittest.py: 14 - Create a new BugzillaQueriesTest testcase and move logic there. 15 * Scripts/modules/buildsteps_unittest.py: 16 - Use Bug 75 instead of 1 since bug 1 doesn't actually exist. 17 * Scripts/modules/commands/queries.py: 18 - Update to use bugzilla.queries 19 * Scripts/modules/commands/queues.py: 20 - Ditto. 21 * Scripts/modules/commands/upload.py: 22 - Ditto. 23 * Scripts/modules/mock_bugzillatool.py: 24 - Add a MockBugzillaQueries. 25 - Make patches and bugs global privates. 26 - Let _id_to_object_dictionary take a variable argument list instead of an array. 27 1 28 2009-12-29 Daniel Bates <dbates@webkit.org> 2 29 -
trunk/WebKitTools/Scripts/modules/bugzilla.py
r52642 r52645 82 82 83 83 84 # A container for all of the logic for making a parsing buzilla queries. 85 class BugzillaQueries(object): 86 def __init__(self, bugzilla): 87 self.bugzila = bugzilla 88 89 def _load_query(self, query): 90 full_url = "%s%s" % (self.bugzilla.bug_server_url, query) 91 return self.bugzilla.browser.open(full_url) 92 93 def _fetch_bug_ids_advanced_query(self, query): 94 soup = BeautifulSoup(self._load_query(query)) 95 # The contents of the <a> inside the cells in the first column happen to be the bug id. 96 return [int(bug_link_cell.find("a").string) for bug_link_cell in soup('td', "first-child")] 97 98 def _parse_attachment_ids_request_query(self, page): 99 digits = re.compile("\d+") 100 attachment_href = re.compile("attachment.cgi\?id=\d+&action=review") 101 attachment_links = SoupStrainer("a", href=attachment_href) 102 return [int(digits.search(tag["href"]).group(0)) for tag in BeautifulSoup(page, parseOnlyThese=attachment_links)] 103 104 def _fetch_attachment_ids_request_query(self, query): 105 return self._parse_attachment_ids_request_query(self._load_query(query)) 106 107 # List of all r+'d bugs. 108 def fetch_bug_ids_from_pending_commit_list(self): 109 needs_commit_query_url = "buglist.cgi?query_format=advanced&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=flagtypes.name&type0-0-0=equals&value0-0-0=review%2B" 110 return self._fetch_bug_ids_advanced_query(needs_commit_query_url) 111 112 def fetch_patches_from_pending_commit_list(self): 113 # FIXME: This should not have to go through self.bugzilla 114 return sum([self.bugzilla.fetch_reviewed_patches_from_bug(bug_id) for bug_id in self.fetch_bug_ids_from_pending_commit_list()], []) 115 116 def fetch_bug_ids_from_commit_queue(self): 117 commit_queue_url = "buglist.cgi?query_format=advanced&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=flagtypes.name&type0-0-0=equals&value0-0-0=commit-queue%2B" 118 return self._fetch_bug_ids_advanced_query(commit_queue_url) 119 120 def fetch_patches_from_commit_queue(self, reject_invalid_patches=False): 121 # FIXME: Once reject_invalid_patches is moved out of this function this becomes a simple list comprehension using fetch_bug_ids_from_commit_queue. 122 patches_to_land = [] 123 for bug_id in self.fetch_bug_ids_from_commit_queue(): 124 # FIXME: This should not have to go through self.bugzilla 125 patches = self.bugzilla.fetch_commit_queue_patches_from_bug(bug_id, reject_invalid_patches) 126 patches_to_land += patches 127 return patches_to_land 128 129 def _fetch_bug_ids_from_review_queue(self): 130 review_queue_url = "buglist.cgi?query_format=advanced&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=flagtypes.name&type0-0-0=equals&value0-0-0=review?" 131 return self._fetch_bug_ids_advanced_query(review_queue_url) 132 133 def fetch_patches_from_review_queue(self, limit=None): 134 # FIXME: We should probably have a self.fetch_bug to minimize the number of self.bugzilla calls. 135 return sum([self.bugzilla.fetch_bug(bug_id).unreviewed_patches() for bug_id in self._fetch_bug_ids_from_review_queue()[:limit]], []) # [:None] returns the whole array. 136 137 # FIXME: Why do we have both fetch_patches_from_review_queue and fetch_attachment_ids_from_review_queue?? 138 # NOTE: This is also the only client of _fetch_attachment_ids_request_query 139 def fetch_attachment_ids_from_review_queue(self): 140 review_queue_url = "request.cgi?action=queue&type=review&group=type" 141 return self._fetch_attachment_ids_request_query(review_queue_url) 142 143 84 144 class Bugzilla(object): 85 145 def __init__(self, dryrun=False, committers=CommitterList()): 86 146 self.dryrun = dryrun 87 147 self.authenticated = False 148 self.queries = BugzillaQueries(self) 88 149 89 150 # FIXME: We should use some sort of Browser mock object when in dryrun mode (to prevent any mistakes). … … 252 313 return commit_queue_patches 253 314 254 def _fetch_bug_ids_advanced_query(self, query):255 page = self.browser.open(query)256 soup = BeautifulSoup(page)257 # The contents of the <a> inside the cells in the first column happen to be the bug id.258 return [int(bug_link_cell.find("a").string) for bug_link_cell in soup('td', "first-child")]259 260 def _parse_attachment_ids_request_query(self, page):261 digits = re.compile("\d+")262 attachment_href = re.compile("attachment.cgi\?id=\d+&action=review")263 attachment_links = SoupStrainer("a", href=attachment_href)264 return [int(digits.search(tag["href"]).group(0)) for tag in BeautifulSoup(page, parseOnlyThese=attachment_links)]265 266 def _fetch_attachment_ids_request_query(self, query):267 return self._parse_attachment_ids_request_query(self.browser.open(query))268 269 def fetch_bug_ids_from_commit_queue(self):270 commit_queue_url = self.bug_server_url + "buglist.cgi?query_format=advanced&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=flagtypes.name&type0-0-0=equals&value0-0-0=commit-queue%2B"271 return self._fetch_bug_ids_advanced_query(commit_queue_url)272 273 # List of all r+'d bugs.274 def fetch_bug_ids_from_needs_commit_list(self):275 needs_commit_query_url = self.bug_server_url + "buglist.cgi?query_format=advanced&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=flagtypes.name&type0-0-0=equals&value0-0-0=review%2B"276 return self._fetch_bug_ids_advanced_query(needs_commit_query_url)277 278 def fetch_bug_ids_from_review_queue(self):279 review_queue_url = self.bug_server_url + "buglist.cgi?query_format=advanced&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=flagtypes.name&type0-0-0=equals&value0-0-0=review?"280 return self._fetch_bug_ids_advanced_query(review_queue_url)281 282 def fetch_attachment_ids_from_review_queue(self):283 review_queue_url = self.bug_server_url + "request.cgi?action=queue&type=review&group=type"284 return self._fetch_attachment_ids_request_query(review_queue_url)285 286 def fetch_patches_from_commit_queue(self, reject_invalid_patches=False):287 patches_to_land = []288 for bug_id in self.fetch_bug_ids_from_commit_queue():289 patches = self.fetch_commit_queue_patches_from_bug(bug_id, reject_invalid_patches)290 patches_to_land += patches291 return patches_to_land292 293 def fetch_patches_from_pending_commit_list(self):294 return sum([self.fetch_reviewed_patches_from_bug(bug_id) for bug_id in self.fetch_bug_ids_from_needs_commit_list()], [])295 296 def fetch_patches_from_review_queue(self, limit=None):297 return sum([self.fetch_bug(bug_id).unreviewed_patches() for bug_id in self.fetch_bug_ids_from_review_queue()[:limit]], []) # [:None] returns the whole array.298 299 315 def authenticate(self): 300 316 if self.authenticated: -
trunk/WebKitTools/Scripts/modules/bugzilla_unittest.py
r52641 r52645 30 30 31 31 from modules.committers import CommitterList, Reviewer, Committer 32 from modules.bugzilla import Bugzilla, parse_bug_id32 from modules.bugzilla import Bugzilla, BugzillaQueries, parse_bug_id 33 33 from modules.outputcapture import OutputCapture 34 34 … … 224 224 self.assertEquals(27314, bugzilla._parse_bug_id_from_attachment_page(self._sample_attachment_detail_page)) 225 225 226 def test_add_cc_to_bug(self): 227 bugzilla = Bugzilla() 228 bugzilla.browser = MockBrowser() 229 bugzilla.authenticate = lambda: None 230 expected_stderr = "Adding ['adam@example.com'] to the CC list for bug 42\n" 231 OutputCapture().assert_outputs(self, bugzilla.add_cc_to_bug, [42, ["adam@example.com"]], expected_stderr=expected_stderr) 232 233 def test_flag_permission_rejection_message(self): 234 bugzilla = Bugzilla() 235 expected_messsage="""foo@foo.com does not have review permissions according to http://trac.webkit.org/browser/trunk/WebKitTools/Scripts/modules/committers.py. 236 237 - If you do not have review rights please read http://webkit.org/coding/contributing.html for instructions on how to use bugzilla flags. 238 239 - If you have review rights please correct the error in WebKitTools/Scripts/modules/committers.py by adding yourself to the file (no review needed). Due to bug 30084 the commit-queue will require a restart after your change. Please contact eseidel@chromium.org to request a commit-queue restart. After restart the commit-queue will correctly respect your review rights.""" 240 self.assertEqual(bugzilla._flag_permission_rejection_message("foo@foo.com", "review"), expected_messsage) 241 242 243 class BugzillaQueriesTest(unittest.TestCase): 226 244 _sample_request_page = """ 227 245 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" … … 272 290 273 291 def test_request_page_parsing(self): 274 bugzilla = Bugzilla() 275 self.assertEquals([40511, 40722, 40723], bugzilla._parse_attachment_ids_request_query(self._sample_request_page)) 276 277 def test_add_cc_to_bug(self): 278 bugzilla = Bugzilla() 279 bugzilla.browser = MockBrowser() 280 bugzilla.authenticate = lambda: None 281 expected_stderr = "Adding ['adam@example.com'] to the CC list for bug 42\n" 282 OutputCapture().assert_outputs(self, bugzilla.add_cc_to_bug, [42, ["adam@example.com"]], expected_stderr=expected_stderr) 283 284 def test_flag_permission_rejection_message(self): 285 bugzilla = Bugzilla() 286 expected_messsage="""foo@foo.com does not have review permissions according to http://trac.webkit.org/browser/trunk/WebKitTools/Scripts/modules/committers.py. 287 288 - If you do not have review rights please read http://webkit.org/coding/contributing.html for instructions on how to use bugzilla flags. 289 290 - If you have review rights please correct the error in WebKitTools/Scripts/modules/committers.py by adding yourself to the file (no review needed). Due to bug 30084 the commit-queue will require a restart after your change. Please contact eseidel@chromium.org to request a commit-queue restart. After restart the commit-queue will correctly respect your review rights.""" 291 self.assertEqual(bugzilla._flag_permission_rejection_message("foo@foo.com", "review"), expected_messsage) 292 292 queries = BugzillaQueries(None) 293 self.assertEquals([40511, 40722, 40723], queries._parse_attachment_ids_request_query(self._sample_request_page)) 293 294 294 295 if __name__ == '__main__': -
trunk/WebKitTools/Scripts/modules/buildsteps_unittest.py
r52640 r52645 39 39 capture = OutputCapture() 40 40 step = UpdateChangeLogsWithReviewerStep(MockBugzillaTool(), []) 41 expected_stderr = "0 reviewed patches on bug 1, cannot infer reviewer.\n"42 capture.assert_outputs(self, step._guess_reviewer_from_bug, [ 1], expected_stderr=expected_stderr)41 expected_stderr = "0 reviewed patches on bug 75, cannot infer reviewer.\n" 42 capture.assert_outputs(self, step._guess_reviewer_from_bug, [75], expected_stderr=expected_stderr) 43 43 44 44 -
trunk/WebKitTools/Scripts/modules/commands/queries.py
r52295 r52645 44 44 45 45 def execute(self, options, args, tool): 46 bug_ids = tool.bugs. fetch_bug_ids_from_commit_queue()46 bug_ids = tool.bugs.queries.fetch_bug_ids_from_commit_queue() 47 47 for bug_id in bug_ids: 48 48 print "%s" % bug_id … … 55 55 56 56 def execute(self, options, args, tool): 57 patches = tool.bugs. fetch_patches_from_commit_queue()57 patches = tool.bugs.queries.fetch_patches_from_commit_queue() 58 58 log("Patches in commit queue:") 59 59 for patch in patches: … … 83 83 84 84 def execute(self, options, args, tool): 85 patches = tool.bugs. fetch_patches_from_pending_commit_list()85 patches = tool.bugs.queries.fetch_patches_from_pending_commit_list() 86 86 patches_needing_cq = filter(self._needs_commit_queue, patches) 87 87 if options.bugs: … … 101 101 102 102 def execute(self, options, args, tool): 103 patch_ids = tool.bugs. fetch_attachment_ids_from_review_queue()103 patch_ids = tool.bugs.queries.fetch_attachment_ids_from_review_queue() 104 104 log("Patches pending review:") 105 105 for patch_id in patch_ids: -
trunk/WebKitTools/Scripts/modules/commands/queues.py
r52430 r52645 134 134 135 135 def next_work_item(self): 136 patches = self.tool.bugs. fetch_patches_from_commit_queue(reject_invalid_patches=True)136 patches = self.tool.bugs.queries.fetch_patches_from_commit_queue(reject_invalid_patches=True) 137 137 if not patches: 138 138 self._update_status("Empty queue") … … 188 188 189 189 def fetch_potential_patch_ids(self): 190 return self.tool.bugs. fetch_attachment_ids_from_review_queue()190 return self.tool.bugs.queries.fetch_attachment_ids_from_review_queue() 191 191 192 192 def status_server(self): -
trunk/WebKitTools/Scripts/modules/commands/upload.py
r52641 r52645 84 84 85 85 def execute(self, options, args, tool): 86 for bug_id in tool.bugs. fetch_bug_ids_from_needs_commit_list():86 for bug_id in tool.bugs.queries.fetch_bug_ids_from_pending_commit_list(): 87 87 self._assign_bug_to_last_patch_attacher(bug_id) 88 88 -
trunk/WebKitTools/Scripts/modules/mock_bugzillatool.py
r52641 r52645 33 33 from modules.bugzilla import Bug 34 34 35 def _id_to_object_dictionary( objects):35 def _id_to_object_dictionary(*objects): 36 36 dictionary = {} 37 37 for thing in objects: … … 39 39 return dictionary 40 40 41 class MockBugzilla(Mock): 42 patch1 = { 43 "id" : 197, 44 "bug_id" : 42, 45 "url" : "http://example.com/197", 46 "is_obsolete" : False, 47 "reviewer" : "Reviewer1", 48 "attacher_email" : "Contributer1", 49 } 50 patch2 = { 51 "id" : 128, 52 "bug_id" : 42, 53 "url" : "http://example.com/128", 54 "is_obsolete" : False, 55 "reviewer" : "Reviewer2", 56 "attacher_email" : "eric@webkit.org", 57 } 58 bug_server_url = "http://example.com" 59 unassigned_email = "unassigned@example.com" 60 41 # FIXME: The ids shoudl be 1, 2, 3 instead of crazy numbers. 42 _patch1 = { 43 "id" : 197, 44 "bug_id" : 42, 45 "url" : "http://example.com/197", 46 "is_obsolete" : False, 47 "is_patch" : True, 48 "reviewer" : "Reviewer1", 49 "attacher_email" : "Contributer1", 50 } 51 _patch2 = { 52 "id" : 128, 53 "bug_id" : 42, 54 "url" : "http://example.com/128", 55 "is_obsolete" : False, 56 "is_patch" : True, 57 "reviewer" : "Reviewer2", 58 "attacher_email" : "eric@webkit.org", 59 } 60 61 # This must be defined before we define the bugs, thus we don't use MockBugzilla.unassigned_email directly. 62 _unassigned_email = "unassigned@example.com" 63 64 # FIXME: The ids should be 1, 2, 3 instead of crazy numbers. 65 _bug1 = { 66 "id" : 42, 67 "assigned_to_email" : _unassigned_email, 68 "attachments" : [_patch1, _patch2], 69 } 70 _bug2 = { 71 "id" : 75, 72 "assigned_to_email" : "foo@foo.com", 73 "attachments" : [], 74 } 75 _bug3 = { 76 "id" : 76, 77 "assigned_to_email" : _unassigned_email, 78 "attachments" : [], 79 } 80 81 class MockBugzillaQueries(Mock): 61 82 def fetch_bug_ids_from_commit_queue(self): 62 83 return [42, 75] … … 66 87 67 88 def fetch_patches_from_commit_queue(self, reject_invalid_patches=False): 68 return [ self.patch1, self.patch2]69 70 def fetch_bug_ids_from_ needs_commit_list(self):89 return [_patch1, _patch2] 90 91 def fetch_bug_ids_from_pending_commit_list(self): 71 92 return [42, 75, 76] 72 73 bug1 = { 74 "id" : 42, 75 "assigned_to_email" : unassigned_email, 76 "attachments" : [patch1, patch2], 77 } 78 bug2 = { 79 "id" : 75, 80 "assigned_to_email" : "foo@foo.com", 81 "attachments" : [], 82 } 83 bug3 = { 84 "id" : 76, 85 "assigned_to_email" : unassigned_email, 86 "attachments" : [], 87 } 88 89 bug_cache = _id_to_object_dictionary([bug1, bug2, bug3]) 93 94 def fetch_patches_from_pending_commit_list(self): 95 return [_patch1, _patch2] 96 97 98 class MockBugzilla(Mock): 99 bug_server_url = "http://example.com" 100 unassigned_email = _unassigned_email 101 bug_cache = _id_to_object_dictionary(_bug1, _bug2, _bug3) 102 attachment_cache = _id_to_object_dictionary(_patch1, _patch2) 103 queries = MockBugzillaQueries() 90 104 91 105 def fetch_bug(self, bug_id): 92 106 return Bug(self.bug_cache.get(bug_id)) 93 107 94 def fetch_patches_from_pending_commit_list(self):95 return [self.patch1, self.patch2]96 97 108 def fetch_reviewed_patches_from_bug(self, bug_id): 98 if bug_id == 42: 99 return [self.patch1, self.patch2] 100 return [] 101 109 return self.fetch_patches_from_bug(bug_id) # Return them all for now. 110 111 def fetch_attachment(self, attachment_id): 112 return self.attachment_cache[attachment_id] # This could be changed to .get() if we wish to allow failed lookups. 113 114 # NOTE: Functions below this are direct copies from bugzilla.py 102 115 def fetch_patches_from_bug(self, bug_id): 103 if bug_id == 42: 104 return [self.patch1, self.patch2] 105 return None 106 107 def fetch_attachment(self, attachment_id): 108 if attachment_id == 197: 109 return self.patch1 110 if attachment_id == 128: 111 return self.patch2 112 raise Exception("Bogus attachment_id in fetch_attachment.") 113 116 return self.fetch_bug(bug_id).patches() 117 114 118 def bug_url_for_bug_id(self, bug_id): 115 119 return "%s/%s" % (self.bug_server_url, bug_id)
Note: See TracChangeset
for help on using the changeset viewer.