コード例 #1
0
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')
コード例 #2
0
    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)
コード例 #3
0
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')
コード例 #4
0
    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
コード例 #5
0
ファイル: views.py プロジェクト: AlexanderND/issues_linker
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
コード例 #6
0
    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
コード例 #7
0
    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')
コード例 #8
0
    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
コード例 #9
0
    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)
コード例 #10
0
    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)
コード例 #11
0
    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)
コード例 #12
0
    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
コード例 #13
0
    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')
コード例 #14
0
    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))
コード例 #15
0
    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')
コード例 #16
0
    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))
コード例 #17
0
    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))
コード例 #18
0
    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
コード例 #19
0
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"
        )
コード例 #20
0
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)
コード例 #21
0
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)
コード例 #22
0
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)
コード例 #23
0
    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()