← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~danilo/launchpad/bug-1000148 into lp:launchpad

 

Данило Шеган has proposed merging lp:~danilo/launchpad/bug-1000148 into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #1000148 in Launchpad itself: "Remove workitems migration script"
  https://bugs.launchpad.net/launchpad/+bug/1000148

For more details, see:
https://code.launchpad.net/~danilo/launchpad/bug-1000148/+merge/105962

= Bug 1000148: remove work items migration script =

Work items migration script has served its purpose: work items have been migrated from the whiteboard to the new dedicated DB objects for projects that wanted it (Ubuntu, in particular, didn't want it because they were close to a release, and they decided to just switch to the new fields for the next Ubuntu cycle).

We don't need this script anymore, so I'd like to remove it.  This should reduce the maintenance cost for LP significantly.

This basically reverts a few revisions that included work on the migration script: r14893, r14898, r14939.

= Tests =

Full test suite run.

= QA =

Test that the garbo job keeps running correctly.

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  database/schema/security.cfg
  lib/lp/scripts/garbo.py
  lib/lp/scripts/tests/test_garbo.py

-- 
https://code.launchpad.net/~danilo/launchpad/bug-1000148/+merge/105962
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~danilo/launchpad/bug-1000148 into lp:launchpad.
=== modified file 'database/schema/security.cfg'
--- database/schema/security.cfg	2012-05-09 13:50:03 +0000
+++ database/schema/security.cfg	2012-05-16 12:12:19 +0000
@@ -2169,13 +2169,11 @@
 public.codeimportevent                  = SELECT, DELETE
 public.codeimporteventdata              = SELECT, DELETE
 public.codeimportresult                 = SELECT, DELETE
-public.distribution                     = SELECT
 public.emailaddress                     = SELECT, UPDATE, DELETE
 public.hwsubmission                     = SELECT, UPDATE
 public.job                              = SELECT, INSERT, DELETE
 public.logintoken                       = SELECT, DELETE
 public.mailinglistsubscription          = SELECT, DELETE
-public.milestone                        = SELECT
 public.milestonetag                     = SELECT
 public.oauthnonce                       = SELECT, DELETE
 public.openidconsumerassociation        = SELECT, DELETE
@@ -2183,14 +2181,11 @@
 public.person                           = SELECT, DELETE
 public.potranslation                    = SELECT, DELETE
 public.potmsgset                        = SELECT, DELETE
-public.product                          = SELECT
 public.revisionauthor                   = SELECT, UPDATE
 public.revisioncache                    = SELECT, DELETE
 public.sourcepackagename                = SELECT
 public.sourcepackagerelease             = SELECT
 public.sourcepackagepublishinghistory   = SELECT, UPDATE
-public.specification                    = SELECT, UPDATE
-public.specificationworkitem            = SELECT, INSERT
 public.suggestivepotemplate             = INSERT, DELETE
 public.teamparticipation                = SELECT, DELETE
 public.translationmessage               = SELECT, DELETE

=== removed file 'lib/lp/blueprints/tests/test_workitem_migration.py'
--- lib/lp/blueprints/tests/test_workitem_migration.py	2012-03-22 23:21:24 +0000
+++ lib/lp/blueprints/tests/test_workitem_migration.py	1970-01-01 00:00:00 +0000
@@ -1,262 +0,0 @@
-# Copyright 2012 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-__metaclass__ = type
-
-from textwrap import dedent
-
-from testtools.matchers import MatchesStructure
-
-from lp.blueprints.enums import SpecificationWorkItemStatus
-from lp.blueprints.workitemmigration import (
-    extractWorkItemsFromWhiteboard,
-    WorkItemParseError,
-    WorkitemParser,
-    )
-from lp.testing import (
-    TestCase,
-    TestCaseWithFactory,
-    )
-from lp.testing.layers import DatabaseFunctionalLayer
-
-
-class FakeSpecification(object):
-    assignee = None
-
-
-class TestWorkItemParser(TestCase):
-
-    def test_parse_line_basic(self):
-        parser = WorkitemParser(FakeSpecification())
-        assignee, description, status = parser.parse_blueprint_workitem(
-            "A single work item: TODO")
-        self.assertEqual(
-            [None, "A single work item", SpecificationWorkItemStatus.TODO],
-            [assignee, description, status])
-
-    def test_parse_line_with_assignee(self):
-        parser = WorkitemParser(FakeSpecification())
-        assignee, description, status = parser.parse_blueprint_workitem(
-            "[salgado] A single work item: TODO")
-        self.assertEqual(
-            ["salgado", "A single work item",
-             SpecificationWorkItemStatus.TODO],
-            [assignee, description, status])
-
-    def test_parse_line_with_missing_closing_bracket_for_assignee(self):
-        parser = WorkitemParser(FakeSpecification())
-        self.assertRaises(
-            WorkItemParseError, parser.parse_blueprint_workitem,
-            "[salgado A single work item: TODO")
-
-    def test_parse_line_without_status(self):
-        parser = WorkitemParser(FakeSpecification())
-        assignee, description, status = parser.parse_blueprint_workitem(
-            "A single work item")
-        self.assertEqual(
-            [None, "A single work item", SpecificationWorkItemStatus.TODO],
-            [assignee, description, status])
-
-    def test_parse_line_with_invalid_status(self):
-        parser = WorkitemParser(FakeSpecification())
-        self.assertRaises(
-            WorkItemParseError, parser.parse_blueprint_workitem,
-            "A single work item: FOO")
-
-    def test_parse_line_without_description(self):
-        parser = WorkitemParser(FakeSpecification())
-        self.assertRaises(
-            WorkItemParseError, parser.parse_blueprint_workitem,
-            " : TODO")
-
-    def test_parse_line_with_completed_status(self):
-        parser = WorkitemParser(FakeSpecification())
-        assignee, description, status = parser.parse_blueprint_workitem(
-            "A single work item: Completed")
-        self.assertEqual(
-            [None, "A single work item", SpecificationWorkItemStatus.DONE],
-            [assignee, description, status])
-
-    def test_parse_line_with_inprogress_status(self):
-        parser = WorkitemParser(FakeSpecification())
-        assignee, description, status = parser.parse_blueprint_workitem(
-            "A single work item: INPROGRESS")
-        self.assertEqual(
-            [None, "A single work item",
-             SpecificationWorkItemStatus.INPROGRESS],
-            [assignee, description, status])
-
-    def test_parse_line_with_postpone_status(self):
-        parser = WorkitemParser(FakeSpecification())
-        assignee, description, status = parser.parse_blueprint_workitem(
-            "A single work item: POSTPONE")
-        self.assertEqual(
-            [None, "A single work item",
-             SpecificationWorkItemStatus.POSTPONED],
-            [assignee, description, status])
-
-    def test_parse_line_with_drop_status(self):
-        parser = WorkitemParser(FakeSpecification())
-        assignee, description, status = parser.parse_blueprint_workitem(
-            "A single work item: DROP")
-        self.assertEqual(
-            [None, "A single work item",
-             SpecificationWorkItemStatus.POSTPONED],
-            [assignee, description, status])
-
-    def test_parse_line_with_dropped_status(self):
-        parser = WorkitemParser(FakeSpecification())
-        assignee, description, status = parser.parse_blueprint_workitem(
-            "A single work item: DROPPED")
-        self.assertEqual(
-            [None, "A single work item",
-             SpecificationWorkItemStatus.POSTPONED],
-            [assignee, description, status])
-
-    def test_parse_empty_line(self):
-        parser = WorkitemParser(FakeSpecification())
-        self.assertRaises(
-            AssertionError, parser.parse_blueprint_workitem, "")
-
-
-class TestSpecificationWorkItemExtractionFromWhiteboard(TestCaseWithFactory):
-    layer = DatabaseFunctionalLayer
-
-    def test_None_whiteboard(self):
-        spec = self.factory.makeSpecification(whiteboard=None)
-        work_items = extractWorkItemsFromWhiteboard(spec)
-        self.assertEqual([], work_items)
-
-    def test_empty_whiteboard(self):
-        spec = self.factory.makeSpecification(whiteboard='')
-        work_items = extractWorkItemsFromWhiteboard(spec)
-        self.assertEqual([], work_items)
-
-    def test_single_work_item(self):
-        whiteboard = dedent("""
-            Work items:
-            A single work item: TODO
-            """)
-        spec = self.factory.makeSpecification(whiteboard=whiteboard)
-        work_items = extractWorkItemsFromWhiteboard(spec)
-        self.assertEqual(1, len(work_items))
-        self.assertThat(work_items[0], MatchesStructure.byEquality(
-            assignee=None, title="A single work item", milestone=None,
-            status=SpecificationWorkItemStatus.TODO, specification=spec))
-
-    def test_multiple_work_items(self):
-        whiteboard = dedent("""
-            Work items:
-            A single work item: TODO
-            Another work item: DONE
-            """)
-        spec = self.factory.makeSpecification(whiteboard=whiteboard)
-        work_items = extractWorkItemsFromWhiteboard(spec)
-        self.assertEqual(2, len(work_items))
-        self.assertThat(work_items[0], MatchesStructure.byEquality(
-            assignee=None, title="A single work item", milestone=None,
-            status=SpecificationWorkItemStatus.TODO, specification=spec))
-        self.assertThat(work_items[1], MatchesStructure.byEquality(
-            assignee=None, title="Another work item", milestone=None,
-            status=SpecificationWorkItemStatus.DONE, specification=spec))
-
-    def test_work_item_with_assignee(self):
-        person = self.factory.makePerson()
-        whiteboard = dedent("""
-            Work items:
-            [%s] A single work item: TODO
-            """ % person.name)
-        spec = self.factory.makeSpecification(whiteboard=whiteboard)
-        work_items = extractWorkItemsFromWhiteboard(spec)
-        self.assertEqual(1, len(work_items))
-        self.assertThat(work_items[0], MatchesStructure.byEquality(
-            assignee=person, title="A single work item", milestone=None,
-            status=SpecificationWorkItemStatus.TODO, specification=spec))
-
-    def test_work_item_with_nonexistent_assignee(self):
-        whiteboard = dedent("""
-            Work items:
-            [nonexistentperson] A single work item: TODO""")
-        spec = self.factory.makeSpecification(whiteboard=whiteboard)
-        self.assertRaises(ValueError, extractWorkItemsFromWhiteboard, spec)
-
-    def test_work_item_with_milestone(self):
-        milestone = self.factory.makeMilestone()
-        whiteboard = dedent("""
-            Work items for %s:
-            A single work item: TODO
-            """ % milestone.name)
-        spec = self.factory.makeSpecification(
-            whiteboard=whiteboard, product=milestone.product)
-        work_items = extractWorkItemsFromWhiteboard(spec)
-        self.assertEqual(1, len(work_items))
-        self.assertThat(work_items[0], MatchesStructure.byEquality(
-            assignee=None, title="A single work item", milestone=milestone,
-            status=SpecificationWorkItemStatus.TODO, specification=spec))
-
-    def test_work_item_with_inactive_milestone(self):
-        milestone = self.factory.makeMilestone(active=False)
-        whiteboard = dedent("""
-            Work items for %s:
-            A single work item: TODO
-            """ % milestone.name)
-        spec = self.factory.makeSpecification(
-            whiteboard=whiteboard, product=milestone.product)
-        work_items = extractWorkItemsFromWhiteboard(spec)
-        self.assertEqual(1, len(work_items))
-        self.assertThat(work_items[0], MatchesStructure.byEquality(
-            assignee=None, title="A single work item", milestone=milestone,
-            status=SpecificationWorkItemStatus.TODO, specification=spec))
-
-    def test_work_item_with_unknown_milestone(self):
-        whiteboard = dedent("""
-            Work items for foo:
-            A single work item: TODO
-            """)
-        spec = self.factory.makeSpecification(whiteboard=whiteboard)
-        self.assertRaises(
-            WorkItemParseError, extractWorkItemsFromWhiteboard, spec)
-
-    def test_blank_line_signals_end_of_work_item_block(self):
-        whiteboard = dedent("""
-            Work items:
-            A single work item: TODO
-
-            Some random notes about this BP.
-              * This is what was discussed during UDS
-              * Oh, yeah, we need to do that too
-            """)
-        spec = self.factory.makeSpecification(whiteboard=whiteboard)
-        work_items = extractWorkItemsFromWhiteboard(spec)
-        self.assertEqual(1, len(work_items))
-        self.assertThat(work_items[0], MatchesStructure.byEquality(
-            assignee=None, title="A single work item",
-            status=SpecificationWorkItemStatus.TODO, specification=spec))
-
-    def test_whiteboard_with_all_possible_sections(self):
-        whiteboard = dedent("""
-            Work items:
-            A single work item: TODO
-
-            Meta:
-            Headline: Foo bar
-            Acceptance: Baz foo
-
-            Complexity:
-            [user1] milestone1: 10
-            """)
-        spec = self.factory.makeSpecification(whiteboard=whiteboard)
-        work_items = extractWorkItemsFromWhiteboard(spec)
-        self.assertEqual(1, len(work_items))
-        self.assertThat(work_items[0], MatchesStructure.byEquality(
-            assignee=None, title="A single work item", milestone=None,
-            status=SpecificationWorkItemStatus.TODO, specification=spec))
-
-        # Now assert that the work items were removed from the whiteboard.
-        self.assertEqual(dedent("""
-            Meta:
-            Headline: Foo bar
-            Acceptance: Baz foo
-
-            Complexity:
-            [user1] milestone1: 10""").strip(), spec.whiteboard.strip())

=== removed file 'lib/lp/blueprints/workitemmigration.py'
--- lib/lp/blueprints/workitemmigration.py	2012-04-02 05:42:19 +0000
+++ lib/lp/blueprints/workitemmigration.py	1970-01-01 00:00:00 +0000
@@ -1,162 +0,0 @@
-# Copyright 2012 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Helper functions for the migration of work items from whiteboards to the
-SpecificationWorkItem table.
-
-This will be removed once the migration is done.
-"""
-
-__metaclass__ = type
-__all__ = [
-    'extractWorkItemsFromWhiteboard',
-    ]
-
-import re
-
-from zope.component import getUtility
-from zope.security.proxy import removeSecurityProxy
-
-from lp.blueprints.enums import SpecificationWorkItemStatus
-from lp.registry.interfaces.person import IPersonSet
-
-
-class WorkItemParseError(Exception):
-    """An error when parsing a work item line from a blueprint's whiteboard."""
-
-
-class WorkitemParser(object):
-    """A parser to extract work items from Blueprint whiteboards."""
-
-    def __init__(self, blueprint):
-        self.blueprint = blueprint
-
-    def _normalize_status(self, status, desc):
-        status = status.strip().lower()
-        if not status:
-            status = SpecificationWorkItemStatus.TODO
-        elif status == u'completed':
-            status = SpecificationWorkItemStatus.DONE
-        elif status in (u'postpone', u'dropped', u'drop'):
-            status = SpecificationWorkItemStatus.POSTPONED
-        else:
-            valid_statuses = SpecificationWorkItemStatus.items
-            if status not in [item.name.lower() for item in valid_statuses]:
-                raise WorkItemParseError('Unknown status: %s' % status)
-            return valid_statuses[status.upper()]
-        return status
-
-    def _parse_line(self, line):
-        try:
-            desc, status = line.rsplit(':', 1)
-        except ValueError:
-            desc = line
-            status = ""
-        assignee_name = None
-        if desc.startswith('['):
-            if ']' in desc:
-                off = desc.index(']')
-                assignee_name = desc[1:off]
-                desc = desc[off + 1:].strip()
-            else:
-                raise WorkItemParseError('Missing closing "]" for assignee')
-        return assignee_name, desc, status
-
-    def parse_blueprint_workitem(self, line):
-        line = line.strip()
-        assert line, "Please don't give us an empty line"
-        assignee_name, desc, status = self._parse_line(line)
-        if not desc:
-            raise WorkItemParseError(
-                'No work item description found on "%s"' % line)
-        status = self._normalize_status(status, desc)
-        return assignee_name, desc, status
-
-
-def milestone_extract(text, valid_milestones):
-    words = text.replace('(', ' ').replace(')', ' ').replace(
-        '[', ' ').replace(']', ' ').replace('<wbr />', '').split()
-    for milestone in valid_milestones:
-        for word in words:
-            if word == milestone.name:
-                return milestone
-    raise WorkItemParseError(
-        "No valid milestones found in %s. Valid milestone names are %s"
-        % (words, [m.name for m in valid_milestones]))
-
-
-def extractWorkItemsFromWhiteboard(spec):
-    work_items = []
-    if not spec.whiteboard:
-        return work_items
-    work_items_re = re.compile('^work items(.*)\s*:\s*$', re.I)
-    meta_re = re.compile('^Meta.*?:$', re.I)
-    complexity_re = re.compile('^Complexity.*?:$', re.I)
-    in_wi_block = False
-    new_whiteboard = []
-
-    target_milestones = list(spec.target.all_milestones)
-    wi_lines = []
-    # Iterate over all lines in the whiteboard and whenever we find a line
-    # matching work_items_re we 'continue' and store the following lines
-    # until we reach the end of the whiteboard or a line matching meta_re or
-    # complexity_re.
-    for line in spec.whiteboard.splitlines():
-        new_whiteboard.append(line)
-        wi_match = work_items_re.search(line)
-        if wi_match:
-            in_wi_block = True
-            milestone = None
-            milestone_part = wi_match.group(1).strip()
-            if milestone_part:
-                milestone = milestone_extract(
-                    milestone_part, target_milestones)
-            new_whiteboard.pop()
-            continue
-        if meta_re.search(line):
-            milestone = None
-            in_wi_block = False
-            continue
-        if complexity_re.search(line):
-            milestone = None
-            in_wi_block = False
-            continue
-
-        if not in_wi_block:
-            # We only care about work-item lines.
-            continue
-
-        if line.strip() == '':
-            # An empty line signals the end of the work-item block:
-            # https://wiki.ubuntu.com/WorkItemsHowto.
-            in_wi_block = False
-            milestone = None
-            continue
-
-        # This is a work-item line, which we don't want in the new
-        # whiteboard because we're migrating them into the
-        # SpecificationWorkItem table.
-        new_whiteboard.pop()
-
-        wi_lines.append((line, milestone))
-
-    # Now parse the work item lines and store them in SpecificationWorkItem.
-    parser = WorkitemParser(spec)
-    sequence = 0
-    for line, milestone in wi_lines:
-        assignee_name, title, status = parser.parse_blueprint_workitem(line)
-        if assignee_name is not None:
-            assignee_name = assignee_name.strip()
-            assignee = getUtility(IPersonSet).getByName(assignee_name)
-            if assignee is None:
-                raise ValueError("Unknown person name: %s" % assignee_name)
-        else:
-            assignee = None
-        workitem = removeSecurityProxy(spec).newWorkItem(
-            status=status, title=title, assignee=assignee,
-            milestone=milestone, sequence=sequence)
-        work_items.append(workitem)
-        sequence += 1
-
-    removeSecurityProxy(spec).whiteboard = "\n".join(new_whiteboard)
-    return work_items

=== modified file 'lib/lp/scripts/garbo.py'
--- lib/lp/scripts/garbo.py	2012-05-09 01:35:41 +0000
+++ lib/lp/scripts/garbo.py	2012-05-16 12:12:19 +0000
@@ -38,8 +38,6 @@
 from zope.security.proxy import removeSecurityProxy
 
 from lp.answers.model.answercontact import AnswerContact
-from lp.blueprints.model.specification import Specification
-from lp.blueprints.workitemmigration import extractWorkItemsFromWhiteboard
 from lp.bugs.interfaces.bug import IBugSet
 from lp.bugs.model.bug import Bug
 from lp.bugs.model.bugattachment import BugAttachment
@@ -65,7 +63,6 @@
 from lp.services.database.lpstorm import IMasterStore
 from lp.services.database.sqlbase import (
     cursor,
-    quote_like,
     session_store,
     sqlvalues,
     )
@@ -992,107 +989,6 @@
         transaction.commit()
 
 
-class SpecificationWorkitemMigrator(TunableLoop):
-    """Migrate work-items from Specification.whiteboard to
-    SpecificationWorkItem.
-
-    Migrating work items from the whiteboard is an all-or-nothing thing; if we
-    encounter any errors when parsing the whiteboard of a spec, we abort the
-    transaction and leave its whiteboard unchanged.
-
-    On a test with production data, only 100 whiteboards (out of almost 2500)
-    could not be migrated. On 24 of those the assignee in at least one work
-    item is not valid, on 33 the status of a work item is not valid and on 42
-    one or more milestones are not valid.
-    """
-
-    maximum_chunk_size = 500
-    offset = 0
-    projects_to_migrate = [
-        'linaro-graphics-misc', 'linaro-powerdebug', 'linaro-mm-sig',
-        'linaro-patchmetrics', 'linaro-android-mirror', 'u-boot-linaro',
-        'lava-dashboard-tool', 'lava-celery', 'smartt', 'linaro-power-kernel',
-        'linaro-django-xmlrpc', 'linaro-multimedia-testcontent',
-        'linaro-status-website', 'linaro-octo-armhf', 'svammel', 'libmatrix',
-        'glproxy', 'lava-test', 'cbuild', 'linaro-ci',
-        'linaro-multimedia-ucm', 'linaro-ubuntu',
-        'linaro-android-infrastructure', 'linaro-wordpress-registration-form',
-        'linux-linaro', 'lava-server', 'linaro-android-build-tools',
-        'linaro-graphics-dashboard', 'linaro-fetch-image', 'unity-gles',
-        'lava-kernel-ci-views', 'cortex-strings', 'glmark2-extra',
-        'lava-dashboard', 'linaro-multimedia-speex', 'glcompbench',
-        'igloocommunity', 'linaro-validation-misc', 'linaro-websites',
-        'linaro-graphics-tests', 'linaro-android',
-        'jenkins-plugin-shell-status', 'binutils-linaro',
-        'linaro-multimedia-project', 'lava-qatracker',
-        'linaro-toolchain-binaries', 'linaro-image-tools',
-        'linaro-toolchain-misc', 'qemu-linaro', 'linaro-toolchain-benchmarks',
-        'lava-dispatcher', 'gdb-linaro', 'lava-android-test', 'libjpeg-turbo',
-        'lava-scheduler-tool', 'glmark2', 'linaro-infrastructure-misc',
-        'lava-lab', 'linaro-android-frontend', 'linaro-powertop',
-        'linaro-license-protection', 'gcc-linaro', 'lava-scheduler',
-        'linaro-offspring', 'linaro-python-dashboard-bundle',
-        'linaro-power-qa', 'lava-tool', 'linaro']
-
-    def __init__(self, log, abort_time=None):
-        super(SpecificationWorkitemMigrator, self).__init__(
-            log, abort_time=abort_time)
-
-        if not getFeatureFlag('garbo.workitem_migrator.enabled'):
-            self.log.info(
-                "Not migrating work items. Change the "
-                "garbo.workitem_migrator.enabled feature flag if you want "
-                "to enable this.")
-            # This will cause isDone() to return True, thus skipping the work
-            # item migration.
-            self.total = 0
-            return
-
-        query = ("product in (select id from product where name in %s)"
-            % ",".join(sqlvalues(self.projects_to_migrate)))
-        # Get only the specs which contain "work items" in their whiteboard
-        # and which don't have any SpecificationWorkItems.
-        query += " and whiteboard ilike '%%' || %s || '%%'" % quote_like(
-            'work items')
-        query += (" and id not in (select distinct specification from "
-                  "SpecificationWorkItem)")
-        self.specs = IMasterStore(Specification).find(Specification, query)
-        self.total = self.specs.count()
-        self.log.info(
-            "Migrating work items from the whiteboard of %d specs"
-            % self.total)
-
-    def getNextBatch(self, chunk_size):
-        end_at = self.offset + int(chunk_size)
-        return self.specs[self.offset:end_at]
-
-    def isDone(self):
-        """See `TunableLoop`."""
-        return self.offset >= self.total
-
-    def __call__(self, chunk_size):
-        """See `TunableLoop`."""
-        for spec in self.getNextBatch(chunk_size):
-            try:
-                work_items = extractWorkItemsFromWhiteboard(spec)
-            except Exception, e:
-                self.log.info(
-                    "Failed to parse whiteboard of %s: %s" % (
-                        spec, unicode(e)))
-                transaction.abort()
-                continue
-
-            if len(work_items) > 0:
-                self.log.info(
-                    "Migrated %d work items from the whiteboard of %s" % (
-                        len(work_items), spec))
-                transaction.commit()
-            else:
-                self.log.info(
-                    "No work items found on the whiteboard of %s" % spec)
-        self.offset += chunk_size
-
-
 class BugTaskFlattener(TunableLoop):
     """A `TunableLoop` to populate BugTaskFlat for all bugtasks."""
 
@@ -1366,7 +1262,6 @@
         OpenIDConsumerNoncePruner,
         OpenIDConsumerAssociationPruner,
         AntiqueSessionPruner,
-        SpecificationWorkitemMigrator,
         ]
     experimental_tunable_loops = []
 

=== modified file 'lib/lp/scripts/tests/test_garbo.py'
--- lib/lp/scripts/tests/test_garbo.py	2012-05-09 01:35:41 +0000
+++ lib/lp/scripts/tests/test_garbo.py	2012-05-16 12:12:19 +0000
@@ -12,7 +12,6 @@
     )
 import logging
 from StringIO import StringIO
-from textwrap import dedent
 import time
 
 from pytz import UTC
@@ -30,14 +29,12 @@
 from testtools.matchers import (
     Equals,
     GreaterThan,
-    MatchesStructure,
     )
 import transaction
 from zope.component import getUtility
 from zope.security.proxy import removeSecurityProxy
 
 from lp.answers.model.answercontact import AnswerContact
-from lp.blueprints.enums import SpecificationWorkItemStatus
 from lp.bugs.model.bugnotification import (
     BugNotification,
     BugNotificationRecipient,
@@ -55,7 +52,6 @@
     )
 from lp.code.model.codeimportevent import CodeImportEvent
 from lp.code.model.codeimportresult import CodeImportResult
-from lp.registry.interfaces.distribution import IDistributionSet
 from lp.registry.interfaces.person import IPersonSet
 from lp.scripts.garbo import (
     AntiqueSessionPruner,
@@ -77,7 +73,6 @@
     UTC_NOW,
     )
 from lp.services.database.lpstorm import IMasterStore
-from lp.services.features import getFeatureFlag
 from lp.services.features.model import FeatureFlag
 from lp.services.identity.interfaces.account import AccountStatus
 from lp.services.identity.interfaces.emailaddress import EmailAddressStatus
@@ -1025,89 +1020,6 @@
         self.runHourly()
         self.assertNotEqual(old_update, naked_bug.heat_last_updated)
 
-    def test_SpecificationWorkitemMigrator_not_enabled_by_default(self):
-        self.assertFalse(getFeatureFlag('garbo.workitem_migrator.enabled'))
-        switch_dbuser('testadmin')
-        whiteboard = dedent("""
-            Work items:
-            A single work item: TODO
-            """)
-        spec = self.factory.makeSpecification(whiteboard=whiteboard)
-        transaction.commit()
-
-        self.runFrequently()
-
-        self.assertEqual(whiteboard, spec.whiteboard)
-        self.assertEqual(0, spec.work_items.count())
-
-    def test_SpecificationWorkitemMigrator(self):
-        # When the migration is successful we remove all work-items from the
-        # whiteboard.
-        switch_dbuser('testadmin')
-        product = self.factory.makeProduct(name='linaro')
-        milestone = self.factory.makeMilestone(product=product)
-        person = self.factory.makePerson()
-        whiteboard = dedent("""
-            Work items for %s:
-            [%s] A single work item: TODO
-
-            Work items:
-            Another work item: DONE
-            """ % (milestone.name, person.name))
-        spec = self.factory.makeSpecification(
-            product=product, whiteboard=whiteboard)
-        IMasterStore(FeatureFlag).add(FeatureFlag(
-            u'default', 0, u'garbo.workitem_migrator.enabled', u'True'))
-        transaction.commit()
-
-        self.runFrequently()
-
-        self.assertEqual('', spec.whiteboard.strip())
-        self.assertEqual(2, spec.work_items.count())
-        self.assertThat(spec.work_items[0], MatchesStructure.byEquality(
-            assignee=person, title="A single work item",
-            status=SpecificationWorkItemStatus.TODO,
-            milestone=milestone, specification=spec))
-        self.assertThat(spec.work_items[1], MatchesStructure.byEquality(
-            assignee=None, title="Another work item",
-            status=SpecificationWorkItemStatus.DONE,
-            milestone=None, specification=spec))
-
-    def test_SpecificationWorkitemMigrator_skips_ubuntu_blueprints(self):
-        switch_dbuser('testadmin')
-        whiteboard = "Work items:\nA work item: TODO"
-        spec = self.factory.makeSpecification(
-            whiteboard=whiteboard,
-            distribution=getUtility(IDistributionSet)['ubuntu'])
-        IMasterStore(FeatureFlag).add(FeatureFlag(
-            u'default', 0, u'garbo.workitem_migrator.enabled', u'True'))
-        transaction.commit()
-        self.runFrequently()
-
-        self.assertEqual(whiteboard, spec.whiteboard)
-        self.assertEqual(0, spec.work_items.count())
-
-    def test_SpecificationWorkitemMigrator_parse_error(self):
-        # When we fail to parse any work items in the whiteboard we leave it
-        # untouched and don't create any SpecificationWorkItem entries.
-        switch_dbuser('testadmin')
-        whiteboard = dedent("""
-            Work items:
-            A work item: TODO
-            Another work item: UNKNOWNSTATUSWILLFAILTOPARSE
-            """)
-        product = self.factory.makeProduct(name='linaro')
-        spec = self.factory.makeSpecification(
-            product=product, whiteboard=whiteboard)
-        IMasterStore(FeatureFlag).add(FeatureFlag(
-            u'default', 0, u'garbo.workitem_migrator.enabled', u'True'))
-        transaction.commit()
-
-        self.runFrequently()
-
-        self.assertEqual(whiteboard, spec.whiteboard)
-        self.assertEqual(0, spec.work_items.count())
-
     def test_BugTaskFlattener(self):
         # Bugs without a record in BugTaskFlat get mirrored.
         # Remove the existing mirrored data.


Follow ups