Raw File
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
***************************************************************************
    ctest2ci.py
    ---------------------
    Date                 : March 2017
    Copyright            : (C) 2017 by Matthias Kuhn
    Email                : matthias@opengis.ch
***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************
"""

__author__ = 'Matthias Kuhn'
__date__ = 'March 2017'
__copyright__ = '(C) 2017, Matthias Kuhn'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'

# This script parses output from ctest and injects
#
#  - Colors for failing unit tests and test cases
#  - Group control sequences to hide uninteresting output by default

import sys
import re
import subprocess
from termcolor import colored
import string

fold_stack = list()
printable = set(string.printable)


def start_fold(tag):
    sys.stdout.write('::group::{}\n'.format(tag))
    fold_stack.append(tag)


def end_fold():
    try:
        tag = fold_stack.pop()
        sys.stdout.write('::endgroup::\n')
    except IndexError:
        updated_line = colored("======================", 'magenta')
        updated_line += colored("ctest2ci error when processing the following line:", 'magenta')
        updated_line += colored("----------------------", 'magenta')
        updated_line += colored(updated_line, 'magenta')
        updated_line += colored("----------------------", 'magenta')
        updated_line += colored("Tried to end fold, but fold was never started.", 'magenta')
        updated_line += colored("======================", 'magenta')


test_count = 0


def start_test_fold():
    global test_count
    sys.stdout.write('Running tests\n')
    start_fold('test.{}'.format(test_count))
    test_count += 1


in_failing_test = False
in_failure = False

p = subprocess.Popen(sys.argv[1:], stdout=subprocess.PIPE)

for line in p.stdout:
    updated_line = line.decode('utf-8')
    # remove non printable characters https://stackoverflow.com/a/8689826/1548052
    filter(lambda x: x in printable, updated_line)
    if re.match('Run dashboard with model Experimental', updated_line):
        start_fold('build')
        updated_line = '{title}\n{line}'.format(title=colored('Running tests...', 'yellow', attrs=['bold']),
                                                line=updated_line)

    elif re.match('Test project /home/runner/QGIS/QGIS/build', updated_line):
        end_fold()  # tag=build
        start_test_fold()

    if re.search(r'\*\*\*Failed', updated_line) or re.search(r'\*\*\*Timeout', updated_line):
        end_fold()
        updated_line = colored(updated_line, 'red')
        in_failing_test = True

    if in_failing_test:
        if re.match('        Start', updated_line):
            start_test_fold()
            in_failing_test = False
        elif in_failure:
            if re.match('PASS', updated_line) or re.match('Ran', updated_line):
                in_failure = False
            else:
                updated_line = colored(updated_line, 'yellow')
        elif re.search(r'\*\*\* Segmentation fault', updated_line):
            start_fold('segfault')
            updated_line = colored(updated_line, 'magenta')
        elif re.match('  Test failed: Segmentation fault', updated_line):
            end_fold()

        else:
            if re.match(r'(FAIL|ERROR)[:\!].*', updated_line):
                updated_line = colored(updated_line, 'yellow')
                in_failure = True

    if not in_failing_test and re.search('[0-9]+% tests passed, [0-9]+ tests failed out of', updated_line):
        tests_failing = re.match(r'.* ([0-9]+) tests failed', updated_line).group(1)
        updated_line += '\n::set-output name=TESTS_FAILING::{}'.format(tests_failing)
        end_fold()

        if re.search('100% tests passed', updated_line):
            updated_line = colored(updated_line, 'green')

    if re.match('Submit files', updated_line):
        start_fold('submit')
    elif re.search('Test results submitted to', updated_line):
        cdash_url = re.match(r'.*(http.*)$', updated_line).group(1)
        updated_line += '\n::set-output name=CDASH_URL::{}'.format(cdash_url)
        end_fold()

    sys.stdout.write(updated_line)

exit(p.wait())
back to top