diff --git a/app/build_containers.py b/app/build_containers.py index 8f03cce..75e78f2 100644 --- a/app/build_containers.py +++ b/app/build_containers.py @@ -21,6 +21,7 @@ # TODO: display the available list of containers; allow re-build of either all or specific containers import os +import sys from decouple import config import subprocess import click @@ -45,6 +46,7 @@ def command(ctx, include, exclude): dry_run = ctx.obj.dry_run local_stack = ctx.obj.local_stack stack = ctx.obj.stack + continue_on_error = ctx.obj.continue_on_error # See: https://stackoverflow.com/questions/25389095/python-get-path-of-root-project-structure container_build_dir = Path(__file__).absolute().parent.joinpath("data", "container-build") @@ -112,8 +114,15 @@ def command(ctx, include, exclude): if verbose: print(f"Executing: {build_command}") build_result = subprocess.run(build_command, shell=True, env=container_build_env) - # TODO: check result in build_result.returncode - print(f"Result is: {build_result}") + if verbose: + print(f"Return code is: {build_result.returncode}") + if build_result.returncode != 0: + print(f"Error running build for {container}") + if not continue_on_error: + print("FATAL Error: container build failed and --continue-on-error not set, exiting") + sys.exit(1) + else: + print("****** Container Build Error, continuing because --continue-on-error is set") else: print("Skipped") diff --git a/app/build_npms.py b/app/build_npms.py index 8091a8a..4f0ea21 100644 --- a/app/build_npms.py +++ b/app/build_npms.py @@ -19,11 +19,12 @@ # CERC_REPO_BASE_DIR defaults to ~/cerc import os +import sys from decouple import config import click import importlib.resources from pathlib import Path -from python_on_whales import docker +from python_on_whales import docker, DockerException import yaml from .util import include_exclude_check @@ -40,6 +41,7 @@ def command(ctx, include, exclude): local_stack = ctx.obj.local_stack debug = ctx.obj.debug stack = ctx.obj.stack + continue_on_error = ctx.obj.continue_on_error if local_stack: dev_root_path = os.getcwd()[0:os.getcwd().rindex("stack-orchestrator")] @@ -84,18 +86,28 @@ def command(ctx, include, exclude): if verbose: print(f"Executing: {build_command}") envs = {"CERC_NPM_AUTH_TOKEN": os.environ["CERC_NPM_AUTH_TOKEN"]} | ({"CERC_SCRIPT_DEBUG": "true"} if debug else {}) - build_result = docker.run("cerc/builder-js", - remove=True, - interactive=True, - tty=True, - user=f"{os.getuid()}:{os.getgid()}", - envs=envs, - add_hosts=[("gitea.local", "host-gateway")], - volumes=[(repo_full_path, "/workspace")], - command=build_command - ) - # TODO: check result in build_result.returncode - print(f"Result is: {build_result}") + try: + docker.run("cerc/builder-js", + remove=True, + interactive=True, + tty=True, + user=f"{os.getuid()}:{os.getgid()}", + envs=envs, + add_hosts=[("gitea.local", "host-gateway")], + volumes=[(repo_full_path, "/workspace")], + command=build_command + ) + # Note that although the docs say that build_result should contain + # the command output as a string, in reality it is always the empty string. + # Since we detect errors via catching exceptions below, we can safely ignore it here. + except DockerException as e: + print(f"Error executing build for {package} in container:\n {e}") + if not continue_on_error: + print("FATAL Error: build failed and --continue-on-error not set, exiting") + sys.exit(1) + else: + print("****** Build Error, continuing because --continue-on-error is set") + else: print("Skipped") diff --git a/app/data/container-build/cerc-builder-js/build-npm-package.sh b/app/data/container-build/cerc-builder-js/build-npm-package.sh index 490389a..e0d1948 100755 --- a/app/data/container-build/cerc-builder-js/build-npm-package.sh +++ b/app/data/container-build/cerc-builder-js/build-npm-package.sh @@ -26,7 +26,7 @@ npm config set @lirewine:registry ${local_npm_registry_url} npm config set @cerc-io:registry ${local_npm_registry_url} npm config set -- ${local_npm_registry_url}:_authToken ${CERC_NPM_AUTH_TOKEN} # First check if the version of this package we're trying to build already exists in the registry -package_exists=$( yarn info --json ${package_name}@${package_publish_version} | jq -r .data.dist.tarball ) +package_exists=$( yarn info --json ${package_name}@${package_publish_version} 2>/dev/null | jq -r .data.dist.tarball ) if [[ ! -z "$package_exists" && "$package_exists" != "null" ]]; then echo "${package_publish_version} of ${package_name} already exists in the registry, skipping build" exit 0 diff --git a/cli.py b/cli.py index c0fa399..04ecd73 100644 --- a/cli.py +++ b/cli.py @@ -27,13 +27,14 @@ CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help']) # TODO: this seems kind of weird and heavy on boilerplate -- check it is # the best Python can do for us. class Options(object): - def __init__(self, stack, quiet, verbose, dry_run, local_stack, debug): + def __init__(self, stack, quiet, verbose, dry_run, local_stack, debug, continue_on_error): self.stack = stack self.quiet = quiet self.verbose = verbose self.dry_run = dry_run self.local_stack = local_stack self.debug = debug + self.continue_on_error = continue_on_error @click.group(context_settings=CONTEXT_SETTINGS) @@ -43,11 +44,12 @@ class Options(object): @click.option('--dry-run', is_flag=True, default=False) @click.option('--local-stack', is_flag=True, default=False) @click.option('--debug', is_flag=True, default=False) +@click.option('--continue-on-error', is_flag=True, default=False) # See: https://click.palletsprojects.com/en/8.1.x/complex/#building-a-git-clone @click.pass_context -def cli(ctx, stack, quiet, verbose, dry_run, local_stack, debug): +def cli(ctx, stack, quiet, verbose, dry_run, local_stack, debug, continue_on_error): """Laconic Stack Orchestrator""" - ctx.obj = Options(stack, quiet, verbose, dry_run, local_stack, debug) + ctx.obj = Options(stack, quiet, verbose, dry_run, local_stack, debug, continue_on_error) cli.add_command(setup_repositories.command, "setup-repositories")