def log_process_error(queue, try_count, sleep_time, process_result): first_task = queue.objects.peekleft() type = first_task.process_type queue_len = queue.objects.get_queue_len() if (type == 1): action = 'link_projects' elif (type == 2): action = 'process_payload_from_rm' elif (type == 3): action = 'process_payload_from_gh' elif (type == 4): action = 'process_comment_payload_from_gh' else: # type == 5 action = 'relink_projects' error_text = 'encountered some error (process_error)' WRITE_LOG('\n' + '=' * 35 + ' ' + str(datetime.datetime.today()) + ' ' + '=' * 35 + '\n' + 'WARNING: Tried to ' + action + ', but ' + error_text + '\n' + ' | queue_len: ' + str(queue_len) + '\n' + ' | try_count: ' + str(try_count) + '\n' + ' | retrying in: ' + str(sleep_time) + '\n' + ' | process_result: ' + str(process_result) + '\n')
def log_label_post(label, post_result): if (not allow_log_project_linking): return 0 if (not detailed_log_project_linking): return 0 post_result_text = str(post_result.text) log_text = '\n' + '-' * 35 + ' ' + str(datetime.datetime.today()) + ' ' + '-' * 35 + '\n' +\ 'POSTing new label to GITHUB:' + '\n' +\ 'LABEL | ---------------------------------------' + '\n' +\ ' | name: ' + label['name'] + '\n' +\ ' | description: ' + label['description'] + '\n' +\ ' | color: ' + label['color'] + '\n' +\ ' | default: ' + label['default'] + '\n' +\ 'POST RESULT | ---------------------------------------' + '\n' +\ ' | status: ' + str(post_result) + '\n' +\ ' | text: ' + post_result_text + '\n' if (post_result.status_code == 201): WRITE_LOG(log_text) # скорее всего, label просто уже существует elif (post_result.status_code == 422): WRITE_LOG_WAR(log_text) else: WRITE_LOG_ERR(log_text)
def log_connection_refused(queue, try_count, sleep_time): first_task = queue.objects.peekleft() type = first_task.process_type queue_len = queue.objects.get_queue_len() if (type == 1): action = 'link_projects' error_text = 'REDMINE is not responding' elif (type == 2): action = 'process_payload_from_rm' error_text = 'GITHUB is not responding' elif (type == 3): action = 'process_payload_from_gh' error_text = 'REDMINE is not responding' elif (type == 4): action = 'process_comment_payload_from_gh' error_text = 'REDMINE is not responding' else: # type == 5 action = 'relink_projects' error_text = 'REDMINE is not responding' WRITE_LOG('\n' + '=' * 35 + ' ' + str(datetime.datetime.today()) + ' ' + '=' * 35 + '\n' + 'WARNING: Tried to ' + action + ', but ' + error_text + '\n' + ' | queue_len: ' + str(queue_len) + '\n' + ' | try_count: ' + str(try_count) + '\n' + ' | retrying in: ' + str(sleep_time) + '\n')
def add_bot_phrase(issue, to): # добавляем фразу бота к описанию issue if (to == 'issue_body'): # добавляем фразу бота author_url_gh = '"' + issue['issue_author_login'] + '":' + 'https://github.com/' + issue['issue_author_login'] issue_url_gh = '"issue":' + issue['issue_url'] issue_body = '>I am a bot, bleep-bloop.\n' +\ '>' + author_url_gh + ' Has opened the ' + issue_url_gh + ' in Github.\n' +\ issue['issue_body'] return issue_body # добавляем фразу бота к комментарию elif (to == 'comment_body'): # добавляем фразу бота author_url = '"' + issue['comment_author_login'] + '":' + 'https://github.com/' + issue['comment_author_login'] comment_url = '"comment":' + issue['issue_url'] + '#issuecomment-' + str(issue['comment_id']) comment_body = '>I am a bot, bleep-bloop.\n' +\ '>' + author_url + ' Has left a ' + comment_url + ' in Github.\n' +\ issue['comment_body'] return comment_body else: WRITE_LOG("\nERROR: 'process_payload_from_gh.add_bot_phrase'\n" + "unknown parameter 'to': " + to + '.\n' + "Please, check your code on possible typos.\n" + "Alternatively, add logic to process '" + to + "' parameter correctly.") return None
def error_server_response(error_text, status_code): WRITE_LOG('\n' + '=' * 35 + ' ' + str(datetime.datetime.today()) + ' ' + '=' * 35 + '\n' + error_text + '\n') response = HttpResponse(error_text, status=status_code) return response
def prevent_cyclic_comment_gh(issue): error_text = ' The user, who left the comment: ' + issue['issue_author_login'] + ' | user id: ' + str(issue['issue_author_id']) + ' (our bot)\n' + \ ' Aborting action, in order to prevent cyclic: GH -> S -> RM -> S -> GH -> ...' if (allow_log_cyclic): WRITE_LOG(error_text) return error_text
def log_linking_error_url(error_text): WRITE_LOG('\n' + '=' * 35 + ' ' + str(datetime.datetime.today()) + ' ' + '=' * 35 + '\n' + 'ERROR: tried to LINK PROJECTS, but ' + error_text + '\n' + 'REDMINE | ---------------------------------------' + '\n' + ' | project_url: ' + url_rm + '\n' + 'GITHUB | ---------------------------------------' + '\n' + ' | repos_url: ' + url_gh + '\n')
def add_bot_phrase(issue, to): # добавляем фразу бота к описанию issue if (to == 'issue_body'): author_url_gh = '"' + issue['issue_author_login'] + '":' + 'https://github.com/' + issue['issue_author_login'] issue_url_gh = '"issue":' + issue['issue_url'] issue_body = '>I am a bot, bleep-bloop.\n' +\ '>' + author_url_gh + ' Has opened the ' + issue_url_gh + ' in Github.\n' +\ issue['issue_body'] return issue_body # добавляем фразу бота к комментарию elif (to == 'comment_body'): # добавляем фразу бота author_url = '"' + issue['comment_author_login'] + '":' + 'https://github.com/' + issue['comment_author_login'] comment_url = '"comment":' + issue['issue_url'] + '#issuecomment-' + str(issue['comment_id']) comment_body = '>I am a bot, bleep-bloop.\n' +\ '>' + author_url + ' Has left a ' + comment_url + ' in Github.\n' +\ issue['comment_body'] return comment_body # добавляем фразу бота к комментарию (изменение своего комментария) elif (to == 'comment_edit'): # добавляем фразу бота author_url = '"' + issue['comment_author_login'] + '":' + 'https://github.com/' + issue['comment_author_login'] comment_url = '"comment":' + issue['issue_url'] + '#issuecomment-' + str(issue['comment_id']) comment_body = '>I am a bot, bleep-bloop.\n' +\ '>' + author_url + ' Has edited his ' + comment_url + ' in Github.\n' +\ issue['comment_body'] return comment_body # добавляем фразу бота к комментарию (изменение чужого комментария) elif (to == "comment_edit_else's"): # добавляем фразу бота sender_url = '"' + issue['sender_login'] + '":' + 'https://github.com/' + issue['sender_login'] author_url = '"' + issue['comment_author_login'] + '":' + 'https://github.com/' + issue['comment_author_login'] comment_url = '"comment":' + issue['issue_url'] + '#issuecomment-' + str(issue['comment_id']) comment_body = '>I am a bot, bleep-bloop.\n' +\ '>' + sender_url + ' Has edited ' + author_url + " 's " + comment_url + ' in Github.\n' +\ issue['comment_body'] return comment_body else: WRITE_LOG("\nERROR: process_comment_payload_from_gh.add_bot_phrase - unknown parameter 'to': " + to + '.' + "\nPlease, check the code on possible typos." + "\nAlternatively, add logic to process '" + to + "' action correctly.\n") return None
def LOGICAL_ERR(error_text): # добавляем, чтобы в начале получилось: 'LOGICAL ERROR' error_text = 'LOGICAL ' + error_text WRITE_LOG('\n' + '=' * 35 + ' ' + str(datetime.datetime.today()) + ' ' + '=' * 35 + '\n' + 'received webhook from GITHUB: issues_comments | ' + 'action: ' + str(issue['action']) + '\n' + error_text) return HttpResponse(error_text, status=200)
def PREPARATION_ERR(error_text): # добавляем, чтобы в начале получилось: 'PREPARATION ERROR' error_text = 'PREPARATION ' + error_text WRITE_LOG('\n' + '=' * 35 + ' ' + str(datetime.datetime.today()) + ' ' + '=' * 35 + '\n' + 'received webhook from REDMINE: issues | ' + 'action: ' + str(issue['action']) + '\n' + error_text) return HttpResponse(error_text, status=200)
def log_linking_error(error_text, request_result): WRITE_LOG('\n' + '=' * 35 + ' ' + str(datetime.datetime.today()) + ' ' + '=' * 35 + '\n' + 'ERROR: tried to LINK PROJECTS, but ' + error_text + '\n' + 'REDMINE | ---------------------------------------' + '\n' + ' | project_url: ' + url_rm + '\n' + 'GITHUB | ---------------------------------------' + '\n' + ' | repos_url: ' + url_gh + '\n' + 'REQUEST_RESULT | ---------------------------------------' + '\n' + ' | status_code: ' + str(request_result.status_code) + '\n' + ' | text: ' + request_result.text)
def add_bot_phrase(issue, to): # добавляем фразу бота к описанию issue if (to == 'issue_body'): firstname = issue['issue_author_firstname'] lastname = issue['issue_author_lastname'] login = issue['issue_author_login'] # добавляем фразу бота issue_body = '>I am a bot, bleep-bloop.\n' +\ '>' + firstname + ' ' + lastname + ' (' + login + ') Has opened the issue in Redmine.\n\n' +\ issue['issue_body'] return issue_body # добавляем фразу бота к комментарию elif (to == 'comment_body'): firstname = issue['comment_author_firstname'] lastname = issue['comment_author_lastname'] login = issue['comment_author_login'] # добавляем фразу бота comment_body = '>I am a bot, bleep-bloop.\n' + \ '>' + firstname + ' ' + lastname + ' (' + login + ') Has commented / edited with comment the issue in Redmine.\n\n' +\ issue['comment_body'] return comment_body # добавляем фразу бота (комментарием) к действию в редмайне (закрыл, изменил и т.д.) elif (to == 'comment_body_action'): firstname = issue['comment_author_firstname'] lastname = issue['comment_author_lastname'] login = issue['comment_author_login'] # добавляем фразу бота comment_body = 'I am a bot, bleep-bloop.\n' +\ firstname + ' ' + lastname + ' (' + login + ') Has edited the issue in Redmine.\n\n' return comment_body else: WRITE_LOG( "\nERROR: process_payload_from_rm.add_bot_phrase - unknown parameter 'to': " + to + '.' + "\nPlease, check your code on possible typos." + "\nAlternatively, add logic to process '" + to + "' action correctly.\n") return None
def log_comment_gh_already_linked(linked_comments): if (not allow_log_project_linking): return 0 if (not detailed_log_project_linking): return 0 WRITE_LOG('\n ' + '-' * 33 + ' ' + str(datetime.datetime.today()) + ' ' + '-' * 33 + '\n' + ' linking comment from GITHUB to REDMINE\n' + ' WARNING: comments are already linked\n' + ' GITHUB | --------------- comment ---------------' + '\n' + ' | comment_id: ' + str(linked_comments.comment_id_gh) + '\n' + ' |\n' + ' REDMINE | --------------- comment ---------------' + '\n' + ' | comment_id: ' + str(linked_comments.comment_id_rm) + '\n')
def log_issue_gh_already_linked(linked_issues, issue): if (not allow_log_project_linking): return 0 if (not detailed_log_project_linking): return 0 WRITE_LOG('\n ' + '-' * 34 + ' ' + str(datetime.datetime.today()) + ' ' + '-' * 34 + '\n' + ' linking issue from GITHUB to REDMINE' + '\n' + ' WARNING: issues are already linked!' + '\n' + ' GITHUB | ---------------- issue ----------------' + '\n' + ' | author_login: '******'issue_author_login']) + '\n' + ' | issue_url: ' + issue['issue_url'] + '\n' + ' | issue_id: ' + str(issue['issue_id']) + '\n' + ' |\n' + ' REDMINE | ---------------- issue ----------------' + '\n' + ' | issue_id: ' + str(linked_issues.issue_id_rm))
def log_server_startup_begin(num_projects, num_issues, num_comments, num_tasks): WRITE_LOG('\n' + '=' * 35 + ' ' + str(datetime.datetime.today()) + ' ' + '=' * 35 + '\n' + 'Starting up the server!\n' + 'Checking server starus:\n' + 'DATABASE | num_projects: ' + str(num_projects) + '\n' + ' | num_issues: ' + str(num_issues) + '\n' + ' | num_comments: ' + str(num_comments) + '\n' + ' | tasks_in_queue: ' + str(num_tasks) + '\n' + ' | --------------------------------' + '\n' + 'SERVER_CONFIG | allow_log: ' + str(allow_log) + '\n' + ' | allow_log_file: ' + str(allow_log_file) + '\n' + ' | allow_log_cyclic: ' + str(allow_log_cyclic) + '\n' + ' | allow_log_project_linking: ' + str(allow_log_project_linking) + '\n' + ' | detailed_log_project_linking: ' + str(detailed_log_project_linking) + '\n' + ' | allow_correct_github_labels: ' + str(allow_correct_github_labels) + '\n' + ' | allow_queue_daemon_restarting: ' + str(allow_queue_daemon_restarting) + '\n' + ' | allow_projects_relinking: ' + str(allow_projects_relinking) + '\n' + ' | allow_issues_post_rm_to_gh: ' + str(allow_issues_post_rm_to_gh) + '\n' + ' | BOT_ID_RM: ' + str(BOT_ID_RM) + '\n' + ' | BOT_ID_GH: ' + str(BOT_ID_GH) + '\n' + ' | tracker_ids_rm: ' + str(tracker_ids_rm) + '\n' + ' | status_ids_rm: ' + str(status_ids_rm) + '\n' + ' | priority_ids_rm: ' + str(priority_ids_rm) + '\n' + ' | url_rm: ' + str(url_rm) + '\n')
def log_comment_gh(result, comment, linked_issues): if (not allow_log_project_linking): return 0 if (not detailed_log_project_linking): return 0 action_rm = 'EDIT' WRITE_LOG('\n ' + '-' * 33 + ' ' + str(datetime.datetime.today()) + ' ' + '-' * 33 + '\n' + ' linking comment from GITHUB to REDMINE' + '\n' + ' ' + action_rm + ' result in REDMINE: ' + str(result.status_code) + ' ' + str(result.reason) + '\n' + ' GITHUB | --------------- comment ---------------' + '\n' + ' | author_login: '******'comment_author_login']) + '\n' + ' | comment_id: ' + str(comment['comment_id']) + '\n' + ' |\n' + ' REDMINE | ---------------- issue ----------------' + '\n' + ' | issue_id: ' + str(linked_issues.issue_id_rm))
def log_issue_gh(result, issue, linked_issues): if (not allow_log_project_linking): return 0 if (not detailed_log_project_linking): return 0 action_rm = 'POST' WRITE_LOG('\n ' + '-' * 34 + ' ' + str(datetime.datetime.today()) + ' ' + '-' * 34 + '\n' + ' linking issue from GITHUB to REDMINE' + '\n' + ' ' + action_rm + ' result in REDMINE: ' + str(result.status_code) + ' ' + str(result.reason) + '\n' + ' GITHUB | ---------------- issue ----------------' + '\n' + ' | author_login: '******'issue_author_login']) + '\n' + ' | issue_url: ' + issue['issue_url'] + '\n' + ' | issue_id: ' + str(issue['issue_id']) + '\n' + ' |\n' + ' REDMINE | ---------------- issue ----------------' + '\n' + ' | issue_id: ' + str(linked_issues.issue_id_rm))
def add_bot_phrase(issue, to): # добавляем фразу бота к описанию issue if (to == 'issue_body'): # добавляем фразу бота author_url_gh = '"' + issue[ 'issue_author_login'] + '":' + 'https://github.com/' + issue[ 'issue_author_login'] issue_url_gh = '"issue":' + issue['issue_url'] issue_body = '>I am a bot, bleep-bloop.\n' +\ '>' + author_url_gh + ' Has opened the ' + issue_url_gh + ' in Github.\n' +\ issue['issue_body'] return issue_body # добавляем фразу бота (комментарием) к действию в гитхабе (закрыл, изменил и т.д.) elif (to == 'comment_body_action'): author_url = '"' + issue[ 'sender_login'] + '":' + 'https://github.com/' + issue[ 'sender_login'] issue_url = '"issue":' + issue['issue_url'] comment_body = 'I am a bot, bleep-bloop.\n' +\ author_url + ' Has ' + issue['action'] + ' the ' + issue_url + ' in Github.\n' return comment_body else: WRITE_LOG("\nERROR: 'process_payload_from_gh.add_bot_phrase'\n" + "unknown parameter 'to': " + to + '.\n' + "Please, check your code on possible typos.\n" + "Alternatively, add logic to process '" + to + "' parameter correctly.") return None
def server_startup(): def log_server_startup_begin(num_projects, num_issues, num_comments, num_tasks): WRITE_LOG('\n' + '=' * 35 + ' ' + str(datetime.datetime.today()) + ' ' + '=' * 35 + '\n' + 'Starting up the server!\n' + 'Checking server starus:\n' + 'DATABASE | num_projects: ' + str(num_projects) + '\n' + ' | num_issues: ' + str(num_issues) + '\n' + ' | num_comments: ' + str(num_comments) + '\n' + ' | tasks_in_queue: ' + str(num_tasks) + '\n' + ' | --------------------------------' + '\n' + 'SERVER_CONFIG | allow_log: ' + str(allow_log) + '\n' + ' | allow_log_file: ' + str(allow_log_file) + '\n' + ' | allow_log_cyclic: ' + str(allow_log_cyclic) + '\n' + ' | allow_log_project_linking: ' + str(allow_log_project_linking) + '\n' + ' | detailed_log_project_linking: ' + str(detailed_log_project_linking) + '\n' + ' | allow_correct_github_labels: ' + str(allow_correct_github_labels) + '\n' + ' | allow_queue_daemon_restarting: ' + str(allow_queue_daemon_restarting) + '\n' + ' | allow_projects_relinking: ' + str(allow_projects_relinking) + '\n' + ' | allow_issues_post_rm_to_gh: ' + str(allow_issues_post_rm_to_gh) + '\n' + ' | BOT_ID_RM: ' + str(BOT_ID_RM) + '\n' + ' | BOT_ID_GH: ' + str(BOT_ID_GH) + '\n' + ' | tracker_ids_rm: ' + str(tracker_ids_rm) + '\n' + ' | status_ids_rm: ' + str(status_ids_rm) + '\n' + ' | priority_ids_rm: ' + str(priority_ids_rm) + '\n' + ' | url_rm: ' + str(url_rm) + '\n') if (allow_queue_daemon_restarting): linked_projects = Linked_Projects.objects.get_all() linked_issues = Linked_Issues.objects.get_all() linked_comments = Linked_Comments.objects.get_all() queue = Tasks_In_Queue num_projects = len(linked_projects) num_issues = len(linked_issues) num_comments = len(linked_comments) num_tasks = queue.objects.get_queue_len() log_server_startup_begin(num_projects, num_issues, num_comments, num_tasks) # перезапуск демона очереди if (num_tasks > 0): WRITE_LOG('Restarting queue daemon...\n') start_queue_daemon() if (allow_projects_relinking): # отправка в очередь задачи на повторную связь проектов if (num_projects > 0): put_task_in_queue('', 5) else: WRITE_LOG( "WARNING: re-linking projects was canceled due to setting 'allow_projects_relinking = False'\n" + "We can't guarantee that the linked data is up-to-date!\n" + "Please, enable the 'allow_projects_relinking' parameter in 'my_functions'\n" ) else: WRITE_LOG( "WARNING: restarting queue_daemon was canceled due to setting 'allow_queue_daemon_restarting = False'\n" + "(re-linking projects was also canceled)\n" + "Please, enable the 'allow_queue_daemon_restarting' parameter in 'my_functions'\n" )
def process_payload_from_rm(payload): # =================================================== ПОДГОТОВКА =================================================== def parse_payload(payload): payload = payload[ 'payload'] # достаём содержимое payload. payload payload. payload? payload! payload_parsed = {} # словарь issue (название, описание, ссылка) # автор issue payload_parsed['issue_author_id'] = payload['issue']['author']['id'] payload_parsed['issue_author_login'] = payload['issue']['author'][ 'login'] payload_parsed['issue_author_firstname'] = payload['issue']['author'][ 'firstname'] payload_parsed['issue_author_lastname'] = payload['issue']['author'][ 'lastname'] payload_parsed['action'] = payload['action'] # совершённое действие # при update возможна добавка комментария if (payload_parsed['action'] == 'updated'): # тело комментария payload_parsed['comment_body'] = payload['journal']['notes'] # id комментария (для связи и логов) payload_parsed['comment_id'] = payload['journal']['id'] # автор комментария payload_parsed['comment_author_id'] = payload['journal']['author'][ 'id'] payload_parsed['comment_author_login'] = payload['journal'][ 'author']['login'] payload_parsed['comment_author_firstname'] = payload['journal'][ 'author']['firstname'] payload_parsed['comment_author_lastname'] = payload['journal'][ 'author']['lastname'] # заполение полей issue payload_parsed['issue_title'] = payload['issue']['subject'] payload_parsed['issue_body'] = payload['issue']['description'] payload_parsed['tracker_id'] = payload['issue']['tracker']['id'] payload_parsed['status_id'] = payload['issue']['status']['id'] payload_parsed['priority_id'] = payload['issue']['priority']['id'] # идентификаторы (для связи и логов) payload_parsed['issue_id'] = payload['issue']['id'] payload_parsed['project_id'] = payload['issue']['project']['id'] # ссылка на issue (для фразы бота и логов) payload_parsed['issue_url'] = payload['url'] return payload_parsed try: issue = parse_payload(payload) except: error_text = 'ERROR: unknown payload type' WRITE_LOG('\n' + '=' * 35 + ' ' + str(datetime.datetime.today()) + ' ' + '=' * 35 + '\n' + 'received webhook from REDMINE: issues' + '\n' + error_text) return HttpResponse(error_text, status=200) # авторизация в гитхабе по токену api_key_github = read_file( 'api_keys/api_key_github.txt') # загрузка ключа для github api api_key_github = api_key_github.replace( '\n', '') # избавляемся от \n в конце строки # загрузка issue template из файла issue_github_template = read_file('data/issue_github_template.json') issue_github_template = Template( issue_github_template) # шаблон для каждого issue # загрузка comment template из файла comment_github_template = read_file('data/comment_github_template.json') comment_github_template = Template( comment_github_template) # шаблон для каждого issue # заголовки авторизации и приложения, при отправке запросов на гитхаб headers = { 'Authorization': 'token ' + api_key_github, 'Content-Type': 'application/json' } # ============================================ ВСПОМОГАТЕЛЬНЫЕ КОМАНДЫ ============================================= # issue_body # comment_body # comment_body_action # issue_label # добавляем фразу бота def add_bot_phrase(issue, to): # добавляем фразу бота к описанию issue if (to == 'issue_body'): firstname = issue['issue_author_firstname'] lastname = issue['issue_author_lastname'] login = issue['issue_author_login'] # добавляем фразу бота issue_body = '>I am a bot, bleep-bloop.\n' +\ '>' + firstname + ' ' + lastname + ' (' + login + ') Has opened the issue in Redmine.\n\n' +\ issue['issue_body'] return issue_body # добавляем фразу бота к комментарию elif (to == 'comment_body'): firstname = issue['comment_author_firstname'] lastname = issue['comment_author_lastname'] login = issue['comment_author_login'] # добавляем фразу бота comment_body = '>I am a bot, bleep-bloop.\n' + \ '>' + firstname + ' ' + lastname + ' (' + login + ') Has commented / edited with comment the issue in Redmine.\n\n' +\ issue['comment_body'] return comment_body # добавляем фразу бота (комментарием) к действию в редмайне (закрыл, изменил и т.д.) elif (to == 'comment_body_action'): firstname = issue['comment_author_firstname'] lastname = issue['comment_author_lastname'] login = issue['comment_author_login'] # добавляем фразу бота comment_body = 'I am a bot, bleep-bloop.\n' +\ firstname + ' ' + lastname + ' (' + login + ') Has edited the issue in Redmine.\n\n' return comment_body else: WRITE_LOG( "\nERROR: process_payload_from_rm.add_bot_phrase - unknown parameter 'to': " + to + '.' + "\nPlease, check your code on possible typos." + "\nAlternatively, add logic to process '" + to + "' action correctly.\n") return None # обновление linked_issues в базе данных сервера (tracker_id, status_id, priority_id) def update_linked_issues(linked_issues, issue): linked_issues.tracker_id_rm = issue['tracker_id'] linked_issues.priority_id_rm = issue['priority_id'] # если rejected if (issue['status_id'] == status_ids_rm[4]): linked_issues.is_opened = False linked_issues.status_id_rm = issue['status_id'] # если closed elif (issue['status_id'] == status_ids_rm[5]): linked_issues.is_opened = False # иначе - открываем else: linked_issues.is_opened = True linked_issues.status_id_rm = issue['status_id'] linked_issues.save() # типичные ошибки на этапе проверки: не связаны проекты, задачи, комментарии, неизвестное действие и т.п. def PREPARATION_ERR(error_text): # добавляем, чтобы в начале получилось: 'PREPARATION ERROR' error_text = 'PREPARATION ' + error_text WRITE_LOG('\n' + '=' * 35 + ' ' + str(datetime.datetime.today()) + ' ' + '=' * 35 + '\n' + 'received webhook from REDMINE: issues | ' + 'action: ' + str(issue['action']) + '\n' + error_text) return HttpResponse(error_text, status=200) # логическая ошибка: неизвестное действие, неправильные label-ы в гитхабе и т.п. def LOGICAL_ERR(error_text): # добавляем, чтобы в начале получилось: 'LOGICAL ERROR' error_text = 'LOGICAL ' + error_text WRITE_LOG('\n' + '=' * 35 + ' ' + str(datetime.datetime.today()) + ' ' + '=' * 35 + '\n' + 'received webhook from REDMINE: issues | ' + 'action: ' + str(issue['action']) + '\n' + error_text) return HttpResponse(error_text, status=200) # ============================================= КОМАНДЫ ДЛЯ ЗАГРУЗКИ =============================================== def post_issue(linked_projects, issue): # ----------------------------------------------- ПОДГОТОВКА ----------------------------------------------- # дополнительная проверка, что проекты связаны if (linked_projects.count() == 0): error_text = "ERROR: process_payload_from_rm.post_issue\n" +\ "issue " + str(issue['action']) + " in REDMINE, but the project is not linked to GITHUB" return PREPARATION_ERR(error_text) linked_projects = linked_projects[0] repos_id_gh = linked_projects.repos_id_gh url_gh = make_gh_repos_url(repos_id_gh) # ------------------------------------------ ОБРАБОТКА ФРАЗЫ БОТА ----------------------------------------- #title = '[From Redmine] ' + issue['issue_title'] title = issue['issue_title'] issue_body = add_bot_phrase(issue, 'issue_body') # добавляем фразу бота # обработка спец. символов title = align_special_symbols(title) issue_body = align_special_symbols(issue_body) # --------------------------------------- ЗАГРУЗКА ДАННЫХ В ГИТХАБ ---------------------------------------- # добавление label-ов tracker = match_tracker_to_gh(issue['tracker_id']) status = match_status_to_gh(issue['status_id']) priority = match_priority_to_gh(issue['priority_id']) issue_templated = issue_github_template.render(title=title, body=issue_body, priority=priority, status=status, tracker=tracker) # кодировка Latin-1 на некоторых задачах приводит к ошибке кодировки в питоне issue_templated = issue_templated.encode('utf-8') request_result = requests.post(url_gh, data=issue_templated, headers=headers) # ------------------------------------------ СОХРАНЕНИЕ ДАННЫХ -------------------------------------------- posted_issue = json.loads(request_result.text) # занесение в базу данных информацию о том, что данные issues связаны linked_issues = Linked_Issues.objects.create_linked_issues( issue['issue_id'], # id issue в редмайне posted_issue['id'], # id issue в гитхабе repos_id_gh, # id репозитория в гитхабе posted_issue['number'], # номер issue в репозитории гитхаба issue['tracker_id'], # id трекера в редмайне issue['status_id'], # id статуса в редмайне issue['priority_id'], # id приоритета в редмайне True) # открыт # добавляем linked_issues в linked_projects linked_projects.add_linked_issues(linked_issues) # ДЕБАГГИНГ log_issue_post_rm(request_result, issue, linked_issues) return request_result # загрузка комментария. нет необходимости в подготовке, так как запускается из edit_issue # (redmine не различает оставление комментария и изменение issue) def post_comment(linked_issues, issue, url_gh): # ------------------------------------------ ОБРАБОТКА ФРАЗЫ БОТА ----------------------------------------- # нет комментария if (issue['comment_body'] == ''): comment_body = add_bot_phrase( issue, 'comment_body_action') # добавляем фразу бота else: comment_body = add_bot_phrase( issue, 'comment_body') # добавляем фразу бота # обработка спец. символов comment_body = align_special_symbols(comment_body) # --------------------------------------- ЗАГРУЗКА ДАННЫХ В ГИТХАБ ---------------------------------------- comment_templated = comment_github_template.render(body=comment_body) # кодировка Latin-1 на некоторых задачах приводит к ошибке кодировки в питоне comment_templated = comment_templated.encode('utf-8') # добавление issue_id к ссылке issue_comments_url_gh = url_gh + '/' + str( linked_issues.issue_num_gh) + '/comments' request_result = requests.post(issue_comments_url_gh, data=comment_templated, headers=headers) # ------------------------------------------ СОХРАНЕНИЕ ДАННЫХ -------------------------------------------- #занесение в базу данных информации о том, что комментарии связаны posted_comment = json.loads(request_result.text) linked_comments = linked_issues.add_comment(issue['comment_id'], posted_comment['id']) # ДЕБАГГИНГ log_comment_rm(request_result, issue, linked_issues, linked_comments) return request_result def edit_issue(linked_projects, issue): # ----------------------------------------------- ПОДГОТОВКА ----------------------------------------------- # дополнительная проверка, что проекты связаны if (linked_projects.count() == 0): error_text = "ERROR: process_payload_from_rm.edit_issue\n" +\ "issue " + str(issue['action']) + " in REDMINE, but the project is not linked to GITHUB" return PREPARATION_ERR(error_text) linked_projects = linked_projects[0] repos_id_gh = linked_projects.repos_id_gh url_gh = make_gh_repos_url(repos_id_gh) linked_issues = linked_projects.get_issue_by_id_rm(issue['issue_id']) # дополнительная проверка, что issue связаны if (linked_issues.count() == 0): error_text = "ERROR: process_payload_from_rm.edit_issue\n" +\ "issue " + str(issue['action']) + " in REDMINE, but it's not linked to GITHUB" return PREPARATION_ERR(error_text) linked_issues = linked_issues[0] # добавление label-ов state_gh = "opened" # открыть / закрыть issue tracker = match_tracker_to_gh(issue['tracker_id']) priority = match_priority_to_gh(issue['priority_id']) if (issue['status_id'] != linked_issues.status_id_rm): status = match_status_to_gh(issue['status_id']) if (status == 'Status: closed'): status = match_status_to_gh( linked_issues.status_id_rm ) # не меняем статус (нет label-а closed) state_gh = 'closed' elif (status == 'Status: rejected'): state_gh = 'closed' else: status = match_status_to_gh(linked_issues.status_id_rm) post_comment(linked_issues, issue, url_gh) # ОТПРАВЛЯЕМ КОММЕНТАРИЙ В ГИТХАБ # ----------------------------------------- ОБРАБОТКА ФРАЗЫ БОТА ------------------------------------------- #title = '[From Redmine (edited)] ' + issue['issue_title'] title = issue['issue_title'] # проверяем, если автор issue - бот if (chk_if_rm_user_is_our_bot(issue['issue_author_id'])): issue_body = del_bot_phrase( issue['issue_body']) # удаляем фразу бота else: issue_body = add_bot_phrase(issue, 'issue_body') # добавляем фразу бота # обработка спец. символов title = align_special_symbols(title) issue_body = align_special_symbols(issue_body) # ---------------------------------------- ЗАГРУЗКА ДАННЫХ В ГИТХАБ ---------------------------------------- issue_templated = issue_github_template.render(title=title, body=issue_body, state=state_gh, priority=priority, status=status, tracker=tracker) # кодировка Latin-1 на некоторых задачах приводит к ошибке кодировки в питоне issue_templated = issue_templated.encode('utf-8') # добавление issue_id к ссылке issue_url_gh = url_gh + '/' + str(linked_issues.issue_num_gh) request_result = requests.patch(issue_url_gh, data=issue_templated, headers=headers) # ------------------------------------------ СОХРАНЕНИЕ ДАННЫХ -------------------------------------------- # обновляем информацию в таблице update_linked_issues(linked_issues, issue) # ДЕБАГГИНГ log_issue_edit_rm(request_result, issue, linked_issues) return request_result # привязка комментария на редмайне к гитхабу (да, это костыль) # пришлось привязать к id комментария в фразе бота на редмайне (редмайн не посылает внятный ответ на PUT запрос) def link_comment_to_github(linked_projects, issue): # ----------------------------------------------- ПОДГОТОВКА ----------------------------------------------- # дополнительная проверка, что проекты связаны if (linked_projects.count() == 0): error_text = "ERROR: process_payload_from_rm.link_comment_to_github\n" +\ "tried to link comment from REDMINE to GITHUB, but the project is not linked to GITHUB" return PREPARATION_ERR(error_text) linked_projects = linked_projects[0] linked_issues = linked_projects.get_issue_by_id_rm(issue['issue_id']) # дополнительная проверка, что issue связаны if (linked_issues.count() == 0): error_text = "ERROR: process_payload_from_rm.link_comment_to_github\n" +\ "tried to link comment from REDMINE to GITHUB, but the issue is not linked to GITHUB" return PREPARATION_ERR(error_text) linked_issues = linked_issues[0] # определяем действие (определяем, нужно ли привязывать комментарий к гитхабу - # комментарий от бота может оказаться сообщением о действии пользователя на гитхабе action = issue['comment_body'].split(' ')[6] if (action == 'left'): # достаём id комментария в гитхабе comment_id_gh_str = issue['comment_body'].split( '#issuecomment-')[1] comment_id_gh_str = comment_id_gh_str.split(' ')[0] comment_id_gh = int(comment_id_gh_str) # занесение в базу данных информацию о том, что комментарии связаны linked_comments = linked_issues.add_comment( issue['comment_id'], comment_id_gh) responce_text = log_link_comment_crutch(issue, linked_comments) return HttpResponse(responce_text, status=201) else: error_text = prevent_cyclic_comment_rm(issue) return HttpResponse(error_text, status=200) # ============================================ ЗАГРУЗКА ISSUE В GITHUB ============================================= linked_projects = Linked_Projects.objects.get_project_by_id_rm( issue['project_id']) if (issue['action'] == 'opened'): if (chk_if_rm_user_is_our_bot(issue['issue_author_id'])): error_text = prevent_cyclic_issue_rm(issue) return HttpResponse(error_text, status=200) if (allow_issues_post_rm_to_gh): request_result = post_issue(linked_projects, issue) else: error_text = "WARNING: process_payload_from_rm\n" + \ "PROHIBITED ACTION" WRITE_LOG('\n' + '=' * 35 + ' ' + str(datetime.datetime.today()) + ' ' + '=' * 35 + '\n' + 'received webhook from REDMINE: issues | ' + 'action: ' + str(issue['action']) + '\n' + error_text) return HttpResponse(error_text, status=200) elif (issue['action'] == 'updated'): if (chk_if_rm_user_is_our_bot(issue['comment_author_id'])): # попытка связать комментарий на редмайне с гитхабом return link_comment_to_github(linked_projects, issue) # изменение issue + добавление комментария request_result = edit_issue(linked_projects, issue) else: error_text = "ERROR: process_payload_from_rm\n" + \ "WRONG ACTION" return LOGICAL_ERR(error_text) return align_request_result(request_result)
def process_comment_payload_from_gh(payload): # =================================================== ПОДГОТОВКА =================================================== def parse_payload(payload): payload_parsed = {} # словарь issue (название, описание, ссылка) # действие и его автор payload_parsed['action'] = payload['action'] payload_parsed['sender_id'] = payload['sender']['id'] # sender - тот, кто совершил действие payload_parsed['sender_login'] = payload['sender']['login'] # заполение полей issue payload_parsed['issue_title'] = payload['issue']['title'] payload_parsed['issue_body'] = payload['issue']['body'] payload_parsed['issue_author_id'] = payload['issue']['user']['id'] payload_parsed['issue_author_login'] = payload['issue']['user']['login'] # идентификаторы (для связи и логов) payload_parsed['issue_id'] = payload['issue']['id'] payload_parsed['repos_id'] = payload['repository']['id'] payload_parsed['issue_number'] = payload['issue']['number'] # ссылка на issue (для фразы бота и логов) payload_parsed['issue_url'] = payload['issue']['html_url'] # комментарий payload_parsed['comment_body'] = payload['comment']['body'] payload_parsed['comment_id'] = payload['comment']['id'] payload_parsed['comment_author_id'] = payload['comment']['user']['id'] payload_parsed['comment_author_login'] = payload['comment']['user']['login'] return payload_parsed try: issue = parse_payload(payload) except: error_text = 'ERROR: unknown payload type' WRITE_LOG('\n' + '=' * 35 + ' ' + str(datetime.datetime.today()) + ' ' + '=' * 35 + '\n' + 'received webhook from GITHUB: issues comments' + '\n' + error_text) return HttpResponse(error_text, status=200) # авторизация в redmine по токену api_key_redmime = read_file('api_keys/api_key_redmime.txt') # загрузка ключа для redmine api api_key_redmime = api_key_redmime.replace('\n', '') # избавляемся от \n в конце строки # загрузка template из файла issue_redmine_template = read_file('data/issue_redmine_template.json') issue_redmine_template = Template(issue_redmine_template) # шаблон для каждого issue # заголовки авторизации и приложения, при отправке запросов на редмайн headers = {'X-Redmine-API-Key': api_key_redmime, 'Content-Type': 'application/json'} # ============================================ ВСПОМОГАТЕЛЬНЫЕ КОМАНДЫ ============================================= # issue_body # comment_body # comment_edit # comment_edit_else's # добавляем фразу бота, со ссылкой на аккаунт пользователя в гитхабе def add_bot_phrase(issue, to): # добавляем фразу бота к описанию issue if (to == 'issue_body'): author_url_gh = '"' + issue['issue_author_login'] + '":' + 'https://github.com/' + issue['issue_author_login'] issue_url_gh = '"issue":' + issue['issue_url'] issue_body = '>I am a bot, bleep-bloop.\n' +\ '>' + author_url_gh + ' Has opened the ' + issue_url_gh + ' in Github.\n' +\ issue['issue_body'] return issue_body # добавляем фразу бота к комментарию elif (to == 'comment_body'): # добавляем фразу бота author_url = '"' + issue['comment_author_login'] + '":' + 'https://github.com/' + issue['comment_author_login'] comment_url = '"comment":' + issue['issue_url'] + '#issuecomment-' + str(issue['comment_id']) comment_body = '>I am a bot, bleep-bloop.\n' +\ '>' + author_url + ' Has left a ' + comment_url + ' in Github.\n' +\ issue['comment_body'] return comment_body # добавляем фразу бота к комментарию (изменение своего комментария) elif (to == 'comment_edit'): # добавляем фразу бота author_url = '"' + issue['comment_author_login'] + '":' + 'https://github.com/' + issue['comment_author_login'] comment_url = '"comment":' + issue['issue_url'] + '#issuecomment-' + str(issue['comment_id']) comment_body = '>I am a bot, bleep-bloop.\n' +\ '>' + author_url + ' Has edited his ' + comment_url + ' in Github.\n' +\ issue['comment_body'] return comment_body # добавляем фразу бота к комментарию (изменение чужого комментария) elif (to == "comment_edit_else's"): # добавляем фразу бота sender_url = '"' + issue['sender_login'] + '":' + 'https://github.com/' + issue['sender_login'] author_url = '"' + issue['comment_author_login'] + '":' + 'https://github.com/' + issue['comment_author_login'] comment_url = '"comment":' + issue['issue_url'] + '#issuecomment-' + str(issue['comment_id']) comment_body = '>I am a bot, bleep-bloop.\n' +\ '>' + sender_url + ' Has edited ' + author_url + " 's " + comment_url + ' in Github.\n' +\ issue['comment_body'] return comment_body else: WRITE_LOG("\nERROR: process_comment_payload_from_gh.add_bot_phrase - unknown parameter 'to': " + to + '.' + "\nPlease, check the code on possible typos." + "\nAlternatively, add logic to process '" + to + "' action correctly.\n") return None # типичные ошибки на этапе проверки: не связаны проекты, задачи, комментарии, неизвестное действие и т.п. def PREPARATION_ERR(error_text): # добавляем, чтобы в начале получилось: 'PREPARATION ERROR' error_text = 'PREPARATION ' + error_text WRITE_LOG('\n' + '=' * 35 + ' ' + str(datetime.datetime.today()) + ' ' + '=' * 35 + '\n' + 'received webhook from GITHUB: issues_comments | ' + 'action: ' + str(issue['action']) + '\n' + error_text) return HttpResponse(error_text, status=200) # логическая ошибка: неизвестное действие, неправильные label-ы в гитхабе и т.п. def LOGICAL_ERR(error_text): # добавляем, чтобы в начале получилось: 'LOGICAL ERROR' error_text = 'LOGICAL ' + error_text WRITE_LOG('\n' + '=' * 35 + ' ' + str(datetime.datetime.today()) + ' ' + '=' * 35 + '\n' + 'received webhook from GITHUB: issues_comments | ' + 'action: ' + str(issue['action']) + '\n' + error_text) return HttpResponse(error_text, status=200) # ============================================= КОМАНДЫ ДЛЯ ЗАГРУЗКИ =============================================== def post_comment(linked_projects, issue): # ----------------------------------------------- ПОДГОТОВКА ---------------------------------------------- # дополнительная проверка, что проекты связаны if (linked_projects.count() == 0): error_text = "ERROR: process_comment_payload_from_gh.post_comment\n" +\ "comment " + str(issue['action']) +" in GITHUB, but the project is not linked to REDMINE" return PREPARATION_ERR(error_text) linked_projects = linked_projects[0] project_id_rm = linked_projects.project_id_rm linked_issues = linked_projects.get_issue_by_id_gh(issue['issue_id']) # дополнительная проверка, что issue связаны if (linked_issues.count() == 0): error_text = "ERROR: process_comment_payload_from_gh.post_comment\n" +\ "comment " + str(issue['action']) + " in GITHUB, but the issue is not linked to REDMINE" return PREPARATION_ERR(error_text) linked_issues = linked_issues[0] # ------------------------------------------ ОБРАБОТКА ФРАЗЫ БОТА ----------------------------------------- # проверяем, если автор issue - бот if (chk_if_gh_user_is_our_bot(issue['issue_author_id'])): issue_body = del_bot_phrase(issue['issue_body']) else: issue_body = add_bot_phrase(issue, 'issue_body') comment_body = add_bot_phrase(issue, 'comment_body') # добавляем фразу бота # обработка спец. символов issue_title = align_special_symbols(issue['issue_title']) issue_body = align_special_symbols(issue_body) comment_body = align_special_symbols(comment_body) # --------------------------------------- ЗАГРУЗКА ДАННЫХ В РЕДМАЙН ---------------------------------------- issue_templated = issue_redmine_template.render( project_id=project_id_rm, issue_id=linked_issues.issue_id_rm, priority_id=linked_issues.priority_id_rm, subject=issue_title, description=issue_body, notes=comment_body) # кодировка Latin-1 на некоторых задачах приводит к ошибке кодировки в питоне issue_templated = issue_templated.encode('utf-8') issue_url_rm = url_rm.replace('.json', '/' + str(linked_issues.issue_id_rm) + '.json') request_result = requests.put(issue_url_rm, data=issue_templated, headers=headers) # ------------------------------------------ СОХРАНЕНИЕ ДАННЫХ -------------------------------------------- # (делаем привязку комментариев после получения веб-хука от редмайна) # ДЕБАГГИНГ log_comment_gh(request_result, issue, linked_issues, linked_projects.project_id_rm) return request_result # изменение комментария (постим новый, пишем 'edited comment') def edit_comment(linked_projects, issue): # ----------------------------------------------- ПОДГОТОВКА ---------------------------------------------- # дополнительная проверка, что проекты связаны if (linked_projects.count() == 0): error_text = "ERROR: process_comment_payload_from_gh.edit_comment\n" +\ "comment " + str(issue['action']) + " in GITHUB, but the project is not linked to REDMINE" return PREPARATION_ERR(error_text) linked_projects = linked_projects[0] project_id_rm = linked_projects.project_id_rm linked_issues = linked_projects.get_issue_by_id_gh(issue['issue_id']) # дополнительная проверка, что issue связаны if (linked_issues.count() == 0): error_text = "ERROR: process_comment_payload_from_gh.edit_comment\n" +\ "comment " + str(issue['action']) + " in GITHUB, but the issue is not linked to REDMINE" return PREPARATION_ERR(error_text) linked_issues = linked_issues[0] linked_comments = linked_issues.get_comment_by_id_gh(issue['comment_id']) # дополнительная проверка, что комментарии связаны if (linked_comments.count() == 0): error_text = "ERROR: process_comment_payload_from_gh.edit_comment\n" +\ "comment " + str(issue['action']) + " in GITHUB, but it's not linked to REDMINE" return PREPARATION_ERR(error_text) linked_comments = linked_comments[0] # ------------------------------------------ ОБРАБОТКА ФРАЗЫ БОТА ----------------------------------------- # проверяем, если автор issue - бот if (chk_if_gh_user_is_our_bot(issue['issue_author_id'])): issue_body = del_bot_phrase(issue['issue_body']) else: issue_body = add_bot_phrase(issue, 'issue_body') # если изменил свой комментарий if (issue['sender_id'] == issue['comment_author_id']): comment_body = add_bot_phrase(issue, 'comment_edit') # добавляем фразу бота # если изменил не свой комментарий else: comment_body = add_bot_phrase(issue, "comment_edit_else's") # добавляем фразу бота # обработка спец. символов issue_title = align_special_symbols(issue['issue_title']) issue_body = align_special_symbols(issue_body) comment_body = align_special_symbols(comment_body) # --------------------------------------- ЗАГРУЗКА ДАННЫХ В РЕДМАЙН ---------------------------------------- issue_templated = issue_redmine_template.render( project_id=project_id_rm, issue_id=linked_issues.issue_id_rm, priority_id=linked_issues.priority_id_rm, subject=issue_title, description=issue_body, notes=comment_body) # кодировка Latin-1 на некоторых задачах приводит к ошибке кодировки в питоне issue_templated = issue_templated.encode('utf-8') issue_url_rm = url_rm.replace('.json', '/' + str(linked_issues.issue_id_rm) + '.json') request_result = requests.put(issue_url_rm, data=issue_templated, headers=headers) # ------------------------------------------ СОХРАНЕНИЕ ДАННЫХ -------------------------------------------- # (делаем привязку комментариев после получения веб-хука от редмайна) # ДЕБАГГИНГ log_comment_gh(request_result, issue, linked_issues, linked_projects.project_id_rm) return request_result ''' # изменение комментария (не постим новый, а изменяем старый) # СТАРЫЙ КОД: перед использованием - привести в порядок (как edit_comment выше) def edit_comment(issue, linked_issues): # дополнительная проверка, что issue связаны # (на случай, если изменили не связанный issue) if (linked_issues.count() == 0): WRITE_LOG('\n' + '='*35 + ' ' + str(datetime.datetime.today()) + ' ' + '='*35 + '\n' + 'received webhook from GITHUB: issue_comments | ' + 'action: ' + str(issue['action']) + '\n' + "ERROR: posted comment in GITHUB, but the issue is not linked to REDMINE") return HttpResponse(status=200) linked_issues = linked_issues[0] # дополнительная проверка, что комментарии связаны linked_comments = linked_issues.get_comment_by_id_gh(issue['comment_id']) if (linked_comments.count() == 0): WRITE_LOG('\n' + '='*35 + ' ' + str(datetime.datetime.today()) + ' ' + '='*35 + '\n' + 'received webhook from GITHUB: issue_comments | ' + 'action: ' + str(issue['action']) + '\n' + "ERROR: edited comment in GITHUB, but it is not linked to REDMINE") return HttpResponse(status=200) linked_comments = linked_comments[0] # ------------------------------------------- ОБРАБАТЫВАЕМ ФРАЗУ БОТА ------------------------------------------ # проверяем, если автор issue - бот if (chk_if_gh_user_is_our_bot(issue['issue_author_id'])): issue_body = del_bot_phrase(issue['issue_body']) else: issue_body = add_bot_phrase(issue) comment_body = bot_speech_comment(issue) # добавляем фразу бота # обработка спец. символов issue_title = align_special_symbols(issue['issue_title']) issue_body = align_special_symbols(issue_body) comment_body = align_special_symbols(comment_body) # ----------------------------------------- ЗАГРУЖАЕМ ДАННЫЕ В РЕДМАЙН ----------------------------------------- issue_templated = issue_redmine_template.render( project_id=project_id_rm, issue_id=linked_issues.issue_id_rm, priority_id=priority_ids_rm[0], subject=issue_title, description=issue_body, notes=comment_body) # кодировка Latin-1 на некоторых задачах приводит к ошибке кодировки в питоне issue_templated = issue_templated.encode('utf-8') issue_url_rm = url_rm.replace('.json', '/' + str(linked_issues.issue_id_rm) + '.json') request_result = requests.put(issue_url_rm, data=issue_templated, headers=headers) # ------------------------------------------- ПРИВЯЗКА КОММЕНТАРИЕВ -------------------------------------------- # (делаем привязку после получения веб-хука от редмайна) # ДЕБАГГИНГ log_comment_gh(request_result, issue, linked_issues) return request_result''' # ========================================= ЗАГРУЗКА КОММЕНТАРИЯ В REDMINE ========================================= linked_projects = Linked_Projects.objects.get_project_by_id_gh(issue['repos_id']) if (issue['action'] == 'created'): if (chk_if_gh_user_is_our_bot(issue['sender_id'])): error_text = prevent_cyclic_comment_gh(issue) return HttpResponse(error_text, status=200) request_result = post_comment(linked_projects, issue) elif (issue['action'] == 'edited'): if (chk_if_gh_user_is_our_bot(issue['sender_id'])): error_text = prevent_cyclic_comment_gh(issue) return HttpResponse(error_text, status=200) request_result = edit_comment(linked_projects, issue) else: error_text = "ERROR: process_comment_payload_from_gh\n" + \ "WRONG ACTION" return LOGICAL_ERR(error_text) return align_request_result(request_result)
def process_payload_from_gh(payload): # =================================================== ПОДГОТОВКА =================================================== def parse_payload(payload): payload_parsed = {} # словарь issue (название, описание, ссылка) # действие и его автор payload_parsed['action'] = payload['action'] payload_parsed['sender_id'] = payload['sender'][ 'id'] # sender - тот, кто совершил действие payload_parsed['sender_login'] = payload['sender']['login'] # заполение полей issue payload_parsed['issue_title'] = payload['issue']['title'] payload_parsed['issue_body'] = payload['issue']['body'] payload_parsed['issue_author_id'] = payload['issue']['user']['id'] payload_parsed['issue_author_login'] = payload['issue']['user'][ 'login'] # идентификаторы (для связи и логов) payload_parsed['issue_id'] = payload['issue']['id'] payload_parsed['repos_id'] = payload['repository']['id'] payload_parsed['issue_number'] = payload['issue']['number'] # ссылка на issue (для фразы бота и логов) payload_parsed['issue_url'] = payload['issue']['html_url'] payload_parsed['labels'] = payload['issue']['labels'] #if ((payload_parsed['action'] == 'labeled') | (payload_parsed['action'] == 'unlabeled')): # payload_parsed['label'] = payload['issue']['label'] return payload_parsed try: issue = parse_payload(payload) except: error_text = 'ERROR: unknown payload type' WRITE_LOG('\n' + '=' * 35 + ' ' + str(datetime.datetime.today()) + ' ' + '=' * 35 + '\n' + 'received webhook from GITHUB: issues' + '\n' + error_text) return HttpResponse(error_text, status=200) # авторизация в redmine по токену api_key_redmime = read_file( 'api_keys/api_key_redmime.txt') # загрузка ключа для redmine api api_key_redmime = api_key_redmime.replace( '\n', '') # избавляемся от \n в конце строки # загрузка template из файла issue_redmine_template = read_file('data/issue_redmine_template.json') issue_redmine_template = Template( issue_redmine_template) # шаблон для каждого issue # заголовки авторизации и приложения, при отправке запросов на редмайн headers_rm = { 'X-Redmine-API-Key': api_key_redmime, 'Content-Type': 'application/json' } # авторизация в гитхабе по токену api_key_github = read_file( 'api_keys/api_key_github.txt') # загрузка ключа для github api api_key_github = api_key_github.replace( '\n', '') # избавляемся от \n в конце строки # загрузка issue template из файла issue_github_template = read_file('data/issue_github_template.json') issue_github_template = Template( issue_github_template) # шаблон для каждого issue # заголовки авторизации и приложения, при отправке запросов на гитхаб headers_gh = { 'Authorization': 'token ' + api_key_github, 'Content-Type': 'application/json' } # ============================================ ВСПОМОГАТЕЛЬНЫЕ КОМАНДЫ ============================================= # issue_body # comment_body_action # добавляем фразу бота, со ссылкой на аккаунт пользователя в гитхабе def add_bot_phrase(issue, to): # добавляем фразу бота к описанию issue if (to == 'issue_body'): # добавляем фразу бота author_url_gh = '"' + issue[ 'issue_author_login'] + '":' + 'https://github.com/' + issue[ 'issue_author_login'] issue_url_gh = '"issue":' + issue['issue_url'] issue_body = '>I am a bot, bleep-bloop.\n' +\ '>' + author_url_gh + ' Has opened the ' + issue_url_gh + ' in Github.\n' +\ issue['issue_body'] return issue_body # добавляем фразу бота (комментарием) к действию в гитхабе (закрыл, изменил и т.д.) elif (to == 'comment_body_action'): author_url = '"' + issue[ 'sender_login'] + '":' + 'https://github.com/' + issue[ 'sender_login'] issue_url = '"issue":' + issue['issue_url'] comment_body = 'I am a bot, bleep-bloop.\n' +\ author_url + ' Has ' + issue['action'] + ' the ' + issue_url + ' in Github.\n' return comment_body else: WRITE_LOG("\nERROR: 'process_payload_from_gh.add_bot_phrase'\n" + "unknown parameter 'to': " + to + '.\n' + "Please, check your code on possible typos.\n" + "Alternatively, add logic to process '" + to + "' parameter correctly.") return None # обновление linked_issues в базе данных сервера (tracker_id, status_id, priority_id) def update_linked_issues(linked_issues, tracker_id, status_id, priority_id, is_opened): linked_issues.tracker_id_rm = tracker_id linked_issues.status_id_rm = status_id linked_issues.priority_id_rm = priority_id linked_issues.is_opened = is_opened linked_issues.save() # TODO: отправлять комментарий бота, что нельзя установить неправильные label-ы + логи? # исправление label-ов в гитхабе def correct_gh_labels(issue, tracker, linked_issues): if (not allow_correct_github_labels): return 0 # добавление label-ов priority = match_priority_to_gh(linked_issues.priority_id_rm) status = match_status_to_gh(linked_issues.status_id_rm) # ---------------------------------------- ЗАГРУЗКА ДАННЫХ В ГИТХАБ ---------------------------------------- issue_templated = issue_github_template.render( title=issue['issue_title'], body=issue['issue_body'], priority=priority, status=status, tracker=tracker) # кодировка Latin-1 на некоторых задачах приводит к ошибке кодировки в питоне issue_templated = issue_templated.encode('utf-8') url_gh = make_gh_repos_url(linked_issues.repos_id_gh) # добавление issue_id к ссылке issue_url_gh = url_gh + '/' + str(linked_issues.issue_num_gh) request_result = requests.patch(issue_url_gh, data=issue_templated, headers=headers_gh) return request_result # TODO: отправлять комментарий бота, что нельзя открыть rejected issue + логи? # закрыть issue в гитхабе def close_gh_issue(linked_issues, url_gh): # ---------------------------------------- ЗАГРУЗКА ДАННЫХ В ГИТХАБ ---------------------------------------- issue_templated = issue_github_template.render(state='closed') # кодировка Latin-1 на некоторых задачах приводит к ошибке кодировки в питоне issue_templated = issue_templated.encode('utf-8') # добавление issue_id к ссылке issue_url_gh = url_gh + '/' + str(linked_issues.issue_num_gh) request_result = requests.patch(issue_url_gh, data=issue_templated, headers=headers_gh) return request_result # типичные ошибки на этапе проверки: не связаны проекты, задачи, комментарии, неизвестное действие и т.п. def PREPARATION_ERR(error_text): # добавляем, чтобы в начале получилось: 'PREPARATION ERROR' error_text = 'PREPARATION ' + error_text WRITE_LOG('\n' + '=' * 35 + ' ' + str(datetime.datetime.today()) + ' ' + '=' * 35 + '\n' + 'received webhook from GITHUB: issues | ' + 'action: ' + str(issue['action']) + '\n' + error_text) return HttpResponse(error_text, status=200) # логическая ошибка: неизвестное действие, неправильные label-ы в гитхабе и т.п. def LOGICAL_ERR(error_text): # добавляем, чтобы в начале получилось: 'LOGICAL ERROR' error_text = 'LOGICAL ' + error_text WRITE_LOG('\n' + '=' * 35 + ' ' + str(datetime.datetime.today()) + ' ' + '=' * 35 + '\n' + 'received webhook from GITHUB: issues | ' + 'action: ' + str(issue['action']) + '\n' + error_text) return HttpResponse(error_text, status=200) # ============================================= КОМАНДЫ ДЛЯ ЗАГРУЗКИ =============================================== def post_issue(linked_projects, issue): # ----------------------------------------------- ПОДГОТОВКА ---------------------------------------------- # дополнительная проверка, что проекты связаны if (linked_projects.count() == 0): error_text = "ERROR: process_payload_from_gh.post_issue\n" +\ "issue " + str(issue['action']) + " in GITHUB, but the project is not linked to REDMINE" return PREPARATION_ERR(error_text) linked_projects = linked_projects[0] project_id_rm = linked_projects.project_id_rm # настройка label-ов tracker_id_rm = None status_id_rm = status_ids_rm[0] priority_id_rm = priority_ids_rm[0] for label in issue['labels']: tracker_rm = match_label_to_rm(label['name']) # если label известный if (tracker_rm != None): if (tracker_rm['type'] == 'Tracker'): if (tracker_id_rm == None): tracker_id_rm = tracker_rm['id_rm'] # если пользователь выбрал более одного трекера -> значение по умолчанию else: tracker_id_rm = tracker_ids_rm[0] # проверяем, был ли установлен трекер if (tracker_id_rm == None): tracker_id_rm = tracker_ids_rm[0] # ------------------------------------------ ОБРАБОТКА ФРАЗЫ БОТА ----------------------------------------- #title = '[From Github] ' + issue['issue_title'] title = issue['issue_title'] issue_body = add_bot_phrase(issue, 'issue_body') # добавляем фразу бота # обработка спец. символов title = align_special_symbols(title) issue_body = align_special_symbols(issue_body) # --------------------------------------- ЗАГРУЗКА ДАННЫХ В РЕДМАЙН ---------------------------------------- issue_templated = issue_redmine_template.render( project_id=project_id_rm, tracker_id=tracker_id_rm, status_id=status_id_rm, priority_id=priority_id_rm, subject=title, description=issue_body) # кодировка по умолчанию (Latin-1) на некоторых задачах приводит к ошибке кодировки в питоне issue_templated = issue_templated.encode('utf-8') request_result = requests.post(url_rm, data=issue_templated, headers=headers_rm) # ------------------------------------------ СОХРАНЕНИЕ ДАННЫХ -------------------------------------------- posted_issue = json.loads(request_result.text) # занесение в базу данных информацию о том, что данные issues связаны linked_issues = Linked_Issues.objects.create_linked_issues( posted_issue['issue']['id'], # id issue в редмайне issue['issue_id'], # id issue в гитхабе issue['repos_id'], # id репозитория в гитхабе issue['issue_number'], # номер issue в репозитории гитхаба tracker_id_rm, # id трекера в редмайне status_id_rm, # id статуса в редмайне priority_id_rm, # id приоритета в редмайне True) # открыт # добавляем linked_issues в linked_projects linked_projects.add_linked_issues(linked_issues) # корректируем label-ы в гитхабе tracker = match_tracker_to_gh(linked_issues.tracker_id_rm) correct_gh_labels(issue, tracker, linked_issues) # ДЕБАГГИНГ log_issue_gh(request_result, issue, linked_issues, linked_projects.project_id_rm) return request_result # is_opened - issue открыто / закрыто def edit_issue(linked_projects, issue, is_opened): # ----------------------------------------------- ПОДГОТОВКА ---------------------------------------------- # дополнительная проверка, что проекты связаны if (linked_projects.count() == 0): error_text = "ERROR: process_payload_from_gh.edit_issue\n" +\ "issue " + str(issue['action']) + " in GITHUB, but the project is not linked to REDMINE" return PREPARATION_ERR(error_text) linked_projects = linked_projects[0] project_id_rm = linked_projects.project_id_rm repos_id_gh = linked_projects.repos_id_gh url_gh = make_gh_repos_url(repos_id_gh) linked_issues = linked_projects.get_issue_by_id_gh(issue['issue_id']) # дополнительная проверка, что issue связаны if (linked_issues.count() == 0): error_text = "ERROR: process_payload_from_gh.edit_issue\n" +\ "issue " + str(issue['action']) + " in GITHUB, but it's not linked to REDMINE" return PREPARATION_ERR(error_text) linked_issues = linked_issues[0] # проверка: что issue был отклонён (запрещаем открывать вновь) """ if (linked_issues.status_id_rm == status_ids_rm[4]): if (is_opened == True): return close_gh_issue(linked_issues, url_gh) """ # настройка label-ов tracker_id_rm = None for label in issue['labels']: tracker_rm = match_label_to_rm(label['name']) # если label известный if (tracker_rm != None): if (tracker_rm['type'] == 'Tracker'): if (tracker_id_rm == None): tracker_id_rm = tracker_rm['id_rm'] # если пользователь выбрал более одного трекера -> значение по умолчанию else: tracker_id_rm = tracker_ids_rm[0] # проверяем, был ли установлен трекер if (tracker_id_rm == None): tracker_id_rm = tracker_ids_rm[0] # корректируем label-ы в гитхабе tracker = match_tracker_to_gh(linked_issues.tracker_id_rm) correct_gh_labels(issue, tracker, linked_issues) # обновляем информацию в таблице update_linked_issues(linked_issues, tracker_id_rm, linked_issues.status_id_rm, linked_issues.priority_id_rm, is_opened) # ------------------------------------------ ОБРАБОТКА ФРАЗЫ БОТА ----------------------------------------- #title = '[From Github] ' + issue['issue_title'] title = issue['issue_title'] # проверяем, если автор issue - бот if (chk_if_gh_user_is_our_bot(issue['issue_author_id'])): issue_body = del_bot_phrase( issue['issue_body']) # удаляем фразу бота else: issue_body = add_bot_phrase(issue, 'issue_body') # добавляем фразу бота comment_body = add_bot_phrase( issue, 'comment_body_action' ) # добавляем фразу бота в комментарий к действию # обработка спец. символов title = align_special_symbols(title) issue_body = align_special_symbols(issue_body) comment_body = align_special_symbols(comment_body) # --------------------------------------- ЗАГРУЗКА ДАННЫХ В РЕДМАЙН ---------------------------------------- if (is_opened): status_id = linked_issues.status_id_rm else: status_id = status_ids_rm[5] # closed issue_templated = issue_redmine_template.render( project_id=project_id_rm, issue_id=linked_issues.issue_id_rm, tracker_id=linked_issues.tracker_id_rm, status_id=status_id, priority_id=linked_issues.priority_id_rm, subject=title, description=issue_body, notes=comment_body) # кодировка Latin-1 на некоторых задачах приводит к ошибке кодировки в питоне issue_templated = issue_templated.encode('utf-8') issue_url_rm = url_rm.replace( '.json', '/' + str(linked_issues.issue_id_rm) + '.json') request_result = requests.put(issue_url_rm, data=issue_templated, headers=headers_rm) # ДЕБАГГИНГ log_issue_gh(request_result, issue, linked_issues, linked_projects.project_id_rm) return request_result def delete_issue(linked_projects, issue): # ----------------------------------------------- ПОДГОТОВКА ----------------------------------------------- # дополнительная проверка, что проекты связаны if (linked_projects.count() == 0): error_text = "ERROR: process_payload_from_gh.delete_issue\n" +\ "issue " + str(issue['action']) + " in GITHUB, but the project is not linked to REDMINE" return PREPARATION_ERR(error_text) linked_projects = linked_projects[0] linked_issues = linked_projects.get_issue_by_id_gh(issue['issue_id']) # дополнительная проверка, что issue связаны if (linked_issues.count() == 0): error_text = "ERROR: process_payload_from_gh.delete_issue\n" +\ "issue " + str(issue['action']) + " in GITHUB, but it's not linked to REDMINE" return PREPARATION_ERR(error_text) linked_issues = linked_issues[0] # -------------------------------------- УДАЛЕНИЕ ДАННЫХ В РЕДМАЙНЕ ---------------------------------------- issue_url_rm = url_rm.replace( '.json', '/' + str(linked_issues.issue_id_rm) + '.json') request_result = requests.delete(issue_url_rm, headers=headers_rm) # удаление linked_issues из базы данных linked_issues.delete() # ДЕБАГГИНГ log_issue_gh(request_result, issue, linked_issues, linked_projects.project_id_rm) return request_result def reject_issue(linked_projects, issue): # ----------------------------------------------- ПОДГОТОВКА ---------------------------------------------- # дополнительная проверка, что проекты связаны if (linked_projects.count() == 0): error_text = "ERROR: process_payload_from_gh.reject_issue\n" +\ "issue " + str(issue['action']) + " in GITHUB, but the project is not linked to REDMINE" return PREPARATION_ERR(error_text) linked_projects = linked_projects[0] project_id_rm = linked_projects.project_id_rm repos_id_gh = linked_projects.repos_id_gh url_gh = make_gh_repos_url(repos_id_gh) linked_issues = linked_projects.get_issue_by_id_gh(issue['issue_id']) # дополнительная проверка, что issue связаны if (linked_issues.count() == 0): error_text = "ERROR: process_payload_from_gh.reject_issue\n" +\ "issue " + str(issue['action']) + " in GITHUB, but it's not linked to REDMINE" return PREPARATION_ERR(error_text) linked_issues = linked_issues[0] # обновляем информацию в таблице update_linked_issues( linked_issues, linked_issues.tracker_id_rm, status_ids_rm[4], # 4 - rejected linked_issues.priority_id_rm, False) # ------------------------------------------ ОБРАБОТКА ФРАЗЫ БОТА ----------------------------------------- #title = '[From Github] ' + issue['issue_title'] title = issue['issue_title'] # проверяем, если автор issue - бот if (chk_if_gh_user_is_our_bot(issue['issue_author_id'])): issue_body = del_bot_phrase( issue['issue_body']) # удаляем фразу бота else: issue_body = add_bot_phrase(issue, 'issue_body') # добавляем фразу бота comment_body = add_bot_phrase( issue, 'comment_body_action' ) # добавляем фразу бота в комментарий к действию # обработка спец. символов title = align_special_symbols(title) issue_body = align_special_symbols(issue_body) comment_body = align_special_symbols(comment_body) # --------------------------------------- ЗАГРУЗКА ДАННЫХ В РЕДМАЙН ---------------------------------------- issue_templated = issue_redmine_template.render( project_id=project_id_rm, issue_id=linked_issues.issue_id_rm, tracker_id=linked_issues.tracker_id_rm, status_id=status_ids_rm[4], # 4 - rejected priority_id=linked_issues.priority_id_rm, subject=title, description=issue_body, notes=comment_body) # кодировка Latin-1 на некоторых задачах приводит к ошибке кодировки в питоне issue_templated = issue_templated.encode('utf-8') issue_url_rm = url_rm.replace( '.json', '/' + str(linked_issues.issue_id_rm) + '.json') request_result = requests.put(issue_url_rm, data=issue_templated, headers=headers_rm) # удаление linked_issues из базы данных linked_issues.delete() # ДЕБАГГИНГ log_issue_gh(request_result, issue, linked_issues, linked_projects.project_id_rm) return request_result # TODO: бот не совсем корректно реагирует, если изменить трекер и что-либо ещё (частично исправил) # TODO: также, бот несколько раз упоминает действие в редмайне (labeled, unlabeld) (так как гитхаб отсылает все изменения столько раз, сколько label-ов было изменено...) def label_issue(linked_projects, issue): # ----------------------------------------------- ПОДГОТОВКА ----------------------------------------------- # дополнительная проверка, что проекты связаны if (linked_projects.count() == 0): error_text = "ERROR: process_payload_from_gh.label_issue\n" +\ "issue " + str(issue['action']) + " in GITHUB, but the project is not linked to REDMINE" return PREPARATION_ERR(error_text) linked_projects = linked_projects[0] project_id_rm = linked_projects.project_id_rm linked_issues = linked_projects.get_issue_by_id_gh(issue['issue_id']) # дополнительная проверка, что issue связаны if (linked_issues.count() == 0): error_text = "ERROR: process_payload_from_gh.label_issue\n" +\ "issue " + str(issue['action']) + " in GITHUB, but it's not linked to REDMINE" return PREPARATION_ERR(error_text) linked_issues = linked_issues[0] priority_id_rm = None status_id_rm = None tracker_id_rm = None incorrect_labels = False labels = issue['labels'] for label in labels: label_gh = match_label_to_rm(label['name']) #если label известный if (label_gh != None): if (label_gh['type'] == 'Priority'): if (priority_id_rm == None): priority_id_rm = label_gh['id_rm'] if (priority_id_rm != linked_issues.priority_id_rm): incorrect_labels = True else: incorrect_labels = True elif (label_gh['type'] == 'Status'): if (status_id_rm == None): status_id_rm = label_gh['id_rm'] if (status_id_rm != linked_issues.status_id_rm): incorrect_labels = True else: incorrect_labels = True elif (label_gh['type'] == 'Tracker'): if (tracker_id_rm == None): tracker_id_rm = label_gh['id_rm'] # пользователь выбрал новый трекер, но не удалил старый -> выбираем новый else: if (tracker_id_rm == linked_issues.tracker_id_rm): tracker_id_rm = label_gh['id_rm'] # проверяем, был ли изменён трекер if (tracker_id_rm == None): tracker_id_rm = linked_issues.tracker_id_rm # ------------------------------------------ ОБРАБОТКА ФРАЗЫ БОТА ----------------------------------------- #title = '[From Github] ' + issue['issue_title'] title = issue['issue_title'] # проверяем, если автор issue - бот if (chk_if_gh_user_is_our_bot(issue['issue_author_id'])): issue_body = del_bot_phrase( issue['issue_body']) # удаляем фразу бота else: issue_body = add_bot_phrase(issue, 'issue_body') # добавляем фразу бота comment_body = add_bot_phrase( issue, 'comment_body_action' ) # добавляем фразу бота в комментарий к действию # обработка спец. символов title = align_special_symbols(title) issue_body = align_special_symbols(issue_body) comment_body = align_special_symbols(comment_body) # --------------------------------------- ЗАГРУЗКА ДАННЫХ В РЕДМАЙН ---------------------------------------- # корректируем label-ы в гитхабе tracker = match_tracker_to_gh(tracker_id_rm) request_result = correct_gh_labels( issue, tracker, linked_issues) # корректируем label-ы в гитхабе if (request_result.status_code != 200): # сообщаем об ошибке error_text = "ERROR: process_payload_from_gh.label_issue\n" +\ "Encountered some error while trying to correct labels in Github" return LOGICAL_ERR(error_text) # TODO: похоже, он не успевает изменить linked_issues.tracker_id_rm: вебхуки приходят почти одновременно # проверяем, был ли изменён трекер и предотвращаем множественную отправку сообщений в гитхаб if ((tracker_id_rm != linked_issues.tracker_id_rm) & (issue['action'] == 'labeled')): # обновляем информацию в таблице update_linked_issues(linked_issues, tracker_id_rm, linked_issues.status_id_rm, linked_issues.priority_id_rm, True) issue_templated = issue_redmine_template.render( project_id=project_id_rm, issue_id=linked_issues.issue_id_rm, tracker_id=tracker_id_rm, status_id=linked_issues.status_id_rm, priority_id=linked_issues.priority_id_rm, subject=title, description=issue_body, notes=comment_body) # кодировка Latin-1 на некоторых задачах приводит к ошибке кодировки в питоне issue_templated = issue_templated.encode('utf-8') issue_url_rm = url_rm.replace( '.json', '/' + str(linked_issues.issue_id_rm) + '.json') request_result = requests.put(issue_url_rm, data=issue_templated, headers=headers_rm) # проверяем, корректные ли label-ы if (incorrect_labels): # сообщаем об ошибке error_text = "ERROR: process_payload_from_gh.label_issue\n" +\ "incorrect labels in GITHUB" return LOGICAL_ERR(error_text) else: # ДЕБАГГИНГ log_issue_gh(request_result, issue, linked_issues, linked_projects.project_id_rm) return request_result # ============================================ ЗАГРУЗКА ISSUE В REDMINE ============================================ do_delete_issues = False # запрет удаления issues (вместо удаления ставим rejected) linked_projects = Linked_Projects.objects.get_project_by_id_gh( issue['repos_id']) if (issue['action'] == 'opened'): if (chk_if_gh_user_is_our_bot(issue['sender_id'])): error_text = prevent_cyclic_issue_gh(issue) return HttpResponse(error_text, status=200) request_result = post_issue(linked_projects, issue) elif (issue['action'] == 'edited'): if (chk_if_gh_user_is_our_bot(issue['sender_id'])): error_text = prevent_cyclic_issue_gh(issue) return HttpResponse(error_text, status=200) request_result = edit_issue(linked_projects, issue, True) elif (issue['action'] == 'closed'): if (chk_if_gh_user_is_our_bot(issue['sender_id'])): error_text = prevent_cyclic_issue_gh(issue) return HttpResponse(error_text, status=200) request_result = edit_issue(linked_projects, issue, False) elif (issue['action'] == 'reopened'): if (chk_if_gh_user_is_our_bot(issue['sender_id'])): error_text = prevent_cyclic_issue_gh(issue) return HttpResponse(error_text, status=200) request_result = edit_issue(linked_projects, issue, True) elif (issue['action'] == 'deleted'): if (chk_if_gh_user_is_our_bot(issue['sender_id'])): error_text = prevent_cyclic_issue_gh(issue) return HttpResponse(error_text, status=200) if (do_delete_issues): request_result = delete_issue(linked_projects, issue) else: request_result = reject_issue(linked_projects, issue) # Совершенно безразлично, 'labeled' или 'unlabeled' elif ((issue['action'] == 'labeled') | (issue['action'] == 'unlabeled')): if (chk_if_gh_user_is_our_bot(issue['sender_id'])): error_text = prevent_cyclic_issue_gh(issue) return HttpResponse(error_text, status=200) request_result = label_issue(linked_projects, issue) else: error_text = "ERROR: process_payload_from_gh\n" +\ "UNKNOWN ACTION" return LOGICAL_ERR(error_text) return align_request_result(request_result)
def link_issues_in_project(linked_projects): # ----------------------------------------------- ПОДГОТОВКА ---------------------------------------------- log_link_issues_start() repos_url_gh = linked_projects.url_gh[19:] # избавляемся от 'https://github.com/' # запрос кол-ва всех issue url_gh = 'https://api.github.com/search/issues?q=repo:' + repos_url_gh request_result = requests.get(url_gh) # для total_count WRITE_LOG(' ISSUES total_count QUERRY RESULT: ' + str(request_result)) num_issues = json.loads(request_result.text)['total_count'] WRITE_LOG(' total_count: ' + str(num_issues)) # ----------------------------------- ЗАПРОС ВСЕХ ЗАДАЧ С ПРОЕКТА В ГИТХАБЕ ------------------------------------ issues = [] WRITE_LOG(' QUERRYING ISSUES FROM GITHUB') #per_page = 6 # для тестов per_page = 100 # кол-во issue за страницу page = 1 # цикл перехода по всем страницам, по 100 issue за страницу while True: WRITE_LOG(' per_page: ' + str(per_page) + ' page: ' + str(page) + ' | status: ' + str(request_result.status_code) + ' ' + str(request_result.reason)) ''' https://api.github.com/search/issues?q=repo:AlexanderND/issues_linker_auto_labels_test/issues&per_page=5&page=1 ''' url = url_gh + '/issues&per_page=' + str(per_page) + '&page=' + str(page) request_result = requests.get(url) issues_on_page = json.loads(request_result.text)['items'] # цикл перебора всех задач на странице for issue in issues_on_page: issue_parsed = parse_issue(issue) # сохраняем данные issues.append(issue_parsed) # переход на след. страницу page += 1 # цикл с постусловием if (page >= 1 + num_issues / per_page): break # --------------------------------- ОТПРАВКА ЗАДАЧ В СВЯЗАННЫЙ ПРОЕКТ В РЕДМАЙНЕ ------------------------------- # отправляем задачи в редмайн в обратном порядке for issue in reversed(issues): if (chk_if_issues_are_linked(issue['issue_id'])): # задачи уже связаны linked_issues = Linked_Issues.objects.get_issue_by_id_gh(issue['issue_id']) log_issue_gh_already_linked(linked_issues[0], issue) link_comments_in_issue(linked_issues[0], issue) continue post_result = post_issue(linked_projects, issue) # если успешно создали новую задачу в редмайне, осуществляем привязку комментариев if (post_result['request_result'].status_code != 201): error_text = ' ERROR WHILE LINKING ISSUES: ' + str(request_result) + '\n ' + str( request_result.text) WRITE_LOG_ERR(error_text) return 0 else: link_comments_in_issue(post_result['linked_issues'], issue) log_link_issues_finish()