def _to_yt_issue(self, issue, project_id): result = Issue() result.comments = [self._to_yt_comment(comment) for comment in self._get_comments(issue)] result.numberInProject = self._get_issue_id(issue) for (key, value) in issue.items(): # we do not need fields with empty values if value is None: continue if isinstance(value, list) and not len(value): continue # get yt field name and field type field_name = self._get_field_name(key, project_id) if field_name is None or field_name == NUMBER_IN_PROJECT: continue field_type = self._get_field_type(field_name) if (field_type is None) and (field_name not in youtrack.EXISTING_FIELDS): continue value = self._import_config.get_field_value(field_name, field_type, value) if isinstance(value, list): for v in value: self._add_value_to_field(project_id, field_name, field_type, v) else: self._add_value_to_field(project_id, field_name, field_type, value) if (field_type is not None) and field_type.startswith(u"user"): if isinstance(value, list): value = [v.login for v in value] else: value = value.login if not isinstance(value, list): value = str(value) result[field_name] = value return result
def _to_yt_issue(self, issue, project_id): result = Issue() result.comments = [self._to_yt_comment(comment) for comment in self._get_comments(issue)] result.numberInProject = self._get_issue_id(issue) for (key, value) in issue.items(): self.process_field(key, project_id, result, value) return result
def to_yt_issue(issue, target): yt_issue = Issue() project = get_project(issue) for key, value in issue.items(): if key != "comments": field_name = get_yt_field_name(key) if field_name == "numberInProject": number_regex = re.compile("\d+") match_result = number_regex.search(value) yt_issue["numberInProject"] = match_result.group() continue field_type = get_yt_field_type(field_name) if field_type is not None: field_value = get_yt_field_value(field_name, field_type, value) if field_value is not None: if isinstance(field_value, list): for elem in field_value: add_value_to_field(target, project, field_name, field_type, elem) else: add_value_to_field(target, project, field_name, field_type, field_value) yt_issue[field_name] = field_value if not hasattr(yt_issue, "reporterName"): yt_issue.reporterName = "guest" yt_issue.comments = [to_yt_comment(yt_issue.reporterName, comment) for comment in issue["comments"]] return yt_issue
def _to_yt_issue(self, issue, project_id): result = Issue() result.comments = [self._to_yt_comment(comment) for comment in self._get_comments(issue)] result.numberInProject = self._get_issue_id(issue) for (key, value) in issue.items(): # we do not need fields with empty values if value is None: continue if isinstance(value, list) and not len(value): continue #get yt field name and field type field_name = self._get_field_name(key, project_id) if field_name is None or field_name == NUMBER_IN_PROJECT: continue field_type = self._get_field_type(field_name) if (field_type is None) and (field_name not in youtrack.EXISTING_FIELDS): continue value = self._import_config.get_field_value(field_name, field_type, value) if isinstance(value, list): for v in value: self._add_value_to_field(project_id, field_name, field_type, v) else: self._add_value_to_field(project_id, field_name, field_type, value) if (field_type is not None) and field_type.startswith(u'user'): if isinstance(value, list): value = [v.login for v in value] else: value = value.login if not isinstance(value, list): value = str(value) result[field_name] = value return result
def test_resolved_date(self): issue = Issue() issue.created = '123' issue.id = 'BACKEND-671' issue = CycleTimeAwareIssue(issue, TestProvider()) self.assertEqual(issue.resolved_date, millis_to_datetime(1472861471941))
def create_yt_issue_from_jira_issue(target, issue, project_id): yt_issue = Issue() yt_issue['comments'] = [] yt_issue.numberInProject = issue['key'][(issue['key'].find('-') + 1):] for field in issue['fields'].values(): field_type = get_yt_field_type(field[u'type']) field_name = get_yt_field_name(field[u'name']) if field_name == 'comment': for comment in field['value']: yt_comment = Comment() yt_comment.text = comment['body'] comment_author_name = "guest" if 'author' in comment: comment_author = comment['author'] create_user(target, comment_author) comment_author_name = comment_author['name'] yt_comment.author = comment_author_name.replace(' ', '_') yt_comment.created = to_unix_date(comment['created']) yt_comment.updated = to_unix_date(comment['updated']) yt_issue['comments'].append(yt_comment) elif (field_name is not None) and (field_type is not None): if 'value' in field: value = field['value'] if len(value): if isinstance(value, list): yt_issue[field_name] = [] for v in value: create_value(target, v, field_name, field_type, project_id) yt_issue[field_name].append(get_value_presentation(field_type, v)) else: create_value(target, value, field_name, field_type, project_id) yt_issue[field_name] = get_value_presentation(field_type, value) return yt_issue
def te_st_live_get_cycle_time(self): yt = Connection('https://tickets.i.gini.net', username, password) print 'connected to [%s]' % yt.baseUrl issue = Issue() issue.id = 'BACKEND-671' issue.created = '123' issue = CycleTimeAwareIssue(issue, YoutrackProvider(yt)) self.assertEqual(7, issue.cycle_time.days)
def _to_yt_issue(self, issue, project_id): result = Issue() result.comments = [ self._to_yt_comment(comment) for comment in self._get_comments(issue) ] result.numberInProject = self._get_issue_id(issue) for (key, value) in issue.items(): self.process_field(key, project_id, result, value) return result
def test_get_cylce_time_for_issue(self): issue = Issue() issue.created = '123' issue.id = 'BACKEND-671' issue = CycleTimeAwareIssue(issue, TestProvider()) self.assertEqual( millis_to_datetime(1472861471944) - millis_to_datetime(1362960471944), issue.cycle_time) self.assertEqual(datetime.datetime(1970, 1, 1, 1, 0, 0, 123000), issue.created_time)
def test_issue_in_state_time(self): issue = Issue() issue.created = '123' issue.id = 'BACKEND-671' issue = CycleTimeAwareIssue(issue, TestProvider()) self.assertEqual( issue.time_in_state('Open'), millis_to_datetime(1362960471944) - issue.created_time) self.assertEqual( issue.time_in_state('In Progress'), millis_to_datetime(1472861471944) - millis_to_datetime(1362960471944)) self.assertEqual(issue.time_in_state('Complete'), datetime.timedelta(0)) self.assertEqual(issue.cycle_time, datetime.timedelta(1272, 3800)) self.assertEqual(issue.first_date_in_state('In Progress'), millis_to_datetime(1362960471944)) self.assertEqual(issue.cycle_time_start, millis_to_datetime(1362960471944)) self.assertEqual(issue.cycle_time_end, millis_to_datetime(1472861471944)) self.assertEqual( str(issue), '[BACKEND-671], (created): 1970-01-01 01:00:00.123000, ' '(Open->In Progress): 2013-03-11 01:07:51.944000, ' '(In Progress->Complete): 2016-09-03 02:11:11.944000, cycle time: 1272 days, 1:03:20' )
def to_yt_issue(target, project_id, g_issue, g_comments): issue = Issue() issue.numberInProject = issue_id(g_issue) issue.summary = g_issue.title.text.encode('utf-8') issue.description = HTMLParser.HTMLParser().unescape(g_issue.content.text).replace("<b>", "*").replace("</b>", "*").encode('utf-8') # issue.description = g_issue.content.text.encode('utf-8') issue.created = to_unix_date(g_issue.published.text) issue.updated = to_unix_date(g_issue.updated.text) reporter = g_issue.author[0].name.text create_user(target, reporter) issue.reporterName = reporter assignee = g_issue.owner.username.text if hasattr(g_issue, "owner") and (g_issue.owner is not None) else None assignee_field_name = get_yt_field_name("owner") if assignee is not None: add_value_to_field(target, project_id, assignee_field_name, googleCode.FIELD_TYPES[assignee_field_name], assignee) issue[assignee_field_name] = assignee status_field_name = get_yt_field_name("status") status = g_issue.status.text if hasattr(g_issue, "status") and (g_issue.status is not None) else None if status is not None: add_value_to_field(target, project_id, status_field_name, googleCode.FIELD_TYPES[status_field_name], status) issue[status_field_name] = status for field_name, field_value in get_custom_field_values(g_issue).items(): for value in field_value: add_value_to_field(target, project_id, field_name, googleCode.FIELD_TYPES[field_name], value) issue[field_name] = field_value issue.comments = [] for comment in g_comments: yt_comment = to_yt_comment(target, comment) if yt_comment is not None: issue.comments.append(yt_comment) return issue
def to_yt_issue(target, issue, project_id, fields_mapping=None, value_mappings=None): yt_issue = Issue() yt_issue['comments'] = [] yt_issue.numberInProject = issue['key'][(issue['key'].find('-') + 1):] for field, value in issue['fields'].items(): if value is None: continue if fields_mapping and field.lower() in fields_mapping: field_name, field_type = fields_mapping[field.lower()] else: field_name = get_yt_field_name(field) field_type = get_yt_field_type(field_name) if field_name == 'comment': for comment in value['comments']: yt_comment = Comment() yt_comment.text = comment['body'] comment_author_name = "guest" if 'author' in comment: comment_author = comment['author'] create_user(target, comment_author) comment_author_name = comment_author['name'] yt_comment.author = comment_author_name.replace(' ', '_') yt_comment.created = to_unix_date(comment['created']) yt_comment.updated = to_unix_date(comment['updated']) yt_issue['comments'].append(yt_comment) elif (field_name is not None) and (field_type is not None): if isinstance(value, list) and len(value): yt_issue[field_name] = [] for v in value: if isinstance(v, dict): v['name'] = get_yt_field_value(field_name, v['name'], value_mappings) else: v = get_yt_field_value(field_name, v, value_mappings) create_value(target, v, field_name, field_type, project_id) yt_issue[field_name].append(get_value_presentation(field_type, v)) else: if field_name.lower() == 'estimation': if field_type == 'period': value = int(int(value) / 60) elif field_type == 'integer': value = int(int(value) / 3600) if isinstance(value, int): value = str(value) if len(value): if isinstance(value, dict): value['name'] = get_yt_field_value(field_name, value['name'], value_mappings) else: value = get_yt_field_value(field_name, value, value_mappings) create_value(target, value, field_name, field_type, project_id) yt_issue[field_name] = get_value_presentation(field_type, value) elif _debug: print 'DEBUG: unclassified field', field_name return yt_issue
def to_yt_issue(target, project_id, story): parent = Issue() parent.numberInProject = str(story[u'id']) parent.summary = story[u'text'] parent['Size'] = story[u'size'] parent['Type'] = 'Feature' parent.created = get_created_date_for_story(story) color = story[u'color'] add_value_to_custom_field(target, project_id, 'Color', color) parent['Color'] = color priority = story[u'priority'] if len(priority): add_value_to_custom_field(target, project_id, 'Priority', priority) parent['Priority'] = priority if u'deadline' in story: parent['Deadline'] = str(to_unix_date(story[u'deadline'])) status = story[u'status'] add_value_to_custom_field(target, project_id, 'Status', status) parent['Status'] = status parent['Phase'] = story[u'phase'][u'name'] creator = story[u'creator'] import_user(target, creator) if u'owner' in story: owner = story[u'owner'] import_user(target, owner) parent['Assignee'] = owner[u'userName'] parent.reporterName = creator[u'userName'] parent.comments = [] if u'comments' in story: for comment in story[u'comments']: parent.comments.append(to_yt_comment(target, comment)) if u'details' in story: parent.description = story[u'details'] return parent
def _to_yt_issue(fb_issue, value_sets): issue = Issue() issue.numberInProject = str(fb_issue.ix_bug) issue.summary = fb_issue.title issue.created = fb_issue.opened issue.reporterName = fb_issue.reporter.replace(' ', "_") for field_name in fb_issue.field_values.keys(): value_set = None if field_name in value_sets: value_set = value_sets[field_name] yt_field_name = get_yt_field_name(field_name) field_value = fb_issue.field_values[field_name] if value_set is not None and field_value not in value_set : field_value = None value = to_yt_field_value(yt_field_name, field_value) if value is not None: issue[yt_field_name] = value issue.comments = [] is_description = True for c in fb_issue.comments : if is_description: issue.description = c.text is_description = False else : issue.comments.append(_to_yt_comment(c)) return issue
def to_yt_issue(target, project_id, story): parent = Issue() parent.numberInProject = str(story[u"id"]) parent.summary = story[u"text"] parent["Size"] = story[u"size"] parent["Type"] = "Feature" parent.created = get_created_date_for_story(story) color = story[u"color"] add_value_to_custom_field(target, project_id, "Color", color) parent["Color"] = color priority = story[u"priority"] if len(priority): add_value_to_custom_field(target, project_id, "Priority", priority) parent["Priority"] = priority if u"deadline" in story: parent["Deadline"] = str(to_unix_date(story[u"deadline"])) status = story[u"status"] add_value_to_custom_field(target, project_id, "Status", status) parent["Status"] = status parent["State"] = story[u"phase"][u"name"] creator = story[u"creator"] import_user(target, creator) if u"owner" in story: owner = story[u"owner"] import_user(target, owner) parent["Assignee"] = owner[u"userName"] parent.reporterName = creator[u"userName"] parent.comments = [] if u"comments" in story: for comment in story[u"comments"]: parent.comments.append(to_yt_comment(target, comment)) if u"details" in story: parent.description = story[u"details"] return parent
def to_yt_issue(target, project_id, story): parent = Issue() parent.numberInProject = str(story[u'id']) parent.summary = story[u'text'] parent['Size'] = story[u'size'] parent['Type'] = 'Feature' parent.created = get_created_date_for_story(story) color = story[u'color'] add_value_to_custom_field(target, project_id, 'Color', color) parent['Color'] = color priority = story[u'priority'] if len(priority): add_value_to_custom_field(target, project_id, 'Priority', priority) parent['Priority'] = priority if u'deadline' in story: parent['Deadline'] = str(to_unix_date(story[u'deadline'])) status = story[u'status'] add_value_to_custom_field(target, project_id, 'Status', status) parent['Status'] = status parent['State'] = story[u'phase'][u'name'] creator = story[u'creator'] import_user(target, creator) if u'owner' in story: owner = story[u'owner'] import_user(target, owner) parent['Assignee'] = owner[u'userName'] parent.reporterName = creator[u'userName'] parent.comments = [] if u'comments' in story: for comment in story[u'comments']: parent.comments.append(to_yt_comment(target, comment)) if u'details' in story: parent.description = story[u'details'] return parent
def _to_yt_issue(fb_issue, value_sets) : issue = Issue() issue.numberInProject = str(fb_issue.ix_bug) issue.summary = fb_issue.title issue.created = fb_issue.opened issue.reporterName = fb_issue.reporter.replace(' ', "_") for field_name in fb_issue.field_values.keys(): value_set = None if field_name in value_sets: value_set = value_sets[field_name] yt_field_name = get_yt_name_from_fb_field_name(field_name) field_value = fb_issue.field_values[field_name] if value_set is not None and field_value not in value_set : field_value = None value = to_yt_field_value(yt_field_name, field_value) if value is not None: issue[yt_field_name] = value issue.comments = [] is_description = True for c in fb_issue.comments : if is_description: issue.description = c.text is_description = False else : issue.comments.append(_to_yt_comment(c)) return issue
def to_yt_issue(target, jira_issue): issue = Issue() issue['comments'] = [] # process issue id issue.numberInProject = jira_issue.key[(jira_issue.key.find('-') + 1):] # process issue fields for jira_name in [ "priority", "updated", "description", "created", "type", "reporter", "fixVersions", "assignee", "status", "components", "affectsVersions", "summary", "resolution", "duedate" ]: field_name = get_yt_field_name(jira_name) field_type = get_yt_field_type(field_name) if field_name is not None: value = getattr(jira_issue, jira_name) if value is not None: if isinstance(value, typedArrayType): if len(value): issue[field_name] = [] for v in value: create_value(target, v, field_name, field_type, jira_issue.project) issue[field_name].append( get_value_presentation(field_type, v)) else: create_value(target, value, field_name, field_type, jira_issue.project) issue[field_name] = get_value_presentation( field_type, value) # process custom fields for custom_field in jira_issue.customFieldValues: field_name = get_yt_field_name(custom_field.customFieldId) field_value = custom_field.values field_type = get_yt_field_type(field_name) if (field_name is not None) and (field_type is not None): pass return issue
def create_yt_issue_from_jira_issue(target, issue, project_id): yt_issue = Issue() yt_issue['comments'] = [] yt_issue.numberInProject = issue['key'][(issue['key'].find('-') + 1):] for field, value in issue['fields'].items(): if value is None: continue field_name = get_yt_field_name(field) field_type = get_yt_field_type(field_name) if field_name == 'comment': for comment in value['comments']: yt_comment = Comment() yt_comment.text = comment['body'] comment_author_name = "guest" if 'author' in comment: comment_author = comment['author'] create_user(target, comment_author) comment_author_name = comment_author['name'] yt_comment.author = comment_author_name.replace(' ', '_') yt_comment.created = to_unix_date(comment['created']) yt_comment.updated = to_unix_date(comment['updated']) yt_issue['comments'].append(yt_comment) elif (field_name is not None) and (field_type is not None): if isinstance(value, list) and len(value): yt_issue[field_name] = [] for v in value: create_value(target, v, field_name, field_type, project_id) yt_issue[field_name].append( get_value_presentation(field_type, v)) else: if isinstance(value, int): value = str(value) if len(value): create_value(target, value, field_name, field_type, project_id) yt_issue[field_name] = get_value_presentation( field_type, value) else: print field_name return yt_issue
def to_yt_issue(target, jira_issue): issue = Issue() issue['comments']= [] # process issue id issue.numberInProject = jira_issue.key[(jira_issue.key.find('-') + 1):] # process issue fields for jira_name in ["priority", "updated", "description", "created", "type", "reporter", "fixVersions", "assignee", "status", "components", "affectsVersions", "summary", "resolution", "duedate"]: field_name = get_yt_field_name(jira_name) field_type = get_yt_field_type(field_name) if field_name is not None: value = getattr(jira_issue, jira_name) if value is not None: if isinstance(value, typedArrayType): if len(value): issue[field_name] = [] for v in value: create_value(target, v, field_name, field_type, jira_issue.project) issue[field_name].append(get_value_presentation(field_type, v)) else: create_value(target, value, field_name, field_type, jira_issue.project) issue[field_name] = get_value_presentation(field_type, value) # process custom fields for custom_field in jira_issue.customFieldValues: field_name = get_yt_field_name(custom_field.customFieldId) field_value = custom_field.values field_type = get_yt_field_type(field_name) if (field_name is not None) and (field_type is not None): pass return issue
def to_yt_sub_task(target, project_id, story, task): issue = Issue() issue.summary = task[u'text'] issue.reporterName = story[u'creator'][u'userName'] issue.created = str(to_unix_date(task[u'createTime'])) if u'finishTime' in task: issue.resolved = str(to_unix_date(task[u'finishTime'])) status = task[u'status'] add_value_to_custom_field(target, project_id, "Status", status) issue['Status'] = status issue['Type'] = 'Task' if u'finishedBy' in task: finished_by = task[u'finishedBy'] import_user(target, finished_by) issue['Assignee'] = finished_by[u'userName'] issue.comments = [] return issue
def to_yt_sub_task(target, project_id, story, task): issue = Issue() issue.summary = task[u"text"] issue.reporterName = story[u"creator"][u"userName"] issue.created = str(to_unix_date(task[u"createTime"])) if u"finishTime" in task: issue.resolved = str(to_unix_date(task[u"finishTime"])) status = task[u"status"] add_value_to_custom_field(target, project_id, "Status", status) issue["Status"] = status issue["Type"] = "Task" if u"finishedBy" in task: finished_by = task[u"finishedBy"] import_user(target, finished_by) issue["Assignee"] = finished_by[u"userName"] issue.comments = [] return issue
raise ex try : target.getProject(target_project_id) except Exception, ex: print "Can't connect to target project [%s]" % target_project_id raise ex #twin issues try : source_issue = source.getIssue(source_issue_id) except Exception, ex : print "Failed to get issue [%s]" % source_issue_id raise ex target_issue = Issue() #import users if needed name_fields = ["reporeterName", "assigneeName", "updaterName"] for field in name_fields : if (field in source_issue) : check_user(source_issue[field], source, target) target_issue.numberInProject = str(get_new_issue_id(target_project_id, target)) #check subsystem target_subsystem = None try : target.getSubsystem(target_project_id, source_issue.subsystem) target_subsystem = source_issue.subsystem except :
def do_move(source_url, source_login, source_password, target_url, target_login, target_password, source_issue_id, target): print("source_url : " + source_url) print("source_login : "******"source_password : "******"target_url : " + target_url) print("target_login : "******"target_password : "******"source_id : " + source_issue_id) if target.find('-') > -1: print("target_id : " + target) target_project_id, target_issue_number = target.split('-') else: print("target_project_id: " + target) target_project_id = target target_issue_number = None # connecting try: target = Connection(target_url, target_login, target_password) print("Connected to target url [%s]" % target_url) except Exception as ex: print("Failed to connect to target url [%s] with login/password [%s/%s]" % (target_url, target_login, target_password)) raise ex try: source = Connection(source_url, source_login, source_password) print("Connected to source url [%s]" % source_url) except Exception as ex: print("Failed to connect to source url [%s] with login/password [%s/%s]" % (source_url, source_login, source_password)) raise ex try: target.getProject(target_project_id) except Exception as ex: print("Can't connect to target project [%s]" % target_project_id) raise ex # twin issues try: source_issue = source.getIssue(source_issue_id) except Exception as ex: print("Failed to get issue [%s]" % source_issue_id) raise ex target_issue = Issue() # import users if needed name_fields = ["reporterName", "assigneeName", "updaterName"] for field in name_fields: if field in source_issue: check_user(source_issue[field], source, target) if not target_issue_number: target_issue_number = str(get_new_issue_id(target_project_id, target)) target_issue.numberInProject = target_issue_number # check subsystem target_subsystem = None try: target.getSubsystem(target_project_id, source_issue.subsystem) target_subsystem = source_issue.subsystem except (YouTrackException, AttributeError): pass target_issue.subsystem = target_subsystem for field in PREDEFINED_FIELDS: if field in source_issue: target_issue[field] = source_issue[field] if "Type" in source_issue: target_issue.type = source_issue["Type"] elif "type" in source_issue: target_issue.type = source_issue["type"] else: target_issue.type = "Bug" # convert custom field target_cfs = target.getProjectCustomFields(target_project_id) for cf in target_cfs: cf_name = cf.name if cf_name in source_issue: target_issue[cf_name] = source_issue[cf_name] # comments target_issue.comments = source_issue.getComments() for comment in target_issue.comments: check_user(comment.author, source, target) # import issue print(target.importIssues( target_project_id, "", [target_issue])) # attachments for attachment in source_issue.getAttachments(): check_user(attachment.authorLogin, source, target) attachment.url = attachment.url.replace(source_url, "") target.createAttachmentFromAttachment( "%s-%s" % (target_project_id, target_issue.numberInProject), attachment) # work items if get_time_tracking_state( source, target, source_issue_id.split('-')[0], target_project_id): workitems = source.getWorkItems(source_issue_id) if workitems: existing_workitems = dict() target_workitems = target.getWorkItems( target_project_id + '-' + target_issue_number) if target_workitems: for w in target_workitems: _id = '%s\n%s\n%s' % (w.date, w.authorLogin, w.duration) if hasattr(w, 'description'): _id += '\n%s' % w.description existing_workitems[_id] = w new_workitems = [] for w in workitems: _id = '%s\n%s\n%s' % (w.date, w.authorLogin, w.duration) if hasattr(w, 'description'): _id += '\n%s' % w.description if _id not in existing_workitems: new_workitems.append(w) if new_workitems: print("Process workitems for issue [ " + source_issue_id + "]") try: for w in new_workitems: check_user(w.authorLogin, source, target) target.importWorkItems( target_project_id + '-' + target_issue_number, new_workitems) except YouTrackException as e: print("Failed to import workitems: " + str(e)) # links link_importer = LinkImporter(target) links2import = source_issue.getLinks() link_importer.collectLinks(links2import) link_importer.addAvailableIssue(source_issue) for l in links2import: link_importer.addAvailableIssue(source.getIssue(l.source)) link_importer.addAvailableIssue(source.getIssue(l.target)) link_importer.importCollectedLinks()
def do_move(source_url, source_login, source_password, target_url, target_login, target_password, source_issue_id, target): print("source_url : " + source_url) print("source_login : "******"source_password : "******"target_url : " + target_url) print("target_login : "******"target_password : "******"source_id : " + source_issue_id) if target.find('-') > -1: print("target_id : " + target) target_project_id, target_issue_number = target.split('-') else: print("target_project_id: " + target) target_project_id = target target_issue_number = None # connecting try: target = Connection(target_url, target_login, target_password) print("Connected to target url [%s]" % target_url) except Exception as ex: print("Failed to connect to target url [%s] with login/password [%s/%s]" % (target_url, target_login, target_password)) raise ex try: source = Connection(source_url, source_login, source_password) print("Connected to source url [%s]" % source_url) except Exception as ex: print("Failed to connect to source url [%s] with login/password [%s/%s]" % (source_url, source_login, source_password)) raise ex try: target.getProject(target_project_id) except Exception as ex: print("Can't connect to target project [%s]" % target_project_id) raise ex # twin issues try: source_issue = source.getIssue(source_issue_id) except Exception as ex: print("Failed to get issue [%s]" % source_issue_id) raise ex target_issue = Issue() # import users if needed name_fields = ["reporterName", "assigneeName", "updaterName"] for field in name_fields: if field in source_issue: check_user(source_issue[field], source, target) if not target_issue_number: target_issue_number = str(get_new_issue_id(target_project_id, target)) target_issue.numberInProject = target_issue_number # check subsystem target_subsystem = None try: target.getSubsystem(target_project_id, source_issue.subsystem) target_subsystem = source_issue.subsystem except (YouTrackException, AttributeError): pass target_issue.subsystem = target_subsystem for field in PREDEFINED_FIELDS: if field in source_issue: target_issue[field] = source_issue[field] if "Type" in source_issue: target_issue.type = source_issue["Type"] elif "type" in source_issue: target_issue.type = source_issue["type"] else: target_issue.type = "Bug" # convert custom field target_cfs = target.getProjectCustomFields(target_project_id) for cf in target_cfs: cf_name = cf.name if cf_name in source_issue: target_issue[cf_name] = source_issue[cf_name] # comments target_issue.comments = source_issue.getComments() for comment in target_issue.comments: check_user(comment.author, source, target) # attachments print(target.importIssues( target_project_id, target.getProjectAssigneeGroups(target_project_id)[0].name, [target_issue])) for attachment in source_issue.getAttachments(): check_user(attachment.authorLogin, source, target) target.createAttachmentFromAttachment( "%s-%s" % (target_project_id, target_issue.numberInProject), attachment)