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:])