From cbdd3b08e464d2df2f04c13005b0467ef55b29a1 Mon Sep 17 00:00:00 2001 From: Matt Mackay Date: Mon, 6 Jul 2020 11:40:48 -0400 Subject: [PATCH] feat: add support for capturing and overriding the exit code within run_node (#1990) --- internal/node/launcher.sh | 15 ++++++++++++++- internal/node/npm_package_bin.bzl | 8 ++++++++ internal/node/test/BUILD.bazel | 8 ++++++++ internal/node/test/exit_code_test.golden | 1 + internal/providers/node_runtime_deps_info.bzl | 6 ++++++ 5 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 internal/node/test/exit_code_test.golden diff --git a/internal/node/launcher.sh b/internal/node/launcher.sh index 9654fb80d1..f9c6c5814a 100644 --- a/internal/node/launcher.sh +++ b/internal/node/launcher.sh @@ -170,6 +170,7 @@ USER_NODE_OPTIONS=() ALL_ARGS=(TEMPLATED_args $NODE_REPOSITORY_ARGS "$@") STDOUT_CAPTURE="" STDERR_CAPTURE="" +EXIT_CODE_CAPTURE="" RUN_LINKER=true NODE_PATCHES=true @@ -179,8 +180,12 @@ for ARG in "${ALL_ARGS[@]:-}"; do case "$ARG" in # Supply custom linker arguments for first-party dependencies --bazel_node_modules_manifest=*) MODULES_MANIFEST="${ARG#--bazel_node_modules_manifest=}" ;; + # Captures stdout of the node process to the file specified --bazel_capture_stdout=*) STDOUT_CAPTURE="${ARG#--bazel_capture_stdout=}" ;; + # Captures stderr of the node process to the file specified --bazel_capture_stderr=*) STDERR_CAPTURE="${ARG#--bazel_capture_stderr=}" ;; + # Captures the exit code of the node process to the file specified + --bazel_capture_exit_code=*) EXIT_CODE_CAPTURE="${ARG#--bazel_capture_exit_code=}" ;; # Disable the node_loader.js monkey patches for require() # Note that this means you need an explicit runfiles helper library --nobazel_patch_module_resolver) PATCH_REQUIRE=false ;; @@ -327,6 +332,10 @@ wait "${child}" RESULT="$?" set -e +if [[ -n "${EXIT_CODE_CAPTURE}" ]]; then + echo "${RESULT}" > "${EXIT_CODE_CAPTURE}" +fi + if [ "${EXPECTED_EXIT_CODE}" != "0" ]; then if [ ${RESULT} != ${EXPECTED_EXIT_CODE} ]; then echo "Expected exit code to be ${EXPECTED_EXIT_CODE}, but got ${RESULT}" >&2 @@ -360,4 +369,8 @@ if [[ -n "${COVERAGE_DIR:-}" ]]; then fi fi -exit ${RESULT} +if [[ -n "${EXIT_CODE_CAPTURE}" ]]; then + exit 0 +else + exit ${RESULT} +fi diff --git a/internal/node/npm_package_bin.bzl b/internal/node/npm_package_bin.bzl index f7d6efccf7..961ec7559d 100644 --- a/internal/node/npm_package_bin.bzl +++ b/internal/node/npm_package_bin.bzl @@ -10,6 +10,7 @@ _ATTRS = { "args": attr.string_list(mandatory = True), "configuration_env_vars": attr.string_list(default = []), "data": attr.label_list(allow_files = True, aspects = [module_mappings_aspect, node_modules_aspect]), + "exit_code_out": attr.output(), "output_dir": attr.bool(), "outs": attr.output_list(), "stderr": attr.output(), @@ -64,6 +65,9 @@ def _impl(ctx): if ctx.outputs.stderr: tool_outputs.append(ctx.outputs.stderr) + if ctx.outputs.exit_code_out: + tool_outputs.append(ctx.outputs.exit_code_out) + run_node( ctx, executable = "tool", @@ -73,6 +77,7 @@ def _impl(ctx): configuration_env_vars = ctx.attr.configuration_env_vars, stdout = ctx.outputs.stdout, stderr = ctx.outputs.stderr, + exit_code_out = ctx.outputs.exit_code_out, ) return [DefaultInfo(files = depset(outputs + tool_outputs))] @@ -110,6 +115,9 @@ def npm_package_bin(tool = None, package = None, package_bin = None, data = [], subject to the same semantics as `outs` stdout: set to capture the stdout of the binary to a file, which can later be used as an input to another target subject to the same semantics as `outs` + exit_code_out: set to capture the exit code of the binary to a file, which can later be used as an input to another target + subject to the same semantics as `outs`. Note that setting this will force the binary to exit 0. + If the binary creates outputs and these are declared, they must still be created args: Command-line arguments to the tool. diff --git a/internal/node/test/BUILD.bazel b/internal/node/test/BUILD.bazel index 414e2e31ad..e23d3d5fc0 100644 --- a/internal/node/test/BUILD.bazel +++ b/internal/node/test/BUILD.bazel @@ -260,6 +260,7 @@ generated_file_test( # capture stderr to diagnostics.out, then analyze it in terser_diagnostics_stats printing some stats # stdout is captured into greeter.min.js (again, without the --output $@ flags) +# the exit code is also capture to a file with exit_code_out, allowing downstream actions to read it npm_package_bin( name = "diagnostics_producing_bin", args = [ @@ -269,6 +270,7 @@ npm_package_bin( "--warn", ], data = ["terser_input_with_diagnostics.js"], + exit_code_out = "exit.code", package = "terser", stderr = "diagnostics.out", stdout = "greeter.min.js", @@ -299,6 +301,12 @@ generated_file_test( generated = ":diagnostics.scrubbed.out", ) +generated_file_test( + name = "exit_code_test", + src = "exit_code_test.golden", + generated = ":exit.code", +) + nodejs_binary( name = "copy_to_directory", entry_point = "copy_to_directory.js", diff --git a/internal/node/test/exit_code_test.golden b/internal/node/test/exit_code_test.golden new file mode 100644 index 0000000000..573541ac97 --- /dev/null +++ b/internal/node/test/exit_code_test.golden @@ -0,0 +1 @@ +0 diff --git a/internal/providers/node_runtime_deps_info.bzl b/internal/providers/node_runtime_deps_info.bzl index e4bb2be8a1..6a7920ae3f 100644 --- a/internal/providers/node_runtime_deps_info.bzl +++ b/internal/providers/node_runtime_deps_info.bzl @@ -87,6 +87,12 @@ def run_node(ctx, inputs, arguments, executable, **kwargs): add_arg(arguments, "--bazel_capture_stderr=%s" % stderr_file.path) outputs = outputs + [stderr_file] + exit_code_file = kwargs.pop("exit_code_out", None) + if exit_code_file: + # this will force the script to exit 0, all declared outputs must still be created + add_arg(arguments, "--bazel_capture_exit_code=%s" % exit_code_file.path) + outputs = outputs + [exit_code_file] + # By using the run_node helper, you suggest that your program # doesn't implicitly use runfiles to require() things # To access runfiles, you must use a runfiles helper in the program instead