travis.py (100 lines of code) (raw):

import subprocess import os import shlex import json import glob import sys import re import shutil from google.oauth2 import service_account from google.cloud import storage class Fold: def __init__(self, name, description=None): self.fold_name = name self.description = description or name def __enter__(self): print('travis_fold:start:%s\033[33;1m%s\033[0m' % (self.fold_name, self.description), flush=True) def __exit__(self, exc_type, exc_value, traceback): print('\ntravis_fold:end:%s\r' % self.fold_name, end='', flush=True) def call(cmd): print(' '.join(shlex.quote(p) for p in cmd), flush=True) subprocess.check_call(cmd) def get_bucket(): credentials_info = json.loads(os.environ['GOOGLE_APPLICATION_CREDENTIALS_DATA']) credentials = service_account.Credentials.from_service_account_info(credentials_info) client = storage.Client(credentials=credentials, project=credentials_info['project_id']) return client.get_bucket('gym-retro') def upload_to_gcs(patterns, dest): bucket = get_bucket() for pattern in patterns: print('uploading %s to %s' % (pattern, dest), flush=True) for filepath in glob.glob(pattern): blob_name = '%s/%s' % (dest, os.path.basename(filepath)) blob = bucket.blob(blob_name) blob.upload_from_filename(filename=filepath) blob.make_public() print('uploaded ', blob.public_url.replace('%2F', '/')) # public_url escapes slashes but that breaks pip install def test(): import pytest import retro.testing as testdata args = [] if os.environ['TRAVIS_BRANCH'] != 'master' or os.environ['TRAVIS_PULL_REQUEST'] != 'false': check = testdata.branch_new('origin/master') if check: args.extend(['-k', ' or '.join(check)]) pytest.main(args) return not testdata.errors def main(): os_name = os.environ['TRAVIS_OS_NAME'] cross = os.environ.get('CROSS') bdist_options = [] with Fold('script.build', 'Building'): if os_name == 'osx': cmake_options = ['-DCMAKE_PREFIX_PATH=/usr/local/opt/qt', '-DBUILD_UI=ON'] elif os_name == 'linux': include_suffix = "m" if float(os.environ['PYVER']) < 3.8 else "" cmake_options = ['-DBUILD_MANYLINUX=ON', '-DPYTHON_INCLUDE_DIR=%s/include/python%s%s' % (sys.base_prefix, os.environ['PYVER'], include_suffix)] if cross in ('win32', 'win64'): cmake_options = ['-DCMAKE_TOOLCHAIN_FILE=docker/cmake/%s.cmake' % cross, '-DBUILD_UI=ON'] if cross == 'win32': bdist_options = ['--plat-name', 'win32'] if cross == 'win64': bdist_options = ['--plat-name', 'win_amd64'] else: raise Exception('unrecognized os name') call(['cmake', '.', '-DBUILD_TESTS=ON'] + cmake_options) call(['python', 'setup.py', '-q', 'build_ext', '-i', '-j3']) if cross not in ('win64', 'win32'): call(['pip', 'install', '-e', '.']) call(['make', '-j3']) if os.environ['TRAVIS_PULL_REQUEST'] == 'false': with Fold('script.package', 'Packaging binaries'): call(['python', 'setup.py', '-q', 'bdist_wheel'] + bdist_options) if os.environ['TRAVIS_BRANCH'] == 'master': upload_dir = 'builds' else: upload_dir = 'builds/%s' % os.environ['TRAVIS_BRANCH'] if os_name == 'osx' or cross in ('win32', 'win64'): # package the UI for uploading call(['cpack']) # assuming this is running on the latest commit, rename # the UI so that we can easily link to the latest version for filepath in glob.glob('Gym Retro-*.*'): basename = os.path.basename(filepath) m = re.match(r'Gym Retro-.*-([^-]+)', basename) new_basename = 'Gym Retro-latest-' + m.group(1) new_filepath = os.path.join(os.path.dirname(filepath), new_basename) shutil.copy(filepath, new_filepath) upload_to_gcs(['Gym Retro-*.*'], upload_dir) elif not cross and os_name == 'linux': call(['auditwheel', 'repair', '-w', 'dist'] + glob.glob('dist/*.whl')) upload_to_gcs(['dist/*.whl'], upload_dir) if cross not in ('win64', 'win32'): with Fold('script.test', 'Running tests'): call(['ctest', '--verbose', '-E', '\.test']) # Exclude libzip tests if os_name == 'linux' and not cross: try: passed = test() assert passed except ImportError: pass if __name__ == '__main__': main()