def build_issue(self, issue): self.create_fields(issue['fields'].keys()) yt_issue = youtrack.Issue() yt_issue.numberInProject = issue['key'][(issue['key'].find('-') + 1):] yt_issue['comments'] = [] yt_issue['description'] = self.build_description(issue) for field, value in issue['fields'].items(): if value is None: continue field_name, field_type = self.describe_field(field) if field_name is None: continue if field_name == 'comment': for comment in value['comments']: yt_issue['comments'].append(self.build_comment(comment)) if field_type is None: if _debug: print 'DEBUG: unclassified field', field continue is_list = isinstance(value, list) values = [] for v in (value if is_list else [value]): values.append(self.build_value(field_name, field_type, v)) if len(values): if is_list: yt_issue[field_name] = values else: yt_issue[field_name] = values[0] if 'reporterName' not in yt_issue: yt_issue['reporterName'] = 'root' return yt_issue
def _make_issue(self, redmine_issue, project_id): issue = youtrack.Issue() issue['comments'] = [] try: if self._params.get('create_redmine_linkage', False): self._add_field_to_issue(project_id, issue, "redmine_id", int(redmine_issue.id)) for name, value in redmine_issue.attributes.items(): if name in ('project', 'attachments'): continue if name == 'assigned_to' and value.name in self._groups: continue if name == 'id': value = str(self._get_yt_issue_number(redmine_issue)) if name == 'custom_fields': for field in value: self._add_field_to_issue(project_id, issue, field.name, field.value) elif name == 'journals': self._add_journals(issue, value) else: if name == 'category': value = self._to_yt_subsystem(value) if name == 'fixed_version': value = self._to_yt_version(value) self._add_field_to_issue(project_id, issue, name, value) except Exception, e: print 'Failed to process issue:' print redmine_issue traceback.print_exc() raise e
def getIssues(self, projectId, filter, after, max): #response, content = self._req('GET', '/project/issues/' + urlquote(projectId) + "?" + response, content = self._req('GET', '/issue/byproject/' + urlquote(projectId) + "?" + urllib.urlencode({'after': str(after), 'max': str(max), 'filter': filter})) xml = minidom.parseString(content) return [youtrack.Issue(e, self) for e in xml.documentElement.childNodes if e.nodeType == Node.ELEMENT_NODE]
def getAllIssues(self, filter = '', after = 0, max = 999999, withFields = ()): urlJobby = [('with',field) for field in withFields] + \ [('after',str(after)), ('max',str(max)), ('filter',filter)] response, content = self._req('GET', '/issue' + "?" + urllib.urlencode(urlJobby)) xml = minidom.parseString(content) return [youtrack.Issue(e, self) for e in xml.documentElement.childNodes if e.nodeType == Node.ELEMENT_NODE]
def get_issues(self, project_id, _filter, after, _max, updated_after=None, wikify=None): # response, content = self._req('GET', '/project/issues/' + urlquote(projectId) + "?" + params = {'after': str(after), 'max': str(_max), 'filter': _filter} if updated_after is not None: params['updatedAfter'] = updated_after if wikify is not None: params['wikifyDescription'] = wikify response, content = self._req('GET', '/issue/byproject/' + urlquote(project_id) + "?" + urllib.parse.urlencode(params)) xml = minidom.parseString(content) return [youtrack.Issue(e, self) for e in xml.documentElement.childNodes if e.nodeType == Node.ELEMENT_NODE]
def to_youtrack_issue(project_ID, trac_issue, check_box_fields): issue = youtrack.Issue() issue.numberInProject = str(trac_issue.id) issue.summary = trac_issue.summary issue.description = trac_issue.description if trac_issue.time > 0: issue.created = str(trac_issue.time) if trac_issue.changetime > 0: issue.updated = str(trac_issue.changetime) # anonymous in trac == guest in util if trac_issue.reporter is None: issue.reporterName = "guest" else: issue.reporterName = trac_issue.reporter # watchers issue.watcherName = set([]) for cc in trac_issue.cc: issue.watcherName.add(cc) # adding custom fields to issue custom_fields = trac_issue.custom_fields for cf in custom_fields.keys(): if cf in check_box_fields: if custom_fields[cf] != "0": issue[cf] = check_box_fields[cf] else: value = custom_fields[cf] if cf in youtrackutils.tracLib.FIELD_NAMES.keys(): cf = youtrackutils.tracLib.FIELD_NAMES[cf] if cf in youtrackutils.tracLib.FIELD_VALUES.keys(): cf_values_mapping = youtrackutils.tracLib.FIELD_VALUES[cf] if value in cf_values_mapping: value = cf_values_mapping[value] if (value is not None) and (value.strip() != ""): issue[cf] = value # handle special case of status:closed / resolution:fixed if (custom_fields["Status"] is not None) and (custom_fields["Status"] == "closed"): if (custom_fields["Resolution"] is not None) and (custom_fields["Resolution"] == "fixed"): issue["State"] = "Verified" unsorted_comments = [] for comment in trac_issue.comments: unsorted_comments.append(to_youtrack_comment(project_ID, comment)) issue.comments = sorted(unsorted_comments, key=lambda it: it.created) return issue
def _make_issue(self, redmine_issue, project_id): issue = youtrack.Issue() issue['comments'] = [] print(("--- ISSUE #{0}".format(redmine_issue.id))) if self._params.get('use_markdown'): issue['markdown'] = "true" try: if not hasattr(redmine_issue, 'author'): redmine_issue.author = 2 # set to Anonymous if self._params.get('create_redmine_linkage', False): self._add_field_to_issue(project_id, issue, "redmine_id", int(redmine_issue.id)) checklist_value = None for name, value in list(redmine_issue.attributes.items()): if name in ('project', 'attachments', 'tags'): continue if name == 'assigned_to' and value.name in self._groups: continue if name == 'id': value = str(self._get_yt_issue_number(redmine_issue)) if name == 'checklist': checklist_value = str(value) continue if name == 'custom_fields': for field in value: self._add_field_to_issue(project_id, issue, field.name, getattr(field, 'value', None)) elif name == 'journals': self._add_journals(issue, value) else: if name == 'category': value = self._to_yt_subsystem(value) self._add_field_to_issue(project_id, issue, name, value) if checklist_value: issue['description'] = issue[ 'description'] + "\n\n#### Checklist\n" + checklist_value except Exception as e: print('Failed to process issue:') print(redmine_issue) traceback.print_exc() raise e return issue
def to_youtrack_issue(trac_issue, check_box_fields): issue = youtrack.Issue() issue.numberInProject = str(trac_issue.id) issue.summary = trac_issue.summary issue.description = trac_issue.description if trac_issue.time > 0: issue.created = str(trac_issue.time) if trac_issue.changetime > 0: issue.updated = str(trac_issue.changetime) # anonymous in trac == guest in youtrack if trac_issue.reporter is None: issue.reporterName = "guest" else: issue.reporterName = trac_issue.reporter #watchers issue.watcherName = set([]) for cc in trac_issue.cc: issue.watcherName.add(cc) #adding custom fields to issue custom_fields = trac_issue.custom_fields for cf in custom_fields.keys(): if cf in check_box_fields: if custom_fields[cf] != "0": issue[cf] = check_box_fields[cf] else: value = custom_fields[cf] if cf in tracLib.FIELD_NAMES.keys(): cf = tracLib.FIELD_NAMES[cf] if cf in tracLib.FIELD_VALUES.keys(): cf_values_mapping = tracLib.FIELD_VALUES[cf] if value in cf_values_mapping: value = cf_values_mapping[value] if (value is not None) and (value.strip() != ""): issue[cf] = value issue.comments = [] for comment in trac_issue.comments: issue.comments.append(to_youtrack_comment(comment)) return issue
def getIssue(self, id): return youtrack.Issue(self._get("/issue/" + id), self)
def get_issue(self, _id): return youtrack.Issue(self._get("/issue/" + _id), self)
def migrate_tasks_to_issues(a_conn, yt_conn, a_work, yt_proj, yt_login): """ Asana Tasks can be in multiple Projects, yet YouTrack Issues can be in only one Subsystem. Thus, we will use the 1st Project in the Asana list to use as the YouTrack Subsystem """ # We must filter tasks by project, tag, or assignee + workspace, so we'll use the last option and migrate tasks # one user at a time numberInProject = 0 for a_id, a_user in _a_users.iteritems(): a_tasks = [ i for i in a_conn.tasks.find_all(params={ 'workspace': a_work['id'], 'assignee': a_id }) ] if len(a_tasks) == 0: continue msg = "Fetching details for {} Asana Tasks assigned to {} in Workspace {}" print msg.format(len(a_tasks), a_user['email'], a_work['name']) a_tasks = get_task_details(a_conn, a_tasks) # print "Asana task details: {}".format(a_tasks) # Add to map merge_into_map(a_tasks, 'name', _task_map) global _a_tasks for i in a_tasks: _a_tasks[i['id']] = i.copy() print "Fetching existing YouTrack tasks" # Checking existing issues in YouTrack yt_filter = "Assignee: {}".format( _user_map[a_user['email']]['yt'].login) yt_issues = [ i for i in yt_conn.getIssues(yt_proj.id, yt_filter, 0, 1000) ] # yt_issues = [yt_conn.getIssue(i.id) for i in yt_conn.getIssues(yt_proj.id, yt_filter, 0, 1000)] merge_into_map(yt_issues, 'summary', _task_map) merge_into_map(yt_issues, 'AsanaID', _asana_id_map) global _yt_issues for i in yt_issues: _yt_issues[i.numberInProject] = i numberInProject = max(numberInProject, int(i.numberInProject)) numberInProject += 1 # print "Task details: {}".format(yt_issues) # Now add Issues from all Tasks new_issues = [] print 'Fetching Asana stories for each task...' for a in a_tasks: # Skip adding tasks where task name matches issue summary if 'yt' in _task_map[a['name']] or str(a['id']) in _asana_id_map: print "Skipping task import : {}".format( a['name'].encode('utf-8')) continue # Look at Asana Story to find out who the YouTrack Issue reporterName should be a_stories = get_task_stories(a_conn, a) a_stories = get_story_details(a_conn, a_stories) # Save for later _a_tasks[a['id']]['stories'] = a_stories # Establish our comments and who created this Task comments = [] reporter_name = None for s in a_stories: if s['type'] == 'comment': comment = yt.Comment() comment.author = a_id_to_yt_login(s['created_by']['id']) # _user_map[_a_users[s['created_by']['id']]['email']]['yt'].login comment.text = s['text'] comment.created = a_to_yt_time(s['created_at']) comments.append(comment) elif s['type'] == 'system' and reporter_name is None and s[ 'text'][:9] in ['assigned ', 'added to ', 'added sub']: # TODO if subtask, link to other YT Issue reporter_name = a_id_to_yt_login(s['created_by']['id']) # Build a list for bulk importing later """[{'numberInProject':'1', 'summary':'some problem', 'description':'some description', 'priority':'1', 'fixedVersion':['1.0', '2.0'], 'comment':[{'author':'yamaxim', 'text':'comment text', 'created':'1267030230127'}]}, {'numberInProject':'2', 'summary':'some problem', 'description':'some description', 'priority':'1'}]""" if reporter_name is None: if a.get('asignee', None) is not None: reporter_name = a_id_to_yt_login(a['assignee']['id']) else: reporter_name = yt_login new_issue = yt.Issue() new_issue.comments = comments new_issue.reporterName = reporter_name new_issue['AsanaID'] = str(a['id']) new_issue.numberInProject = str(numberInProject) new_issue.summary = a.get('name', '') new_issue.description = a.get('notes', '') new_issue.state = 'Fixed' if a.get('completed', False) is True else 'Submitted' new_issue.assignee = a_id_to_yt_login(a['assignee']['id']) if a['due_on'] is not None: new_issue['Due Date'] = a_to_yt_date(a['due_on']) # new_issue = dict(numberInProject=str(a['id']), summary=a.get('name', ''), description=a.get('notes', ''), # state='Fixed' if a.get('completed', False) is True else 'Submitted') if 'created_at' in a: # created = datetime.strptime(a['created_at'], '%Y-%m-%dT%H:%M:%S.%fZ') # created = "{}{}".format(created.strftime('%s'), created.strftime('%f'))[:-3] new_issue.created = a_to_yt_time(a['created_at']) if 'modified_at' in a: # updated = datetime.strptime(a['modified_at'], '%Y-%m-%dT%H:%M:%S.%fZ') # updated = "{}{}".format(updated.strftime('%s'), updated.strftime('%f'))[:-3] # new_issue.updated = updated new_issue.updated = a_to_yt_time(a['modified_at']) if a.get('completed_at', None) is not None: # resolved = datetime.strptime(a['completed_at'], '%Y-%m-%dT%H:%M:%S.%fZ') # resolved = "{}{}".format(resolved.strftime('%s'), resolved.strftime('%f'))[:-3] # new_issue.resolved = resolved new_issue.resolved = a_to_yt_time(a['completed_at']) if 'projects' in a and len(a['projects']) > 0: new_issue['subsystem'] = a['projects'][0]['name'] new_issues.append(new_issue) numberInProject += 1 print 'Creating new YouTrack Issues for {} (Asana IDs: {})'.format( a_user['email'], [n.AsanaID for n in new_issues]) print yt_conn.importIssues(yt_proj.id, None, new_issues, test=False)