Created
December 21, 2025 16:09
-
-
Save alexeagle/44fd5444b43707766f59a3be2422dc63 to your computer and use it in GitHub Desktop.
Wrap 'bazel build' to run linting aspects, without using Aspect CLI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # | |
| # Shows an end-to-end workflow for linting without failing the build. | |
| # This is meant to mimic the behavior of the `aspect lint` command that you'd have | |
| # by using the Aspect CLI [lint task](https://github.com/aspect-build/rules_lint/blob/main/lint/lint.axl). | |
| # | |
| # To make the build fail when a linter warning is present, run with `--fail-on-violation`. | |
| # To auto-fix violations, run with `--fix` (or `--fix --dry-run` to just print the patches) | |
| set -o errexit -o pipefail -o nounset | |
| if [ "$#" -eq 0 ]; then | |
| echo "usage: lint.sh [target pattern...]" | |
| exit 1 | |
| fi | |
| fix="" | |
| buildevents=$(mktemp) | |
| filter='.namedSetOfFiles | values | .files[] | select(.name | endswith($ext)) | ((.pathPrefix | join("/")) + "/" + .name)' | |
| # FIXME: Register your linters here | |
| args=( | |
| "--aspects=//tools/lint:linters.bzl%eslint" | |
| "--aspects=//tools/lint:linters.bzl%keep-sorted" | |
| # ... more linters | |
| ) | |
| # NB: perhaps --remote_download_toplevel is needed as well with remote execution? | |
| args+=( | |
| "--build_event_json_file=$buildevents" | |
| # Required for the buf allow_comment_ignores option to work properly | |
| # See https://github.com/bufbuild/rules_buf/issues/64#issuecomment-2125324929 | |
| "--experimental_proto_descriptor_sets_include_source_info" | |
| "--remote_download_regex='.*AspectRulesLint.*'" | |
| ) | |
| # This is a rudimentary flag parser. | |
| if [ $1 == "--fail-on-violation" ]; then | |
| args+=( | |
| "--@aspect_rules_lint//lint:fail_on_violation" | |
| "--keep_going" | |
| ) | |
| shift | |
| else | |
| args+=( | |
| # Allow lints of code that fails some validation action | |
| # See https://github.com/aspect-build/rules_ts/pull/574#issuecomment-2073632879 | |
| "--norun_validations" | |
| # Without validation actions, the linters won't run unless we request their output | |
| "--output_groups=rules_lint_human" | |
| ) | |
| fi | |
| # Allow a `--fix` option on the command-line. | |
| # This happens to make output of the linter such as ruff's | |
| # [*] 1 fixable with the `--fix` option. | |
| # so that the naive thing of pasting that flag to lint.sh will do what the user expects. | |
| if [ $1 == "--fix" ]; then | |
| fix="patch" | |
| args+=( | |
| "--@aspect_rules_lint//lint:fix" | |
| # Trigger the fixer actions to run by requesting the patch outputs | |
| "--output_groups=rules_lint_patch" | |
| ) | |
| shift | |
| fi | |
| # NB: the --dry-run flag must immediately follow the --fix flag | |
| if [ $1 == "--dry-run" ]; then | |
| fix="print" | |
| shift | |
| fi | |
| # Run linters | |
| bazel build ${args[@]} $@ | |
| # TODO: Maybe this could be hermetic with bazel run @bazel_lib//tools:jq or sth | |
| # jq on windows outputs CRLF which breaks this script. https://github.com/jqlang/jq/issues/92 | |
| valid_reports=$(jq --arg ext .out --raw-output "$filter" "$buildevents" | tr -d '\r') | |
| # Show the results. | |
| while IFS= read -r report; do | |
| # Exclude coverage reports, and check if the output is empty. | |
| if [[ "$report" == *coverage.dat ]] || [[ ! -s "$report" ]]; then | |
| # Report is empty. No linting errors. | |
| continue | |
| fi | |
| echo "From ${report}:" | |
| cat "${report}" | |
| echo | |
| done <<<"$valid_reports" | |
| if [ -n "$fix" ]; then | |
| valid_patches=$(jq --arg ext .patch --raw-output "$filter" "$buildevents" | tr -d '\r') | |
| while IFS= read -r patch; do | |
| # Exclude coverage, and check if the patch is empty. | |
| if [[ "$patch" == *coverage.dat ]] || [[ ! -s "$patch" ]]; then | |
| # Patch is empty. No linting errors. | |
| continue | |
| fi | |
| case "$fix" in | |
| "print") | |
| echo "From ${patch}:" | |
| cat "${patch}" | |
| echo | |
| ;; | |
| "patch") | |
| patch -p1 <${patch} | |
| ;; | |
| *) | |
| echo >2 "ERROR: unknown fix type $fix" | |
| exit 1 | |
| ;; | |
| esac | |
| done <<<"$valid_patches" | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment