Merge lp:~ursinha/shadow-database/add-milestone-distro-distroseries into lp:shadow-database
- add-milestone-distro-distroseries
- Merge into trunk
Proposed by
Ursula Junque
Status: | Merged |
---|---|
Merge reported by: | Chris J Arges |
Merged at revision: | not available |
Proposed branch: | lp:~ursinha/shadow-database/add-milestone-distro-distroseries |
Merge into: | lp:shadow-database |
Prerequisite: | lp:~ursinha/shadow-database/pep8-compliant-stuff |
Diff against target: |
444 lines (+225/-33) 4 files modified
ShadowDatabase/lp.py (+11/-1) ShadowDatabase/models.py (+34/-7) ShadowDatabase/sql.py (+171/-19) database/tables.sql (+9/-6) |
To merge this branch: | bzr merge lp:~ursinha/shadow-database/add-milestone-distro-distroseries |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Chris J Arges | Pending | ||
Review via email: mp+143596@code.launchpad.net |
Commit message
Description of the change
Implements add_milestone, add_distro, add_distroseries and also handles when an user is gone or merged in launchpad, that was causing the script to fail and abort.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'ShadowDatabase/lp.py' |
2 | --- ShadowDatabase/lp.py 2013-01-16 21:43:19 +0000 |
3 | +++ ShadowDatabase/lp.py 2013-01-16 21:43:19 +0000 |
4 | @@ -77,11 +77,21 @@ |
5 | try: |
6 | search_json = self.get_json_from_link(search_link) |
7 | break |
8 | - except (NotFound, HTTPError, ClientError, ServerError): |
9 | + except ClientError, e: |
10 | + response_status = e.response["status"] |
11 | + if response_status == '410': |
12 | + self.logger.error("Object %s is gone." % search_link) |
13 | + raise |
14 | + if response_status == '404': |
15 | + self.logger.error("Object %s not found." % search_link) |
16 | + raise |
17 | + continue |
18 | + except (NotFound, HTTPError, ServerError), e: |
19 | continue |
20 | pass |
21 | except Exception, e: |
22 | self.logger.error("Unexpected exception: %s" % str(e)) |
23 | + self.logger.exception(e) |
24 | pass |
25 | |
26 | return search_json |
27 | |
28 | === modified file 'ShadowDatabase/models.py' |
29 | --- ShadowDatabase/models.py 2013-01-16 21:43:19 +0000 |
30 | +++ ShadowDatabase/models.py 2013-01-16 21:43:19 +0000 |
31 | @@ -8,6 +8,7 @@ |
32 | from storm.locals import Int |
33 | from storm.expr import SQL |
34 | from datetime import datetime |
35 | +from pytz import UTC |
36 | import dateutil.parser |
37 | |
38 | |
39 | @@ -29,6 +30,7 @@ |
40 | series_target = IntCol() |
41 | target = IntCol() |
42 | release = IntCol() |
43 | + self_link = StringCol() |
44 | |
45 | |
46 | class Person(object): |
47 | @@ -46,6 +48,29 @@ |
48 | private = BoolCol(notNull=True, default=False,) |
49 | irc_nicknames = StringCol() |
50 | is_team = BoolCol(notNull=True, default=False,) |
51 | + is_gone = BoolCol(notNull=True, default=False,) |
52 | + |
53 | + def __init__(self): |
54 | + pass |
55 | + |
56 | + |
57 | +class MissingPerson(Person): |
58 | + |
59 | + def __init__(self, person_link): |
60 | + super(MissingPerson, self).__init__() |
61 | + # The only thing we have is the name, because of the link. |
62 | + self.name = self.display_name = "".join(person_link.split("~")[1:]) |
63 | + self.date_created = datetime.utcnow().replace(tzinfo=UTC) |
64 | + self.hide_email_addresses = True |
65 | + self.private = False |
66 | + self.is_team = False |
67 | + self.is_valid = False |
68 | + if not self.is_merged: |
69 | + self.is_gone = True |
70 | + |
71 | + @property |
72 | + def is_merged(self): |
73 | + return "merged" in self.name |
74 | |
75 | |
76 | class Bug(object): |
77 | @@ -125,6 +150,7 @@ |
78 | web_link = StringCol(notNull=True,) |
79 | name = StringCol(notNull=True,) |
80 | display_name = StringCol(notNull=True,) |
81 | + target_type = StringCol(notNull=True,) |
82 | |
83 | |
84 | class Bugtracker(object): |
85 | @@ -235,13 +261,13 @@ |
86 | self.date_left_closed = parseDate(json['date_left_closed']) |
87 | self.date_left_new = parseDate(json['date_left_new']) |
88 | self.date_triaged = parseDate(json['date_triaged']) |
89 | - # self.milestone = 0 # FIXME |
90 | + self.milestone = sql.add_milestone(json['milestone_link']) |
91 | self.owner = sql.add_person(json['owner_link']) |
92 | self.status = sql.lp.StatusMap[json['status']] |
93 | self.importance = (sql.lp.ImportanceMap[json['importance']]) |
94 | self.target = sql.add_bug_target(json['target_link']) # FIXME |
95 | self.bug_target_name = json['bug_target_name'] |
96 | - # self.bug_watch = 0 # FIXME |
97 | + # self.bug_watch = sql.add_bug_watch(json['bug_watch_link']) |
98 | |
99 | def update(self, db): |
100 | # FIXME: there has to be a better way. |
101 | @@ -284,10 +310,10 @@ |
102 | display_name = StringCol(notNull=True,) |
103 | summary = StringCol(notNull=True,) |
104 | bug_supervisor = IntCol() |
105 | - security_contact = IntCol() |
106 | driver = IntCol() |
107 | current_series = IntCol() |
108 | date_created = UtcDateTimeCol(notNull=True,) |
109 | + self_link = StringCol(notNull=True,) |
110 | |
111 | |
112 | class Sourcepackage(object): |
113 | @@ -316,15 +342,15 @@ |
114 | sourcepackage = IntCol() |
115 | |
116 | |
117 | -class Distroseries(object): |
118 | +class DistroSeries(object): |
119 | __storm_table__ = "distroseries" |
120 | id = Int(primary=True,) |
121 | owner = IntCol() |
122 | registrant = IntCol() |
123 | status = StringCol() |
124 | name = StringCol() |
125 | - display_name = StringCol() |
126 | - full_series_name = StringCol() |
127 | + displayname = StringCol() |
128 | + fullseriesname = StringCol() |
129 | summary = StringCol() |
130 | supported = BoolCol(notNull=True, default=False,) |
131 | title = StringCol() |
132 | @@ -333,7 +359,8 @@ |
133 | component_names = StringCol() |
134 | distribution = IntCol() |
135 | date_created = UtcDateTimeCol(notNull=True,) |
136 | - date_released = UtcDateTimeCol() |
137 | + datereleased = UtcDateTimeCol() |
138 | + self_link = StringCol(notNull=True,) |
139 | |
140 | |
141 | class Distrosourcepackage(object): |
142 | |
143 | === modified file 'ShadowDatabase/sql.py' |
144 | --- ShadowDatabase/sql.py 2013-01-16 21:43:19 +0000 |
145 | +++ ShadowDatabase/sql.py 2013-01-16 21:43:19 +0000 |
146 | @@ -15,6 +15,8 @@ |
147 | import json |
148 | |
149 | from datetime import datetime |
150 | +from lazr.restfulclient.errors import ClientError |
151 | +from pytz import UTC |
152 | from ShadowDatabase.lp import LP |
153 | from ShadowDatabase.models import * |
154 | from storm.expr import * |
155 | @@ -154,6 +156,8 @@ |
156 | bug_target.web_link = bug_target_json['web_link'] |
157 | bug_target.name = bug_target_json['name'] |
158 | bug_target.display_name = bug_target_json['display_name'] |
159 | + target_type = bug_target_json['resource_type_link'].split("#")[1] |
160 | + bug_target.target_type = target_type |
161 | |
162 | # Add the object. |
163 | self.store.add(bug_target) |
164 | @@ -171,12 +175,142 @@ |
165 | ret_str = ",".join(list(set(ret))) |
166 | return ",".join(ret) |
167 | |
168 | + def add_bug_watch(self, bug_watch_link): |
169 | + # TODO: implement this |
170 | + pass |
171 | + |
172 | + def add_milestone(self, milestone_link): |
173 | + if milestone_link is None: |
174 | + return None |
175 | + |
176 | + # Get milestone id and check if it exists: |
177 | + result = self.store.find(Milestone, |
178 | + Milestone.self_link == milestone_link).one() |
179 | + if result: |
180 | + return result.id |
181 | + |
182 | + milestone_json = self.lp.check_and_fetch_json(milestone_link) |
183 | + if milestone_json is None: |
184 | + return 0 |
185 | + |
186 | + milestone = Milestone() |
187 | + milestone.name = milestone_json["name"] |
188 | + milestone.code_name = milestone_json["code_name"] |
189 | + milestone.title = milestone_json["title"] |
190 | + # milestone.release = self.add_release(milestone_json["release_link"]) |
191 | + milestone.is_active = milestone_json["is_active"] |
192 | + milestone.summary = milestone_json["summary"] |
193 | + milestone.target = self.add_distro(milestone_json["target_link"]) |
194 | + milestone.series_target = self.add_distroseries( |
195 | + milestone_json["series_target_link"]) |
196 | + milestone.self_link = milestone_json["self_link"] |
197 | + milestone.official_bug_tags = ",".join( |
198 | + milestone_json["official_bug_tags"]) |
199 | + try: |
200 | + date_targeted = milestone.date_targeted = self.parseDate( |
201 | + milestone_json["date_targeted"]) |
202 | + except ValueError: |
203 | + date_targeted = self.parseDate( |
204 | + milestone_json["date_targeted"]).replace(tzinfo=UTC) |
205 | + milestone.date_targeted = date_targeted |
206 | + |
207 | + # Add the object. |
208 | + self.store.add(milestone) |
209 | + self.store.flush() |
210 | + self.logger.debug("MILESTONE: %s ... added." % str(milestone.name)) |
211 | + return milestone.id |
212 | + |
213 | + def add_distro(self, distro_link): |
214 | + if distro_link is None: |
215 | + return None |
216 | + |
217 | + result = self.store.find(Distribution, |
218 | + Distribution.self_link == distro_link).one() |
219 | + |
220 | + if result: |
221 | + return result.id |
222 | + |
223 | + distro_json = self.lp.check_and_fetch_json(distro_link) |
224 | + if distro_json is None: |
225 | + return 0 |
226 | + |
227 | + distro = Distribution() |
228 | + distro.name = distro_json["name"] |
229 | + distro.title = distro_json["title"] |
230 | + distro.description = distro_json["description"] |
231 | + distro.owner = self.add_person(distro_json["owner_link"]) |
232 | + distro.display_name = distro_json["display_name"] |
233 | + distro.summary = distro_json["summary"] |
234 | + distro.bug_supervisor = self.add_person( |
235 | + distro_json["bug_supervisor_link"]) |
236 | + distro.driver = self.add_person(distro_json["driver_link"]) |
237 | + distro.date_created = self.parseDate(distro_json["date_created"]) |
238 | + distro.self_link = distro_json["self_link"] |
239 | + |
240 | + # Add the object. |
241 | + self.store.add(distro) |
242 | + self.store.flush() |
243 | + # Have to add the distro after adding the distroseries to avoid |
244 | + # circular dependency. |
245 | + distro.current_series = self.add_distroseries( |
246 | + distro_json["current_series_link"]) |
247 | + self.store.commit() |
248 | + |
249 | + self.logger.debug("DISTRO: %s ... added." % str(distro.name)) |
250 | + return distro.id |
251 | + |
252 | + def add_distroseries(self, distroseries_link): |
253 | + if distroseries_link is None: |
254 | + return None |
255 | + |
256 | + result = self.store.find( |
257 | + DistroSeries, DistroSeries.self_link == distroseries_link).one() |
258 | + |
259 | + if result: |
260 | + return result.id |
261 | + |
262 | + distroseries_json = self.lp.check_and_fetch_json(distroseries_link) |
263 | + if distroseries_json is None: |
264 | + return 0 |
265 | + |
266 | + distroseries = DistroSeries() |
267 | + distroseries.name = distroseries_json["name"] |
268 | + distroseries.owner = self.add_person(distroseries_json["owner_link"]) |
269 | + distroseries.registrant = self.add_person( |
270 | + distroseries_json["registrant_link"]) |
271 | + distroseries.status = distroseries_json["status"] |
272 | + distroseries.displayname = distroseries_json["displayname"] |
273 | + distroseries.fullseriesname = distroseries_json["fullseriesname"] |
274 | + distroseries.summary = distroseries_json["summary"] |
275 | + distroseries.supported = distroseries_json["supported"] |
276 | + distroseries.title = distroseries_json["title"] |
277 | + distroseries.version = distroseries_json["version"] |
278 | + distroseries.suite_names = ",".join(distroseries_json["suite_names"]) |
279 | + distroseries.component_names = ",".join( |
280 | + distroseries_json["component_names"]) |
281 | + distroseries.distribution = self.add_distro( |
282 | + distroseries_json["distribution_link"]) |
283 | + distroseries.date_created = self.parseDate( |
284 | + distroseries_json["date_created"]) |
285 | + distroseries.date_released = self.parseDate( |
286 | + distroseries_json["datereleased"]) |
287 | + distroseries.self_link = distroseries_json["self_link"] |
288 | + |
289 | + # Add the object. |
290 | + self.store.add(distroseries) |
291 | + self.store.flush() |
292 | + self.logger.debug("DISTROSERIES: %s ... added." % str( |
293 | + distroseries.name)) |
294 | + return distroseries.id |
295 | + |
296 | def add_person(self, person_link): |
297 | if person_link is None: |
298 | return None |
299 | |
300 | # Quickly get the username by taking the end of the URL. |
301 | person_name = person_link.split('~')[1] |
302 | + person_is_gone = False |
303 | + person_is_merged = False |
304 | result = self.store.find(Person, Person.name == person_name).one() |
305 | if result: |
306 | # self.logger.debug("PERSON: %s ... skipping (exists)." % |
307 | @@ -186,26 +320,44 @@ |
308 | return result.id |
309 | |
310 | # if the person wasn't found lets add it |
311 | - person_json = self.lp.check_and_fetch_json(person_link) |
312 | - if person_json is None: |
313 | + person_json = None |
314 | + try: |
315 | + person_json = self.lp.check_and_fetch_json(person_link) |
316 | + except ClientError, e: |
317 | + # If user is no longer available, was deactivated or deleted |
318 | + # because it is spam, we have to add it anyway, marking on the |
319 | + # table it's gone. |
320 | + response_status = e.response["status"] |
321 | + if response_status == '410': |
322 | + # Oops, user is no more |
323 | + person_is_gone = True |
324 | + if response_status == '404': |
325 | + # User not found (was merged or hidden -- spammer) |
326 | + if "merged" in person_name: |
327 | + person_is_merged = True |
328 | + |
329 | + if person_is_gone or person_is_merged: |
330 | + person = MissingPerson(person_link) |
331 | + self.logger.debug("PERSON: %s ... is gone." % str(person.name)) |
332 | + elif person_json is None: |
333 | return 0 |
334 | - |
335 | - person = Person() |
336 | - person.display_name = person_json['display_name'] |
337 | - if 'description' in person_json.keys(): |
338 | - person.description = person_json['description'] |
339 | - person.name = person_json['name'] |
340 | - person.date_created = self.parseDate(person_json['date_created']) |
341 | - person.hide_email_addresses = person_json['hide_email_addresses'] |
342 | - person.preferred_mail_address_id = 0 # FIXME |
343 | - person.is_valid = person_json['is_valid'] |
344 | - person.private = person_json['private'] |
345 | - person.irc_nicknames = self.parse_irc_nicknames_collection( |
346 | - person_json['irc_nicknames_collection_link']) |
347 | - person.is_team = person_json['is_team'] |
348 | - person.karma = person_json['karma'] |
349 | - if person.is_team: |
350 | - person.owner = self.add_person(person_json['team_owner_link']) |
351 | + else: |
352 | + person = Person() |
353 | + person.display_name = person_json['display_name'] |
354 | + if 'description' in person_json.keys(): |
355 | + person.description = person_json['description'] |
356 | + person.name = person_json['name'] |
357 | + person.date_created = self.parseDate(person_json['date_created']) |
358 | + person.hide_email_addresses = person_json['hide_email_addresses'] |
359 | + person.preferred_mail_address_id = 0 # FIXME |
360 | + person.is_valid = person_json['is_valid'] |
361 | + person.private = person_json['private'] |
362 | + person.irc_nicknames = self.parse_irc_nicknames_collection( |
363 | + person_json['irc_nicknames_collection_link']) |
364 | + person.is_team = person_json['is_team'] |
365 | + person.karma = person_json['karma'] |
366 | + if person.is_team: |
367 | + person.owner = self.add_person(person_json['team_owner_link']) |
368 | |
369 | # Add the object. |
370 | self.store.add(person) |
371 | |
372 | === modified file 'database/tables.sql' |
373 | --- database/tables.sql 2012-10-17 18:52:52 +0000 |
374 | +++ database/tables.sql 2013-01-16 21:43:19 +0000 |
375 | @@ -9,6 +9,7 @@ |
376 | series_target integer, |
377 | target integer, |
378 | release integer, |
379 | + self_link text NOT NULL, |
380 | PRIMARY KEY (id) |
381 | ); |
382 | |
383 | @@ -24,6 +25,7 @@ |
384 | hide_email_addresses boolean DEFAULT false NOT NULL, |
385 | preferred_mail_address integer, |
386 | is_valid boolean, |
387 | + is_gone boolean DEFAULT false NOT NULL, |
388 | private boolean DEFAULT false NOT NULL, |
389 | irc_nicknames text, |
390 | is_team boolean DEFAULT false NOT NULL, |
391 | @@ -64,6 +66,7 @@ |
392 | web_link text NOT NULL, |
393 | name text NOT NULL, |
394 | display_name text NOT NULL, |
395 | + target_type text NOT NULL, |
396 | PRIMARY KEY (id) |
397 | ); |
398 | |
399 | @@ -124,7 +127,7 @@ |
400 | web_link text, |
401 | PRIMARY KEY (id), |
402 | FOREIGN KEY (bug) REFERENCES bug(id), |
403 | - FOREIGN KEY (message) REFERENCES bugmessage(id), |
404 | + FOREIGN KEY (message) REFERENCES bugmessage(id) |
405 | ); |
406 | |
407 | CREATE TABLE bugstatus ( |
408 | @@ -238,14 +241,13 @@ |
409 | display_name text NOT NULL, |
410 | summary text NOT NULL, |
411 | bug_supervisor integer, |
412 | - security_contact integer, |
413 | driver integer, |
414 | current_series integer, |
415 | date_created timestamp without time zone NOT NULL, |
416 | + self_link text NOT NULL, |
417 | PRIMARY KEY (id), |
418 | FOREIGN KEY (owner) REFERENCES person(id), |
419 | FOREIGN KEY (bug_supervisor) REFERENCES person(id), |
420 | - FOREIGN KEY (security_contact) REFERENCES person(id), |
421 | FOREIGN KEY (driver) REFERENCES person(id) |
422 | ); |
423 | |
424 | @@ -285,8 +287,8 @@ |
425 | registrant integer, |
426 | status text, |
427 | name text, |
428 | - display_name text, |
429 | - full_series_name text, |
430 | + displayname text, |
431 | + fullseriesname text, |
432 | summary text, |
433 | supported boolean DEFAULT false NOT NULL, |
434 | title text, |
435 | @@ -295,7 +297,8 @@ |
436 | component_names text, |
437 | distribution integer, |
438 | date_created timestamp without time zone NOT NULL, |
439 | - date_released timestamp without time zone, |
440 | + datereleased timestamp without time zone, |
441 | + self_link text NOT NULL, |
442 | PRIMARY KEY (id), |
443 | FOREIGN KEY (distribution) REFERENCES distribution(id), |
444 | FOREIGN KEY (owner) REFERENCES person(id), |