oslotest/tools/oslo_run_pre_release_tests
Hervé Beraud 2f4cb354f7 Adding pre-commit
Introduced changes:
- pre-commit config and rules
- Add pre-commit to pep8 gate, Flake8 is covered in the pre-commit hooks.
- Applying fixes for pre-commit compliance in all code.

Also commit hash will be used instead of version tags in pre-commit to
prevend arbitrary code from running in developer's machines.

pre-commit will be used to:
- trailing whitespace;
- Replaces or checks mixed line ending (mixed-line-ending);
- Forbid files which have a UTF-8 byte-order marker (check-byte-order-marker);
- Checks that non-binary executables have a proper
  shebang (check-executables-have-shebangs);
- Check for files that contain merge conflict strings (check-merge-conflict);
- Check for debugger imports and py37+ breakpoint()
  calls in python source (debug-statements);
- Attempts to load all yaml files to verify syntax (check-yaml);
- Run flake8 checks (flake8) (local)

For further details about tests please refer to:
https://github.com/pre-commit/pre-commit-hooks

Change-Id: Icd2a9bded756b2bcba1fb7da6abe48503fd9b2d6
Signed-off-by: Moisés Guimarães de Medeiros <moguimar@redhat.com>
2020-09-15 17:10:31 +02:00

211 lines
6.5 KiB
Python
Executable File

#!/usr/bin/env python
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Run unit tests for projects that use a library.
"""
import glob
import os
import subprocess
import sys
from oslo_config import cfg
from oslotest.tools import config as tconfig
from pbr import packaging
import pkg_resources
def find_all_projects(repo_root):
"""Scan the checked out repositories for all available projects."""
pattern = os.path.join(repo_root, 'openstack/*')
candidates = glob.glob(pattern)
prefix_len = len(repo_root)
return [
c[prefix_len:].lstrip('/')
for c in candidates
if os.path.isdir(c)
]
def find_consuming_projects(lib_name, repo_root, projects):
"""Filter the list of projects
Filter the list of projects to only include entries that use the library.
"""
for p in projects:
consumer = False
for base in packaging.get_requirements_files():
req_file = os.path.join(repo_root, p, base)
for req in packaging.parse_requirements([req_file]):
try:
parsed_req = pkg_resources.Requirement.parse(req)
req_name = parsed_req.project_name
except ValueError:
continue
if req_name == lib_name:
consumer = True
yield p
break
if consumer:
break
def main():
conf = tconfig.get_config_parser()
conf.register_cli_opt(
cfg.StrOpt(
'library-under-test',
short='l',
default='',
help=('the name of the library being tested; '
'defaults to current dir'),
)
)
conf.register_cli_opt(
cfg.BoolOpt(
'update',
short='u',
default=False,
help='update consumers before running tests',
)
)
conf.register_cli_opt(
cfg.BoolOpt(
'verbose',
short='v',
default=False,
help='print verbose output',
)
)
conf.register_cli_opt(
cfg.StrOpt(
'ref',
short='r',
default='HEAD',
help='the commit reference to test; defaults to HEAD',
)
)
conf.register_cli_opt(
cfg.MultiStrOpt(
'env',
short='e',
default=['py27', 'pep8'],
help=('the name of the tox environment to test; '
'defaults to py27 and pep8'),
)
)
conf.register_cli_opt(
cfg.MultiStrOpt(
'consumer',
positional=True,
default=[],
help='the name of a project to test with; may be repeated',
)
)
tconfig.parse_arguments(conf)
repo_root = os.path.expanduser(conf.repo_root)
# Figure out which library is being tested
lib_name = conf.library_under_test
if not lib_name:
if conf.verbose:
print('finding library name')
lib_name = subprocess.check_output(
['python', 'setup.py', '--name']
).strip()
lib_dir = os.getcwd()
else:
lib_dir = os.path.join(repo_root, 'openstack', lib_name)
print('testing %s in %s' % (lib_name, lib_dir))
projects = set(conf.consumer)
if not projects:
# TODO(dhellmann): Need to update this to look at gerrit, so
# we can check out the projects we want to test with.
if conf.verbose:
print('defaulting to all projects under %s/openstack' % repo_root)
projects = find_all_projects(repo_root)
# Filter out projects that do not require the library under test
before = len(projects)
projects = list(find_consuming_projects(lib_name, repo_root, projects))
after = len(projects)
if (after < before) and conf.verbose:
print('ignoring %s projects that do not use %s'
% (before - after, lib_name))
projects = list(sorted(projects))
if not projects:
print('ERROR: found no projects using %s' % lib_name)
return 1
if conf.verbose:
print('preparing to test %s projects' % after)
# Make sure the lib being tested is set to the reference intended.
if conf.ref != 'HEAD':
if conf.verbose:
print('ensuring %s is updated to %s' % (lib_name, conf.ref))
subprocess.check_call(
['git', 'checkout', conf.ref],
cwd=lib_dir,
)
git_quiet = ['-q'] if not conf.verbose else []
failures = []
for p in projects:
if conf.verbose:
print()
proj_dir = os.path.join(repo_root, p)
if conf.update:
if conf.verbose:
print('updating %s with "git pull"' % p)
subprocess.Popen(
['git', 'pull'] + git_quiet,
cwd=proj_dir,
).communicate()
p_log_name = p.split('/')[-1].replace('.', '-')
for e in conf.env:
log_name = 'cross-test-%s-%s.log' % (p_log_name, e)
with open(log_name, 'w') as log_file:
print('testing %s in %s, logging to %s' % (e, p, log_name),
end=' ')
sys.stdout.flush()
command = ['oslo_run_cross_tests', proj_dir, e]
log_file.write('running: %s\n' % ' '.join(command))
log_file.flush() # since Popen is going to use the fd directly
cmd = subprocess.Popen(
command,
cwd=lib_dir,
stdout=log_file,
stderr=log_file
)
cmd.communicate()
log_file.write('\nexit code: %s\n' % cmd.returncode)
if cmd.returncode:
print('FAIL')
failures.append((p, e, cmd.returncode))
else:
print('PASS')
if failures:
print('\nFAILED %d jobs' % len(failures))
return 1
print('\nPASSED all jobs')
return 0
if __name__ == '__main__':
sys.exit(main())