def bugzilla2youtrack(target_url, target_login, target_pass, bz_db, bz_host, bz_port, bz_login, bz_pass,
                      bz_product_names, issues_filter):
    # connecting to bz
    client = Client(bz_host, int(bz_port), bz_login, bz_pass, db_name=bz_db)

    if not len(bz_product_names):
        answer = raw_input("All projects will be imported. Are you sure? [y/n]")
        if answer.capitalize() != "Y":
            sys.exit()
        bz_product_names = client.get_product_names()

    print("bz_product_names :   " + repr(bz_product_names))

    # connecting to yt
    target = Connection(target_url, target_login, target_pass)

    print("Creating issue link types")
    link_types = client.get_issue_link_types()
    for link in link_types:
        print("Processing link type [ %s ]" % link.name)
        try:
            target.createIssueLinkType(to_yt_issue_link_type(link))
        except YouTrackException:
            print("Can't create link type [ %s ] (maybe because it already exists)" % link.name)
    print("Creating issue link types finished")

    print("Creating custom fields")
    custom_fields = client.get_custom_fields()
    for cf in custom_fields:
        create_yt_custom_field(cf, target)
    print("Creating custom fields finished")

    for key in youtrackutils.bugzilla.FIELD_TYPES:
        if key not in youtrack.EXISTING_FIELDS:
            create_custom_field(target, youtrackutils.bugzilla.FIELD_TYPES[key], key, True, bundle_policy="1")

    bz_product_ids = []

    for name in bz_product_names:
        product_id = str(client.get_product_id_by_name(name))
        bz_product_ids.append(product_id)
        print("Creating project [ %s ] with name [ %s ]" % (product_id, name))
        try:
            target.getProject(str(product_id))
        except YouTrackException:
            target.createProjectDetailed(str(product_id), name, client.get_project_description(product_id),
                target_login)

        print("Importing components for project [ %s ]" % product_id)
        process_components(client.get_components(product_id), product_id, target)
        print("Importing components finished for project [ %s ]" % product_id)

        print("Importing versions for project [ %s ]" % product_id)
        process_versions(client.get_versions(product_id), product_id, target)
        print("Importing versions finished for project [ %s ] finished" % product_id)

        print("Importing issues to project [ %s ]" % product_id)
        max_count = 100
        count = 0
        from_id = 0
        bz_issues_count = client.get_issues_count(product_id)
        while count < bz_issues_count:
            batch = client.get_issues(product_id, from_id, from_id + max_count)
            batch = [bz_issue for bz_issue in batch if (issues_filter(bz_issue))]
            count += len(batch)
            from_id += max_count
            target.importIssues(product_id, product_id + " assignees",
                [to_yt_issue(bz_issue, product_id, target) for bz_issue in batch])
            # todo convert to good tags import
            for issue in batch:
                tags = issue["keywords"] | issue["flags"]
                for t in tags:
                    print("Processing tag [ %s ]" % t.encode('utf8'))
                    target.executeCommand(str(product_id) + "-" + str(issue[get_number_in_project_field_name()]),
                        "tag " + t.encode('utf8'))
            for issue in batch:
                for attach in issue["attachments"]:
                    print("Processing attachment [ %s ]" % (attach.name.encode('utf8')))
                    content = StringIO(attach.content)
                    target.createAttachment(str(product_id) + "-" + str(issue[get_number_in_project_field_name()]),
                        attach.name, content, attach.reporter.login
                        , created=str(int(attach.created) * 1000))
        print("Importing issues to project [ %s ] finished" % product_id)

    # todo add pagination to links
    print("Importing issue links")
    cf_links = client.get_issue_links()
    duplicate_links = client.get_duplicate_links()
    if len(duplicate_links):
        try:
            target.createIssueLinkTypeDetailed("Duplicate", "duplicates", "is duplicated by", True)
        except YouTrackException:
            print("Can't create link type [ Duplicate ] (maybe because it already exists)")
    depend_links = client.get_dependencies_link()
    if len(depend_links):
        try:
            target.createIssueLinkTypeDetailed("Depend", "depends on", "is required for", True)
        except YouTrackException:
            print("Can't create link type [ Depend ] (maybe because it already exists)")
    links = cf_links | duplicate_links | depend_links

    links_to_import = list([])
    for link in links:
        print("Processing link %s for issue%s" % (link.name, link.source))
        if (str(link.target_product_id) in bz_product_ids) and (str(link.source_product_id) in bz_product_ids):
            links_to_import.append(to_yt_issue_link(link))
    print(target.importLinks(links_to_import))
    print("Importing issue links finished")
def fb2youtrack(params):
    # Connection to FogBugz
    source = FBClient(params['fb_url'],
                      params['fb_login'],
                      params['fb_password'])

    # Connecting to YouTrack
    token = params.get('token')
    if not token and 'token_file' in params:
        try:
            with open(params['token_file'], 'r') as f:
                token = f.read().strip()
        except (OSError, IOError) as e:
            print("Cannot load token from file: " + str(e))
            sys.exit(1)
    if token:
        target = Connection(params['yt_url'], token=token)
    elif 'yt_login' in params:
        target = Connection(params['yt_url'],
                            params.get('yt_login'),
                            params.get('yt_password'))
    else:
        print("You have to provide token or login/password to import data")
        sys.exit(1)

    if not params.get('project_lead_login'):
        project_lead = params.get('yt_login')
        if not project_lead:
            for login in ('root', 'admin', 'administrator', 'guest'):
                try:
                    project_lead = target.getUser(login).login
                    break
                except youtrack.YouTrackException:
                    continue
        params['project_lead_login'] = project_lead

    max_issue_id = params['fb_max_issue_id']

    project_names = youtrackutils.fbugz.PROJECTS_TO_IMPORT
    accessible_projects = source.list_project_names()
    for p_name in project_names:
        if not (p_name in accessible_projects.keys()):
            print('Unknown project names. Exiting...')
            sys.exit()

#    for p_name in accessible_projects :
#        if (p_name.encode('utf-8') in project_names_str) :
#            project_names_str.remove(p_name.encode('utf-8'))
#            project_names.append(p_name)
#
#    if (len(project_names_str) != 0) :
#        print 'Unknown project names!'

    print('Creating custom fields')
#
#    for field_name in ['Category', 'Priority', 'Status']:
#        field_name = get_yt_name_from_fb__field_name(field_name)
#        create_custom_field(target, fbugz.CF_TYPES[field_name], field_name, False)

    fb_category_bundle_name = u'FB Categories'
    fb_priorities_bundle_name = u'FB Priorities'
    fb_statuses_bundle_name = u'FB Statuses'

    common_fields = {
        u'category'  :   fb_category_bundle_name,
        u'priority'  :   fb_priorities_bundle_name,
        u'status'    :   fb_statuses_bundle_name
    }

    field_name = u'category'
    create_bundle_with_values(
        target,
        youtrackutils.fbugz.CF_TYPES[get_yt_field_name(field_name)],
        common_fields[field_name],
        source.list_categories(),
        lambda bundle, value:
        bundle.createElement(to_yt_field_value(field_name, value)))
    field_name = u'priority'
    create_bundle_with_values(target, youtrackutils.fbugz.CF_TYPES[get_yt_field_name(field_name)],
                              common_fields[field_name],
                              [elem[0] + '-' + elem[1] for elem in source.list_priorities()],
                              lambda bundle, value : bundle.createElement(to_yt_field_value(field_name, value)))

    field_name = u'status'
    statuses = [(to_yt_field_value(field_name, value), resolved) for (value, resolved) in source.list_statuses()]
    create_bundle_with_values(target, youtrackutils.fbugz.CF_TYPES[get_yt_field_name(field_name)],
                              common_fields[field_name],
                              statuses, lambda bundle, value : to_yt_status(bundle, value))

    simple_fields = [u'original_title', u'version', u'computer', u'due', u'estimate']

    for name in simple_fields:
        name = get_yt_field_name(name)
        create_custom_field(target, youtrackutils.fbugz.CF_TYPES[name], name, False)

    print('Importing users')
    for name in ['Normal', 'Deleted', 'Community', 'Virtual'] :
        group = Group()
        group.name = name
        try :
            target.createGroup(group)
            print('Group with name [ %s ] successfully created' % name)
        except:
            print("Can't create group with name [ %s ] (maybe because it already exists)" % name)

    users_to_import = []
    max = 100
    for user in source.get_users() :
        yt_user = _to_yt_user(user)
        print('Importing user [ %s ]' % yt_user.login)
        users_to_import.append(yt_user)
        if len(users_to_import) >= max:
            _do_import_users(target, users_to_import)
            users_to_import = []
    _do_import_users(target, users_to_import)
    print('Importing users finished')

    # to handle linked issues
    try :
        target.createIssueLinkTypeDetailed('parent-child', 'child of', 'parent of', True)
    except YouTrackException:
        print("Can't create issue link type [ parent-child ] (maybe because it already exists)")
    links_to_import = []

    for project_name in project_names:
        value_sets = dict([])

        project_id = accessible_projects[project_name]
        print('Importing project [ %s ]' % project_name)
        target.createProjectDetailed(project_id,
                                     project_name.encode('utf-8'),
                                     '',
                                     params['project_lead_login'])

        print('Creating custom fields in project [ %s ]' % project_name)

        for cf_name in common_fields:
            bundle_name = common_fields[cf_name]
            cf_name = get_yt_field_name(cf_name)
            target.deleteProjectCustomField(project_id, cf_name)
            target.createProjectCustomFieldDetailed(project_id, cf_name, 'No ' + cf_name.lower(),
                    {'bundle' : bundle_name})

        for cf_name in simple_fields:
            cf_name = get_yt_field_name(cf_name)
            try:
                target.createProjectCustomFieldDetailed(project_id, cf_name, 'No ' + cf_name.lower())
            except YouTrackException:
                print("Can't create custom field with name [%s]" % cf_name)
        cf_name = get_yt_field_name('fix_for')
        milestones = source.get_milestones(project_id)
        value_sets["fix_for"] = []
        for milestone in milestones:
            value_sets["fix_for"].append(milestone.name)
            milestone.name = to_yt_field_value('fix_for', milestone.name)
        add_values_to_field(target, cf_name, project_id, milestones,
                            lambda bundle, value: _to_yt_version(bundle, value))

        cf_name = get_yt_field_name('area')
        areas = source.get_areas(project_id)
        value_sets["area"] = []
        for area in areas:
            value_sets["area"].append(area.name)
            area.name = to_yt_field_value('area', area.name)
        add_values_to_field(target, cf_name, project_id, areas,
                            lambda bundle, value: _to_yt_subsystem(bundle, value))

        print('Importing issues for project [ %s ]' % project_name)
        start = 0
        issues_to_import = []
        # create dictionary with child : parent pairs
        while start <= max_issue_id:
            fb_issues = source.get_issues(project_name, start, 30)
            for issue in fb_issues :
                add_values_to_field(target, get_yt_field_name('area'), project_id,
                                    [issue.field_values['area']], lambda bundle, value: bundle.createElement(value))
                issues_to_import.append(_to_yt_issue(issue, value_sets))
            target.importIssues(project_id, project_name.encode('utf-8') + " assignees", issues_to_import)
            for issue in fb_issues :
                full_issue_id = '%s-%s' % (project_id, issue.ix_bug)
                for attach in issue.attachments :
                    target.createAttachmentFromAttachment(full_issue_id, attach)
                for tag in issue.tags :
                    target.executeCommand(full_issue_id, 'tag ' + tag)
                if issue.bug_parent is not None:
                    parent_issue_id = '%s-%s' % (source.get_issue_project_id(issue.bug_parent), issue.bug_parent)
                    link = Link()
                    link.typeName = 'parent-child'
                    link.source = full_issue_id
                    link.target = parent_issue_id
                    links_to_import.append(link)
            issues_to_import = []
            start += 30
        print('Importing issues for project [ %s ] finished' % project_name)

    print('Importing issue links')
    print(target.importLinks(links_to_import))
    print('Importing issue links finished')
def bugzilla2youtrack(target_url, target_login, target_pass, bz_db, bz_host, bz_port, bz_login, bz_pass,
                      bz_product_names, issues_filter):
    # connecting to bz
    client = Client(bz_host, int(bz_port), bz_login, bz_pass, db_name=bz_db)

    if not len(bz_product_names):
        answer = raw_input("All projects will be imported. Are you sure? [y/n]")
        if answer.capitalize() != "Y":
            sys.exit()
        bz_product_names = client.get_product_names()

    print "bz_product_names :   " + repr(bz_product_names)

    # connecting to yt
    target = Connection(target_url, target_login, target_pass)

    print "Creating issue link types"
    link_types = client.get_issue_link_types()
    for link in link_types:
        print "Processing link type [ %s ]" % link.name
        try:
            target.createIssueLinkType(to_yt_issue_link_type(link))
        except YouTrackException:
            print "Can't create link type [ %s ] (maybe because it already exists)" % link.name
    print "Creating issue link types finished"

    print "Creating custom fields"
    custom_fields = client.get_custom_fields()
    for cf in custom_fields:
        create_yt_custom_field(cf, target)
    print "Creating custom fields finished"

    for key in bugzilla.FIELD_TYPES:
        if key not in youtrack.EXISTING_FIELDS:
            create_custom_field(target, bugzilla.FIELD_TYPES[key], key, True, bundle_policy="1")

    bz_product_ids = []

    for name in bz_product_names:
        product_id = str(client.get_product_id_by_name(name))
        bz_product_ids.append(product_id)
        print "Creating project [ %s ] with name [ %s ]" % (product_id, name)
        try:
            target.getProject(str(product_id))
        except YouTrackException:
            target.createProjectDetailed(str(product_id), name, client.get_project_description(product_id),
                target_login)

        print "Importing components for project [ %s ]" % product_id
        process_components(client.get_components(product_id), product_id, target)
        print "Importing components finished for project [ %s ]" % product_id

        print "Importing versions for project [ %s ]" % product_id
        process_versions(client.get_versions(product_id), product_id, target)
        print "Importing versions finished for project [ %s ] finished" % product_id

        print "Importing issues to project [ %s ]" % product_id
        max_count = 100
        count = 0
        from_id = 0
        bz_issues_count = client.get_issues_count(product_id)
        while count < bz_issues_count:
            batch = client.get_issues(product_id, from_id, from_id + max_count)
            batch = [bz_issue for bz_issue in batch if (issues_filter(bz_issue))]
            count += len(batch)
            from_id += max_count
            target.importIssues(product_id, product_id + " assignees",
                [to_yt_issue(bz_issue, product_id, target) for bz_issue in batch])
            # todo convert to good tags import
            for issue in batch:
                tags = issue["keywords"] | issue["flags"]
                for t in tags:
                    print "Processing tag [ %s ]" % t.encode('utf8')
                    target.executeCommand(str(product_id) + "-" + str(issue[get_number_in_project_field_name()]),
                        "tag " + t.encode('utf8'))
            for issue in batch:
                for attach in issue["attachments"]:
                    print "Processing attachment [ %s ]" % (attach.name.encode('utf8'))
                    content = StringIO(attach.content)
                    target.createAttachment(str(product_id) + "-" + str(issue[get_number_in_project_field_name()]),
                        attach.name, content, attach.reporter
                        , created=str(int(attach.created) * 1000))
        print "Importing issues to project [ %s ] finished" % product_id

    # todo add pagination to links
    print "Importing issue links"
    cf_links = client.get_issue_links()
    duplicate_links = client.get_duplicate_links()
    if len(duplicate_links):
        try:
            target.createIssueLinkTypeDetailed("Duplicate", "duplicates", "is duplicated by", True)
        except YouTrackException:
            print "Can't create link type [ Duplicate ] (maybe because it already exists)"
    depend_links = client.get_dependencies_link()
    if len(depend_links):
        try:
            target.createIssueLinkTypeDetailed("Depend", "depends on", "is required for", True)
        except YouTrackException:
            print "Can't create link type [ Depend ] (maybe because it already exists)"
    links = cf_links | duplicate_links | depend_links

    links_to_import = list([])
    for link in links:
        print "Processing link %s for issue%s" % (link.name, link.source)
        if (str(link.target_product_id) in bz_product_ids) and (str(link.source_product_id) in bz_product_ids):
            links_to_import.append(to_yt_issue_link(link))
    print target.importLinks(links_to_import)
    print "Importing issue links finished"
Esempio n. 4
0
def fb2youtrack(target_url, target_login, target_password, source_url,
                source_login, source_password, project_names, max_issue_id):
    #encoding = 'utf-8'
    source = FBClient(source_url, source_login, source_password)
    target = Connection(target_url, target_login, target_password)
    accessible_projects = source.list_project_names()
    for p_name in project_names:
        if not (p_name in accessible_projects.keys()):
            print 'Unknown project names. Exiting...'
            sys.exit()


#    for p_name in accessible_projects :
#        if (p_name.encode('utf-8') in project_names_str) :
#            project_names_str.remove(p_name.encode('utf-8'))
#            project_names.append(p_name)
#
#    if (len(project_names_str) != 0) :
#        print 'Unknown project names!'

    print('Creating custom fields')
    #
    #    for field_name in ['Category', 'Priority', 'Status']:
    #        field_name = get_yt_name_from_fb__field_name(field_name)
    #        create_custom_field(target, fbugz.CF_TYPES[field_name], field_name, False)

    fb_category_bundle_name = u'FB Categories'
    fb_priorities_bundle_name = u'FB Priorities'
    fb_statuses_bundle_name = u'FB Statuses'

    common_fields = {
        u'category': fb_category_bundle_name,
        u'priority': fb_priorities_bundle_name,
        u'status': fb_statuses_bundle_name
    }

    field_name = u'category'
    create_bundle_with_values(
        target, fbugz.CF_TYPES[get_yt_name_from_fb_field_name(field_name)],
        common_fields[field_name], source.list_categories(),
        lambda bundle, value: bundle.createElement(
            to_yt_field_value(field_name, value)))
    field_name = u'priority'
    create_bundle_with_values(
        target, fbugz.CF_TYPES[get_yt_name_from_fb_field_name(field_name)],
        common_fields[field_name],
        [elem[0] + '-' + elem[1] for elem in source.list_priorities()],
        lambda bundle, value: bundle.createElement(
            to_yt_field_value(field_name, value)))

    field_name = u'status'
    statuses = [(to_yt_field_value(field_name, value), resolved)
                for (value, resolved) in source.list_statuses()]
    create_bundle_with_values(
        target, fbugz.CF_TYPES[get_yt_name_from_fb_field_name(field_name)],
        common_fields[field_name], statuses,
        lambda bundle, value: to_yt_status(bundle, value))

    simple_fields = [
        u'original_title', u'version', u'computer', u'due', u'estimate'
    ]

    for name in simple_fields:
        name = get_yt_name_from_fb_field_name(name)
        create_custom_field(target, fbugz.CF_TYPES[name], name, False)

    print 'Importing users'
    for name in ['Normal', 'Deleted', 'Community', 'Virtual']:
        group = Group()
        group.name = name
        try:
            target.createGroup(group)
            print 'Group with name [ %s ] successfully created' % name
        except:
            print "Can't create group with name [ %s ] (maybe because it already exists)" % name

    users_to_import = []
    max = 100
    for user in source.get_users():
        yt_user = _to_yt_user(user)
        print 'Importing user [ %s ]' % yt_user.login
        users_to_import.append(yt_user)
        if len(users_to_import) >= max:
            _do_import_users(target, users_to_import)
            users_to_import = []
    _do_import_users(target, users_to_import)
    print 'Importing users finished'

    # to handle linked issues
    try:
        target.createIssueLinkTypeDetailed('parent-child', 'child of',
                                           'parent of', True)
    except YouTrackException:
        print "Can't create issue link type [ parent-child ] (maybe because it already exists)"
    links_to_import = []

    for project_name in project_names:
        value_sets = dict([])

        project_id = accessible_projects[project_name]
        print 'Importing project [ %s ]' % project_name
        target.createProjectDetailed(project_id, project_name.encode('utf-8'),
                                     'no description', 'root')

        print 'Creating custom fields in project [ %s ]' % project_name

        for cf_name in common_fields:
            bundle_name = common_fields[cf_name]
            cf_name = get_yt_name_from_fb_field_name(cf_name)
            target.deleteProjectCustomField(project_id, cf_name)
            target.createProjectCustomFieldDetailed(project_id, cf_name,
                                                    'No ' + cf_name.lower(),
                                                    {'bundle': bundle_name})

        for cf_name in simple_fields:
            cf_name = get_yt_name_from_fb_field_name(cf_name)
            try:
                target.createProjectCustomFieldDetailed(
                    project_id, cf_name, 'No ' + cf_name.lower())
            except YouTrackException:
                print "Can't create custom field with name [%s]" % cf_name
        cf_name = get_yt_name_from_fb_field_name('fix_for')
        milestones = source.get_milestones(project_id)
        value_sets["fix_for"] = []
        for milestone in milestones:
            value_sets["fix_for"].append(milestone.name)
            milestone.name = to_yt_field_value('fix_for', milestone.name)
        add_values_to_field(
            target, cf_name, project_id, milestones,
            lambda bundle, value: _to_yt_version(bundle, value))

        cf_name = get_yt_name_from_fb_field_name('area')
        areas = source.get_areas(project_id)
        value_sets["area"] = []
        for area in areas:
            value_sets["area"].append(area.name)
            area.name = to_yt_field_value('area', area.name)
        add_values_to_field(
            target, cf_name, project_id, areas,
            lambda bundle, value: _to_yt_subsystem(bundle, value))

        print 'Importing issues for project [ %s ]' % project_name
        start = 0
        issues_to_import = []
        # create dictionary with child : parent pairs
        while start <= max_issue_id:
            fb_issues = source.get_issues(project_name, start, 30)
            for issue in fb_issues:
                add_values_to_field(
                    target, get_yt_name_from_fb_field_name('area'), project_id,
                    [issue.field_values['area']],
                    lambda bundle, value: bundle.createElement(value))
                issues_to_import.append(_to_yt_issue(issue, value_sets))
            target.importIssues(project_id,
                                project_name.encode('utf-8') + " assignees",
                                issues_to_import)
            for issue in fb_issues:
                full_issue_id = '%s-%s' % (project_id, issue.ix_bug)
                for attach in issue.attachments:
                    target.createAttachmentFromAttachment(
                        full_issue_id, attach)
                for tag in issue.tags:
                    target.executeCommand(full_issue_id, 'tag ' + tag)
                if issue.bug_parent is not None:
                    parent_issue_id = '%s-%s' % (source.get_issue_project_id(
                        issue.bug_parent), issue.bug_parent)
                    link = Link()
                    link.typeName = 'parent-child'
                    link.source = full_issue_id
                    link.target = parent_issue_id
                    links_to_import.append(link)
            issues_to_import = []
            start += 30
        print 'Importing issues for project [ %s ] finished' % project_name

    print 'Importing issue links'
    print target.importLinks(links_to_import)
    print 'Importing issue links finished'
Esempio n. 5
0
def bugzilla2youtrack(params):
    # Connecting to Bugzilla
    client = Client(host=params['bz_host'],
                    port=int(params['bz_port']),
                    login=params['bz_login'],
                    password=params['bz_password'],
                    db_name=params['bz_db'])

    bz_product_names = params.get('bz_product_names')
    if not bz_product_names:
        answer = raw_input(
            "All projects will be imported. Are you sure? [Y/n] ")
        if answer.strip().lower() not in ("y", "yes", ""):
            sys.exit()
        bz_product_names = client.get_product_names()

    print("bz_product_names: " + repr(bz_product_names))

    # Connecting to YouTrack
    token = params.get('token')
    if not token and 'token_file' in params:
        try:
            with open(params['token_file'], 'r') as f:
                token = f.read().strip()
        except (OSError, IOError) as e:
            print("Cannot load token from file: " + str(e))
            sys.exit(1)
    if token:
        target = Connection(params['yt_url'], token=token)
    elif 'yt_login' in params:
        target = Connection(params['yt_url'], params.get('yt_login'),
                            params.get('yt_password'))
    else:
        print("You have to provide token or login/password to import data")
        sys.exit(1)

    print("Creating issue link types")
    link_types = client.get_issue_link_types()
    for link in link_types:
        print("Processing link type [ %s ]" % link.name)
        try:
            target.createIssueLinkType(to_yt_issue_link_type(link))
        except YouTrackException:
            print(
                "Can't create link type [ %s ] (maybe because it already exists)"
                % link.name)
    print("Creating issue link types finished")

    print("Creating custom fields")
    custom_fields = client.get_custom_fields()
    for cf in custom_fields:
        create_yt_custom_field(cf, target)
    print("Creating custom fields finished")

    for key in youtrackutils.bugzilla.FIELD_TYPES:
        if key not in youtrack.EXISTING_FIELDS:
            create_custom_field(target,
                                youtrackutils.bugzilla.FIELD_TYPES[key],
                                key,
                                True,
                                bundle_policy="1")

    bz_product_ids = []

    for name in bz_product_names:
        product_id = str(client.get_product_id_by_name(name))
        bz_product_ids.append(product_id)
        print("Creating project [ %s ] with name [ %s ]" % (product_id, name))
        try:
            target.getProject(product_id)
        except YouTrackException:
            target.createProjectDetailed(
                product_id, name, client.get_project_description(product_id),
                'root')

        print("Importing components for project [ %s ]" % product_id)
        process_components(client.get_components(product_id), product_id,
                           target)
        print("Importing components finished for project [ %s ]" % product_id)

        print("Importing versions for project [ %s ]" % product_id)
        process_versions(client.get_versions(product_id), product_id, target)
        print("Importing versions finished for project [ %s ] finished" %
              product_id)

        print("Importing issues to project [ %s ]" % product_id)
        max_count = 100
        count = 0
        from_id = 0
        bz_issues_count = client.get_issues_count(product_id)
        while count < bz_issues_count:
            batch = client.get_issues(product_id, from_id, from_id + max_count)
            batch = [bz_issue for bz_issue in batch]
            count += len(batch)
            from_id += max_count
            target.importIssues(product_id, product_id + " assignees", [
                to_yt_issue(bz_issue, product_id, target) for bz_issue in batch
            ])
            # todo convert to good tags import
            for issue in batch:
                tags = issue["keywords"] | issue["flags"]
                for t in tags:
                    print("Processing tag [ %s ]" % t.encode('utf8'))
                    target.executeCommand(
                        str(product_id) + "-" +
                        str(issue[get_number_in_project_field_name()]),
                        "tag " + t.encode('utf8'))
            for issue in batch:
                issue_id = str(product_id) + '-' + \
                           str(issue[get_number_in_project_field_name()])
                for attach in issue["attachments"]:
                    print("Processing attachment [ %s ] for issue %s" %
                          (utf8encode(attach.name), issue_id))
                    content = StringIO(attach.content)
                    try:
                        target.importAttachment(
                            issue_id, attach.name, content,
                            attach.reporter.login, None, None,
                            str(int(attach.created) * 1000))
                    except urllib2.HTTPError as e:
                        print("WARN: Cant import attachment [ %s ]" %
                              utf8encode(attach.name))
                        print(e.code)
                        print(e.read())
                        print("Please check Max Upload File Size in YouTrack")
                        continue
        print("Importing issues to project [ %s ] finished" % product_id)

    # todo add pagination to links
    print("Importing issue links")
    cf_links = client.get_issue_links()
    duplicate_links = client.get_duplicate_links()
    if len(duplicate_links):
        try:
            target.createIssueLinkTypeDetailed("Duplicate", "duplicates",
                                               "is duplicated by", True)
        except YouTrackException:
            print(
                "Can't create link type [ Duplicate ] (maybe because it already exists)"
            )
    depend_links = client.get_dependencies_link()
    if len(depend_links):
        try:
            target.createIssueLinkTypeDetailed("Depend", "depends on",
                                               "is required for", True)
        except YouTrackException:
            print(
                "Can't create link type [ Depend ] (maybe because it already exists)"
            )
    links = cf_links | duplicate_links | depend_links

    links_to_import = list([])
    for link in links:
        print("Processing link %s for issue%s" % (link.name, link.source))
        if (str(link.target_product_id) in bz_product_ids) and (str(
                link.source_product_id) in bz_product_ids):
            links_to_import.append(to_yt_issue_link(link))
    print(target.importLinks(links_to_import))
    print("Importing issue links finished")
def fb2youtrack(target_url, target_login, target_password, source_url, source_login, source_password, project_names, max_issue_id) :
    #encoding = 'utf-8'
    source = FBClient(source_url, source_login, source_password)
    target = Connection(target_url, target_login, target_password)
    accessible_projects = source.list_project_names()
    for p_name in project_names :
        if not(p_name in  accessible_projects.keys()) :
            print 'Unknown project names. Exiting...'
            sys.exit()

#    for p_name in accessible_projects :
#        if (p_name.encode('utf-8') in project_names_str) :
#            project_names_str.remove(p_name.encode('utf-8'))
#            project_names.append(p_name)
#
#    if (len(project_names_str) != 0) :
#        print 'Unknown project names!'

    print('Creating custom fields')
#
#    for field_name in ['Category', 'Priority', 'Status']:
#        field_name = get_yt_name_from_fb__field_name(field_name)
#        create_custom_field(target, fbugz.CF_TYPES[field_name], field_name, False)

    fb_category_bundle_name = u'FB Categories'
    fb_priorities_bundle_name = u'FB Priorities'
    fb_statuses_bundle_name = u'FB Statuses'

    common_fields = {
        u'category'  :   fb_category_bundle_name,
        u'priority'  :   fb_priorities_bundle_name,
        u'status'    :   fb_statuses_bundle_name
    }

    field_name = u'category'
    create_bundle_with_values(target,fbugz.CF_TYPES[get_yt_name_from_fb_field_name(field_name)],
                              common_fields[field_name],
                              source.list_categories(),
                              lambda bundle, value : bundle.createElement(to_yt_field_value(field_name, value)))
    field_name = u'priority'
    create_bundle_with_values(target, fbugz.CF_TYPES[get_yt_name_from_fb_field_name(field_name)],
                              common_fields[field_name],
                              [elem[0] + '-' + elem[1] for elem in source.list_priorities()],
                              lambda bundle, value : bundle.createElement(to_yt_field_value(field_name, value)))

    field_name = u'status'
    statuses = [(to_yt_field_value(field_name, value), resolved) for (value, resolved) in source.list_statuses()]
    create_bundle_with_values(target, fbugz.CF_TYPES[get_yt_name_from_fb_field_name(field_name)],
                              common_fields[field_name],
                              statuses, lambda bundle, value : to_yt_status(bundle, value))

    simple_fields = [u'original_title', u'version', u'computer', u'due', u'estimate']

    for name in simple_fields:
        name = get_yt_name_from_fb_field_name(name)
        create_custom_field(target, fbugz.CF_TYPES[name], name, False)

    print 'Importing users'
    for name in ['Normal', 'Deleted', 'Community', 'Virtual'] :
        group = Group()
        group.name = name
        try :
            target.createGroup(group)
            print 'Group with name [ %s ] successfully created' % name
        except:
            print "Can't create group with name [ %s ] (maybe because it already exists)" % name


    users_to_import = []
    max = 100
    for user in source.get_users() :
        yt_user = _to_yt_user(user)
        print 'Importing user [ %s ]' % yt_user.login
        users_to_import.append(yt_user)
        if len(users_to_import) >= max:
            _do_import_users(target, users_to_import)
            users_to_import = []
    _do_import_users(target, users_to_import)
    print 'Importing users finished'

    # to handle linked issues
    try :
        target.createIssueLinkTypeDetailed('parent-child', 'child of', 'parent of', True)
    except YouTrackException:
        print "Can't create issue link type [ parent-child ] (maybe because it already exists)"
    links_to_import = []

    for project_name in project_names :
        value_sets = dict([])

        project_id = accessible_projects[project_name]
        print 'Importing project [ %s ]' % project_name
        target.createProjectDetailed(project_id, project_name.encode('utf-8'), 'no description', 'root')

        print 'Creating custom fields in project [ %s ]' % project_name

        for cf_name in common_fields:
            bundle_name = common_fields[cf_name]
            cf_name = get_yt_name_from_fb_field_name(cf_name)
            target.deleteProjectCustomField(project_id, cf_name)
            target.createProjectCustomFieldDetailed(project_id, cf_name, 'No ' + cf_name.lower(),
                    {'bundle' : bundle_name})

        for cf_name in simple_fields:
            cf_name = get_yt_name_from_fb_field_name(cf_name)
            try:
                target.createProjectCustomFieldDetailed(project_id, cf_name, 'No ' + cf_name.lower())
            except YouTrackException:
                print "Can't create custom field with name [%s]" % cf_name
        cf_name = get_yt_name_from_fb_field_name('fix_for')
        milestones = source.get_milestones(project_id)
        value_sets["fix_for"] = []
        for milestone in milestones:
            value_sets["fix_for"].append(milestone.name)
            milestone.name = to_yt_field_value('fix_for', milestone.name)
        add_values_to_field(target, cf_name, project_id, milestones,
                            lambda bundle, value: _to_yt_version(bundle, value))

        cf_name = get_yt_name_from_fb_field_name('area')
        areas = source.get_areas(project_id)
        value_sets["area"] = []
        for area in areas:
            value_sets["area"].append(area.name)
            area.name = to_yt_field_value('area', area.name)
        add_values_to_field(target, cf_name, project_id, areas,
                            lambda bundle, value: _to_yt_subsystem(bundle, value))

        print 'Importing issues for project [ %s ]' % project_name
        start = 0
        issues_to_import = []
        # create dictionary with child : parent pairs
        while start <= max_issue_id:
            fb_issues = source.get_issues(project_name, start, 30)
            for issue in fb_issues :
                add_values_to_field(target, get_yt_name_from_fb_field_name('area'), project_id,
                    [issue.field_values['area']], lambda bundle, value: bundle.createElement(value))
                issues_to_import.append(_to_yt_issue(issue, value_sets))
            target.importIssues(project_id, project_name.encode('utf-8') + " assignees", issues_to_import)
            for issue in fb_issues :
                full_issue_id = '%s-%s' % (project_id, issue.ix_bug)
                for attach in issue.attachments :
                    target.createAttachmentFromAttachment(full_issue_id, attach)
                for tag in issue.tags :
                    target.executeCommand(full_issue_id, 'tag ' + tag)
                if issue.bug_parent is not None:
                    parent_issue_id = '%s-%s' % (source.get_issue_project_id(issue.bug_parent), issue.bug_parent)
                    link = Link()
                    link.typeName = 'parent-child'
                    link.source = full_issue_id
                    link.target = parent_issue_id
                    links_to_import.append(link)
            issues_to_import = []
            start += 30
        print 'Importing issues for project [ %s ] finished' % project_name

    print 'Importing issue links'
    print target.importLinks(links_to_import)
    print 'Importing issue links finished'