noxfile.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. # -*- coding: utf-8 -*-
  2. '''
  3. noxfile
  4. ~~~~~~~
  5. Nox configuration script
  6. '''
  7. # Import Python libs
  8. from __future__ import absolute_import, unicode_literals, print_function
  9. import os
  10. import sys
  11. import json
  12. import pprint
  13. if __name__ == '__main__':
  14. sys.stderr.write('Do not execute this file directly. Use nox instead, it will know how to handle this file\n')
  15. sys.stderr.flush()
  16. exit(1)
  17. # Import 3rd-party libs
  18. import nox
  19. # Global Path Definitions
  20. REPO_ROOT = os.path.abspath(os.path.dirname(__file__))
  21. SITECUSTOMIZE_DIR = os.path.join(REPO_ROOT, 'tests', 'support', 'coverage')
  22. IS_WINDOWS = sys.platform.lower().startswith('win')
  23. REQUIREMENTS_OVERRIDES = {
  24. None: [
  25. 'jsonschema <= 2.6.0'
  26. ],
  27. 'ubuntu-14.04': [
  28. 'tornado < 5.0'
  29. ]
  30. }
  31. # Python versions to run against
  32. _PYTHON_VERSIONS = ('2', '2.7', '3', '3.4', '3.5', '3.6')
  33. # Nox options
  34. # Reuse existing virtualenvs
  35. nox.options.reuse_existing_virtualenvs = True
  36. # Don't fail on missing interpreters
  37. nox.options.error_on_missing_interpreters = False
  38. def _create_ci_directories():
  39. for dirname in ('logs', 'coverage', 'xml-unittests-output'):
  40. path = os.path.join(REPO_ROOT, 'artifacts', dirname)
  41. if not os.path.exists(path):
  42. os.makedirs(path)
  43. def _install_requirements(session, *extra_requirements):
  44. # Install requirements
  45. distro_requirements = None
  46. if IS_WINDOWS:
  47. _distro_requirements = os.path.join(REPO_ROOT, 'requirements', 'static', 'windows.txt')
  48. if os.path.exists(_distro_requirements):
  49. with open(_distro_requirements) as rfh:
  50. if 'ioflo' in rfh.read():
  51. # Because we still install ioflo, which requires setuptools-git, which fails with a
  52. # weird SSL certificate issue(weird because the requirements file requirements install
  53. # fine), let's previously have setuptools-git installed
  54. session.install('setuptools-git')
  55. distro_requirements = _distro_requirements
  56. else:
  57. # The distro package doesn't output anything for Windows
  58. session.install('distro')
  59. output = session.run('distro', '-j', silent=True)
  60. distro = json.loads(output.strip())
  61. session.log('Distro information:\n%s', pprint.pformat(distro))
  62. distro_keys = [
  63. '{id}'.format(**distro),
  64. '{id}-{version}'.format(**distro),
  65. '{id}-{version_parts[major]}'.format(**distro)
  66. ]
  67. for distro_key in distro_keys:
  68. _distro_requirements = os.path.join(REPO_ROOT, 'requirements', 'static', '{}.txt'.format(distro_key))
  69. if os.path.exists(_distro_requirements):
  70. distro_requirements = _distro_requirements
  71. break
  72. if distro_requirements is not None:
  73. _requirements_files = [distro_requirements]
  74. requirements_files = []
  75. else:
  76. _requirements_files = [
  77. os.path.join(REPO_ROOT, 'requirements', 'pytest.txt')
  78. ]
  79. if sys.platform.startswith('linux'):
  80. requirements_files = [
  81. os.path.join(REPO_ROOT, 'requirements', 'tests.txt')
  82. ]
  83. elif sys.platform.startswith('win'):
  84. requirements_files = [
  85. os.path.join(REPO_ROOT, 'pkg', 'windows', 'req.txt'),
  86. ]
  87. elif sys.platform.startswith('darwin'):
  88. requirements_files = [
  89. os.path.join(REPO_ROOT, 'pkg', 'osx', 'req.txt'),
  90. os.path.join(REPO_ROOT, 'pkg', 'osx', 'req_ext.txt'),
  91. ]
  92. while True:
  93. if not requirements_files:
  94. break
  95. requirements_file = requirements_files.pop(0)
  96. if requirements_file not in _requirements_files:
  97. _requirements_files.append(requirements_file)
  98. session.log('Processing {}'.format(requirements_file))
  99. with open(requirements_file) as rfh: # pylint: disable=resource-leakage
  100. for line in rfh:
  101. line = line.strip()
  102. if not line:
  103. continue
  104. if line.startswith('-r'):
  105. reqfile = os.path.join(os.path.dirname(requirements_file), line.strip().split()[-1])
  106. if reqfile in _requirements_files:
  107. continue
  108. _requirements_files.append(reqfile)
  109. continue
  110. for requirements_file in _requirements_files:
  111. session.install('-r', requirements_file)
  112. if extra_requirements:
  113. session.install(*extra_requirements)
  114. def _run_with_coverage(session, *test_cmd):
  115. session.install('coverage==4.5.3')
  116. session.run('coverage', 'erase')
  117. python_path_env_var = os.environ.get('PYTHONPATH') or None
  118. if python_path_env_var is None:
  119. python_path_env_var = SITECUSTOMIZE_DIR
  120. else:
  121. python_path_env_var = '{}:{}'.format(SITECUSTOMIZE_DIR, python_path_env_var)
  122. session.run(
  123. *test_cmd,
  124. env={
  125. 'PYTHONPATH': python_path_env_var,
  126. 'COVERAGE_PROCESS_START': os.path.join(REPO_ROOT, '.coveragerc')
  127. }
  128. )
  129. session.run('coverage', 'combine')
  130. session.run('coverage', 'xml', '-o', os.path.join(REPO_ROOT, 'artifacts', 'coverage', 'coverage.xml'))
  131. @nox.session(python=_PYTHON_VERSIONS)
  132. @nox.parametrize('coverage', [False, True])
  133. def runtests(session, coverage):
  134. # Install requirements
  135. _install_requirements(session, 'unittest-xml-reporting==2.2.1')
  136. # Create required artifacts directories
  137. _create_ci_directories()
  138. cmd_args = [
  139. '--tests-logfile={}'.format(
  140. os.path.join(REPO_ROOT, 'artifacts', 'logs', 'runtests.log')
  141. )
  142. ] + session.posargs
  143. if coverage is True:
  144. _run_with_coverage(session, 'coverage', 'run', '-m', 'tests.runtests', *cmd_args)
  145. else:
  146. session.run('python', os.path.join('tests', 'runtests.py'), *cmd_args)
  147. @nox.session(python=_PYTHON_VERSIONS)
  148. @nox.parametrize('coverage', [False, True])
  149. def pytest(session, coverage):
  150. # Install requirements
  151. _install_requirements(session)
  152. # Create required artifacts directories
  153. _create_ci_directories()
  154. cmd_args = [
  155. '--rootdir', REPO_ROOT,
  156. '--log-file={}'.format(
  157. os.path.join(REPO_ROOT, 'artifacts', 'logs', 'runtests.log')
  158. ),
  159. '--no-print-logs',
  160. '-ra',
  161. '-s'
  162. ] + session.posargs
  163. if coverage is True:
  164. _run_with_coverage(session, 'coverage', 'run', '-m', 'py.test', *cmd_args)
  165. else:
  166. session.run('py.test', *cmd_args)