File: ci.py

package info (click to toggle)
ttkthemes 3.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, sid
  • size: 12,620 kB
  • sloc: tcl: 6,130; python: 804; makefile: 18
file content (141 lines) | stat: -rw-r--r-- 4,217 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
"""
Author: RedFantom
License: GNU GPLv3
Copyright (c) 2017-2018 RedFantom
"""
import os
from shutil import rmtree
import sys

DEPENDENCIES = ["pillow"]
REQUIREMENTS = ["codecov", "coverage", "nose", "setuptools", "pip", "wheel", "semantic_version"]
PACKAGES = "python-tk python3-tk libtk-img"

SDIST = os.environ.get("SDIST", "false") == "true"

TO_DELETE = ["ttkthemes"]


class Version(object):
    """
    Parses a semantic version string.
    """
    def __init__(self, string):
        """
        :param string: semantic version string (major.minor.patch)
        """
        elements = tuple(map(int, string.split(".")))
        if len(elements) == 3:
            self.major, self.minor, self.patch = elements
        else:
            (self.major, self.minor), self.patch = elements, 0
        self.version = (self.major, self.minor, self.patch)

    def __ge__(self, other):
        return all(elem1 >= elem2 for elem1, elem2 in zip(self.version, other.version))


def run_command(command):
    """
    :param command: command to run on os.system
    :return: exit code
    """
    print("Running system command: ", command)
    return_info = os.system(command)
    if sys.platform == "win32":
        return return_info
    else:
        return os.WEXITSTATUS(return_info)


def check_wheel_existence():
    """Return True if a wheel is built"""
    return len([file for file in os.listdir("dist") if file.endswith((".whl", ".tar.gz"))]) != 0


def build_and_install_wheel(python):
    """Build a binary distribution wheel and install it"""
    dist_type = "bdist_wheel" if not SDIST else "sdist"
    return_code = run_command("{} setup.py {}".format(python, dist_type))
    if return_code != 0:
        print("Building and installing wheel failed.")
        exit(return_code)
    # Check if an artifact exists
    assert check_wheel_existence()
    print("Wheel file exists.")
    # Install the wheel file
    wheel = [file for file in os.listdir("dist") if file.endswith((".whl", ".tar.gz"))][0]
    wheel = os.path.join("dist", wheel)
    print("Wheel file:", wheel)
    return_code = run_command("{} -m pip install --ignore-installed {}".format(python, wheel))
    if return_code != 0:
        print("Installation of wheel failed.")
        exit(return_code)
    print("Wheel file installed.")


def ci(python="python", codecov="codecov", coverage_file="coverage.xml", wheel=True):
    """
    Run the most common CI tasks
    """

    # Import pip
    from pip import __version__ as pip_version
    if Version(pip_version) >= Version("10.0.0"):
        import pip._internal as pip
    else:
        import pip

    # Install requirements with pip
    pip.main(["install"] + DEPENDENCIES + REQUIREMENTS + ["-U"])
    # Build the installation wheel
    if wheel is True:
        build_and_install_wheel(python)
        # Remove all non-essential files
        for to_delete in TO_DELETE:
            rmtree(to_delete)
    # Run the tests on the installed ttkthemes
    return_code = run_command("{} -m nose --with-coverage --cover-xml --cover-package=ttkthemes".format(python))
    if return_code != 0:
        print("Tests failed.")
        exit(return_code)
    print("Tests successful.")
    # Run codecov
    return_code = run_command("{} -f {}".format(codecov, coverage_file))
    if return_code != 0:
        print("Codecov failed.")
        exit(return_code)
    # Successfully finished CI
    exit(0)


def ci_windows():
    """
    Run CI tasks on AppVeyor. CI on AppVeyor is relatively easy, so
    just the general ci() is used.
    """
    ci(
        python="%PYTHON%\\python.exe",
        codecov="%PYTHON%\\Scripts\\codecov.exe",
        coverage_file="C:\\projects\\ttk-themes\\coverage.xml",
        wheel=False
    )


def ci_linux():
    """
    Setup Travis-CI linux for installation and testing
    """
    run_command("sudo apt-get install {}".format(PACKAGES))
    ci()


# Run CI tasks on AppVeyor and Travis-CI (macOS and Linux)
if __name__ == '__main__':
    if sys.platform == "win32":
        ci_windows()
    elif "linux" in sys.platform:   # linux2 on Python 2, linux on Python 3
        ci_linux()
    else:
        raise RuntimeError("Invalid platform: ", sys.platform)