Skip to content

Commit cbdd3b0

Browse files
authored
feat: add support for capturing and overriding the exit code within run_node (#1990)
1 parent d800c70 commit cbdd3b0

5 files changed

Lines changed: 37 additions & 1 deletion

File tree

internal/node/launcher.sh

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ USER_NODE_OPTIONS=()
170170
ALL_ARGS=(TEMPLATED_args $NODE_REPOSITORY_ARGS "$@")
171171
STDOUT_CAPTURE=""
172172
STDERR_CAPTURE=""
173+
EXIT_CODE_CAPTURE=""
173174

174175
RUN_LINKER=true
175176
NODE_PATCHES=true
@@ -179,8 +180,12 @@ for ARG in "${ALL_ARGS[@]:-}"; do
179180
case "$ARG" in
180181
# Supply custom linker arguments for first-party dependencies
181182
--bazel_node_modules_manifest=*) MODULES_MANIFEST="${ARG#--bazel_node_modules_manifest=}" ;;
183+
# Captures stdout of the node process to the file specified
182184
--bazel_capture_stdout=*) STDOUT_CAPTURE="${ARG#--bazel_capture_stdout=}" ;;
185+
# Captures stderr of the node process to the file specified
183186
--bazel_capture_stderr=*) STDERR_CAPTURE="${ARG#--bazel_capture_stderr=}" ;;
187+
# Captures the exit code of the node process to the file specified
188+
--bazel_capture_exit_code=*) EXIT_CODE_CAPTURE="${ARG#--bazel_capture_exit_code=}" ;;
184189
# Disable the node_loader.js monkey patches for require()
185190
# Note that this means you need an explicit runfiles helper library
186191
--nobazel_patch_module_resolver) PATCH_REQUIRE=false ;;
@@ -327,6 +332,10 @@ wait "${child}"
327332
RESULT="$?"
328333
set -e
329334

335+
if [[ -n "${EXIT_CODE_CAPTURE}" ]]; then
336+
echo "${RESULT}" > "${EXIT_CODE_CAPTURE}"
337+
fi
338+
330339
if [ "${EXPECTED_EXIT_CODE}" != "0" ]; then
331340
if [ ${RESULT} != ${EXPECTED_EXIT_CODE} ]; then
332341
echo "Expected exit code to be ${EXPECTED_EXIT_CODE}, but got ${RESULT}" >&2
@@ -360,4 +369,8 @@ if [[ -n "${COVERAGE_DIR:-}" ]]; then
360369
fi
361370
fi
362371

363-
exit ${RESULT}
372+
if [[ -n "${EXIT_CODE_CAPTURE}" ]]; then
373+
exit 0
374+
else
375+
exit ${RESULT}
376+
fi

internal/node/npm_package_bin.bzl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ _ATTRS = {
1010
"args": attr.string_list(mandatory = True),
1111
"configuration_env_vars": attr.string_list(default = []),
1212
"data": attr.label_list(allow_files = True, aspects = [module_mappings_aspect, node_modules_aspect]),
13+
"exit_code_out": attr.output(),
1314
"output_dir": attr.bool(),
1415
"outs": attr.output_list(),
1516
"stderr": attr.output(),
@@ -64,6 +65,9 @@ def _impl(ctx):
6465
if ctx.outputs.stderr:
6566
tool_outputs.append(ctx.outputs.stderr)
6667

68+
if ctx.outputs.exit_code_out:
69+
tool_outputs.append(ctx.outputs.exit_code_out)
70+
6771
run_node(
6872
ctx,
6973
executable = "tool",
@@ -73,6 +77,7 @@ def _impl(ctx):
7377
configuration_env_vars = ctx.attr.configuration_env_vars,
7478
stdout = ctx.outputs.stdout,
7579
stderr = ctx.outputs.stderr,
80+
exit_code_out = ctx.outputs.exit_code_out,
7681
)
7782

7883
return [DefaultInfo(files = depset(outputs + tool_outputs))]
@@ -110,6 +115,9 @@ def npm_package_bin(tool = None, package = None, package_bin = None, data = [],
110115
subject to the same semantics as `outs`
111116
stdout: set to capture the stdout of the binary to a file, which can later be used as an input to another target
112117
subject to the same semantics as `outs`
118+
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
119+
subject to the same semantics as `outs`. Note that setting this will force the binary to exit 0.
120+
If the binary creates outputs and these are declared, they must still be created
113121
114122
args: Command-line arguments to the tool.
115123

internal/node/test/BUILD.bazel

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ generated_file_test(
260260

261261
# capture stderr to diagnostics.out, then analyze it in terser_diagnostics_stats printing some stats
262262
# stdout is captured into greeter.min.js (again, without the --output $@ flags)
263+
# the exit code is also capture to a file with exit_code_out, allowing downstream actions to read it
263264
npm_package_bin(
264265
name = "diagnostics_producing_bin",
265266
args = [
@@ -269,6 +270,7 @@ npm_package_bin(
269270
"--warn",
270271
],
271272
data = ["terser_input_with_diagnostics.js"],
273+
exit_code_out = "exit.code",
272274
package = "terser",
273275
stderr = "diagnostics.out",
274276
stdout = "greeter.min.js",
@@ -299,6 +301,12 @@ generated_file_test(
299301
generated = ":diagnostics.scrubbed.out",
300302
)
301303

304+
generated_file_test(
305+
name = "exit_code_test",
306+
src = "exit_code_test.golden",
307+
generated = ":exit.code",
308+
)
309+
302310
nodejs_binary(
303311
name = "copy_to_directory",
304312
entry_point = "copy_to_directory.js",
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0

internal/providers/node_runtime_deps_info.bzl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ def run_node(ctx, inputs, arguments, executable, **kwargs):
8787
add_arg(arguments, "--bazel_capture_stderr=%s" % stderr_file.path)
8888
outputs = outputs + [stderr_file]
8989

90+
exit_code_file = kwargs.pop("exit_code_out", None)
91+
if exit_code_file:
92+
# this will force the script to exit 0, all declared outputs must still be created
93+
add_arg(arguments, "--bazel_capture_exit_code=%s" % exit_code_file.path)
94+
outputs = outputs + [exit_code_file]
95+
9096
# By using the run_node helper, you suggest that your program
9197
# doesn't implicitly use runfiles to require() things
9298
# To access runfiles, you must use a runfiles helper in the program instead

0 commit comments

Comments
 (0)