]> git.ipfire.org Git - people/jschlag/pbs.git/blame - src/buildservice/bugtracker.py
Merge branch 'master' of git://git.ipfire.org/pbs
[people/jschlag/pbs.git] / src / buildservice / bugtracker.py
CommitLineData
f6e6ff79
MT
1#!/usr/bin/python
2
f6e6ff79
MT
3import xmlrpclib
4
2c909128 5from . import base
f6e6ff79 6
cc05687f
MT
7from .decorators import *
8
f6e6ff79
MT
9class BugzillaBug(base.Object):
10 def __init__(self, bugzilla, bug_id):
11 base.Object.__init__(self, bugzilla.pakfire)
12 self.bugzilla = bugzilla
13
14 self.bug_id = bug_id
15 self._data = None
16
17 def __cmp__(self, other):
18 return cmp(self.bug_id, other.bug_id)
19
20 def call(self, *args, **kwargs):
21 args = (("Bug",) + args)
22
23 return self.bugzilla.call(*args, **kwargs)
24
25 @property
26 def id(self):
27 return self.bug_id
28
cc05687f 29 @lazy_property
f6e6ff79 30 def data(self):
cc05687f
MT
31 # Fetch bug information from cache
32 data = self.backend.cache.get(self._cache_key)
33
34 # Hit
35 if data:
36 return data
37
38 # Fetch bug information from Bugzilla
39 for data in self.call("get", ids=[self.id,])["bugs"]:
40 # Put it into the cache
41 self.backend.cache.set(self._cache_key, data, self.backend.bugzilla.cache_lifetime)
f6e6ff79 42
cc05687f
MT
43 return data
44
45 @property
46 def _cache_key(self):
47 return "bug-%s" % self.bug_id
f6e6ff79
MT
48
49 @property
50 def url(self):
51 return self.bugzilla.bug_url(self.id)
52
53 @property
54 def summary(self):
55 return self.data.get("summary")
56
57 @property
58 def assignee(self):
59 return self.data.get("assigned_to")
60
61 @property
62 def status(self):
63 return self.data.get("status")
64
65 @property
66 def resolution(self):
67 return self.data.get("resolution")
68
69 @property
70 def is_closed(self):
71 return not self.data["is_open"]
72
73 def set_status(self, status, resolution=None, comment=None):
74 kwargs = { "status" : status }
75 if resolution:
76 kwargs["resolution"] = resolution
77 if comment:
78 kwargs["comment"] = { "body" : comment }
79
80 self.call("update", ids=[self.id,], **kwargs)
f6e6ff79 81
cc05687f
MT
82 # Invalidate cache
83 self.backend.cache.delete(self.cache_key)
84
f6e6ff79
MT
85
86class Bugzilla(base.Object):
87 def __init__(self, pakfire):
88 base.Object.__init__(self, pakfire)
89
90 # Open the connection to the server.
91 self.server = xmlrpclib.ServerProxy(self.url, use_datetime=True)
92
93 # Cache the credentials.
94 self.__credentials = {
95 "Bugzilla_login" : self.user,
96 "Bugzilla_password" : self.password,
97 }
98
99 def call(self, *args, **kwargs):
100 # Add authentication information.
101 kwargs.update(self.__credentials)
102
103 method = self.server
104 for arg in args:
105 method = getattr(method, arg)
106
107 return method(kwargs)
108
1aae140a 109 def bug_url(self, bug_id):
f6e6ff79
MT
110 url = self.settings.get("bugzilla_url", None)
111
1aae140a 112 return url % { "bug_id" : bug_id }
f6e6ff79
MT
113
114 def enter_url(self, component):
115 args = {
116 "product" : self.settings.get("bugzilla_product", ""),
117 "component" : component,
118 }
119
120 url = self.settings.get("bugzilla_url_new")
121
122 return url % args
123
124 def buglist_url(self, component):
125 args = {
126 "product" : self.settings.get("bugzilla_product", ""),
127 "component" : component,
128 }
129
130 url = self.settings.get("bugzilla_url_buglist")
131
132 return url % args
133
134 @property
135 def url(self):
136 return self.settings.get("bugzilla_url_xmlrpc", None)
137
138 @property
139 def user(self):
140 return self.settings.get("bugzilla_xmlrpc_user", "")
141
142 @property
143 def password(self):
144 return self.settings.get("bugzilla_xmlrpc_password")
145
cc05687f
MT
146 @lazy_property
147 def cache_lifetime(self):
148 return self.settings.get("bugzilla_cache_lifetime", 3600)
149
f6e6ff79
MT
150 def get_bug(self, bug_id):
151 try:
152 bug = BugzillaBug(self, bug_id)
f6e6ff79
MT
153
154 except xmlrpclib.Fault:
155 return None
156
157 return bug
158
159 def find_users(self, pattern):
966498de
MT
160 users = self.call("User", "get", match=[pattern,])
161 if users:
162 return users["users"]
f6e6ff79
MT
163
164 def find_user(self, pattern):
165 users = self.find_users(pattern)
166
167 if not users:
168 return
169
170 elif len(users) > 1:
171 raise Exception, "Got more than one result."
172
173 return users[0]
174
175 def get_bugs_from_component(self, component, closed=False):
176 kwargs = {
177 "product" : self.settings.get("bugzilla_product", ""),
178 "component" : component,
179 }
180
181 query = self.call("Bug", "search", include_fields=["id"], **kwargs)
182
183 bugs = []
184 for bug in query["bugs"]:
185 bug = self.get_bug(bug["id"])
186
187 if not bug.is_closed == closed:
188 continue
189
190 bugs.append(bug)
191
192 return bugs
76353712
MT
193
194 def send_all(self, limit=100):
195 # Get up to ten updates.
196 query = self.db.query("SELECT * FROM builds_bugs_updates \
197 WHERE error IS FALSE ORDER BY time LIMIT %s", limit)
198
199 # XXX CHECK IF BZ IS ACTUALLY REACHABLE AND WORKING
200
201 for update in query:
202 try:
203 bug = self.backend.bugzilla.get_bug(update.bug_id)
204 if not bug:
205 logging.error("Bug #%s does not exist." % update.bug_id)
206 continue
207
208 # Set the changes.
209 bug.set_status(update.status, update.resolution, update.comment)
210
211 except Exception, e:
212 # If there was an error, we save that and go on.
213 self.db.execute("UPDATE builds_bugs_updates SET error = 'Y', error_msg = %s \
214 WHERE id = %s", "%s" % e, update.id)
215
216 else:
217 # Remove the update when it has been done successfully.
218 self.db.execute("DELETE FROM builds_bugs_updates WHERE id = %s", update.id)