From 6f52f21ad2ca311591b3731d717a43fdfdceeede Mon Sep 17 00:00:00 2001 From: Connor Baker Date: Fri, 28 Feb 2025 23:21:38 +0000 Subject: [PATCH] testers.shfmt: init --- doc/build-helpers/testers.chapter.md | 58 +++++++++++++++++++ doc/redirects.json | 12 ++++ pkgs/build-support/testers/default.nix | 2 + pkgs/build-support/testers/shfmt/default.nix | 29 ++++++++++ .../testers/shfmt/src/indent2.sh | 3 + pkgs/build-support/testers/shfmt/tests.nix | 43 ++++++++++++++ pkgs/build-support/testers/test/default.nix | 2 + 7 files changed, 149 insertions(+) create mode 100644 pkgs/build-support/testers/shfmt/default.nix create mode 100644 pkgs/build-support/testers/shfmt/src/indent2.sh create mode 100644 pkgs/build-support/testers/shfmt/tests.nix diff --git a/doc/build-helpers/testers.chapter.md b/doc/build-helpers/testers.chapter.md index 74e70162ed3d..502133bb7ff7 100644 --- a/doc/build-helpers/testers.chapter.md +++ b/doc/build-helpers/testers.chapter.md @@ -165,6 +165,64 @@ testers.shellcheck { A derivation that runs `shellcheck` on the given script(s). The build will fail if `shellcheck` finds any issues. +## `shfmt` {#tester-shfmt} + +Run files through `shfmt`, a shell script formatter, failing if any files are reformatted. + +:::{.example #ex-shfmt} +# Run `testers.shfmt` + +A single script + +```nix +testers.shfmt { + name = "script"; + src = ./script.sh; +} +``` + +Multiple files + +```nix +let + inherit (lib) fileset; +in +testers.shfmt { + name = "nixbsd"; + src = fileset.toSource { + root = ./.; + fileset = fileset.unions [ + ./lib.sh + ./nixbsd-activate + ]; + }; +} +``` + +::: + +### Inputs {#tester-shfmt-inputs} + +`name` (string) +: The name of the test. + `name` is required because it massively improves traceability of test failures. + The name of the derivation produced by the tester is `shfmt-${name}`. + +`src` (path-like) +: The path to the shell script(s) to check. + This can be a single file or a directory containing shell files. + All files in `src` will be checked, so you may want to provide `fileset`-based source instead of a whole directory. + +`indent` (integer, optional) +: The number of spaces to use for indentation. + Defaults to `2`. + A value of `0` indents with tabs. + +### Return value {#tester-shfmt-return} + +A derivation that runs `shfmt` on the given script(s), producing an empty output upon success. +The build will fail if `shfmt` reformats anything. + ## `testVersion` {#tester-testVersion} Checks that the output from running a command contains the specified version string in it as a whole word. diff --git a/doc/redirects.json b/doc/redirects.json index fe713d03384a..7da140253173 100644 --- a/doc/redirects.json +++ b/doc/redirects.json @@ -8,6 +8,9 @@ "ex-build-helpers-extendMkDerivation": [ "index.html#ex-build-helpers-extendMkDerivation" ], + "ex-shfmt": [ + "index.html#ex-shfmt" + ], "ex-testBuildFailurePrime-doc-example": [ "index.html#ex-testBuildFailurePrime-doc-example" ], @@ -335,6 +338,15 @@ "footnote-stdenv-find-inputs-location.__back.0": [ "index.html#footnote-stdenv-find-inputs-location.__back.0" ], + "tester-shfmt": [ + "index.html#tester-shfmt" + ], + "tester-shfmt-inputs": [ + "index.html#tester-shfmt-inputs" + ], + "tester-shfmt-return": [ + "index.html#tester-shfmt-return" + ], "tester-testBuildFailurePrime": [ "index.html#tester-testBuildFailurePrime" ], diff --git a/pkgs/build-support/testers/default.nix b/pkgs/build-support/testers/default.nix index 9934e84d7b5e..e9e0945b552f 100644 --- a/pkgs/build-support/testers/default.nix +++ b/pkgs/build-support/testers/default.nix @@ -190,4 +190,6 @@ testMetaPkgConfig = callPackage ./testMetaPkgConfig/tester.nix { }; shellcheck = callPackage ./shellcheck/tester.nix { }; + + shfmt = callPackage ./shfmt { }; } diff --git a/pkgs/build-support/testers/shfmt/default.nix b/pkgs/build-support/testers/shfmt/default.nix new file mode 100644 index 000000000000..44a30e4f65d5 --- /dev/null +++ b/pkgs/build-support/testers/shfmt/default.nix @@ -0,0 +1,29 @@ +{ + lib, + shfmt, + stdenvNoCC, +}: +# See https://nixos.org/manual/nixpkgs/unstable/#tester-shfmt +# or doc/build-helpers/testers.chapter.md +{ + name, + src, + indent ? 2, +}: +stdenvNoCC.mkDerivation (finalAttrs: { + __structuredAttrs = true; + strictDeps = true; + inherit src indent; + name = "shfmt-${name}"; + dontUnpack = true; # Unpack phase tries to extract archive + nativeBuildInputs = [ shfmt ]; + doCheck = true; + dontConfigure = true; + dontBuild = true; + checkPhase = '' + shfmt --diff --indent $indent --simplify "$src" + ''; + installPhase = '' + touch "$out" + ''; +}) diff --git a/pkgs/build-support/testers/shfmt/src/indent2.sh b/pkgs/build-support/testers/shfmt/src/indent2.sh new file mode 100644 index 000000000000..799580434917 --- /dev/null +++ b/pkgs/build-support/testers/shfmt/src/indent2.sh @@ -0,0 +1,3 @@ +hello() { + echo "hello" +} diff --git a/pkgs/build-support/testers/shfmt/tests.nix b/pkgs/build-support/testers/shfmt/tests.nix new file mode 100644 index 000000000000..359cf27c9be5 --- /dev/null +++ b/pkgs/build-support/testers/shfmt/tests.nix @@ -0,0 +1,43 @@ +{ lib, testers }: +lib.recurseIntoAttrs { + # Positive tests + indent2 = testers.shfmt { + name = "indent2"; + indent = 2; + src = ./src/indent2.sh; + }; + indent2Bin = testers.shfmt { + name = "indent2Bin"; + indent = 2; + src = ./src; + }; + # Negative tests + indent2With0 = testers.testBuildFailure' { + drv = testers.shfmt { + name = "indent2"; + indent = 0; + src = ./src/indent2.sh; + }; + }; + indent2BinWith0 = testers.testBuildFailure' { + drv = testers.shfmt { + name = "indent2Bin"; + indent = 0; + src = ./src; + }; + }; + indent2With4 = testers.testBuildFailure' { + drv = testers.shfmt { + name = "indent2"; + indent = 4; + src = ./src/indent2.sh; + }; + }; + indent2BinWith4 = testers.testBuildFailure' { + drv = testers.shfmt { + name = "indent2Bin"; + indent = 4; + src = ./src; + }; + }; +} diff --git a/pkgs/build-support/testers/test/default.nix b/pkgs/build-support/testers/test/default.nix index 7e4df128391d..9ef5f7d76e46 100644 --- a/pkgs/build-support/testers/test/default.nix +++ b/pkgs/build-support/testers/test/default.nix @@ -39,6 +39,8 @@ lib.recurseIntoAttrs { shellcheck = pkgs.callPackage ../shellcheck/tests.nix { }; + shfmt = pkgs.callPackages ../shfmt/tests.nix { }; + runCommand = lib.recurseIntoAttrs { bork = pkgs.python3Packages.bork.tests.pytest-network;