OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/python |
| 2 |
| 3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. |
| 6 |
| 7 """Helper functions for accessing the issue tracker in a pythonic way.""" |
| 8 |
| 9 import os.path |
| 10 import pprint |
| 11 import sys |
| 12 |
| 13 # import the GData libraries |
| 14 import gdata.client |
| 15 import gdata.projecthosting.client |
| 16 |
| 17 DEFAULT_TRACKER_SOURCE = "chromite-tracker-access-1.0" |
| 18 VERBOSE = True # Set to True to get extra debug info... |
| 19 |
| 20 class TrackerAccess(object): |
| 21 """Class for accessing the tracker on code.google.com.""" |
| 22 |
| 23 def __init__(self, email="", password="", |
| 24 tracker_source=DEFAULT_TRACKER_SOURCE): |
| 25 """TrackerAccess constructor. |
| 26 |
| 27 Args: |
| 28 email: The email address to Login with; may be "" for anonymous access. |
| 29 password: The password that goes with the email address; may be "" if |
| 30 the email is "". |
| 31 tracker_source: A string describing this program. This can be anything |
| 32 you like but should should give some indication of which |
| 33 app is making the request. |
| 34 """ |
| 35 # Save parameters... |
| 36 self._email = email |
| 37 self._password = password |
| 38 self._tracker_source = tracker_source |
| 39 |
| 40 # This will be initted on first login... |
| 41 self._tracker_client = None |
| 42 |
| 43 def Login(self): |
| 44 """Login, if needed. This may be safely called more than once. |
| 45 |
| 46 Commands will call this function as their first line, so the client |
| 47 of this class need not call it themselves unless trying to debug login |
| 48 problems. |
| 49 |
| 50 This function should be called even if we're accessing anonymously. |
| 51 """ |
| 52 # Bail immediately if we've already logged in... |
| 53 if self._tracker_client is not None: |
| 54 return |
| 55 |
| 56 self._tracker_client = gdata.projecthosting.client.ProjectHostingClient() |
| 57 if self._email and self._password: |
| 58 self._tracker_client.client_login(self._email, self._password, |
| 59 source=self._tracker_source, |
| 60 service="code", account_type='GOOGLE') |
| 61 |
| 62 def GetKeyedLabels(self, project_name, issue_id): |
| 63 """Get labels of the form "Key-Value" attached to the given issue. |
| 64 |
| 65 Any labels that don't have a dash in them are ignored. |
| 66 |
| 67 Args: |
| 68 project_name: The tracker project to query. |
| 69 issue_id: The ID of the issue to query; should be an int but a string |
| 70 will probably work too. |
| 71 |
| 72 Returns: |
| 73 A dictionary mapping key/value pairs from the issue's labels, like: |
| 74 |
| 75 {'Area': 'Build', |
| 76 'Iteration': '15', |
| 77 'Mstone': 'R9.x', |
| 78 'Pri': '1', |
| 79 'Type': 'Bug'} |
| 80 """ |
| 81 # Login if needed... |
| 82 self.Login() |
| 83 |
| 84 # Construct the query... |
| 85 query = gdata.projecthosting.client.Query(issue_id=issue_id) |
| 86 try: |
| 87 feed = self._tracker_client.get_issues(project_name, query=query) |
| 88 except gdata.client.RequestError, e: |
| 89 if VERBOSE: |
| 90 print >>sys.stderr, "ERROR: Unable to access bug %s:%s: %s" % ( |
| 91 project_name, issue_id, str(e)) |
| 92 return {} |
| 93 |
| 94 # There should be exactly one result... |
| 95 assert len(feed.entry) == 1, "Expected exactly 1 result" |
| 96 (entry,) = feed.entry |
| 97 |
| 98 # We only care about labels that look like: Key-Value |
| 99 # We'll return a dictionary of those. |
| 100 keyed_labels = {} |
| 101 for label in entry.label: |
| 102 if "-" in label.text: |
| 103 label_key, label_val = label.text.split("-", 1) |
| 104 keyed_labels[label_key] = label_val |
| 105 |
| 106 return keyed_labels |
| 107 |
| 108 |
| 109 def _TestGetKeyedLabels(project_name, email, passwordFile, *bug_ids): |
| 110 """Test code for GetKeyedLabels(). |
| 111 |
| 112 Args: |
| 113 project_name: The name of the project we're looking at. |
| 114 email: The email address to use to login. May be "" |
| 115 passwordFile: A file containing the password for the email address. |
| 116 May be "" if email is "" for anon access. |
| 117 bug_ids: A list of bug IDs to query. |
| 118 """ |
| 119 # If password was specified as a file, read it. |
| 120 if passwordFile: |
| 121 password = open(passwordFile, "r").read().strip() |
| 122 else: |
| 123 password = "" |
| 124 |
| 125 ta = TrackerAccess(email, password) |
| 126 |
| 127 if not bug_ids: |
| 128 print "No bugs were specified" |
| 129 else: |
| 130 for bug_id in bug_ids: |
| 131 print bug_id, ta.GetKeyedLabels(project_name, int(bug_id)) |
| 132 |
| 133 |
| 134 def _DoHelp(commands, *args): |
| 135 """Print help for the script.""" |
| 136 |
| 137 if len(args) >= 2 and args[0] == "help" and args[1] in commands: |
| 138 # If called with arguments 'help' and 'command', show that commands's doc. |
| 139 command_name = args[1] |
| 140 print commands[command_name].__doc__ |
| 141 else: |
| 142 # Something else: show generic help... |
| 143 print ( |
| 144 "Usage %s <command> <command args>\n" |
| 145 "\n" |
| 146 "Known commands: \n" |
| 147 " %s\n" |
| 148 ) % (sys.argv[0], pprint.pformat(["help"] + sorted(commands))) |
| 149 |
| 150 |
| 151 def main(): |
| 152 """Main function of the script.""" |
| 153 |
| 154 commands = { |
| 155 "TestGetKeyedLabels": _TestGetKeyedLabels, |
| 156 } |
| 157 |
| 158 if len(sys.argv) <= 1 or sys.argv[1] not in commands: |
| 159 # Argument 1 isn't in list of commands; show help and pass all arguments... |
| 160 _DoHelp(commands, *sys.argv[1:]) |
| 161 else: |
| 162 command_name = sys.argv[1] |
| 163 commands[command_name](*sys.argv[2:]) |
| 164 |
| 165 if __name__ == "__main__": |
| 166 main() |
OLD | NEW |