Skip to content

Commit

Permalink
Add diff_test_failure_message attribute to write_source_file*
Browse files Browse the repository at this point in the history
This makes it so that developers can add a custom error message to the
diff test failure messages when using `write_source_file` and
`write_source_files`.
  • Loading branch information
jameskuszmaul-brt committed Jan 24, 2025
1 parent b2d88f0 commit 524db9b
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 14 deletions.
27 changes: 25 additions & 2 deletions docs/write_source_files.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

62 changes: 50 additions & 12 deletions lib/private/write_source_file.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ def write_source_file(
additional_update_targets = [],
suggested_update_target = None,
diff_test = True,
diff_test_failure_message = "{{DEFAULT_MESSAGE}}",
file_missing_failure_message = "{{DEFAULT_MESSAGE}}",
check_that_out_file_exists = True,
**kwargs):
"""Write a file or directory to the source tree.
Expand Down Expand Up @@ -48,6 +50,22 @@ def write_source_file(
diff_test: Test that the source tree file or directory exist and is up to date.
diff_test_failure_message: Text to print when the diff test fails, with templating options for
relevant targets.
Substitutions are performed on the failure message, with the following substitutions being available:
`{{DEFAULT_MESSAGE}}`: Prints the default error message, listing the target(s) that
may be run to update the file(s).
`{{TARGET}}`: The target to update the individual file that does not match in the
diff test.
`{{SUGGESTED_UPDATE_TARGET}}`: The suggested_update_target if specified.
file_missing_failure_message: Text to print when the output file is missing. Subject to the same
substitutions as diff_test_failure_message.
check_that_out_file_exists: Test that the output file exists and print a helpful error message if it doesn't.
If `True`, the output file or directory must be in the same containing Bazel package as the target since the underlying mechanism
Expand Down Expand Up @@ -92,27 +110,32 @@ def write_source_file(
out_file_missing = check_that_out_file_exists and _is_file_missing(out_file)
test_target_name = "%s_test" % name

update_target_string = "//%s:%s" % (native.package_name(), name)
suggested_update_target_string = str(utils.to_label(suggested_update_target)) if suggested_update_target else None

if out_file_missing:
if suggested_update_target == None:
message = """
default_message = """
%s does not exist. To create & update this file, run:
bazel run //%s:%s
bazel run %s
""" % (out_file, native.package_name(), name)
""" % (out_file, update_target_string)
else:
message = """
default_message = """
%s does not exist. To create & update this and other generated files, run:
bazel run %s
To create an update *only* this file, run:
bazel run //%s:%s
bazel run %s
""" % (out_file, suggested_update_target_string, update_target_string)

""" % (out_file, utils.to_label(suggested_update_target), native.package_name(), name)
message = _do_diff_test_message_replacements(file_missing_failure_message, default_message, update_target_string, suggested_update_target_string)

# Stamp out a test that fails with a helpful message when the source file doesn't exist.
# Note that we cannot simply call fail() here since it will fail during the analysis
Expand All @@ -126,25 +149,27 @@ To create an update *only* this file, run:
)
else:
if suggested_update_target == None:
message = """
default_message = """
%s is out of date. To update this file, run:
bazel run //%s:%s
bazel run %s
""" % (out_file, native.package_name(), name)
""" % (out_file, update_target_string)
else:
message = """
default_message = """
%s is out of date. To update this and other generated files, run:
bazel run %s
To update *only* this file, run:
bazel run //%s:%s
bazel run %s
""" % (out_file, suggested_update_target_string, update_target_string)

""" % (out_file, utils.to_label(suggested_update_target), native.package_name(), name)
message = _do_diff_test_message_replacements(diff_test_failure_message, default_message, update_target_string, suggested_update_target_string)

# Stamp out a diff test the check that the source file is up to date
_diff_test(
Expand Down Expand Up @@ -394,3 +419,16 @@ def _is_file_missing(label):
subpackage_glob = native.subpackages(include = [file_rel], allow_empty = True)

return len(file_glob) == 0 and len(subpackage_glob) == 0

def _do_diff_test_message_replacements(message, default_message, target, suggested_update_target):
"""Constructs the diff test failures message from the provided template.
Replaces the {{DEFAULT_MESSAGE}}, {{TARGET}}, and {{SUGGESTED_UPDATE_TARGET}} strings in
message with the corresponding arguments.
Args:
message: The user-provided message to do template replacement on.
default_message: The message to fill in for the {{DEFAULT_MESSAGE}} parameter.
target: The string to fill in for the {{TARGET}} parameter.
suggested_update_target: The string to fill in for the {{SUGGESTED_UPDATE_TARGET}} parameter."""
return message.replace("{{DEFAULT_MESSAGE}}", default_message).replace("{{TARGET}}", target).replace("{{SUGGESTED_UPDATE_TARGET}}", suggested_update_target if suggested_update_target else "")
3 changes: 3 additions & 0 deletions lib/tests/write_source_files/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ write_source_file_test(

write_source_file(
name = "e_dir_test",
diff_test_failure_message = "\nSample failure message for {{TARGET}}. Default message:\n{{DEFAULT_MESSAGE}}",
file_missing_failure_message = "\nSample failure message for a missing {{TARGET}}. Default message:\n{{DEFAULT_MESSAGE}}",
in_file = ":e_dir-desired",
out_file = "e_dir",
)
Expand Down Expand Up @@ -161,6 +163,7 @@ write_source_files(
additional_update_targets = [
"//lib/tests/write_source_files/subdir:macro_smoke_test",
],
diff_test_failure_message = "\nSample failure message for {{TARGET}} of {{SUGGESTED_UPDATE_TARGET}}. Default message:\n{{DEFAULT_MESSAGE}}",
files = {
"a2.js": ":a-desired",
"b2.js": ":b-desired",
Expand Down
38 changes: 38 additions & 0 deletions lib/write_source_files.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,23 @@ To update *only* this file, run:
bazel run //a/b/c:write_foo
```
You can also add a more customized error message using the `diff_test_failure_message` argument:
```starlark
write_source_file(
name = "write_foo",
out_file = "foo.json",
in_file = ":generated-foo",
diff_test_failure_message = "Failed to build Foo; please run {{TARGET}} to update."
)
```
A test failure from `foo.json` being out of date will then yield:
```
Failed to build Foo; please run //a/b/c:write_foo to update.
```
If you have many `write_source_files` targets that you want to update as a group, we recommend wrapping
`write_source_files` in a macro that defaults `suggested_update_target` to the umbrella update target.
Expand All @@ -96,6 +113,8 @@ def write_source_files(
additional_update_targets = [],
suggested_update_target = None,
diff_test = True,
diff_test_failure_message = "{{DEFAULT_MESSAGE}}",
file_missing_failure_message = "{{DEFAULT_MESSAGE}}",
check_that_out_file_exists = True,
**kwargs):
"""Write one or more files and/or directories to the source tree.
Expand Down Expand Up @@ -125,6 +144,23 @@ def write_source_files(
diff_test: Test that the source tree files and/or directories exist and are up to date.
diff_test_failure_message: Text to print when the diff test fails, with templating options for
relevant targets.
Substitutions are performed on the failure message, with the following substitutions being available:
`{{DEFAULT_MESSAGE}}`: Prints the default error message, listing the target(s) that
may be run to update the file(s).
`{{TARGET}}`: The target to update the individual file that does not match in the
diff test.
`{{SUGGESTED_UPDATE_TARGET}}`: The suggested_update_target if specified, or the
target which will update all of the files which do not match.
file_missing_failure_message: Text to print when the output file is missing. Subject to the same
substitutions as diff_test_failure_message.
check_that_out_file_exists: Test that each output file exists and print a helpful error message if it doesn't.
If `True`, destination files and directories must be in the same containing Bazel package as the target since the underlying
Expand Down Expand Up @@ -157,6 +193,8 @@ def write_source_files(
additional_update_targets = additional_update_targets if single_update_target else [],
suggested_update_target = this_suggested_update_target,
diff_test = diff_test,
diff_test_failure_message = diff_test_failure_message,
file_missing_failure_message = file_missing_failure_message,
check_that_out_file_exists = check_that_out_file_exists,
**kwargs
)
Expand Down

0 comments on commit 524db9b

Please sign in to comment.