scripts/test-examples.py (130 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: graphql-dgs-codegen, version: ([0-9A-Z\-.]+)")
out = subprocess.check_output([gradlew, "-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 find_replace_version(content, version):
regex = re.compile(r"(<<<CODEGEN_SNAPSHOT>>>)")
return re.sub(regex, version, content)
def generate_gradle_settings(settings_template, version, settings_target):
file = open(settings_template, 'r')
file_data = file.read()
file.close()
file_data = find_replace_version(file_data, version)
file = open(settings_target, 'w')
file.write(file_data)
file.close()
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 run_example_build(settings_file, project_dir):
command = [gradlew, "-p", project_dir, "-c", settings_file, "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 | codegen= : 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}].
-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 <codegen version>
"""
projects_dir = examples_path
codegen_version = ""
keep_project_dir = False
try:
opts, args = getopt.getopt(argv, "hvkc:p:", ["codegen=", "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", "--codegen"):
codegen_version = arg
elif opt in ("-p", "--path"):
projects_dir = os.path.abspath(arg)
elif opt in ("-k"):
keep_project_dir = True
elif opt in ("-v"):
State.verbose = True
if not codegen_version:
Out.info("Codgen version not supplied, inferring...")
codegen_version = infer_version()
if codegen_version:
Out.info(f"Codegen Version resolved to {BColors.OKGREEN}{codegen_version}{BColors.ENDC}")
else:
Out.error("Unable to resolved a Codegen Version!")
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}]...")
infer_build_file(project_root)
gradle_settings_file_path = f"{project_root}/settings.gradle.kts"
generate_gradle_settings(settings_gradle_kts_template, codegen_version, gradle_settings_file_path)
run_example_build(gradle_settings_file_path, project_root)
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:])