1
by Martin Pool
Baby steps towards bug dashboard |
1 |
#! /usr/bin/python
|
2 |
||
3 |
import collections |
|
4 |
import os.path |
|
5 |
import subprocess |
|
6 |
import sys |
|
7 |
||
8 |
import launchpadlib |
|
9 |
from launchpadlib.credentials import Credentials |
|
10 |
||
11 |
from launchpadlib.launchpad import ( |
|
12 |
Launchpad, STAGING_SERVICE_ROOT, |
|
13 |
EDGE_SERVICE_ROOT, |
|
14 |
)
|
|
15 |
||
2.1.2
by Martin Pool
Start splitting out hydrazine helpers |
16 |
import hydrazine |
17 |
||
1
by Martin Pool
Baby steps towards bug dashboard |
18 |
service_root = EDGE_SERVICE_ROOT |
2.1.2
by Martin Pool
Start splitting out hydrazine helpers |
19 |
|
1
by Martin Pool
Baby steps towards bug dashboard |
20 |
project_name = 'bzr' |
21 |
||
22 |
||
2.1.2
by Martin Pool
Start splitting out hydrazine helpers |
23 |
|
1
by Martin Pool
Baby steps towards bug dashboard |
24 |
def run_external(args): |
25 |
sys.stderr.write(">> %s\n" % args) |
|
2.1.8
by Martin Pool
Fix up for splitout of hydrazine library |
26 |
rc = subprocess.call(args) |
27 |
if rc != 0: |
|
1
by Martin Pool
Baby steps towards bug dashboard |
28 |
sys.stderr.write("failed %s!" % rc) |
29 |
raise AssertionError() |
|
30 |
||
31 |
||
32 |
def trace(s): |
|
33 |
sys.stderr.write(s + '\n') |
|
34 |
||
35 |
||
36 |
lplib_cachedir = os.path.expanduser("~/.cache/launchpadlib/") |
|
37 |
hydrazine_cachedir = os.path.expanduser("~/.cache/hydrazine/") |
|
38 |
rrd_dir = os.path.expanduser("~/.cache/hydrazine/rrd") |
|
39 |
for d in [lplib_cachedir, hydrazine_cachedir, rrd_dir]: |
|
40 |
if not os.path.isdir(d): |
|
41 |
os.makedirs(d, mode=0700) |
|
42 |
||
4
by Martin Pool
Refactor capture-bug-counts |
43 |
|
2
by Martin Pool
Clean up code into concept of bug categories |
44 |
def create_session(): |
45 |
hydrazine_credentials_filename = os.path.join(hydrazine_cachedir, |
|
46 |
'credentials') |
|
47 |
if os.path.exists(hydrazine_credentials_filename): |
|
48 |
credentials = Credentials() |
|
49 |
credentials.load(file( |
|
50 |
os.path.expanduser("~/.cache/hydrazine/credentials"), |
|
51 |
"r")) |
|
52 |
trace('loaded existing credentials') |
|
53 |
return Launchpad(credentials, service_root, |
|
54 |
lplib_cachedir) |
|
55 |
# TODO: handle the case of having credentials that have expired etc
|
|
56 |
else: |
|
57 |
launchpad = Launchpad.get_token_and_login( |
|
58 |
'Hydrazine', |
|
59 |
service_root, |
|
60 |
lplib_cachedir) |
|
61 |
trace('saving credentials...') |
|
62 |
launchpad.credentials.save(file( |
|
63 |
hydrazine_credentials_filename, |
|
64 |
"w")) |
|
65 |
return launchpad |
|
66 |
||
67 |
def get_project(): |
|
68 |
sys.stderr.write('getting project... ') |
|
69 |
project = launchpad.projects[project_name] |
|
70 |
sys.stderr.write('%s (%s)\n' % (project.name, project.title)) |
|
71 |
return project |
|
72 |
||
73 |
||
74 |
class BugCategory(object): |
|
75 |
"""Holds a set of logically-related bugs"""
|
|
76 |
||
77 |
def __init__(self): |
|
78 |
self.bugs = set() |
|
79 |
||
80 |
def add(self, bt): |
|
81 |
self.bugs.add(bt) |
|
82 |
||
3
by Martin Pool
Refactor into canned queries |
83 |
def count_bugs(self): |
2
by Martin Pool
Clean up code into concept of bug categories |
84 |
return len(self.bugs) |
85 |
||
86 |
def get_link_url(self): |
|
87 |
return None |
|
88 |
||
89 |
||
90 |
class HasPatchBugCategory(BugCategory): |
|
91 |
||
92 |
def get_name(self): |
|
93 |
return 'HasPatch' |
|
94 |
||
95 |
def get_link_url(self): |
|
96 |
return 'https://bugs.edge.launchpad.net/%s/+bugs' \ |
|
97 |
'?search=Search&field.has_patch=on' \
|
|
98 |
% (project_name) |
|
99 |
||
100 |
||
101 |
class StatusBugCategory(BugCategory): |
|
102 |
||
103 |
def __init__(self, status): |
|
104 |
BugCategory.__init__(self) |
|
105 |
self.status = status |
|
106 |
||
107 |
def get_name(self): |
|
108 |
return self.status |
|
109 |
||
110 |
def get_link_url(self): |
|
111 |
return 'https://bugs.edge.launchpad.net/%s/+bugs?search=Search&field.status=%s' \ |
|
112 |
% (project_name, self.status) |
|
113 |
||
114 |
||
3
by Martin Pool
Refactor into canned queries |
115 |
class CannedQuery(object): |
116 |
||
117 |
def __init__(self, project): |
|
118 |
self.project = project |
|
119 |
||
4
by Martin Pool
Refactor capture-bug-counts |
120 |
def _run_query(self, from_collection): |
121 |
sys.stderr.write(self.get_name()) |
|
7
by Martin Pool
Show all bugs in query |
122 |
for bt in from_collection: |
4
by Martin Pool
Refactor capture-bug-counts |
123 |
yield bt |
124 |
sys.stderr.write('.') |
|
125 |
sys.stderr.write('\n') |
|
126 |
||
3
by Martin Pool
Refactor into canned queries |
127 |
def show_text(self): |
128 |
# print self.get_name()
|
|
129 |
for category in self.query_categories(): |
|
130 |
print '%6d %s %s' % (category.count_bugs(), |
|
131 |
category.get_name(), |
|
132 |
category.get_link_url() or '') |
|
133 |
print
|
|
134 |
||
135 |
||
136 |
class PatchCannedQuery(CannedQuery): |
|
137 |
||
138 |
def get_collection(self): |
|
139 |
return self.project.searchTasks(has_patch=True) |
|
140 |
||
141 |
def get_name(self): |
|
142 |
return 'Bugs with patches' |
|
143 |
||
144 |
def query_categories(self): |
|
145 |
has_patches = HasPatchBugCategory() |
|
4
by Martin Pool
Refactor capture-bug-counts |
146 |
for bt in self._run_query( |
147 |
self.project.searchTasks(has_patch=True)): |
|
148 |
has_patches.add(bt) |
|
3
by Martin Pool
Refactor into canned queries |
149 |
return [has_patches] |
150 |
||
151 |
||
152 |
class StatusCannedQuery(CannedQuery): |
|
153 |
||
154 |
def get_name(self): |
|
155 |
return 'By Status' |
|
156 |
||
157 |
def query_categories(self): |
|
4
by Martin Pool
Refactor capture-bug-counts |
158 |
by_status = {} |
159 |
for bugtask in self._run_query(self.project.searchTasks()): |
|
160 |
if bugtask.status not in by_status: |
|
161 |
by_status[bugtask.status] = StatusBugCategory(bugtask.status) |
|
162 |
by_status[bugtask.status].add(bugtask) |
|
163 |
return by_status.values() |
|
3
by Martin Pool
Refactor into canned queries |
164 |
|
165 |
||
166 |
def show_bug_report(project): |
|
167 |
for query_class in StatusCannedQuery, PatchCannedQuery: |
|
168 |
query_class(project).show_text() |
|
2
by Martin Pool
Clean up code into concept of bug categories |
169 |
|
170 |
||
2.1.8
by Martin Pool
Fix up for splitout of hydrazine library |
171 |
launchpad = hydrazine.create_session() |
2
by Martin Pool
Clean up code into concept of bug categories |
172 |
project = get_project() |
3
by Martin Pool
Refactor into canned queries |
173 |
show_bug_report(project) |