1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Utility functions to query the chromium issue tracker.
7 Note that documentation for the Issue Tracker API says it's DEPRECATED, however
8 it seems to be in use in other places like the performance dashboard. Also,
9 this module attempts to handle most exceptions thrown by querying the tracker
10 so that when and if this api is turned off no impact is caused to the bisection
16 SINGLE_ISSUE_URL
= ('https://code.google.com/feeds/issues/p/chromium/issues'
17 '/full?id=%s&alt=json')
20 class IssueTrackerQueryException(Exception):
24 def QuerySingleIssue(issue_id
, url_template
=SINGLE_ISSUE_URL
):
25 """Queries the tracker for a specific issue. Returns a dict.
27 This uses the deprecated Issue Tracker API to fetch a JSON representation of
31 issue_id: An int or string representing the issue id.
32 url_template: URL to query the tracker with '%s' instead of the bug id.
35 A dictionary as parsed by the JSON library from the tracker response.
38 urllib2.HTTPError when appropriate.
40 assert str(issue_id
).isdigit()
41 response
= urllib2
.urlopen(url_template
% issue_id
).read()
42 return json
.loads(response
)
45 def GetIssueState(issue_id
):
46 """Returns either 'closed' or 'open' for the given bug ID.
49 issue_id: string or string-castable object containing a numeric bug ID.
51 'open' or 'closed' depending on the state of the bug.
53 IssueTrackerQueryException if the data cannot be retrieved or parsed.
56 query_response
= QuerySingleIssue(issue_id
)
57 # We assume the query returns a single result hence the [0]
58 issue_detail
= query_response
['feed']['entry'][0]
59 state
= issue_detail
['issues$state']['$t']
61 except urllib2
.URLError
:
62 raise IssueTrackerQueryException(
63 'Could not fetch the details form the issue tracker.')
65 raise IssueTrackerQueryException(
66 'Could not parse the issue tracker\'s response as a json doc.')
68 raise IssueTrackerQueryException(
69 'The data from the issue tracker is not in the expected format.')
72 def CheckIssueClosed(issue_id
):
73 """Checks if a given issue is closed. Returns False when in doubt."""
74 # We only check when issue_id appears to be valid
75 if str(issue_id
).isdigit():
77 return GetIssueState(issue_id
) == 'closed'
78 except IssueTrackerQueryException
:
79 # We let this fall through to the return False
81 # We return False for anything other than a positive number