scripts/test-examples.py (154 lines of code) (raw):
#!/usr/bin/env python3
#
# Copyright 2020 Netflix, Inc.
#
# 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.
#
import getopt
import os
import re
import subprocess
import shutil
import sys
import yaml
import git
from common import Out
from common import BColors
from common import State
base_path = os.path.dirname(os.path.realpath(__file__))
config_file = os.path.abspath(f"{base_path}/config.yml")
examples_path = os.path.abspath(f"{base_path}/../build/examples")
settings_gradle_kts_template = os.path.abspath(f"{base_path}/settings.gradle.kts")
gradle_wd = os.path.abspath(f"{base_path}/..")
gradlew = os.path.abspath(f"{base_path}/../gradlew")
def load_config():
with open(config_file, "r") as yml_file:
config = yaml.load(yml_file, Loader=yaml.SafeLoader)
Out.debug(f"Configuration loaded from [{config_file}]:\n{config}\n", State.verbose)
return config
def clone_repos(config, target):
if not target:
Out.error("Unable to determine the target path for the cloned repos,"
" make sure the config defines a target value.")
exit(-2)
if not os.path.exists(target):
Out.info(f"Dir [{target}] is missing, creating... ")
os.mkdir(target)
cloned_repos = []
git_uris = config["repositories"]
if not git_uris:
Out.error("The repositories to clone are missing, make sure the config file defines a repos section.")
exit(-2)
for g_uri in git_uris:
try:
cloned_repo = git.Git(target).clone(g_uri)
if cloned_repo:
cloned_repos.append(cloned_repo)
Out.info(f"Repository [{g_uri}] cloned to [{target}].")
except git.exc.GitCommandError as git_error:
Out.warn(f"Unable to clone [{g_uri}].", git_error)
def infer_version():
regex = re.compile(r"Inferred project: dgs-framework, version: ([0-9A-Z\-.]+)")
out = subprocess.check_output([gradlew, "--info", "--stacktrace", "-p", gradle_wd, "project"]).decode("utf-8")
Out.debug(f"Process output:\n{out}", State.verbose)
match = re.search(regex, out)
return match.group(1) if match else ""
def infer_build_file(project_dir):
if os.path.isfile(f"{project_dir}/build.gradle.kts"):
build_file = f"{project_dir}/build.gradle.kts"
elif os.path.isfile(f"{project_dir}/build.gradle"):
Out.error(f"We only support Gradle Kotlin (build.gradle.kts) files.")
sys.exit(2)
else:
Out.error(f"Unable to infer the build file for project [{project_dir}]~")
sys.exit(2)
return build_file
def infer_gradle_settings_file(project_dir):
if os.path.isfile(f"{project_dir}/settings.gradle.kts"):
file = f"{project_dir}/settings.gradle.kts"
elif os.path.isfile(f"{project_dir}/settings.gradle"):
file = f"{project_dir}/settings.gradle"
else:
file = ""
return file
def find_replace_version(content, version):
regex = re.compile(r"graphql-dgs-platform-dependencies:([0-9\w\-.]+)")
return re.sub(regex, f"graphql-dgs-platform-dependencies:{version}", content)
def update_build(build_file, version):
file = open(build_file, 'r')
file_data = file.read()
file.close()
file_data = find_replace_version(file_data, version)
file = open(build_file, 'w')
file.write(file_data)
file.close()
def run_example_build(project_dir, build_file="", settings_file=""):
command = [gradlew, "-p", project_dir, "-s", "-w", "--info", "--stacktrace"]
if settings_file:
command.extend(["-c", settings_file])
else:
Out.error(f"The project {project_dir} is missing a Gradle settings file!")
sys.exit(2)
command.extend(["clean", "check"])
str_cmd = " ".join(command)
try:
Out.info(f"Running {str_cmd}")
p = subprocess.check_output(command)
Out.info(p.decode("utf-8"))
except subprocess.SubprocessError as error:
Out.error(f"Unable to test {project_dir}, command '{str_cmd}' failed!", error)
sys.exit(2)
def main(argv):
script_name = os.path.basename(__file__)
help_message = f"""
{BColors.HEADER}Options{BColors.ENDC}:
-c | version= : Version we need to apply, if left empty it will calculate the version based
on Gradle's Project task.
-p | path= : Path where the examples should be found. Defaults to [{examples_path}].
-g : Clone the examples before attempting to execute them, this is done via git-clone.
The repositories are specified via the "repositories:" section in {config_file}.
-k : By default the directory defined in the path will be removed on success.
If this flag is set the directory will be kept.
-v : Verbose
{BColors.HEADER}Example{BColors.ENDC}: {script_name} -c <project version>
"""
projects_dir = examples_path
p_version = ""
git_clone_projects = False
keep_project_dir = False
try:
opts, args = getopt.getopt(argv, "hvkgc:p:", ["version=", "path="])
except getopt.GetoptError:
Out.usage(script_name, help_message)
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
Out.usage(script_name, help_message)
sys.exit()
elif opt in ("-c", "--version"):
p_version = arg
elif opt in ("-p", "--path"):
projects_dir = os.path.abspath(arg)
elif opt in "-g":
git_clone_projects = True
elif opt in "-k":
keep_project_dir = True
elif opt in "-v":
State.verbose = True
if not p_version:
Out.info("Version not supplied, inferring...")
p_version = infer_version()
if p_version:
Out.info(f"Version resolved to {BColors.OKGREEN}{p_version}{BColors.ENDC}")
else:
Out.error("Unable to resolved a version!")
exit(2)
if git_clone_projects:
Out.info(f"Cloning example repositories to {projects_dir}...")
clone_repos(load_config(), projects_dir)
if not os.path.exists(projects_dir):
Out.error(f"Can not find projects to build, the path {projects_dir} doesn't exist!")
exit(2)
projects = next(os.walk(projects_dir))[1]
if not projects:
Out.error(f"No projects available at [{projects_dir}]!")
exit(2)
for project in projects:
project_root = f"{projects_dir}/{project}"
Out.info(f"Processing project [{project_root}]...")
build_file = infer_build_file(project_root)
settings_file = infer_gradle_settings_file(project_root)
update_build(build_file, p_version)
run_example_build(project_root, build_file=build_file, settings_file=settings_file)
if not keep_project_dir:
Out.info(f"Removing {projects_dir}...")
try:
shutil.rmtree(projects_dir)
except Exception as error:
Out.error(f"Failed deleting {projects_dir}.", error)
Out.ok(f"Build successful.")
if __name__ == "__main__":
main(sys.argv[1:])