def push_event_hook(): push_event = request.json app.logger.debug(push_event) user_name = push_event['user_name'] repo_name = push_event['repository']['name'] repo_url = push_event['repository']['url'] repo_homepage = push_event['repository']['homepage'] refspec = push_event['ref'] app.logger.debug('Received push event by %s in branch %s on repository %s', user_name, refspec, repo_url) for commit in push_event['commits']: app.logger.debug('Processing commit %s by %s (%s) in %s', commit['id'], commit['author']['name'], commit['author']['email'], commit['url']) commit_time = dateutil.parser.parse(commit['timestamp']) issues = re.findall(app.config['REGEX'], commit['message'], re.MULTILINE) if not issues: app.logger.debug( '''Didn't find any referenced issues in commit %s''', commit['id']) else: app.logger.debug('Found %d referenced issues in commit %s', len(issues), commit['id']) yt = Connection(app.config['YOUTRACK_URL'], app.config['YOUTRACK_USERNAME'], app.config['YOUTRACK_PASSWORD']) user_login = get_user_login(yt, commit['author']['email']) if user_login is None: app.logger.warn( "Couldn't find user with email address %s. Using default user.", commit['author']['email']) default_user = yt.getUser(app.config['DEFAULT_USER']) user_login = default_user['login'] for issue_id in issues: app.logger.debug('Processing reference to issue %s', issue_id) try: yt.getIssue(issue_id) comment_string = 'Commit [%(url)s %(id)s] on branch %(refspec)s in [%(repo_homepage)s %(repo_name)s] made by %(author)s on %(date)s\n{quote}%(message)s{quote}' % { 'url': commit['url'], 'id': commit['id'], 'author': commit['author']['name'], 'date': str(commit_time), 'message': commit['message'], 'repo_homepage': repo_homepage, 'repo_name': repo_name, 'refspec': refspec } app.logger.debug(comment_string) yt.executeCommand(issueId=issue_id, command='comment', comment=comment_string.encode('utf-8'), run_as=user_login.encode('utf-8')) except YouTrackException: app.logger.warn("Couldn't find issue %s", issue_id) return Response('Push event processed. Thanks!', mimetype='text/plain')
def push_event_hook(room=None): push_event = request.json app.logger.debug(push_event) app.logger.debug("slack_room:%s" % room) # process mergerequest if 'object_kind' in push_event and push_event['object_kind'] == 'merge_request': obj = push_event['object_attributes'] user = push_event['user'] slack = Slacker(app.config['SLACK_TOKEN']) url = "%s/%s/%s/merge_requests/%d" % (app.config['GITLAB_HOME'], obj['target']['namespace'], obj['target']['name'], obj['iid']) print url event = "Pull Request(%s): %s - %s\n%s" % (obj['state'], url, obj['title'], obj['description']) slack.chat.post_message('#%s' % room, event, username=user['username'], icon_url=user['avatar_url']) return Response('Push event processed. Thanks!', mimetype='text/plain') user_name = push_event['user_name'] repo_name = push_event['repository']['name'] repo_url = push_event['repository']['url'] repo_homepage = push_event['repository']['homepage'] refspec = push_event['ref'] app.logger.debug('Received push event by %s in branch %s on repository %s', user_name, refspec, repo_url) for commit in push_event['commits']: app.logger.debug('Processing commit %s by %s (%s) in %s', commit['id'], commit['author']['name'], commit['author']['email'], commit['url']) commit_time = dateutil.parser.parse(commit['timestamp']) issues = re.findall(app.config['REGEX'], commit['message'], re.MULTILINE) if not issues: app.logger.debug('''Didn't find any referenced issues in commit %s''', commit['id']) else: app.logger.debug('Found %d referenced issues in commit %s', len(issues), commit['id']) yt = Connection(app.config['YOUTRACK_URL'], app.config['YOUTRACK_USERNAME'], app.config['YOUTRACK_PASSWORD']) user_login = get_user_login(yt, commit['author']['email']) if user_login is None: app.logger.warn("Couldn't find user with email address %s. Using default user.", commit['author']['email']) default_user = yt.getUser(app.config['DEFAULT_USER']) user_login = default_user['login'] for issue_id in issues: app.logger.debug('Processing reference to issue %s', issue_id) try: yt.getIssue(issue_id) comment_string = 'Commit [%(url)s %(id)s] on branch %(refspec)s in [%(repo_homepage)s %(repo_name)s] made by %(author)s on %(date)s\n{quote}%(message)s{quote}' % {'url': commit['url'], 'id': commit['id'], 'author': commit['author']['name'], 'date': str(commit_time), 'message': commit['message'], 'repo_homepage': repo_homepage, 'repo_name': repo_name, 'refspec': refspec} app.logger.debug(comment_string) yt.executeCommand(issueId=issue_id, command='comment', comment=comment_string.encode('utf-8'), run_as=user_login.encode('utf-8')) except YouTrackException: app.logger.warn("Couldn't find issue %s", issue_id) return Response('Push event processed. Thanks!', mimetype='text/plain')
class ConnectionTest(unittest.TestCase): def setUp(self): #self.con = Connection('http://teamsys.intellij.net', 'resttest', 'resttest') self.con = Connection("http://localhost:8081", "root", "root") def test_getProject(self): p = self.con.getProject('SB') self.assertEqual(p.id, 'SB') self.assertEqual(p.name, 'Sandbox') def test_getSubsystems(self): subsystems = self.con.getSubsystems('SB') default = [s for s in subsystems if s.isDefault][0] self.assertTrue(default is not None) def test_getIssue(self): i = self.con.getIssue('SB-1') self.assertEqual(i.id, 'SB-1') self.assertEqual(i.numberInProject, '1') self.assertEqual(i.projectShortName, 'SB') def test_createIssue(self): i = self.con.createIssue('SB', 'resttest', 'Test issue', 'Test description', '2', 'Bug', 'First', 'Open', '', '', '') self.assertEqual(i.projectShortName, 'SB') self.assertEqual(i.priority, '2') self.assertEqual(i.type, 'Bug') self.assertEqual(i.subsystem, 'First') def test_createIssueAttachment(self): i = self.con.createIssue('SB', 'resttest', 'For attachmkents test', 'Test description', '2', 'Bug', 'First', 'Open', '', '', '') fname = 'connection_test.py' content = open(fname) self.con.createAttachment(i.id, fname, content) self.assertEqual(fname, self.con.getAttachments(i.id)[0].name) def test_createAndDeleteSubsystem(self): name = 'Test Subsystem [' + str(random.random()) + "]" self.con.createSubsystemDetailed('SB', name, False, 'resttest') s = self.con.getSubsystem('SB', name) self.assertEqual(s.name, name) self.assertEqual(s.isDefault, 'false') #todo: uncomment when fix deployed to teamsys #self.assertEqual(s.defaultAssignee, 'resttest') self.con.deleteSubsystem('SB', name) def test_importIssues(self): issues = self.con.getIssues("A", "", 0, 10) for issue in issues: if hasattr(issue, "Assignee"): issue["assigneeName"] = issue["Assignee"] del issue.Assignee self.con.importIssues("B", "assignees", issues)
def recibir_horas(bot, update, user_data): try: duracion = int(update.message.text) logger.info(duracion) except ValueError: logger.error("No entiendo el número!") update.message.reply_text("No entiendo el número!") return RECIBIR work_item = { 'duration': duracion, 'date': str(datetime.now()), 'worktype': user_data['tipo_nom'], 'description': 'bot :)' } work_item = dotdict(work_item) logger.info(work_item) try: connection = Connection(user_data['host']['host'], user_data['host']['username'], user_data['host']['pass']) connection.createWorkItem(user_data['issue'], work_item) logger.info('Guardar tiempo {} {}'.format(user_data['issue'], duracion)) issue = connection.getIssue(user_data['issue']) keyboard = [] if user_data['tipo_tarea'] == '#Unresolved': keyboard.append([ InlineKeyboardButton('Marcar como cerrada', callback_data='issue_estado_cerrar') ]) else: keyboard.append([ InlineKeyboardButton('Marcar como en progreso', callback_data='issue_estado_en_progreso') ]) keyboard.append([ InlineKeyboardButton('Dejar como {}'.format(issue['State']), callback_data='terminar') ]) reply_markup = InlineKeyboardMarkup(keyboard, resize_keyboard=True, one_time_keyboard=True) update.message.reply_text("Gracias amego! Y ahora?", reply_markup=reply_markup) return CONFIRMAR except Exception as e: logger.error(e) update.message.reply_text("No eh!") return ConversationHandler.END
def __init__(self, host, user, password, api_key): connection = Connection(url=host, api_key=api_key) # get one issue issue = connection.getIssue('PI-1000') # get first 10 issues in project JT for query 'for: me #unresolved' issues = connection.getIssues( 'pi', '#Resolved Fixed in build: {Next Build}', 0, 10) for issue in issues: print(issue)
class ConnectionTest(unittest.TestCase): def setUp(self): #self.con = Connection('http://teamsys.intellij.net', 'resttest', 'resttest') self.con = Connection("http://localhost:8081", "root", "root") def test_getProject(self): p = self.con.getProject('SB') self.assertEqual(p.id, 'SB') self.assertEqual(p.name, 'Sandbox') def test_getSubsystems(self): subsystems = self.con.getSubsystems('SB') default = [s for s in subsystems if s.isDefault][0] self.assertTrue(default is not None) def test_getIssue(self): i = self.con.getIssue('SB-1') self.assertEqual(i.id, 'SB-1') self.assertEqual(i.numberInProject, '1') self.assertEqual(i.projectShortName, 'SB') def test_createIssue(self): i = self.con.createIssue('SB', 'resttest', 'Test issue', 'Test description', '2', 'Bug', 'First', 'Open', '', '', '') self.assertEqual(i.projectShortName, 'SB') self.assertEqual(i.priority, '2') self.assertEqual(i.type, 'Bug') self.assertEqual(i.subsystem, 'First') def test_createIssueAttachment(self): i = self.con.createIssue('SB', 'resttest', 'For attachmkents test', 'Test description', '2', 'Bug', 'First', 'Open', '', '', '') fname = 'connection_test.py' content = open(fname) self.con.createAttachment(i.id, fname, content) self.assertEqual(fname, self.con.getAttachments(i.id)[0].name) def test_createAndDeleteSubsystem(self): name = 'Test Subsystem [' + str(random.random()) + "]" self.con.createSubsystemDetailed('SB', name, False, 'resttest') s = self.con.getSubsystem('SB', name) self.assertEqual(s.name, name) self.assertEqual(s.isDefault, 'false') #todo: uncomment when fix deployed to teamsys #self.assertEqual(s.defaultAssignee, 'resttest') self.con.deleteSubsystem('SB', name) def test_importIssues(self): issues = self.con.getIssues("A", "", 0, 10) for issue in issues: if hasattr(issue, "Assignee"): issue["assigneeName"] = issue["Assignee"] del issue.Assignee self.con.importIssues("B", "assignees", issues)
def push_event_hook(): push_event = request.json app.logger.debug(push_event) user_name = push_event['user_name'] repo_name = push_event['repository']['name'] repo_url = push_event['repository']['url'] repo_homepage = push_event['repository']['homepage'] refspec = push_event['ref'] app.logger.debug('Received push event by %s in branch %s on repository %s', user_name, refspec, repo_url) for commit in push_event['commits']: app.logger.debug('Processing commit %s by %s (%s) in %s', commit['id'], commit['author']['name'], commit['author']['email'], commit['url']) commit_time = dateutil.parser.parse(commit['timestamp']) issues = re.findall(app.config['REGEX'], commit['message'], re.MULTILINE) if not issues: app.logger.debug('''Didn't find any referenced issues in commit %s''', commit['id']) else: app.logger.debug('Found %d referenced issues in commit %s', len(issues), commit['id']) yt = Connection(app.config['YOUTRACK_URL'], app.config['YOUTRACK_USERNAME'], app.config['YOUTRACK_PASSWORD']) user_login = get_user_login(yt, commit['author']['email']) if user_login is None: app.logger.warn("Couldn't find user with email address %s. Using default user.", commit['author']['email']) default_user = yt.getUser(app.config['DEFAULT_USER']) user_login = default_user['login'] for issue_id in issues: app.logger.debug('Processing reference to issue %s', issue_id) try: yt.getIssue(issue_id) comment_string = 'Commit [%(url)s %(id)s] on branch %(refspec)s in [%(repo_homepage)s %(repo_name)s] made by %(author)s on %(date)s\n{quote}%(message)s{quote}' % {'url': commit['url'], 'id': commit['id'], 'author': commit['author']['name'], 'date': str(commit_time), 'message': commit['message'], 'repo_homepage': repo_homepage, 'repo_name': repo_name, 'refspec': refspec} app.logger.debug(comment_string) yt.executeCommand(issueId=issue_id, command='comment', comment=comment_string.encode('utf-8'), run_as=user_login.encode('utf-8')) except YouTrackException: app.logger.warn("Couldn't find issue %s", issue_id) return Response('Push event processed. Thanks!', mimetype='text/plain')
class YtClient(object): def __init__(self, server, username, password): self.logger = LoggerFactory.getLogger("com.xebialabs.yourtrack.Server") if server is None: sys.exit("No server provided.") if username is not None: youtrackUsername = username else: youtrackUsername = server['username'] if password is not None: youtrackPassword = password else: youtrackPassword = server['password'] if server['token'] is not None: # authentication request with permanent token self.youtrack = YouTrack(server['url'], token=server['token']) else: # authentication with username and password self.youtrack = YouTrack(server['url'], login=youtrackUsername, password=youtrackPassword) def getIssue(self, issueId): return self.youtrack.getIssue(issueId) def getAllIssues(self, query, withFields): self.logger.debug("getAllIssues") self.logger.debug("Query = %s" % query) self.logger.debug("Fields = %s" % withFields) return self.youtrack.getAllIssues(filter=query, withFields=withFields) def updateIssuesByQuery(self, query, fieldsToUpdate, comment): command = "" for key in fieldsToUpdate: command += key + " " + fieldsToUpdate[key] foundIssues = self.youtrack.getAllIssues(filter=query, withFields=[]) for issue in foundIssues: self.youtrack.executeCommand(issue['id'], command, comment) def getIssuesByQuery(self, query, fieldList=[]): self.logger.debug("getIssuesByQuery") return self.youtrack.getAllIssues(filter=query, withFields=[])
def receive_hook(): payload = request.json user_name = payload['user_name'] repo_url = payload['repository']['url'] app.logger.debug('Received payload for a push by %s on repository %s', user_name, repo_url) for commit in payload['commits']: app.logger.debug('Processing commit %s by %s (%s) in %s', commit['id'], commit['author']['name'], commit['author']['email'], commit['url']) commit_time = dateutil.parser.parse(commit['timestamp']) refs = re.findall(app.config['REGEX'], commit['message'], re.MULTILINE) if not refs: app.logger.info('''Didn't find any referenced issues in commit %s''', commit['id']) else: app.logger.info('Found %d referenced issues in commit %s', len(refs), commit['id']) yt = Connection(app.config['YOUTRACK_URL'], app.config['YOUTRACK_USERNAME'], app.config['YOUTRACK_PASSWORD']) user = app.config['DEFAULT_USER'] users = yt.getUsers({ 'q': commit['author']['email'] }) if not users: app.logger.warn('''Couldn't find user with email address %s. Using default user.''', commit['author']['email']) elif len(users) > 1: app.logger.warn('''Found more than one user with email address %s. Using default user.''', commit['author']['email']) else: user = users[0]['login'] for ref in refs: app.logger.info('Processing reference to issue %s', ref) try: issue = yt.getIssue(ref) comment_string = 'Commit [%(url)s %(id)s] made by %(author)s on %(date)s\n{quote}%(message)s{quote}' % {'url': commit['url'], 'id': commit['id'], 'author': commit['author']['name'], 'date': str(commit_time), 'message': commit['message']} app.logger.debug(comment_string) yt.executeCommand(issueId=ref, command='comment', comment=comment_string, run_as=user) except YouTrackException: app.logger.warn('''Couldn't find issue %s''', ref) return Response('Payload processed. Thanks!', mimetype='text/plain')
from youtrack.connection import Connection as YouTrack from config.settings import YOUTRACK_TOKEN yt = YouTrack('https://jingyi.myjetbrains.com/youtrack', token=YOUTRACK_TOKEN) issue = yt.getIssue('FEJIS-4') print(issue) print(issue)
redmine_users = get_redmine_users() redmine_trackers = get_redmine_trackers() redmine_statuses = get_redmine_statuses() redmine_priorities = get_redmine_priorities() redmine_versions = get_redmine_project_versions() redmine_custom_fields = get_redmine_custom_fields() except Exception as e: print e sys.exit(0) issues_dict = {} print "==========Copying from YouTrack to Redmine==========" for issue in issues_list: issue_id = issue.id youtrack_issue = youtrack.getIssue(id=issue_id) print "Processing " + youtrack_issue.id + " " + youtrack_issue.summary redmine_issue = redmine.issue.new() redmine_issue.project_id = redmine.project.get(REDMINE_PROJECT).id set_assignee() sey_subject() set_type() set_status() set_estimation() set_storypoints() set_planfixdate() set_affected_versions() set_description() add_attachments() redmine_issue.save() add_comments()
try : source = Connection(source_url, source_login, source_password) print "Connected to source url [%s]" % source_url except Exception, 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, 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
redmine_users = get_redmine_users() redmine_trackers = get_redmine_trackers() redmine_statuses = get_redmine_statuses() redmine_priorities = get_redmine_priorities() redmine_versions = get_redmine_project_versions() redmine_custom_fields = get_redmine_custom_fields() except Exception as e: print e sys.exit(0) issues_dict = {} print "==========Copying from YouTrack to Redmine==========" for issue in issues_list: issue_id = issue.id youtrack_issue = youtrack.getIssue(id=issue_id) print "Processing " + youtrack_issue.id + " " + youtrack_issue.summary redmine_issue = redmine.issue.new() redmine_issue.project_id = redmine.project.get(REDMINE_PROJECT).id set_assignee() sey_subject() set_type() set_status() set_estimation() set_storypoints() set_planfixdate() set_affected_versions() set_description() add_attachments() redmine_issue.save() add_comments()
def issues(request): yt = YouTrack(settings.YOUTRACK_BASE_URL, token=settings.YOUTRACK_TOKEN) issue = yt.getIssue("2-119920") return Response(issue.to_dict())
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 Main(sendTo, subject, yamlMessage): """ Workflow Zabbix-YouTrack :param sendTo: URL to Youtrack (ex. https://youtrack.example.com) :param subject: subject from Zabbix Action :param yamlMessage: message from Zabbix Action :return: """ # ----- Use below example yamlMessage to debug ----- # yamlMessage = """Name: 'Test Zabbix-YT workflow, ignore it' # Text: 'Agent ping (server:agent.ping()): DOWN (1) ' # Hostname: 'server.exmpale.ru' # Status: "OK" # Severity: "High" # EventID: "96976" # TriggerID: "123456789012" """ messages = yaml.load(yamlMessage) # ----- START Issue parameters ----- # Correspondence between the YouTrackPriority and ZabbixSeverity # Critical >= High # Normal < High ytPriority = 'Normal' if messages['Severity'] == 'Disaster' or messages['Severity'] == 'High': ytPriority = 'Critical' ytName = "{} ZabbixTriggerID::{}".format(messages['Name'], messages['TriggerID']) # ----- END Issue parameters ----- # ----- START Youtrack Issue description ----- # Search link to other issue searchString = "Hostname: '{}'".format(messages['Hostname']) linkToHostIssue = "{youtrack}/issues/{projectname}?q={query}".format( youtrack=sendTo, projectname=YT_PROJECT_NAME, query=urllib.parse.quote(searchString, safe='') ) issueDescription = """ {ytName} ----- {yamlMessage} ----- - [https://zabbix.example.com/zabbix.php?action=dashboard.view Zabbix Dashboard] - Show [{linkToHostIssue} all issue for *this host*] """.format( ytName=ytName, yamlMessage=yamlMessage, linkToHostIssue=linkToHostIssue, ) # ----- END Youtrack Issue description ----- # ----- START Youtrack current week ----- # Create connect to Youtrack API connection = Connection(sendTo, YT_USER, YT_PASSWORD) # Get current week in YT format (Sprint planned) version = connection.getAllBundles('version') for fixVersion in version[0].values: if fixVersion['archived'] == False and fixVersion['released'] == False: fixVersionWeek = fixVersion['name'] break # ----- END Youtrack current week ----- # ----- START Youtrack get or create issue ----- # Get issue if exist # Search for TriggerID createNewIssue = False logger.debug("Get issue with text '{}'".format(messages['TriggerID'])) issue = connection.getIssues(YT_PROJECT_NAME, "ZabbixTriggerID::{}".format(messages['TriggerID']), 0, 1) if len(issue) == 0: createNewIssue = True else: # if issue contains TriggerID in summary, then it's good issue # else create new issue, this is bad issue, not from Zabbix if "ZabbixTriggerID::{}".format(messages['TriggerID']) in issue[0]['summary']: issueId = issue[0]['id'] issue = connection.getIssue(issueId) else: createNewIssue = True # Create new issue if createNewIssue: logger.debug("Create new issue because it is not exist") issue = connection.createIssue(YT_PROJECT_NAME, 'Unassigned', ytName, issueDescription, priority=ytPriority, subsystem=YT_SUBSYSTEM, type=YT_TYPE, ) time.sleep(3) # Parse ID for new issue result = re.search(r'(CM-\d*)', issue[0]['location']) issueId = result.group(0) issue = connection.getIssue(issueId) logger.debug("Issue have id={}".format(issueId)) # Set issue service ExecAndLog(connection, issueId, "Service {}".format(YT_SERVICE)) # Update priority ExecAndLog(connection, issueId, "Priority {}".format(ytPriority)) # ----- END Youtrack get or create issue ----- # ----- START PROBLEM block ------ if messages['Status'] == "PROBLEM": # Issue exist and NOT Hold on, Unnassigned and Estimated time set if issue['State'] != 'Hold on': # Estimated time ExecAndLog(connection, issueId, "Estimated time {}".format(YT_TIME)) # Update fix version ExecAndLog(connection=connection, issueId=issueId, command="Sprint planned {}".format(fixVersionWeek)) # Reopen if Fixed or Verified or Canceled if issue['State'] == 'Fixed' or issue['State'] == 'Verified' or issue['State'] == 'Canceled': # Reopen Issue ExecAndLog(connection, issueId, "State reopen") # Assignee issue ExecAndLog(connection, issueId, command="Assignee Unassigned") # Update summary and description for issue logger.debug("Run command in {issueId}: {command}".format(issueId=issueId, command="""Update summary and description with connection.updateIssue method""" )) connection.updateIssue(issueId=issueId, summary=ytName, description=issueDescription) # Add comment logger.debug("Run command in {issueId}: {command}".format(issueId=issueId, command="""Now is PROBLEM {}""".format( messages['Text']) )) connection.executeCommand(issueId=issueId, command="", comment=YT_COMMENT.format( status=messages['Status'], text=messages['Text']) ) # Send ID to Zabbix: logger.debug("ZABBIX-API: Send Youtrack ID to {}".format(messages['EventID'])) Zbx.event.acknowledge(eventids=messages['EventID'], message="Create Youtrack task") Zbx.event.acknowledge(eventids=messages['EventID'], message="https://youtrack.example.com/issue/{}".format(issueId)) # ----- End PROBLEM block ------ # ----- Start OK block ----- if messages['Status'] == "OK": if issue['State'] == 'Hold on' or issue['State'] == 'Registered': # Cancel if not in work ExecAndLog(connection, issueId, command="State Cancel") # Assignee issue ExecAndLog(connection, issueId, command="Assignee {}".format(YT_ASSIGNEE)) if issue['State'] == 'Fixed': # Verify if Fixed ExecAndLog(connection, issueId, command="State verify") logger.debug("Run command in {issueId}: {command}".format(issueId=issueId, command="""Now is OK {}""".format(messages['Text']) )) connection.executeCommand(issueId=issueId, command="", comment=YT_COMMENT.format( status=messages['Status'], text=messages['Text']) )
for comment in issue.getComments(): if not hasattr(comment, "text") or (len(comment.text.strip()) == 0): setattr(comment, 'text', 'no text') user_importer.importUsersRecursively(users) print "Create issues [" + str(len(issues)) + "]" if params.get('create_new_issues'): last_created_issue_number = create_issues(target, issues, last_created_issue_number) else: print target.importIssues(projectId, project.name + ' Assignees', issues) link_importer.addAvailableIssues(issues) for issue in issues: try: target_issue = target.getIssue(issue.id) except youtrack.YouTrackException, e: print "Cannot get target issue" print e continue if params.get('add_new_comments'): target_comments = dict() max_id = 0 for c in target_issue.getComments(): target_comments[c.created] = c if max_id < c.created: max_id = c.created for c in issue.getComments(): if c.created > max_id or c.created not in target_comments: group = None
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)
user_importer.importUsersRecursively(users) print "Create issues [" + str(len(issues)) + "]" if params.get('create_new_issues'): last_created_issue_number = create_issues( target, issues, last_created_issue_number) else: print target.importIssues(projectId, project.name + ' Assignees', issues) link_importer.addAvailableIssues(issues) for issue in issues: try: target_issue = target.getIssue(issue.id) except youtrack.YouTrackException, e: print "Cannot get target issue" print e continue if params.get('sync_tags') and issue.tags: try: for tag in issue.tags: tag = re.sub(r'[,&<>]', '_', tag) try: target.executeCommand( issue.id, 'tag ' + tag, disable_notifications=True) except youtrack.YouTrackException:
def youtrack2youtrack(source_url, source_login, source_password, target_url, target_login, target_password, project_ids, query='', source_token=None, target_token=None, params=None): if not len(project_ids): print("You should sign at least one project to import") return if params is None: params = {} source = Connection(source_url, source_login, source_password) if (source_token is None) else Connection(source_url, token=source_token) target = Connection(target_url, target_login, target_password) if (target_token is None) else Connection(target_url, token=target_token) # , proxy_info = httplib2.ProxyInfo(socks.PROXY_TYPE_HTTP, 'localhost', 8888) print("Import issue link types") for ilt in source.getIssueLinkTypes(): try: print(target.createIssueLinkType(ilt)) except youtrack.YouTrackException as e: print(e.message) user_importer = UserImporter(source, target, caching_users=params.get('enable_user_caching', True)) link_importer = LinkImporter(target) # create all projects with minimum info and project lead set created_projects = [] for project_id in project_ids: created = create_project_stub(source, target, project_id, user_importer) created_projects.append(created) # save created project ids to create correct group roles afterwards user_importer.addCreatedProjects([project.id for project in created_projects]) # import project leads with group they are included and roles assigned to these groups user_importer.importUsersRecursively([target.getUser(project.lead) for project in created_projects]) # afterwards in a script any user import imply recursive import cf_names_to_import = set([]) # names of cf prototypes that should be imported for project_id in project_ids: cf_names_to_import.update([pcf.name.capitalize() for pcf in source.getProjectCustomFields(project_id)]) target_cf_names = [pcf.name.capitalize() for pcf in target.getCustomFields()] period_cf_names = [] for cf_name in cf_names_to_import: source_cf = source.getCustomField(cf_name) if source_cf.type.lower() == 'period': period_cf_names.append(source_cf.name.lower()) print("Processing custom field '%s'" % utf8encode(cf_name)) if cf_name in target_cf_names: target_cf = target.getCustomField(cf_name) if not (target_cf.type == source_cf.type): print("In your target and source YT instances you have field with name [ %s ]" % utf8encode(cf_name)) print("They have different types. Source field type [ %s ]. Target field type [ %s ]" % (source_cf.type, target_cf.type)) print("exiting...") exit() else: if hasattr(source_cf, "defaultBundle"): create_bundle_from_bundle(source, target, source_cf.defaultBundle, source_cf.type, user_importer) target.createCustomField(source_cf) failed_commands = [] for projectId in project_ids: source = Connection(source_url, source_login, source_password) if (source_token is None) else Connection( source_url, token=source_token) target = Connection(target_url, target_login, target_password) if (target_token is None) else Connection( target_url, token=target_token) # , proxy_info = httplib2.ProxyInfo(socks.PROXY_TYPE_HTTP, 'localhost', 8888) # reset connections to avoid disconnections user_importer.resetConnections(source, target) link_importer.resetConnections(target) # copy project, subsystems, versions project = source.getProject(projectId) link_importer.addAvailableIssuesFrom(projectId) project_custom_fields = source.getProjectCustomFields(projectId) # create bundles and additional values for pcf_ref in project_custom_fields: pcf = source.getProjectCustomField(projectId, pcf_ref.name) if hasattr(pcf, "bundle"): try: create_bundle_from_bundle(source, target, pcf.bundle, source.getCustomField(pcf.name).type, user_importer) except youtrack.YouTrackException as e: if e.response.status != 409: raise e else: print(e) target_project_fields = [pcf.name.lower() for pcf in target.getProjectCustomFields(projectId)] for field in project_custom_fields: if field.name.lower() in target_project_fields: if hasattr(field, 'bundle'): if field.bundle != target.getProjectCustomField(projectId, field.name).bundle: target.deleteProjectCustomField(projectId, field.name) create_project_custom_field(target, field, projectId) else: try: create_project_custom_field(target, field, projectId) except youtrack.YouTrackException as e: if e.response.status != 409: raise e else: print(e) # copy issues start = 0 max = 20 sync_workitems = enable_time_tracking(source, target, projectId) tt_settings = target.getProjectTimeTrackingSettings(projectId) print("Import issues") last_created_issue_number = 0 while True: try: print("Get issues from " + str(start) + " to " + str(start + max)) issues = source.getIssues(projectId, query, start, max) if len(issues) <= 0: break if convert_period_values and period_cf_names: for issue in issues: for pname in period_cf_names: for fname in issue.__dict__: if fname.lower() != pname: continue issue[fname] = period_to_minutes(issue[fname]) users = set([]) for issue in issues: print("Collect users for issue [%s]" % issue.id) users.add(issue.getReporter()) if issue.hasAssignee(): if isinstance(issue.Assignee, (list, tuple)): users.update(issue.getAssignee()) else: users.add(issue.getAssignee()) # TODO: http://youtrack.jetbrains.net/issue/JT-6100 users.add(issue.getUpdater()) if issue.hasVoters(): users.update(issue.getVoters()) for comment in issue.getComments(): users.add(comment.getAuthor()) print("Collect links for issue [%s]" % issue.id) link_importer.collectLinks(issue.getLinks(True)) # links.extend(issue.getLinks(True)) # fix problem with comment.text for comment in issue.getComments(): if not hasattr(comment, "text") or (len(comment.text.strip()) == 0): setattr(comment, 'text', 'no text') user_importer.importUsersRecursively(users) print("Create issues [" + str(len(issues)) + "]") if params.get('create_new_issues'): create_issues(target, issues, last_created_issue_number) else: print(target.importIssues(projectId, project.name + ' Assignees', issues)) link_importer.addAvailableIssues(issues) for issue in issues: try: target_issue = target.getIssue(issue.id) except youtrack.YouTrackException as e: print("Cannot get target issue") print(e) continue if params.get('sync_tags') and issue.tags: try: for tag in issue.tags: tag = re.sub(r'[,&<>]', '_', tag) try: target.executeCommand(issue.id, 'tag ' + tag, disable_notifications=True) except youtrack.YouTrackException: tag = re.sub(r'[\s-]', '_', tag) target.executeCommand(issue.id, 'tag ' + tag, disable_notifications=True) except youtrack.YouTrackException as e: print("Cannot sync tags for issue " + issue.id) print(e) if params.get('add_new_comments'): target_comments = dict() max_id = 0 for c in target_issue.getComments(): target_comments[c.created] = c if max_id < c.created: max_id = c.created for c in issue.getComments(): if c.created > max_id or c.created not in target_comments: group = None if hasattr(c, 'permittedGroup'): group = c.permittedGroup try: target.executeCommand(issue.id, 'comment', c.text, group, c.author, disable_notifications=True) except youtrack.YouTrackException as e: print('Cannot add comment to issue') print(e) if params.get('sync_custom_fields'): skip_fields = [] if tt_settings and tt_settings.Enabled and tt_settings.TimeSpentField: skip_fields.append(tt_settings.TimeSpentField) skip_fields = [name.lower() for name in skip_fields] for pcf in [pcf for pcf in project_custom_fields if pcf.name.lower() not in skip_fields]: target_cf_value = None if pcf.name in target_issue: target_cf_value = target_issue[pcf.name] if isinstance(target_cf_value, (list, tuple)): target_cf_value = set(target_cf_value) elif target_cf_value == target.getProjectCustomField(projectId, pcf.name).emptyText: target_cf_value = None source_cf_value = None if pcf.name in issue: source_cf_value = issue[pcf.name] if isinstance(source_cf_value, (list, tuple)): source_cf_value = set(source_cf_value) elif source_cf_value == source.getProjectCustomField(projectId, pcf.name).emptyText: source_cf_value = None if source_cf_value == target_cf_value: continue if isinstance(source_cf_value, set) or isinstance(target_cf_value, set): if source_cf_value is None: source_cf_value = set([]) elif not isinstance(source_cf_value, set): source_cf_value = set([source_cf_value]) if target_cf_value is None: target_cf_value = set([]) elif not isinstance(target_cf_value, set): target_cf_value = set([target_cf_value]) for v in target_cf_value: if v not in source_cf_value: target.executeCommand(issue.id, 'remove %s %s' % (pcf.name, v), disable_notifications=True) for v in source_cf_value: if v not in target_cf_value: target.executeCommand(issue.id, 'add %s %s' % (pcf.name, v), disable_notifications=True) else: if source_cf_value is None: source_cf_value = target.getProjectCustomField(projectId, pcf.name).emptyText if pcf.type.lower() == 'date': m = re.match(r'(\d{10})(?:\d{3})?', str(source_cf_value)) if m: source_cf_value = datetime.datetime.fromtimestamp( int(m.group(1))).strftime('%Y-%m-%d') elif pcf.type.lower() == 'period': source_cf_value = '%sm' % source_cf_value command = '%s %s' % (pcf.name, source_cf_value) try: target.executeCommand(issue.id, command, disable_notifications=True) except youtrack.YouTrackException as e: if e.response.status == 412 and e.response.reason.find('Precondition Failed') > -1: print('WARN: Some workflow blocks following command: %s' % command) failed_commands.append((issue.id, command)) if sync_workitems: workitems = source.getWorkItems(issue.id) if workitems: existing_workitems = dict() target_workitems = target.getWorkItems(issue.id) 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 [ " + issue.id + "]") try: user_importer.importUsersRecursively( [source.getUser(w.authorLogin) for w in new_workitems]) target.importWorkItems(issue.id, new_workitems) except youtrack.YouTrackException as e: if e.response.status == 404: print("WARN: Target YouTrack doesn't support workitems importing.") print("WARN: Workitems won't be imported.") sync_workitems = False else: print("ERROR: Skipping workitems because of error:" + str(e)) print("Process attachments for issue [%s]" % issue.id) existing_attachments = dict() try: for a in target.getAttachments(issue.id): existing_attachments[a.name + '\n' + a.created] = a except youtrack.YouTrackException as e: if e.response.status == 404: print("Skip importing attachments because issue %s doesn't exist" % issue.id) continue raise e attachments = [] users = set([]) for a in issue.getAttachments(): if a.name + '\n' + a.created in existing_attachments and not params.get('replace_attachments'): a.name = utf8encode(a.name) try: print("Skip attachment '%s' (created: %s) because it's already exists" % (utf8encode(a.name), utf8encode(a.created))) except Exception: pass continue attachments.append(a) author = a.getAuthor() if author is not None: users.add(author) user_importer.importUsersRecursively(users) for a in attachments: print("Transfer attachment of " + utf8encode(issue.id) + ": " + utf8encode(a.name)) # TODO: add authorLogin to workaround http://youtrack.jetbrains.net/issue/JT-6082 # a.authorLogin = target_login try: target.createAttachmentFromAttachment(issue.id, a) except BaseException as e: print("Cant import attachment [ %s ]" % utf8encode(a.name)) print(repr(e)) continue if params.get('replace_attachments'): try: old_attachment = existing_attachments.get(a.name + '\n' + a.created) if old_attachment: print('Deleting old attachment') target.deleteAttachment(issue.id, old_attachment.id) except BaseException as e: print("Cannot delete attachment '%s' from issue %s" % ( utf8encode(a.name), utf8encode(issue.id))) print(e) except Exception as e: print('Cant process issues from ' + str(start) + ' to ' + str(start + max)) traceback.print_exc() raise e start += max print("Import issue links") link_importer.importCollectedLinks() print("Trying to execute failed commands once again") for issue_id, command in failed_commands: try: print('Executing command on issue %s: %s' % (issue_id, command)) target.executeCommand(issue_id, command, disable_notifications=True) except youtrack.YouTrackException as e: print('Failed to execute command for issue #%s: %s' % (issue_id, command)) print(e)
def Main(sendTo, subject, yamlMessage): """ Workflow Zabbix-YouTrack :param sendTo: URL to Youtrack (ex. https://youtrack.example.com) :param subject: subject from Zabbix Action :param yamlMessage: message from Zabbix Action :return: """ # ----- Use below example yamlMessage to debug ----- # yamlMessage = """Name: 'Test Zabbix-YT workflow, ignore it' # Text: 'Agent ping (server:agent.ping()): DOWN (1) ' # Hostname: 'server.exmpale.ru' # Status: "OK" # Severity: "High" # EventID: "96976" # TriggerID: "123456789012" """ messages = yaml.load(yamlMessage) # ----- START Issue parameters ----- # Correspondence between the YouTrackPriority and ZabbixSeverity # Critical >= High # Normal < High ytPriority = 'Normal' if messages['Severity'] == 'Disaster' or messages['Severity'] == 'High': ytPriority = 'Critical' ytName = "{} ZabbixTriggerID::{}".format(messages['Name'], messages['TriggerID']) # ----- END Issue parameters ----- # ----- START Youtrack Issue description ----- # Search link to other issue searchString = "Hostname: '{}'".format(messages['Hostname']) linkToHostIssue = "{youtrack}/issues/{projectname}?q={query}".format( youtrack=sendTo, projectname=YT_PROJECT_NAME, query=urllib.parse.quote(searchString, safe='')) issueDescription = """ {ytName} ----- {yamlMessage} ----- - [https://zabbix.example.com/zabbix.php?action=dashboard.view Zabbix Dashboard] - Show [{linkToHostIssue} all issue for *this host*] """.format( ytName=ytName, yamlMessage=yamlMessage, linkToHostIssue=linkToHostIssue, ) # ----- END Youtrack Issue description ----- # ----- START Youtrack current week ----- # Create connect to Youtrack API connection = Connection(sendTo, YT_USER, YT_PASSWORD) # Get current week in YT format (Sprint planned) version = connection.getAllBundles('version') for fixVersion in version[0].values: if fixVersion['archived'] == False and fixVersion['released'] == False: fixVersionWeek = fixVersion['name'] break # ----- END Youtrack current week ----- # ----- START Youtrack get or create issue ----- # Get issue if exist # Search for TriggerID createNewIssue = False logger.debug("Get issue with text '{}'".format(messages['TriggerID'])) issue = connection.getIssues( YT_PROJECT_NAME, "ZabbixTriggerID::{}".format(messages['TriggerID']), 0, 1) if len(issue) == 0: createNewIssue = True else: # if issue contains TriggerID in summary, then it's good issue # else create new issue, this is bad issue, not from Zabbix if "ZabbixTriggerID::{}".format( messages['TriggerID']) in issue[0]['summary']: issueId = issue[0]['id'] issue = connection.getIssue(issueId) else: createNewIssue = True # Create new issue if createNewIssue: logger.debug("Create new issue because it is not exist") issue = connection.createIssue( YT_PROJECT_NAME, 'Unassigned', ytName, issueDescription, priority=ytPriority, subsystem=YT_SUBSYSTEM, type=YT_TYPE, ) time.sleep(3) # Parse ID for new issue result = re.search(r'(CM-\d*)', issue[0]['location']) issueId = result.group(0) issue = connection.getIssue(issueId) logger.debug("Issue have id={}".format(issueId)) # Set issue service ExecAndLog(connection, issueId, "Service {}".format(YT_SERVICE)) # Update priority ExecAndLog(connection, issueId, "Priority {}".format(ytPriority)) # ----- END Youtrack get or create issue ----- # ----- START PROBLEM block ------ if messages['Status'] == "PROBLEM": # Issue exist and NOT Hold on, Unnassigned and Estimated time set if issue['State'] != 'Hold on': # Estimated time ExecAndLog(connection, issueId, "Estimated time {}".format(YT_TIME)) # Update fix version ExecAndLog(connection=connection, issueId=issueId, command="Sprint planned {}".format(fixVersionWeek)) # Reopen if Fixed or Verified or Canceled if issue['State'] == 'Fixed' or issue['State'] == 'Verified' or issue[ 'State'] == 'Canceled': # Reopen Issue ExecAndLog(connection, issueId, "State reopen") # Assignee issue ExecAndLog(connection, issueId, command="Assignee Unassigned") # Update summary and description for issue logger.debug("Run command in {issueId}: {command}".format( issueId=issueId, command= """Update summary and description with connection.updateIssue method""" )) connection.updateIssue(issueId=issueId, summary=ytName, description=issueDescription) # Add comment logger.debug("Run command in {issueId}: {command}".format( issueId=issueId, command="""Now is PROBLEM {}""".format(messages['Text']))) connection.executeCommand(issueId=issueId, command="", comment=YT_COMMENT.format( status=messages['Status'], text=messages['Text'])) # Send ID to Zabbix: logger.debug("ZABBIX-API: Send Youtrack ID to {}".format( messages['EventID'])) Zbx.event.acknowledge(eventids=messages['EventID'], message="Create Youtrack task") Zbx.event.acknowledge( eventids=messages['EventID'], message="https://youtrack.example.com/issue/{}".format(issueId)) # ----- End PROBLEM block ------ # ----- Start OK block ----- if messages['Status'] == "OK": if issue['State'] == 'Hold on' or issue['State'] == 'Registered': # Cancel if not in work ExecAndLog(connection, issueId, command="State Cancel") # Assignee issue ExecAndLog(connection, issueId, command="Assignee {}".format(YT_ASSIGNEE)) if issue['State'] == 'Fixed': # Verify if Fixed ExecAndLog(connection, issueId, command="State verify") logger.debug("Run command in {issueId}: {command}".format( issueId=issueId, command="""Now is OK {}""".format(messages['Text']))) connection.executeCommand(issueId=issueId, command="", comment=YT_COMMENT.format( status=messages['Status'], text=messages['Text']))