def __init__(self, master, slave, logger, issue_binder, project_id, fields_to_sync, query, last_run=None, current_run=None): self.slave = None self.master = master self.slave = slave self.logger = logger self.master_executor = SafeCommandExecutor(master, logger) self.slave_executor = SafeCommandExecutor(slave, logger) self.issue_binder = issue_binder self.query = query self.last_run = last_run self.current_run = current_run self.project_id = project_id self.link_synchronizer = LinkSynchronizer(self.master_executor, self.slave_executor, self.issue_binder) self.issue_synchronizer = AsymmetricIssueMerger( master, slave, self.master_executor, self.slave_executor, self.issue_binder, self.link_synchronizer, fields_to_sync, last_run, current_run, project_id)
def __init__(self, master, slave, logger, issue_binder, project_id, fields_to_sync, query, last_run=None, current_run=None): self.slave = None self.master = master self.slave = slave self.logger = logger self.master_executor = SafeCommandExecutor(master, logger) self.slave_executor = SafeCommandExecutor(slave, logger) self.issue_binder = issue_binder self.query = query self.last_run = last_run self.current_run = current_run self.project_id = project_id self.link_synchronizer = LinkSynchronizer(self.master_executor, self.slave_executor, self.issue_binder) self.issue_synchronizer = AsymmetricIssueMerger(master, slave, self.master_executor, self.slave_executor, self.issue_binder, self.link_synchronizer, fields_to_sync, last_run, current_run, project_id)
class YouTrackSynchronizer(object): def __init__(self, master, slave, logger, issue_binder, project_id, fields_to_sync, query, last_run=None, current_run=None): self.slave = None self.master = master self.slave = slave self.logger = logger self.master_executor = SafeCommandExecutor(master, logger) self.slave_executor = SafeCommandExecutor(slave, logger) self.issue_binder = issue_binder self.query = query self.last_run = last_run self.current_run = current_run self.project_id = project_id self.link_synchronizer = LinkSynchronizer(self.master_executor, self.slave_executor, self.issue_binder) self.issue_synchronizer = AsymmetricIssueMerger( master, slave, self.master_executor, self.slave_executor, self.issue_binder, self.link_synchronizer, fields_to_sync, last_run, current_run, project_id) def setDebugMode(self, on): self.master_executor.setDebugMode(on) self.slave_executor.setDebugMode(on) def sync(self): #0. create if not existed and attach synchronization field self._create_and_attach_sync_field(self.slave, self.project_id, master_sync_field_name) #1. synchronize sync-issues in slave which have no synchronized clone in master imported_slave_ids_set = self._apply_to_issues( self._get_tagged_only_in_slave, self._import_to_master, log_header='[Sync, Importing new issues from slave to master]') #2. synchronize sync-issues in master which have no synchronized clone in slave sync_set = set(self.issue_binder.s_to_m.values()) imported_master_ids_set = self._apply_to_issues( self._get_tagged_in_master, self._import_to_slave, excluded_ids=sync_set, log_header='[Sync, Importing new issues from master to slave]') #3. synchronize sync-issues updated in slave which have synchronized clone in master updated_slave_ids_set = self._apply_to_issues( self._get_updated_in_slave_from_last_run, self._sync_to_master, excluded_ids=imported_slave_ids_set, log_header='[Sync, Merging sync issues updated in slave]') #4. synchronize sync-issues updated in master which have synchronized clone in slave (if clone hasn't been updated) updated_master_ids_set = self._slave_ids_set_to_sync_ids_set( updated_slave_ids_set) | imported_master_ids_set self._apply_to_issues( self._get_updated_in_master_from_last_run, self._sync_to_slave, excluded_ids=updated_master_ids_set, log_header= '[Sync, Merging sync issues updated in master and unchanged in slave]' ) #5. synchronize links self.link_synchronizer.syncCollectedLinks() def syncAfterImport(self): self._create_and_attach_sync_field(self.slave, self.project_id, master_sync_field_name) start = 0 issues = self.slave.getIssues(self.project_id, '', start, batch) while len(issues): for issue in issues: issue_id = issue.id issue_number = issue_id.rpartition('-')[2] self._mark_issues_as_sync(issue_number, issue_id, issue_id) start += batch issues = self.slave.getIssues(self.project_id, '', start, batch) def _slave_ids_set_to_sync_ids_set(self, ids): return set( [self.issue_binder.slaveIssueIdToMasterIssueId(id) for id in ids]) def _import_to_master(self, slave_issue): master_issue_id = self.issue_synchronizer.clone_issue_to_master( slave_issue) if master_issue_id: self._mark_issues_as_sync( master_issue_id.rpartition('-')[2], master_issue_id, slave_issue.id) def _import_to_slave(self, master_issue): slave_issue_id = self.issue_synchronizer.clone_issue_to_slave( master_issue) if slave_issue_id: self._mark_issues_as_sync(master_issue.numberInProject, master_issue.id, slave_issue_id) def _sync_to_master(self, slave_issue): self.issue_synchronizer.sync(None, slave_issue.id) def _sync_to_slave(self, master_issue): self.issue_synchronizer.sync(master_issue.id, None) def _apply_to_issues(self, issues_getter, action, excluded_ids=None, log_header=''): if not issues_getter or not action: return start = 0 print log_header + ' started...' issues = issues_getter(start, batch) processed_issue_ids_set = set([]) while len(issues): for issue in issues: sync_id = str(issue.id) if not (excluded_ids and sync_id in excluded_ids): action(issue) processed_issue_ids_set.add(sync_id) print log_header + ' processed ' + str(start + len(issues)) + ' issues' start += batch issues = issues_getter(start, batch) print log_header + ' action applied to ' + str( len(processed_issue_ids_set)) + ' issues' return processed_issue_ids_set def _get_tagged_only_in_slave(self, start, batch): rq = self.query + ' ' + master_sync_field_name + ': {' + empty_field_text + '}' return self.slave.getIssues(self.project_id, rq, start, batch) def _get_tagged_in_master(self, start, batch): rq = self.query return self.master.getIssues(self.project_id, rq, start, batch) def _get_updated_in_slave_from_last_run(self, start, batch): rq = get_advanced_query(self.query, self.last_run, self.current_run) return self.slave.getIssues(self.project_id, rq, start, batch) def _get_updated_in_master_from_last_run(self, start, batch): rq = get_advanced_query(self.query, self.last_run, self.current_run) return self.master.getIssues(self.project_id, rq, start, batch) def _mark_issues_as_sync(self, master_issue_number, master_issue_id, slave_issue_id): self.master_executor.executeCommand(master_issue_id, "tag " + tag) self.slave_executor.executeCommand(slave_issue_id, "tag " + tag) self.slave_executor.executeCommand( slave_issue_id, master_sync_field_name + " " + master_issue_number) self.issue_binder.addBinding(master_issue_id, slave_issue_id) def _create_and_attach_sync_field(self, yt, project_id, sync_field_name): sync_field_created = any(field.name == sync_field_name for field in yt.getCustomFields()) if not sync_field_created: yt.createCustomFieldDetailed(sync_field_name, "integer", False, True) sync_field_attached = any( field.name == sync_field_name for field in yt.getProjectCustomFields(project_id)) if not sync_field_attached: yt.createProjectCustomFieldDetailed(project_id, sync_field_name, empty_field_text)
class YouTrackSynchronizer(object): def __init__(self, master, slave, logger, issue_binder, project_id, fields_to_sync, query, last_run=None, current_run=None): self.slave = None self.master = master self.slave = slave self.logger = logger self.master_executor = SafeCommandExecutor(master, logger) self.slave_executor = SafeCommandExecutor(slave, logger) self.issue_binder = issue_binder self.query = query self.last_run = last_run self.current_run = current_run self.project_id = project_id self.link_synchronizer = LinkSynchronizer(self.master_executor, self.slave_executor, self.issue_binder) self.issue_synchronizer = AsymmetricIssueMerger(master, slave, self.master_executor, self.slave_executor, self.issue_binder, self.link_synchronizer, fields_to_sync, last_run, current_run, project_id) def setDebugMode(self, on): self.master_executor.setDebugMode(on) self.slave_executor.setDebugMode(on) def sync(self): #0. create if not existed and attach synchronization field self._create_and_attach_sync_field(self.slave, self.project_id, master_sync_field_name) #1. synchronize sync-issues in slave which have no synchronized clone in master imported_slave_ids_set = self._apply_to_issues(self._get_tagged_only_in_slave, self._import_to_master, log_header='[Sync, Importing new issues from slave to master]') #2. synchronize sync-issues in master which have no synchronized clone in slave sync_set = set(self.issue_binder.s_to_m.values()) imported_master_ids_set = self._apply_to_issues(self._get_tagged_in_master, self._import_to_slave, excluded_ids=sync_set, log_header='[Sync, Importing new issues from master to slave]') #3. synchronize sync-issues updated in slave which have synchronized clone in master updated_slave_ids_set = self._apply_to_issues(self._get_updated_in_slave_from_last_run, self._sync_to_master, excluded_ids=imported_slave_ids_set, log_header='[Sync, Merging sync issues updated in slave]') #4. synchronize sync-issues updated in master which have synchronized clone in slave (if clone hasn't been updated) updated_master_ids_set = self._slave_ids_set_to_sync_ids_set(updated_slave_ids_set) | imported_master_ids_set self._apply_to_issues(self._get_updated_in_master_from_last_run, self._sync_to_slave, excluded_ids=updated_master_ids_set, log_header='[Sync, Merging sync issues updated in master and unchanged in slave]') #5. synchronize links self.link_synchronizer.syncCollectedLinks() def syncAfterImport(self): self._create_and_attach_sync_field(self.slave, self.project_id, master_sync_field_name) start = 0 issues = self.slave.getIssues(self.project_id, '', start, batch) while len(issues): for issue in issues: issue_id = issue.id issue_number = issue_id.rpartition('-')[2] self._mark_issues_as_sync(issue_number, issue_id, issue_id) start += batch issues = self.slave.getIssues(self.project_id, '', start, batch) def _slave_ids_set_to_sync_ids_set(self, ids): return set([self.issue_binder.slaveIssueIdToMasterIssueId(id) for id in ids]) def _import_to_master(self, slave_issue): master_issue_id = self.issue_synchronizer.clone_issue_to_master(slave_issue) if master_issue_id: self._mark_issues_as_sync(master_issue_id.rpartition('-')[2], master_issue_id, slave_issue.id) def _import_to_slave(self, master_issue): slave_issue_id = self.issue_synchronizer.clone_issue_to_slave(master_issue) if slave_issue_id: self._mark_issues_as_sync(master_issue.numberInProject, master_issue.id, slave_issue_id) def _sync_to_master(self, slave_issue): self.issue_synchronizer.sync(None, slave_issue.id) def _sync_to_slave(self, master_issue): self.issue_synchronizer.sync(master_issue.id, None) def _apply_to_issues(self, issues_getter, action, excluded_ids=None, log_header=''): if not issues_getter or not action: return start = 0 print log_header + ' started...' issues = issues_getter(start, batch) processed_issue_ids_set = set([]) while len(issues): for issue in issues: sync_id = str(issue.id) if not (excluded_ids and sync_id in excluded_ids): action(issue) processed_issue_ids_set.add(sync_id) print log_header + ' processed ' + str(start + len(issues)) + ' issues' start += batch issues = issues_getter(start, batch) print log_header + ' action applied to ' + str(len(processed_issue_ids_set)) + ' issues' return processed_issue_ids_set def _get_tagged_only_in_slave(self, start, batch): rq = self.query + ' ' + master_sync_field_name + ': {' + empty_field_text + '}' return self.slave.getIssues(self.project_id, rq, start, batch) def _get_tagged_in_master(self, start, batch): rq = self.query return self.master.getIssues(self.project_id, rq, start, batch) def _get_updated_in_slave_from_last_run(self, start, batch): rq = get_advanced_query(self.query, self.last_run, self.current_run) return self.slave.getIssues(self.project_id, rq, start, batch) def _get_updated_in_master_from_last_run(self, start, batch): rq = get_advanced_query(self.query, self.last_run, self.current_run) return self.master.getIssues(self.project_id, rq, start, batch) def _mark_issues_as_sync(self, master_issue_number, master_issue_id, slave_issue_id): self.master_executor.executeCommand(master_issue_id, "tag " + tag) self.slave_executor.executeCommand(slave_issue_id, "tag " + tag) self.slave_executor.executeCommand(slave_issue_id, master_sync_field_name + " " + master_issue_number) self.issue_binder.addBinding(master_issue_id, slave_issue_id) def _create_and_attach_sync_field(self, yt, project_id, sync_field_name): sync_field_created = any(field.name == sync_field_name for field in yt.getCustomFields()) if not sync_field_created: yt.createCustomFieldDetailed(sync_field_name, "integer", False, True) sync_field_attached = any(field.name == sync_field_name for field in yt.getProjectCustomFields(project_id)) if not sync_field_attached: yt.createProjectCustomFieldDetailed(project_id, sync_field_name, empty_field_text)