From 3b5efc8f0f3a9f671e852433f94ae8e612508c18 Mon Sep 17 00:00:00 2001 From: David Boreham Date: Thu, 19 Jan 2023 13:00:06 -0700 Subject: [PATCH 1/5] Remove extraneous stderr output --- app/data/container-build/cerc-builder-js/build-npm-package.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 490389a3..e0d19481 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 From 68c7f91052a6b6c14eb4c7f8e8c0f7936441114d Mon Sep 17 00:00:00 2001 From: David Boreham Date: Thu, 19 Jan 2023 13:00:35 -0700 Subject: [PATCH 2/5] Catch docker run exceptions --- app/build_npms.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/app/build_npms.py b/app/build_npms.py index 8091a8a0..6801dd7d 100644 --- a/app/build_npms.py +++ b/app/build_npms.py @@ -23,7 +23,7 @@ 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 @@ -84,18 +84,21 @@ 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: + 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}") + except DockerException as e: + print(f"FATAL error executing build in container:\n {e}") else: print("Skipped") From bbbb57ec065ae50a81484614ac2800f7f41c5a40 Mon Sep 17 00:00:00 2001 From: David Boreham Date: Thu, 19 Jan 2023 13:20:53 -0700 Subject: [PATCH 3/5] Implement stop on error building containers --- app/build_containers.py | 13 +++++++++++-- cli.py | 8 +++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/app/build_containers.py b/app/build_containers.py index 8f03ccec..75e78f2d 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/cli.py b/cli.py index c0fa3990..04ecd738 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") From 6faa933d42a6f80abecee635c8497d9d3502010d Mon Sep 17 00:00:00 2001 From: David Boreham Date: Thu, 19 Jan 2023 13:30:01 -0700 Subject: [PATCH 4/5] Remove result code check --- app/build_npms.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/app/build_npms.py b/app/build_npms.py index 6801dd7d..526f78f1 100644 --- a/app/build_npms.py +++ b/app/build_npms.py @@ -85,18 +85,19 @@ def command(ctx, include, exclude): print(f"Executing: {build_command}") envs = {"CERC_NPM_AUTH_TOKEN": os.environ["CERC_NPM_AUTH_TOKEN"]} | ({"CERC_SCRIPT_DEBUG": "true"} if debug else {}) try: - 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}") + 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"FATAL error executing build in container:\n {e}") else: From 34aa613d04574284383885586f6d72e068603d19 Mon Sep 17 00:00:00 2001 From: David Boreham Date: Thu, 19 Jan 2023 13:38:04 -0700 Subject: [PATCH 5/5] Implement continue on error for npm builds --- app/build_npms.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/build_npms.py b/app/build_npms.py index 526f78f1..4f0ea219 100644 --- a/app/build_npms.py +++ b/app/build_npms.py @@ -19,6 +19,7 @@ # CERC_REPO_BASE_DIR defaults to ~/cerc import os +import sys from decouple import config import click import importlib.resources @@ -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")] @@ -99,7 +101,13 @@ def command(ctx, include, exclude): # 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"FATAL error executing build in container:\n {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")