diff --git a/doc/source/migration.rst b/doc/source/migration.rst index 3a706b1d..987ed24f 100644 --- a/doc/source/migration.rst +++ b/doc/source/migration.rst @@ -89,6 +89,16 @@ Test Migration `$PROJECT_IN_STORYBOARD` should be replaced the name of the project you are importing into in StoryBoard, for example `openstack/monasca`. + Two parameters of the `storyboard-migrate` command + allows for filtering by the tags associated to the bug. + Both parameters accept a comma-separated lists of tags + and they are mutually exclusive. + + --only-tags=tags select only the bugs which have all + the specified tag(s) + --exclude-tags=tags exclude the bugs which have any + of the specified tag(s) + Then you must wait for some time to pass whilst the project is migrated. You can watch the output if you like. Sometimes it will crash with a traceback saying the database object already exists. diff --git a/storyboard/migrate/cli.py b/storyboard/migrate/cli.py index 82851ad7..8e6321cc 100644 --- a/storyboard/migrate/cli.py +++ b/storyboard/migrate/cli.py @@ -12,6 +12,9 @@ # License for the specific language governing permissions and limitations # under the License. +from __future__ import print_function +import sys + from oslo_config import cfg from oslo_log import log @@ -30,7 +33,13 @@ IMPORT_OPTS = [ help="The origin system from which to import."), cfg.IntOpt("auto-increment", default=None, - help="Optionally set the auto-increment on the stories table.") + help="Optionally set the auto-increment on the stories table."), + cfg.ListOpt("only-tags", + default=[], + help="Include only the bugs with specified tags."), + cfg.ListOpt("exclude-tags", + default=[], + help="Exclude the bugs with the specified tags.") ] CONF = cfg.CONF @@ -46,6 +55,12 @@ def main(): log.setup(CONF, 'storyboard') CONF(project='storyboard') + # only_tags and exclude_tags are mutually exclusive + if CONF.only_tags and CONF.exclude_tags: + print('ERROR: only-tags and exclude-tags are mutually exclusive', + file=sys.stderr) + exit(1) + # If the user requested an autoincrement value, set that before we start # importing things. Note that mysql will automatically set the # autoincrement to the next-available id equal to or larger than the @@ -58,7 +73,8 @@ def main(): % (auto_increment,)) if CONF.origin is 'launchpad': - loader = LaunchpadLoader(CONF.from_project, CONF.to_project) + loader = LaunchpadLoader(CONF.from_project, CONF.to_project, + set(CONF.only_tags), set(CONF.exclude_tags)) loader.run() else: print('Unsupported import origin: %s' % CONF.origin) diff --git a/storyboard/migrate/launchpad/loader.py b/storyboard/migrate/launchpad/loader.py index 7a53d9e7..65d20a53 100644 --- a/storyboard/migrate/launchpad/loader.py +++ b/storyboard/migrate/launchpad/loader.py @@ -17,16 +17,40 @@ from storyboard.migrate.launchpad.writer import LaunchpadWriter class LaunchpadLoader(object): - def __init__(self, from_project, to_project): + def __init__(self, from_project, to_project, only_tags=None, + excluded_tags=None): """Create a new loader instance from launchpad.org """ self.writer = LaunchpadWriter(to_project) self.reader = LaunchpadReader(from_project) + self.only_tags = only_tags + self.excluded_tags = excluded_tags + + def bug_matches_requested_tags(self, tags): + """Check whether the set of tag matches the requirement: + - the tag is in the set of the requested tags + if the inclusion list is specified; + - the tag is not in the set of the excluded tags + if the inclusion list is specified. + """ + if self.only_tags: + return (tags.intersection(self.only_tags) == self.only_tags) + if self.excluded_tags: + return not tags.intersection(self.excluded_tags) + return True def run(self): for lp_bug in self.reader: bug = lp_bug.bug + tags_set = set() + if hasattr(bug, 'tags') and bug.tags: + tags_set = set(bug.tags) + if not self.bug_matches_requested_tags(tags_set): + print("WARNING: Skipping bug %s due to tag rules" % + (bug.self_link)) + continue + # Preload the tags. tags = self.writer.write_tags(bug)