diff --git a/README.md b/README.md index f39d69d0..23690b15 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ This leads to some minor differences in how they are used in rules_lint. | CSS/HTML | [Prettier] | | | JSON | [Prettier] | | | Markdown | [Prettier] | | -| Bash | [prettier-plugin-sh] | [shellcheck] | +| Bash | [shfmt] | [shellcheck] | | SQL | [prettier-plugin-sql] | | | Starlark (Bazel) | [Buildifier] | | | Swift | [SwiftFormat] (1) | | @@ -72,13 +72,13 @@ This leads to some minor differences in how they are used in rules_lint. [buf]: https://docs.buf.build/format/usage [ktfmt]: https://github.com/facebook/ktfmt [buildifier]: https://github.com/keith/buildifier-prebuilt -[prettier-plugin-sh]: https://github.com/un-ts/prettier [prettier-plugin-sql]: https://github.com/un-ts/prettier [gofmt]: https://pkg.go.dev/cmd/gofmt [jsonnetfmt]: https://github.com/google/go-jsonnet [scalafmt]: https://scalameta.org/scalafmt [ruff]: https://docs.astral.sh/ruff/ [shellcheck]: https://www.shellcheck.net/ +[shfmt]: https://github.com/mvdan/sh 1. Non-hermetic: requires that a swift toolchain is installed on the machine. See https://github.com/bazelbuild/rules_swift#1-install-swift diff --git a/docs/format.md b/docs/format.md index 4628572a..0d39af07 100644 --- a/docs/format.md +++ b/docs/format.md @@ -37,7 +37,7 @@ multi_formatter_binary( ## multi_formatter_binary
-multi_formatter_binary(name, go, java, javascript, jsonnet, kotlin, python, starlark, swift, +multi_formatter_binary(name, go, java, javascript, jsonnet, kotlin, python, sh, starlark, swift, terraform)@@ -55,6 +55,7 @@ Produces an executable that aggregates the supplied formatter binaries | jsonnet | a binary target that runs jsonnetfmt | Label | optional |
None
|
| kotlin | a binary target that runs ktfmt | Label | optional | None
|
| python | a binary target that runs ruff | Label | optional | None
|
+| sh | a binary target that runs shfmt | Label | optional | None
|
| starlark | a binary target that runs buildifier | Label | optional | None
|
| swift | a binary target that runs swiftformat | Label | optional | None
|
| terraform | a binary target that runs terraform | Label | optional | None
|
diff --git a/example/MODULE.bazel b/example/MODULE.bazel
index 92bf9bf4..845c6757 100644
--- a/example/MODULE.bazel
+++ b/example/MODULE.bazel
@@ -28,7 +28,6 @@ npm.npm_translate_lock(
pnpm_lock = "//:pnpm-lock.yaml",
public_hoist_packages = {
"@typescript-eslint/eslint-plugin": [""],
- "prettier-plugin-sh": [""],
"prettier-plugin-sql": [""],
},
)
diff --git a/example/WORKSPACE.bazel b/example/WORKSPACE.bazel
index 74770262..374ee05e 100644
--- a/example/WORKSPACE.bazel
+++ b/example/WORKSPACE.bazel
@@ -151,6 +151,7 @@ load(
"fetch_jsonnet",
"fetch_ktfmt",
"fetch_pmd",
+ "fetch_shfmt",
"fetch_swiftformat",
"fetch_terraform",
)
@@ -165,6 +166,8 @@ fetch_java_format()
fetch_ktfmt()
+fetch_shfmt()
+
fetch_swiftformat()
load("@aspect_rules_lint//lint:ruff.bzl", "fetch_ruff")
diff --git a/example/WORKSPACE.bzlmod b/example/WORKSPACE.bzlmod
index 9a172123..6f846fbb 100644
--- a/example/WORKSPACE.bzlmod
+++ b/example/WORKSPACE.bzlmod
@@ -9,6 +9,7 @@ load(
"fetch_jsonnet",
"fetch_ktfmt",
"fetch_pmd",
+ "fetch_shfmt",
"fetch_swiftformat",
"fetch_terraform",
)
@@ -24,6 +25,8 @@ fetch_java_format()
fetch_ktfmt()
+fetch_shfmt()
+
fetch_swiftformat()
fetch_ruff()
diff --git a/example/lint.sh b/example/lint.sh
index 700b502f..6eab05f0 100755
--- a/example/lint.sh
+++ b/example/lint.sh
@@ -8,8 +8,8 @@
set -o errexit -o pipefail -o nounset
if [ "$#" -eq 0 ]; then
- echo "usage: lint.sh [target pattern...]"
- exit 1
+ echo "usage: lint.sh [target pattern...]"
+ exit 1
fi
# Produce report files
@@ -17,12 +17,11 @@ fi
# TODO: put back ruff after the output paths don't collide
bazel build --aspects //tools:lint.bzl%eslint,//tools:lint.bzl%buf,//tools:lint.bzl%flake8,//tools:lint.bzl%pmd,//tools:lint.bzl%shellcheck --output_groups=rules_lint_report $@
-
# Show the results.
# `-mtime -1`: only look at files modified in the last day, to mitigate showing stale results of old bazel runs.
# `-size +1c`: don't show files containing zero bytes
for report in $(find $(bazel info bazel-bin) -mtime -1 -size +1c -type f -name "*.aspect_rules_lint.report"); do
- echo "From ${report}:"
- cat "${report}"
- echo
+ echo "From ${report}:"
+ cat "${report}"
+ echo
done
diff --git a/example/package.json b/example/package.json
index afab9fe0..660f6928 100644
--- a/example/package.json
+++ b/example/package.json
@@ -5,7 +5,6 @@
"@typescript-eslint/eslint-plugin": "*",
"typescript": "4.9.5",
"prettier": "^2.8.7",
- "prettier-plugin-sh": "^0.12.8",
"prettier-plugin-sql": "^0.14.0"
},
"//FIXME(alexeagle)": "This section shouldn't be needed since these are plugins",
@@ -13,7 +12,6 @@
"packageExtensions": {
"prettier": {
"peerDependencies": {
- "prettier-plugin-sh": "*",
"prettier-plugin-sql": "*"
}
}
diff --git a/example/tools/BUILD b/example/tools/BUILD
index d05d0a24..ba653b09 100644
--- a/example/tools/BUILD
+++ b/example/tools/BUILD
@@ -6,7 +6,6 @@ we don't want to trigger eager fetches of these for builds that don't want to ru
load("@aspect_rules_lint//format:defs.bzl", "multi_formatter_binary")
load("@npm//:prettier/package_json.bzl", prettier = "bin")
-load("@rules_python//python/entry_points:py_console_script_binary.bzl", "py_console_script_binary")
package(default_visibility = ["//:__pkg__"])
@@ -64,6 +63,16 @@ java_binary(
runtime_deps = ["@ktfmt//jar"],
)
+alias(
+ name = "shfmt",
+ actual = select({
+ "@bazel_tools//src/conditions:linux_x86_64": "@shfmt_linux_x86_64//file:shfmt",
+ "@bazel_tools//src/conditions:linux_aarch64": "@shfmt_linux_aarch64//file:shfmt",
+ "@bazel_tools//src/conditions:darwin_arm64": "@shfmt_darwin_aarch64//file:shfmt",
+ "@bazel_tools//src/conditions:darwin_x86_64": "@shfmt_darwin_x86_64//file:shfmt",
+ }),
+)
+
alias(
name = "swiftformat",
# TODO: keith says it would be okay to upstream a proper toolchain for this
@@ -82,6 +91,7 @@ multi_formatter_binary(
jsonnet = ":jsonnetfmt",
kotlin = ":ktfmt",
python = ":ruff",
+ sh = ":shfmt",
starlark = "@buildifier_prebuilt//:buildifier",
swift = ":swiftformat",
terraform = ":terraform",
diff --git a/format/private/format.sh b/format/private/format.sh
index dab317c1..2071e4bc 100755
--- a/format/private/format.sh
+++ b/format/private/format.sh
@@ -50,6 +50,7 @@ case "$mode" in
swiftmode="--lint"
prettiermode="--check"
ruffmode="format --check"
+ shfmtmode="-l"
javamode="--set-exit-if-changed --dry-run"
ktmode="--set-exit-if-changed --dry-run"
gofmtmode="-l"
@@ -62,6 +63,7 @@ case "$mode" in
swiftmode=""
prettiermode="--write"
ruffmode="format"
+ shfmtmode="-w"
javamode="--replace"
ktmode=""
gofmtmode="-w"
@@ -85,9 +87,9 @@ if [ -n "$files" ] && [ -n "$bin" ]; then
fi
if [ "$#" -eq 0 ]; then
- files=$(git ls-files '*.js' '*.cjs' '*.mjs' '*.sh' '*.ts' '*.tsx' '*.mts' '*.cts' '*.json' '*.css' '*.html' '*.md' '*.sql')
+ files=$(git ls-files '*.js' '*.cjs' '*.mjs' '*.ts' '*.tsx' '*.mts' '*.cts' '*.json' '*.css' '*.html' '*.md' '*.sql')
else
- files=$(find "$@" -name '*.js' -or -name '*.cjs' -or -name '*.mjs' -or -name '*.sh' -or -name '*.ts' -or -name '*.tsx' -or -name '*.mts' -or -name '*.cts' -or -name '*.json' -or -name '*.css' -or -name '*.html' -or -name '*.md' -or -name '*.sql')
+ files=$(find "$@" -name '*.js' -or -name '*.cjs' -or -name '*.mjs' -or -name '*.ts' -or -name '*.tsx' -or -name '*.mts' -or -name '*.cts' -or -name '*.json' -or -name '*.css' -or -name '*.html' -or -name '*.md' -or -name '*.sql')
fi
bin=$(rlocation {{prettier}})
if [ -n "$files" ] && [ -n "$bin" ]; then
@@ -186,6 +188,17 @@ if [ -n "$files" ] && [ -n "$bin" ]; then
fi
fi
+if [ "$#" -eq 0 ]; then
+ files=$(git ls-files '*.sh' '*.bash')
+else
+ files=$(find "$@" -name '*.sh' -or -name '*.bash')
+fi
+bin=$(rlocation {{shfmt}})
+if [ -n "$files" ] && [ -n "$bin" ]; then
+ echo "Running shfmt..."
+ echo "$files" | tr \\n \\0 | xargs -0 $bin $shfmtmode
+fi
+
if [ "$#" -eq 0 ]; then
files=$(git ls-files '*.swift')
else
diff --git a/format/private/formatter_binary.bzl b/format/private/formatter_binary.bzl
index cb070ce2..cbea4c53 100644
--- a/format/private/formatter_binary.bzl
+++ b/format/private/formatter_binary.bzl
@@ -12,6 +12,7 @@ _attrs = {
"java": attr.label(doc = "a binary target that runs google-java-format", executable = True, cfg = "exec", allow_files = True),
"swift": attr.label(doc = "a binary target that runs swiftformat", executable = True, cfg = "exec", allow_files = True),
"go": attr.label(doc = "a binary target that runs go fmt", executable = True, cfg = "exec", allow_files = True),
+ "sh": attr.label(doc = "a binary target that runs shfmt", executable = True, cfg = "exec", allow_files = True),
"_bin": attr.label(default = "//format/private:format.sh", allow_single_file = True),
"_runfiles_lib": attr.label(default = "@bazel_tools//tools/bash/runfiles", allow_single_file = True),
}
@@ -29,6 +30,7 @@ def _formatter_binary_impl(ctx):
"java-format": ctx.attr.java,
"swiftformat": ctx.attr.swift,
"gofmt": ctx.attr.go,
+ "shfmt": ctx.attr.sh,
}
for tool, attr in tools.items():
if attr:
diff --git a/format/repositories.bzl b/format/repositories.bzl
index bcb1ee5d..0af29086 100644
--- a/format/repositories.bzl
+++ b/format/repositories.bzl
@@ -3,12 +3,15 @@
Needed until Bazel 7 allows MODULE.bazel to directly call repository rules.
"""
-load("@bazel_tools//tools/build_defs/repo:http.bzl", _http_archive = "http_archive", _http_jar = "http_jar")
+load("@bazel_tools//tools/build_defs/repo:http.bzl", _http_archive = "http_archive", _http_file = "http_file", _http_jar = "http_jar")
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
def http_archive(name, **kwargs):
maybe(_http_archive, name = name, **kwargs)
+def http_file(name, **kwargs):
+ maybe(_http_file, name = name, **kwargs)
+
def http_jar(name, **kwargs):
maybe(_http_jar, name = name, **kwargs)
@@ -53,6 +56,42 @@ def fetch_jsonnet():
urls = ["https://github.com/google/go-jsonnet/releases/download/v{0}/go-jsonnet_{0}_Linux_arm64.tar.gz".format(jsonnet_version)],
)
+# buildifier: disable=function-docstring
+def fetch_shfmt():
+ shfmt_version = "3.7.0"
+
+ http_file(
+ name = "shfmt_darwin_x86_64",
+ downloaded_file_path = "shfmt",
+ executable = True,
+ sha256 = "ae1d1ab961c113fb3dc2ff1150f33c3548983550d91da889b3171a5bcfaab14f",
+ urls = ["https://github.com/mvdan/sh/releases/download/v{0}/shfmt_v{0}_darwin_amd64".format(shfmt_version)],
+ )
+
+ http_file(
+ name = "shfmt_darwin_aarch64",
+ downloaded_file_path = "shfmt",
+ executable = True,
+ sha256 = "ad7ff6f666adba3d801eb17365a15539f07296718d39fb62cc2fde6b527178aa",
+ urls = ["https://github.com/mvdan/sh/releases/download/v{0}/shfmt_v{0}_darwin_arm64".format(shfmt_version)],
+ )
+
+ http_file(
+ name = "shfmt_linux_x86_64",
+ downloaded_file_path = "shfmt",
+ executable = True,
+ sha256 = "0264c424278b18e22453fe523ec01a19805ce3b8ebf18eaf3aadc1edc23f42e3",
+ urls = ["https://github.com/mvdan/sh/releases/download/v{0}/shfmt_v{0}_linux_amd64".format(shfmt_version)],
+ )
+
+ http_file(
+ name = "shfmt_linux_aarch64",
+ downloaded_file_path = "shfmt",
+ executable = True,
+ sha256 = "111612560d15bd53d8e8f8f85731176ce12f3b418ec473d39a40ed6bbec772de",
+ urls = ["https://github.com/mvdan/sh/releases/download/v{0}/shfmt_v{0}_linux_arm64".format(shfmt_version)],
+ )
+
def fetch_terraform():
tf_version = "1.4.0"