Permalink
Browse files

add sync script

  • Loading branch information...
1 parent 58b47c3 commit a3c76b876761b0692b404d0d0471be1788f11702 anna.zhdan committed Apr 9, 2012
@@ -0,0 +1,23 @@
+import SOAPpy
+import SOAPpy.Types
+import getpass
+import datetime
+import time
+
+class JiraSoapClient:
+ def __init__(self, url, login, password):
+ self._soap = SOAPpy.WSDL.Proxy(url + '/rpc/soap/jirasoapservice-v2?wsdl')
+ self._auth = self._soap.login(login, password)
+
+ def get_issues(self, project_id, from_id, to_id):
+ issues = []
+ for i in range(from_id, to_id):
+ issue_id = project_id + '-' + str(i)
+ try:
+ issue = self._soap.getIssue(self._auth, issue_id)
+ issues.append(issue)
+ except BaseException:
+ print "Can't find issue wih id [ %s ]" % issue_id
+ pass
+ return issues
+
@@ -0,0 +1,135 @@
+from SOAPpy.Types import typedArrayType
+import jira
+from jira.jiraSoapClient import JiraSoapClient
+from youtrack import Issue, YouTrackException
+from youtrack.connection import Connection
+from youtrack.importHelper import create_bundle_safe
+
+def to_unix_date(time_tuple):
+ return "27000000"
+
+def create_user(target, value):
+ try:
+ target.createUserDetailed(value.replace(' ', '_'), value, 'fake_email', 'fake_jabber')
+ except YouTrackException, e:
+ print(str(e))
+
+
+def get_yt_field_name(jira_name):
+ if jira_name in jira.FIELD_NAMES:
+ return jira.FIELD_NAMES[jira_name]
+ return jira_name
+
+
+def get_yt_field_type(jira_name):
+ if jira_name in jira.SOAP_TYPES:
+ return jira.SOAP_TYPES[jira_name]
+ return None
+
+def create_value(target, value, field_name, field_type, project_id):
+ if (field_type is not None) and field_type.startswith('user'):
+ create_user(target, value)
+ value = value.replace(' ', '_')
+ if field_name in jira.EXISTING_FIELDS:
+ return
+ if field_name.lower() not in [field.name.lower() for field in target.getProjectCustomFields(project_id)]:
+ if field_name.lower() not in [field.name.lower() for field in target.getCustomFields()]:
+ target.createCustomFieldDetailed(field_name, field_type, False, True, False, {})
+ if field_type in ['string', 'date', 'integer']:
+ target.createProjectCustomFieldDetailed(project_id, field_name, "No " + field_name)
+ else:
+ bundle_name = field_name + " bundle"
+ create_bundle_safe(target, bundle_name, field_type)
+ target.createProjectCustomFieldDetailed(project_id, field_name, "No " + field_name, {'bundle': bundle_name})
+ if field_type in ['string', 'date', 'integer']:
+ return
+ project_field = target.getProjectCustomField(project_id, field_name)
+ bundle = target.getBundle(field_type, project_field.bundle)
+ try:
+ if isinstance(value, str):
+ target.addValueToBundle(bundle, value)
+ elif hasattr(value, 'name'):
+ target.addValueToBundle(bundle, value.name)
+ elif hasattr(value, 'value'):
+ target.addValueToBundle(bundle, value.value)
+ except YouTrackException:
+ pass
+
+def get_value_presentation(field_type, value):
+ if field_type == 'date':
+ return to_unix_date(value)
+ if field_type == 'integer':
+ return str(value)
+ if field_type == 'string':
+ return value
+ if hasattr(value, 'name'):
+ return value.name
+ if (field_type is not None) and field_type.startswith('user'):
+ return value.replace(' ', '_')
+ return value
+
+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
+
+
+
+source = JiraSoapClient("http://bugs.adobe.com/jira", "anna239", "948200")
+target = Connection('http://localhost:8081', 'root', 'root')
+
+project_ids = {'ACS' : 100,
+ 'ASL' : 100,
+ 'BLZ' : 100,
+ 'CGM' : 100,
+ 'DURANGO' : 100,
+ 'FCM' : 100,
+ 'FLEXDMV' : 100,
+ 'FLEXDOCS' : 100,
+ 'FLEXENT' : 100,
+ 'SDK' : 100,
+ 'FLEXPMD' : 100,
+ 'FXU' : 100
+}
+
+
+for p_id in project_ids:
+ target.createProjectDetailed(p_id, p_id, "", "root")
+ step = 10
+ for i in range(0, project_ids[p_id] / step + 1):
+ yt_issues = []
+ for issue in source.get_issues(p_id, i * 10, (i + 1) * 10):
+ yt_issues.append(to_yt_issue(target, issue))
+ target.importIssues(p_id, p_id + " assignees", yt_issues)
View
@@ -0,0 +1,161 @@
+from youtrack import YouTrackException
+from youtrack.connection import Connection
+from youtrack2youtrack import youtrack2youtrack
+
+last_run = 0
+project_id = "JT"
+tag = "sync"
+fields_to_sync = ['state', 'type', 'priority', 'subsystem', 'assigneeName', 'fixVersions', 'affectedVersions']
+query = "tag: " + tag
+
+def get_updated_issues(yt, after):
+ return yt.getIssues(project_id, query, 0, 100)
+
+def get_issue_changes(yt, issue, after):
+# yt.headers['Accepts'] = 'application/json;charset=utf-8'
+ result = yt.get_changes_for_issue(issue.id)
+ new_changes = []
+ for change in result:
+ if change['updated'] < after:
+ break
+ else:
+ new_changes.append(change)
+ return new_changes
+
+def apply_changes_to_issue(to_yt, from_yt, issue_id, changes, fields_to_ignore = []):
+ changed_fields = set()
+ for change in changes:
+ run_as = change.updater_name
+ to_yt.importUsers([from_yt.getUser(run_as)])
+ comment = None
+ if len(change.comments):
+ comment = change.comments[0]
+ command = ""
+ for field in change.fields:
+ field_name = field.name.lower()
+ if field.name != 'links' and field_name in fields_to_sync and field_name not in fields_to_ignore:
+ for value in field.new_value:
+ changed_fields.add(field_name)
+ command += field_name + " " + value + " "
+ if (not len(command)) and comment is not None:
+ command = comment
+ to_yt.executeCommand(project_id + "-" + issue_id, command, comment, run_as=run_as)
+ return changed_fields
+
+
+def apply_changes_to_new_issue(yt, issue_id_to_apply, original_issue):
+ command = ""
+ for field in fields_to_sync:
+ field_value = original_issue[field]
+ if len(field_value):
+ if isinstance(field_value, list):
+ for value in field_value:
+ command += field + " " + value + " "
+ else:
+ command += field + " " + field_value + " "
+
+ yt.executeCommand(project_id + "-" + issue_id_to_apply, command)
+ for comment in original_issue.getComments():
+ yt.executeCommand(issue_id_to_apply, "comment", comment.text, None, comment.author)
+
+def merge_and_apply_changes(left_yt, left_issue_id, left_changes, right_yt, right_issue_id, right_changes):
+ changed_fields = apply_changes_to_issue(right_yt, left_yt, right_issue_id, left_changes)
+ apply_changes_to_issue(left_yt, right_yt, left_issue_id, right_changes, changed_fields)
+
+master_issue_id_field_name = 'masterIssueId'
+
+master = Connection("http://teamsys.labs.intellij.net", "root", "root")
+slave = Connection("http://localhost:13864", "root", "root")
+
+try:
+ slave.getProject(project_id)
+except YouTrackException:
+ slave.createCustomFieldDetailed(master, "integer", False, True, True)
+ youtrack2youtrack("http://teamsys.labs.intellij.net", "root", "root", "http://localhost:13864", "root", "root", [project_id], query)
+ go_on = True
+ start = 0
+ amount = 100
+ while go_on:
+ go_on = False
+ issues = slave.getIssues(project_id, '', start, amount)
+ start += amount
+ for issue in issues:
+ go_on = True
+ slave.executeCommand(issue.id, master_issue_id_field_name + " " + issue.numberInProject)
+
+
+updated_master_issues = get_updated_issues(master, last_run)
+updated_slave_issues = get_updated_issues(slave, last_run)
+
+updated_slave_issue_ids = [issue[master_issue_id_field_name] for issue in updated_slave_issues if
+ master_issue_id_field_name in issue and issue[master_issue_id_field_name] is not None]
+updated_master_issue_ids = [issue.numberInProject for issue in updated_master_issues]
+
+changed_in_master = [issue for issue in updated_master_issues if issue.numberInProject not in updated_slave_issue_ids]
+changed_in_slave = [issue for issue in updated_slave_issues if
+ master_issue_id_field_name not in issue or issue[
+ master_issue_id_field_name] not in updated_slave_issue_ids]
+changed_in_both = [issue for issue in updated_slave_issue_ids if
+ master_issue_id_field_name in issue and issue[master_issue_id_field_name] in updated_master_issue_ids]
+
+links_to_be_added_in_slave = []
+links_to_be_removed_in_slave = []
+links_to_be_added_in_master = []
+links_to_be_removed_in_master = []
+
+for issue in changed_in_slave:
+ links_to_be_added_in_master += issue.getLinks(True)
+ if master_issue_id_field_name in issue:
+ master_issue_id = issue[master_issue_id_field_name]
+ if master_issue_id is not None:
+ changes = get_issue_changes(slave, issue, last_run)
+ apply_changes_to_issue(master, slave, master_issue_id, changes)
+ continue
+ #if we are here now, it means that issue is not currently in master instance, so create it!
+ created_issue = master.createIssue(project_id, None, issue.summary, issue.description, None, None, None, None, None,
+ None, None)
+ issue_id = created_issue.rpartition('-')[2]
+ apply_changes_to_new_issue(master, issue_id, issue)
+ master.executeCommand(issue_id, "tag " + tag)
+ slave.executeCommand(issue.id, master_issue_id_field_name + " " + issue_id)
+
+for issue in changed_in_master:
+ links_to_be_added_in_slave += issue.getLinks(True)
+ slave_issues = slave.getIssues(project_id, master_issue_id_field_name + ": " + issue.id, 0, 1)
+ if len(slave_issues):
+ slave_issue_id = slave_issues[0].id
+ changes = get_issue_changes(master, issue, last_run)
+ apply_changes_to_issue(slave, master, slave_issue_id, changes)
+ else:
+ slave_issue_id = project_id + "-" + slave.createIssue(project_id, issue.summary, issue.description, None, None, None, None, None,
+ None, None, None).rpartition('-')[2]
+ apply_changes_to_new_issue(slave, slave_issue_id, issue)
+ slave.executeCommand(slave_issue_id, master_issue_id_field_name + " " + issue.numberInProject)
+ slave.executeCommand(slave_issue_id, "tag " + tag)
+
+for issue in changed_in_both:
+ links_to_be_added_in_master += issue.getLinks(True)
+ slave_changes = get_issue_changes(slave, issue, last_run)
+ master_issue_id = project_id + "-" + issue[master_issue_id_field_name]
+ links_to_be_added_in_slave += master.getIssue(master_issue_id).getLinks(True)
+ master_changes = get_issue_changes(master, master.getIssue(master_issue_id), last_run)
+ merge_and_apply_changes(slave, issue.id, slave_changes, master, master_issue_id, master_changes)
+
+for link in links_to_be_added_in_slave:
+ source = link.source
+# link.source = link.target
+# link.target = source
+ link.source = slave.getIssues(project_id, master_issue_id_field_name + ": " + link.source.rpartition('-')[2], 0, 1)[0].id
+ link.target = slave.getIssues(project_id, master_issue_id_field_name + ": " + link.traget.rpartition('-')[2], 0, 1)[0].id
+
+for link in links_to_be_added_in_master:
+ source = link.source
+# link.source = link.target
+# link.target = source
+ link.source = project_id + "-" + slave.getIssue(link.source)[master_issue_id_field_name]
+ link.target = project_id + "-" + slave.getIssue(link.target)[master_issue_id_field_name]
+
+slave.importLinks(links_to_be_added_in_slave)
+master.importLinks(links_to_be_added_in_master)
+
+
Oops, something went wrong. Retry.

0 comments on commit a3c76b8

Please sign in to comment.