Launchpad Import now imports multi-project bugs.

This patch does two thigns: First it removes the on-disk imported
stories cache, so that a story found for a different project may be
imported and assigned to that project as well. Secondly, it adds
additional filtering to check for story tasks in the associated
project, so that new tasks may also be added.

Also adds more human-readable output.

Change-Id: I49c0a96e25fab41926030e5bd34fdd7fe1b5b7ae
This commit is contained in:
Michael Krotscheck
2014-11-12 15:44:32 -08:00
parent 6fb2cf9039
commit a2caad3f20
2 changed files with 37 additions and 46 deletions

View File

@@ -12,9 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import shelve
import tempfile
from storyboard.migrate.launchpad.reader import LaunchpadReader
from storyboard.migrate.launchpad.writer import LaunchpadWriter
@@ -23,45 +20,38 @@ class LaunchpadLoader(object):
def __init__(self, from_project, to_project):
"""Create a new loader instance from launchpad.org
"""
tmp_dir = tempfile.gettempdir()
self.cache = shelve.open("%s/launchpad_migrate.db" % (tmp_dir))
self.writer = LaunchpadWriter(to_project)
self.reader = LaunchpadReader(from_project)
def run(self):
for lp_bug in self.reader:
bug = lp_bug.bug
cache_key = str(unicode(bug.self_link))
if cache_key not in self.cache:
# Preload the tags.
tags = self.writer.write_tags(bug)
# Preload the tags.
tags = self.writer.write_tags(bug)
# Preload the story owner.
owner = self.writer.write_user(bug.owner)
# Preload the story owner.
owner = self.writer.write_user(bug.owner)
# Preload the story's assignee (stored on lp_bug, not bug).
if hasattr(lp_bug, 'assignee') and lp_bug.assignee:
assignee = self.writer.write_user(lp_bug.assignee)
else:
assignee = None
# Preload the story's assignee (stored on lp_bug, not bug).
if hasattr(lp_bug, 'assignee') and lp_bug.assignee:
assignee = self.writer.write_user(lp_bug.assignee)
else:
assignee = None
# Preload the story discussion participants.
for message in bug.messages:
self.writer.write_user(message.owner)
# Preload the story discussion participants.
for message in bug.messages:
self.writer.write_user(message.owner)
# Write the bug.
priority = map_lp_priority(lp_bug.importance)
status = map_lp_status(lp_bug.status)
story = self.writer.write_bug(bug=bug,
owner=owner,
assignee=assignee,
priority=priority,
status=status,
tags=tags)
# Cache things.
self.cache[cache_key] = story.id
# Write the bug.
priority = map_lp_priority(lp_bug.importance)
status = map_lp_status(lp_bug.status)
self.writer.write_bug(bug=bug,
owner=owner,
assignee=assignee,
priority=priority,
status=status,
tags=tags)
def map_lp_priority(lp_priority):

View File

@@ -169,8 +169,6 @@ class LaunchpadWriter(object):
return
launchpad_id = int(url_match.groups()[0])
print "Importing %s" % (bug.self_link,)
# If the title is too long, prepend it to the description and
# truncate it.
title = bug.title
@@ -193,18 +191,22 @@ class LaunchpadWriter(object):
}
duplicate = db_api.entity_get(Story, launchpad_id)
if not duplicate:
print "Importing Story: %s" % (bug.self_link,)
story = db_api.entity_create(Story, story)
else:
story = db_api.entity_update(Story, launchpad_id, story)
print "Existing Story: %s" % (bug.self_link,)
story = duplicate
# Duplicate check- launchpad import creates one task per story,
# so if we already have a task on this story, skip it. This is to
# properly replay imports in the case where errors occurred during
# import.
# so if we already have a project task on this story, skip it. This
# is to properly replay imports in the case where errors occurred
# during import.
existing_task = db_api.model_query(Task) \
.filter(Task.story_id == launchpad_id) \
.filter(Task.project_id == self.project.id) \
.first()
if not existing_task:
print "- Adding task in project %s" % (self.project.name,)
task = db_api.entity_create(Task, {
'title': title,
'assignee_id': assignee.id if assignee else None,
@@ -216,6 +218,7 @@ class LaunchpadWriter(object):
'status': status
})
else:
print "- Existing task in %s" % (self.project.name,)
task = existing_task
# Duplication Check - If this story already has a creation event,
@@ -226,6 +229,7 @@ class LaunchpadWriter(object):
.filter(TimeLineEvent.event_type == event_types.STORY_CREATED) \
.first()
if not story_created_event:
print "- Generating story creation event"
db_api.entity_create(TimeLineEvent, {
'story_id': launchpad_id,
'author_id': owner.id,
@@ -233,13 +237,10 @@ class LaunchpadWriter(object):
'created_at': created_at
})
# Create the creation event for the task, assuming it doesn't
# exist yet.
task_created_event = db_api.model_query(TimeLineEvent) \
.filter(TimeLineEvent.story_id == launchpad_id) \
.filter(TimeLineEvent.event_type == event_types.TASK_CREATED) \
.first()
if not task_created_event:
# Create the creation event for the task, but only if we just created
# a new task.
if not existing_task:
print "- Generating task creation event"
db_api.entity_create(TimeLineEvent, {
'story_id': launchpad_id,
'author_id': owner.id,
@@ -257,6 +258,8 @@ class LaunchpadWriter(object):
.filter(TimeLineEvent.event_type == event_types.USER_COMMENT) \
.count()
desired_count = len(bug.messages)
print "- %s of %s comments already imported." % (current_count,
desired_count)
for i in range(current_count, desired_count):
print '- Importing comment %s of %s' % (i + 1, desired_count)
message = bug.messages[i]
@@ -276,5 +279,3 @@ class LaunchpadWriter(object):
'comment_id': comment.id,
'created_at': message_created_at
})
return story