From 1c7815ef99727dbe36d54e4f98889a44a46dfa58 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Sat, 30 Mar 2024 18:27:53 +0100 Subject: [PATCH] add installation test --- .github/workflows/ci.yaml | 2 +- README.md | 9 +++-- flake.nix | 2 +- modules/hook.nix | 2 +- modules/pre-commit.nix | 16 ++++---- modules/supported-hooks.nix | 30 +++++++++++++++ nix/default.nix | 1 + nix/installation-test.nix | 74 +++++++++++++++++++++++++++++++++++++ 8 files changed, 123 insertions(+), 13 deletions(-) create mode 100644 modules/supported-hooks.nix create mode 100644 nix/installation-test.nix diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4c6935a4..19142fba 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -30,5 +30,5 @@ jobs: name: pre-commit-hooks signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}' - run: rm -rf /opt& - - run: nix flake check --show-trace + - run: nix flake check -L --show-trace - run: nix eval .#lib.x86_64-linux.run --show-trace diff --git a/README.md b/README.md index f904335c..bd0ebd11 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ nix develop ormolu.enable = true; ormolu.package = pkgs.haskellPackages.ormolu; ormolu.settings.defaultExtensions = [ "lhs" "hs" ]; - + # some hooks have more than one package, like clippy: clippy.enable = true; clippy.packageOverrides.cargo = pkgs.cargo; @@ -109,7 +109,7 @@ nix develop 3. Integrate hooks to prepare environment as part of `shell.nix`: ```nix - let + let pre-commit = import ./default.nix; in (import {}).mkShell { shellHook = '' @@ -318,7 +318,7 @@ clang-format = { }; ``` -Otherwise, the default internal list is used which includes everything that +Otherwise, the default internal list is used which includes everything that clang-format supports. ## Git @@ -373,6 +373,9 @@ Example configuration: # Set this to false to not pass the changed files # to the command (default: true): pass_filenames = false; + + # Which git hooks the command should run for (default: [ "pre-commit" ]): + stages = ["pre-push"]; }; }; }; diff --git a/flake.nix b/flake.nix index b789f70c..c937ea24 100644 --- a/flake.nix +++ b/flake.nix @@ -35,7 +35,7 @@ } // flake-utils.lib.eachSystem defaultSystems (system: let - exposed = import ./nix { nixpkgs = nixpkgs; inherit system; gitignore-nix-src = gitignore; isFlakes = true; }; + exposed = import ./nix { inherit nixpkgs system; gitignore-nix-src = gitignore; isFlakes = true; }; exposed-stable = import ./nix { nixpkgs = nixpkgs-stable; inherit system; gitignore-nix-src = gitignore; isFlakes = true; }; in { diff --git a/modules/hook.nix b/modules/hook.nix index d6195893..45831b9e 100644 --- a/modules/hook.nix +++ b/modules/hook.nix @@ -155,7 +155,7 @@ in }; stages = mkOption { - type = types.listOf types.str; + type = (import ./supported-hooks.nix { inherit lib; }).supportedHooksType; description = lib.mdDoc '' Confines the hook to run at a particular stage. ''; diff --git a/modules/pre-commit.nix b/modules/pre-commit.nix index 4b0df75c..02fcaecb 100644 --- a/modules/pre-commit.nix +++ b/modules/pre-commit.nix @@ -10,12 +10,15 @@ let mkIf mkOption types + remove ; inherit (pkgs) runCommand writeText git; cfg = config; - install_stages = lib.unique (cfg.default_stages ++ (builtins.concatLists (lib.mapAttrsToList (_: h: h.stages) enabledHooks))); + install_stages = lib.unique (builtins.concatLists (lib.mapAttrsToList (_: h: h.stages) enabledHooks)); + + supportedHooksLib = import ./supported-hooks.nix { inherit lib; }; hookType = types.submodule { imports = [ @@ -175,7 +178,7 @@ in The predefined hooks are: ${ - lib.concatStringsSep + concatStringsSep "\n" (lib.mapAttrsToList (hookName: hookConf: @@ -253,14 +256,14 @@ in default_stages = mkOption { - type = types.listOf types.str; + type = supportedHooksLib.supportedHooksType; description = lib.mdDoc '' A configuration wide option for the stages property. Installs hooks to the defined stages. See [https://pre-commit.com/#confining-hooks-to-run-at-certain-stages](https://pre-commit.com/#confining-hooks-to-run-at-certain-stages). ''; - default = [ "commit" ]; + default = [ "pre-commit" ]; }; rawConfig = @@ -332,12 +335,11 @@ in # These update procedures compare before they write, to avoid # filesystem churn. This improves performance with watch tools like lorri - # and prevents installation loops by via lorri. + # and prevents installation loops by lorri. if ! readlink "''${GIT_WC}/.pre-commit-config.yaml" >/dev/null \ || [[ $(readlink "''${GIT_WC}/.pre-commit-config.yaml") != ${configFile} ]]; then echo 1>&2 "pre-commit-hooks.nix: updating $PWD repo" - [ -L .pre-commit-config.yaml ] && unlink .pre-commit-config.yaml if [ -e "''${GIT_WC}/.pre-commit-config.yaml" ]; then @@ -349,7 +351,7 @@ in else ln -fs ${configFile} "''${GIT_WC}/.pre-commit-config.yaml" # Remove any previously installed hooks (since pre-commit itself has no convergent design) - hooks="pre-commit pre-merge-commit pre-push prepare-commit-msg commit-msg post-checkout post-commit" + hooks="${concatStringsSep " " (remove "manual" supportedHooksLib.supportedHooks )}" for hook in $hooks; do pre-commit uninstall -t $hook done diff --git a/modules/supported-hooks.nix b/modules/supported-hooks.nix new file mode 100644 index 00000000..97605c78 --- /dev/null +++ b/modules/supported-hooks.nix @@ -0,0 +1,30 @@ +{ lib }: +let inherit (lib) types; + # according to https://pre-commit.com/#supported-git-hooks + supportedHooks = [ + "commit-msg" + "post-checkout" + "post-commit" + "post-merge" + "post-rewrite" + "pre-commit" + "pre-merge-commit" + "pre-push" + "pre-rebase" + "prepare-commit-msg" + "manual" + ]; +in +{ + inherit supportedHooks; + + supportedHooksType = + let + deprecatedHooks = [ + "commit" + "push" + "merge-commit" + ]; + in + types.listOf (types.enum (supportedHooks ++ deprecatedHooks)); +} diff --git a/nix/default.nix b/nix/default.nix index 8ef299c5..dc93e7fc 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -27,6 +27,7 @@ let typos.enable = true; }; }; + installation-test = pkgs.callPackage ./installation-test.nix { inherit run; }; all-tools-eval = let config = lib.evalModules { diff --git a/nix/installation-test.nix b/nix/installation-test.nix new file mode 100644 index 00000000..11a11abd --- /dev/null +++ b/nix/installation-test.nix @@ -0,0 +1,74 @@ +# Test that checks whether the correct hooks are created in the hooks folder. +{ git, perl, coreutils, runCommand, run, lib }: +let + tests = { + basic-test = { + expectedHooks = [ "pre-commit" ]; + conf.hooks.shellcheck.enable = true; + }; + + multiple-hooks-test = { + expectedHooks = [ "commit-msg" "pre-commit" ]; + conf.hooks = { + shellcheck.enable = true; + nixpkgs-fmt = { + enable = true; + stages = [ "commit-msg" ]; + }; + }; + }; + + non-default-stage-test = { + expectedHooks = [ "commit-msg" ]; + conf.hooks.nixpkgs-fmt = { + enable = true; + stages = [ "commit-msg" ]; + }; + }; + + default-stage-test = { + expectedHooks = [ "commit-msg" ]; + conf = { + default_stages = [ "commit-msg" ]; + hooks.nixpkgs-fmt.enable = true; + }; + }; + }; + + executeTest = lib.mapAttrsToList + (name: test: + let runDerivation = run ({ src = null; } // test.conf); + in '' + rm /build/.git/hooks/* + ${runDerivation.shellHook} + actualHooks=(`find /build/.git/hooks -type f -printf "%f "`) + read -a expectedHooks <<< "${builtins.toString test.expectedHooks}" + if [ assertArraysEqual "''${actualHooks[@]}" "''${expectedHooks[@]}" -eq false ]; then + echo "${name} failed: Expected hooks '${builtins.toString test.expectedHooks}' but found '$actualHooks'." + return 1 + fi + '') + tests; +in +runCommand "installation-test" { nativeBuildInputs = [ git perl coreutils ]; } '' + set -eoux + + HOME=/build + git init + + assertArraysEqual(){ + local -n _array_one=$1 + local -n _array_two=$2 + diffArray=(`echo ''${_array_one[@]} ''${_array_two[@]} | sort | uniq -u`) + if [ ''${#diffArray[@]} -eq 0 ] + then + true + else + false + fi + } + + ${lib.concatStrings executeTest} + + echo "success" > $out +''