]>
Commit | Line | Data |
---|---|---|
f6e6ff79 MT |
1 | #!/usr/bin/python |
2 | ||
f6e6ff79 MT |
3 | import xmlrpclib |
4 | ||
2c909128 | 5 | from . import base |
f6e6ff79 | 6 | |
cc05687f MT |
7 | from .decorators import * |
8 | ||
f6e6ff79 MT |
9 | class 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 | |
86 | class 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) |