Skip to content

Commit 642dce0

Browse files
authored
Merge pull request #423 from m1-s/installationTest
add hook installation test
2 parents f3bb954 + 649fb51 commit 642dce0

File tree

8 files changed

+150
-16
lines changed

8 files changed

+150
-16
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,5 @@ jobs:
3030
name: pre-commit-hooks
3131
signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
3232
- run: rm -rf /opt&
33-
- run: nix flake check --show-trace
33+
- run: nix flake check -L --show-trace
3434
- run: nix eval .#lib.x86_64-linux.run --show-trace

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ nix develop
9292
ormolu.enable = true;
9393
ormolu.package = pkgs.haskellPackages.ormolu;
9494
ormolu.settings.defaultExtensions = [ "lhs" "hs" ];
95-
95+
9696
# some hooks have more than one package, like clippy:
9797
clippy.enable = true;
9898
clippy.packageOverrides.cargo = pkgs.cargo;
@@ -109,7 +109,7 @@ nix develop
109109
1. Integrate hooks to prepare environment as part of `shell.nix`:
110110

111111
```nix
112-
let
112+
let
113113
pre-commit = import ./default.nix;
114114
in (import <nixpkgs> {}).mkShell {
115115
shellHook = ''
@@ -412,6 +412,9 @@ Example configuration:
412412
# Set this to false to not pass the changed files
413413
# to the command (default: true):
414414
pass_filenames = false;
415+
416+
# Which git hooks the command should run for (default: [ "pre-commit" ]):
417+
stages = ["pre-push"];
415418
};
416419
};
417420
};

flake.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
}
3636
// flake-utils.lib.eachSystem defaultSystems (system:
3737
let
38-
exposed = import ./nix { nixpkgs = nixpkgs; inherit system; gitignore-nix-src = gitignore; isFlakes = true; };
38+
exposed = import ./nix { inherit nixpkgs system; gitignore-nix-src = gitignore; isFlakes = true; };
3939
exposed-stable = import ./nix { nixpkgs = nixpkgs-stable; inherit system; gitignore-nix-src = gitignore; isFlakes = true; };
4040
in
4141
{

modules/hook.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ in
155155
};
156156

157157
stages = mkOption {
158-
type = types.listOf types.str;
158+
type = (import ./supported-hooks.nix { inherit lib; }).supportedHooksType;
159159
description = lib.mdDoc ''
160160
Confines the hook to run at a particular stage.
161161
'';

modules/pre-commit.nix

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,15 @@ let
1010
mkIf
1111
mkOption
1212
types
13+
remove
1314
;
1415

1516
inherit (pkgs) runCommand writeText git;
1617

1718
cfg = config;
18-
install_stages = lib.unique (cfg.default_stages ++ (builtins.concatLists (lib.mapAttrsToList (_: h: h.stages) enabledHooks)));
19+
install_stages = lib.unique (builtins.concatLists (lib.mapAttrsToList (_: h: h.stages) enabledHooks));
20+
21+
supportedHooksLib = import ./supported-hooks.nix { inherit lib; };
1922

2023
hookType = types.submodule hookModule;
2124

@@ -170,7 +173,7 @@ in
170173
The predefined hooks are:
171174
172175
${
173-
lib.concatStringsSep
176+
concatStringsSep
174177
"\n"
175178
(lib.mapAttrsToList
176179
(hookName: hookConf:
@@ -248,14 +251,14 @@ in
248251

249252
default_stages =
250253
mkOption {
251-
type = types.listOf types.str;
254+
type = supportedHooksLib.supportedHooksType;
252255
description = lib.mdDoc
253256
''
254257
A configuration wide option for the stages property.
255258
Installs hooks to the defined stages.
256259
See [https://pre-commit.com/#confining-hooks-to-run-at-certain-stages](https://pre-commit.com/#confining-hooks-to-run-at-certain-stages).
257260
'';
258-
default = [ "commit" ];
261+
default = [ "pre-commit" ];
259262
};
260263

261264
rawConfig =
@@ -327,12 +330,11 @@ in
327330
328331
# These update procedures compare before they write, to avoid
329332
# filesystem churn. This improves performance with watch tools like lorri
330-
# and prevents installation loops by via lorri.
333+
# and prevents installation loops by lorri.
331334
332335
if ! readlink "''${GIT_WC}/.pre-commit-config.yaml" >/dev/null \
333336
|| [[ $(readlink "''${GIT_WC}/.pre-commit-config.yaml") != ${configFile} ]]; then
334337
echo 1>&2 "pre-commit-hooks.nix: updating $PWD repo"
335-
336338
[ -L .pre-commit-config.yaml ] && unlink .pre-commit-config.yaml
337339
338340
if [ -e "''${GIT_WC}/.pre-commit-config.yaml" ]; then
@@ -344,24 +346,23 @@ in
344346
else
345347
ln -fs ${configFile} "''${GIT_WC}/.pre-commit-config.yaml"
346348
# Remove any previously installed hooks (since pre-commit itself has no convergent design)
347-
hooks="pre-commit pre-merge-commit pre-push prepare-commit-msg commit-msg post-checkout post-commit"
349+
hooks="${concatStringsSep " " (remove "manual" supportedHooksLib.supportedHooks )}"
348350
for hook in $hooks; do
349351
pre-commit uninstall -t $hook
350352
done
351353
${git}/bin/git config --local core.hooksPath ""
352354
# Add hooks for configured stages (only) ...
353355
if [ ! -z "${concatStringsSep " " install_stages}" ]; then
354356
for stage in ${concatStringsSep " " install_stages}; do
355-
if [[ "$stage" == "manual" ]]; then
356-
continue
357-
fi
358357
case $stage in
358+
manual)
359+
;;
359360
# if you amend these switches please also review $hooks above
360361
commit | merge-commit | push)
361362
stage="pre-"$stage
362363
pre-commit install -t $stage
363364
;;
364-
prepare-commit-msg | commit-msg | post-checkout | post-commit)
365+
${concatStringsSep "|" supportedHooksLib.supportedHooks})
365366
pre-commit install -t $stage
366367
;;
367368
*)

modules/supported-hooks.nix

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{ lib }:
2+
let inherit (lib) types;
3+
# according to https://pre-commit.com/#supported-git-hooks
4+
supportedHooks = [
5+
"commit-msg"
6+
"post-checkout"
7+
"post-commit"
8+
"post-merge"
9+
"post-rewrite"
10+
"pre-commit"
11+
"pre-merge-commit"
12+
"pre-push"
13+
"pre-rebase"
14+
"prepare-commit-msg"
15+
"manual"
16+
];
17+
in
18+
{
19+
inherit supportedHooks;
20+
21+
supportedHooksType =
22+
let
23+
deprecatedHooks = [
24+
"commit"
25+
"push"
26+
"merge-commit"
27+
];
28+
in
29+
types.listOf (types.enum (supportedHooks ++ deprecatedHooks));
30+
}

nix/default.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ let
2727
typos.enable = true;
2828
};
2929
};
30+
installation-test = pkgs.callPackage ./installation-test.nix { inherit run; };
3031
all-tools-eval =
3132
let
3233
config = lib.evalModules {

nix/installation-test.nix

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Test that checks whether the correct hooks are created in the hooks folder.
2+
{ git, perl, coreutils, runCommand, run, lib, mktemp }:
3+
let
4+
tests = {
5+
basic-test = {
6+
expectedHooks = [ "pre-commit" ];
7+
conf.hooks.shellcheck.enable = true;
8+
};
9+
10+
multiple-hooks-test = {
11+
expectedHooks = [ "commit-msg" "pre-commit" ];
12+
conf.hooks = {
13+
shellcheck.enable = true;
14+
nixpkgs-fmt = {
15+
enable = true;
16+
stages = [ "commit-msg" ];
17+
};
18+
};
19+
};
20+
21+
non-default-stage-test = {
22+
expectedHooks = [ "commit-msg" ];
23+
conf.hooks.nixpkgs-fmt = {
24+
enable = true;
25+
stages = [ "commit-msg" ];
26+
};
27+
};
28+
29+
default-stage-test = {
30+
expectedHooks = [ "commit-msg" ];
31+
conf = {
32+
default_stages = [ "commit-msg" ];
33+
hooks.nixpkgs-fmt.enable = true;
34+
};
35+
};
36+
37+
manual-default-stage-test = {
38+
expectedHooks = [ ];
39+
conf = {
40+
default_stages = [ "manual" ];
41+
hooks.nixpkgs-fmt.enable = true;
42+
};
43+
};
44+
45+
multiple-default-stages-test = {
46+
expectedHooks = [ "pre-push" ];
47+
conf = {
48+
default_stages = [ "manual" "pre-push" ];
49+
hooks.nixpkgs-fmt.enable = true;
50+
};
51+
};
52+
53+
deprecated-gets-prefixed-test = {
54+
expectedHooks = [ "pre-push" ];
55+
conf.hooks.nixpkgs-fmt = {
56+
enable = true;
57+
stages = [ "push" ];
58+
};
59+
};
60+
};
61+
62+
executeTest = lib.mapAttrsToList
63+
(name: test:
64+
let runDerivation = run ({ src = null; } // test.conf);
65+
in ''
66+
rm -f ~/.git/hooks/*
67+
${runDerivation.shellHook}
68+
actualHooks=(`find ~/.git/hooks -type f -printf "%f "`)
69+
read -a expectedHooks <<< "${builtins.toString test.expectedHooks}"
70+
if ! assertArraysEqual actualHooks expectedHooks; then
71+
echo "${name} failed: Expected hooks '${builtins.toString test.expectedHooks}' but found '$actualHooks'."
72+
return 1
73+
fi
74+
'')
75+
tests;
76+
in
77+
runCommand "installation-test" { nativeBuildInputs = [ git perl coreutils mktemp ]; } ''
78+
set -eoux
79+
80+
HOME=$(mktemp -d)
81+
cd $HOME
82+
git init
83+
84+
assertArraysEqual() {
85+
local -n _array_one=$1
86+
local -n _array_two=$2
87+
diffArray=(`echo ''${_array_one[@]} ''${_array_two[@]} | tr ' ' '\n' | sort | uniq -u`)
88+
if [ ''${#diffArray[@]} -eq 0 ]
89+
then
90+
return 0
91+
else
92+
return 1
93+
fi
94+
}
95+
96+
${lib.concatStrings executeTest}
97+
98+
echo "success" > $out
99+
''

0 commit comments

Comments
 (0)