3 Commits

Author SHA1 Message Date
eric
71c7fe09cd chore(release): v3.4.0 2026-03-15 17:15:23 +01:00
eric
45f3830794 ci: limit lefthook logging 2026-03-15 17:14:25 +01:00
eric
b8d0a69d4d fix: lefthook logging 2026-03-15 17:10:26 +01:00
7 changed files with 80 additions and 8 deletions

1
.envrc
View File

@@ -1 +1,2 @@
watch_file flake.nix
use flake use flake

View File

@@ -15,7 +15,7 @@
## Use the template ## Use the template
```bash ```bash
nix flake new myapp -t 'git+https://git.dgren.dev/eric/nix-flake-lib?ref=refs/tags/v3.3.0#default' --refresh nix flake new myapp -t 'git+https://git.dgren.dev/eric/nix-flake-lib?ref=refs/tags/v3.4.0#default' --refresh
``` ```
## Use the library ## Use the library
@@ -23,7 +23,7 @@ nix flake new myapp -t 'git+https://git.dgren.dev/eric/nix-flake-lib?ref=refs/ta
Add this flake input: Add this flake input:
```nix ```nix
inputs.repo-lib.url = "git+https://git.dgren.dev/eric/nix-flake-lib?ref=refs/tags/v3.3.0"; inputs.repo-lib.url = "git+https://git.dgren.dev/eric/nix-flake-lib?ref=refs/tags/v3.4.0";
inputs.repo-lib.inputs.nixpkgs.follows = "nixpkgs"; inputs.repo-lib.inputs.nixpkgs.follows = "nixpkgs";
``` ```
@@ -73,6 +73,7 @@ outputs = { self, nixpkgs, repo-lib, ... }:
- merged `packages` and `apps` from `perSystem` - merged `packages` and `apps` from `perSystem`
Checks are installed through `lefthook`, with `pre-commit` and `pre-push` commands configured to run in parallel. Checks are installed through `lefthook`, with `pre-commit` and `pre-push` commands configured to run in parallel.
repo-lib also sets Lefthook `output = [ "failure" "summary" ]` by default.
For advanced Lefthook features, use raw `config.lefthook` or `perSystem.lefthook`. Those attrsets are merged after generated checks, so you can augment a generated command with fields that the simple `checks` abstraction does not carry, such as `stage_fixed`: For advanced Lefthook features, use raw `config.lefthook` or `perSystem.lefthook`. Those attrsets are merged after generated checks, so you can augment a generated command with fields that the simple `checks` abstraction does not carry, such as `stage_fixed`:

View File

@@ -1,4 +1,4 @@
3.3.0 3.4.0
stable stable
0 0

View File

@@ -415,16 +415,27 @@ let
// formatting.programs; // formatting.programs;
settings.formatter = { } // formatting.settings; settings.formatter = { } // formatting.settings;
}; };
treefmtWrapper = treefmtEval.config.build.wrapper;
lefthookBinWrapper = pkgs.writeShellScript "lefthook-dumb-term" ''
exec env TERM=dumb ${lib.getExe pkgs.lefthook} "$@"
'';
normalizedLefthookConfig = normalizeLefthookConfig "lefthook config" lefthookConfig; normalizedLefthookConfig = normalizeLefthookConfig "lefthook config" lefthookConfig;
lefthookCheck = lefthookNix.lib.${system}.run { lefthookCheck = lefthookNix.lib.${system}.run {
inherit src; inherit src;
config = lib.foldl' lib.recursiveUpdate { } ( config = lib.foldl' lib.recursiveUpdate { } (
[ [
{
output = [
"failure"
"summary"
];
}
(parallelHookStageConfig "pre-commit") (parallelHookStageConfig "pre-commit")
(parallelHookStageConfig "pre-push") (parallelHookStageConfig "pre-push")
(lib.setAttrByPath [ "pre-commit" "commands" "treefmt" ] { (lib.setAttrByPath [ "pre-commit" "commands" "treefmt" ] {
run = "${treefmtEval.config.build.wrapper}/bin/treefmt --ci {staged_files}"; run = "${treefmtWrapper}/bin/treefmt --no-cache {staged_files}";
stage_fixed = true;
}) })
(lib.setAttrByPath [ "pre-commit" "commands" "gitleaks" ] { (lib.setAttrByPath [ "pre-commit" "commands" "gitleaks" ] {
run = "${pkgs.gitleaks}/bin/gitleaks protect --staged"; run = "${pkgs.gitleaks}/bin/gitleaks protect --staged";
@@ -439,6 +450,7 @@ let
); );
}; };
selectedCheckOutputs = { selectedCheckOutputs = {
formatting-check = treefmtEval.config.build.check src;
hook-check = lefthookCheck; hook-check = lefthookCheck;
lefthook-check = lefthookCheck; lefthook-check = lefthookCheck;
}; };
@@ -549,10 +561,17 @@ let
in in
{ {
checks = selectedCheckOutputs; checks = selectedCheckOutputs;
formatter = treefmtEval.config.build.wrapper; formatter = treefmtWrapper;
shell = pkgs.mkShell { shell = pkgs.mkShell {
LEFTHOOK_BIN = builtins.toString lefthookBinWrapper;
packages = lib.unique ( packages = lib.unique (
selectedStandardPackages ++ extraPackages ++ toolPackages ++ [ pkgs.lefthook ] selectedStandardPackages
++ extraPackages
++ toolPackages
++ [
pkgs.lefthook
treefmtWrapper
]
); );
shellHook = buildShellHook { shellHook = buildShellHook {
hooksShellHook = lefthookCheck.shellHook; hooksShellHook = lefthookCheck.shellHook;

View File

@@ -1 +1,2 @@
watch_file flake.nix
use flake use flake

View File

@@ -4,7 +4,7 @@
inputs = { inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
repo-lib.url = "git+https://git.dgren.dev/eric/nix-flake-lib?ref=refs/tags/v3.3.0"; repo-lib.url = "git+https://git.dgren.dev/eric/nix-flake-lib?ref=refs/tags/v3.4.0";
repo-lib.inputs.nixpkgs.follows = "nixpkgs"; repo-lib.inputs.nixpkgs.follows = "nixpkgs";
}; };
@@ -53,6 +53,7 @@
# These checks become lefthook commands in the generated `lefthook.yml`. # These checks become lefthook commands in the generated `lefthook.yml`.
# repo-lib runs `pre-commit` and `pre-push` hook commands in parallel. # repo-lib runs `pre-commit` and `pre-push` hook commands in parallel.
# It also sets `output = [ "failure" "summary" ]` by default.
checks = { checks = {
tests = { tests = {
command = "echo 'No tests defined yet.'"; command = "echo 'No tests defined yet.'";

View File

@@ -35,7 +35,7 @@ assert_contains() {
local needle="$1" local needle="$1"
local haystack_file="$2" local haystack_file="$2"
local message="$3" local message="$3"
if ! grep -Fq "$needle" "$haystack_file"; then if ! grep -Fq -- "$needle" "$haystack_file"; then
fail "$message (missing '$needle')" fail "$message (missing '$needle')"
fi fi
} }
@@ -296,6 +296,16 @@ write_mk_repo_lefthook_flake() {
EOF EOF
} }
init_git_repo() {
local repo_dir="$1"
run_capture_ok "init_git_repo: git init failed" git -C "$repo_dir" init
run_capture_ok "init_git_repo: git config user.name failed" git -C "$repo_dir" config user.name "Repo Lib Test"
run_capture_ok "init_git_repo: git config user.email failed" git -C "$repo_dir" config user.email "repo-lib-test@example.com"
run_capture_ok "init_git_repo: git add failed" git -C "$repo_dir" add flake.nix
run_capture_ok "init_git_repo: git commit failed" git -C "$repo_dir" commit -m "init"
}
write_tool_failure_flake() { write_tool_failure_flake() {
local repo_dir="$1" local repo_dir="$1"
cat >"$repo_dir/flake.nix" <<EOF cat >"$repo_dir/flake.nix" <<EOF
@@ -1248,6 +1258,7 @@ run_mk_repo_lefthook_case() {
run_capture_ok "$case_name: lefthook.yml derivation show failed" bash -c 'nix derivation show "$1" >"$2"' _ "$lefthook_yml_drv" "$lefthook_yml_json" run_capture_ok "$case_name: lefthook.yml derivation show failed" bash -c 'nix derivation show "$1" >"$2"' _ "$lefthook_yml_drv" "$lefthook_yml_json"
assert_contains '\"pre-push\":{\"commands\":{\"tests\":{' "$lefthook_yml_json" "$case_name: generated check missing from pre-push" assert_contains '\"pre-push\":{\"commands\":{\"tests\":{' "$lefthook_yml_json" "$case_name: generated check missing from pre-push"
assert_contains 'repo-lib-check-tests' "$lefthook_yml_json" "$case_name: generated check command missing from lefthook config" assert_contains 'repo-lib-check-tests' "$lefthook_yml_json" "$case_name: generated check command missing from lefthook config"
assert_contains '\"output\":[\"failure\",\"summary\"]' "$lefthook_yml_json" "$case_name: lefthook output config missing"
assert_contains '\"stage_fixed\":true' "$lefthook_yml_json" "$case_name: stage_fixed missing from lefthook config" assert_contains '\"stage_fixed\":true' "$lefthook_yml_json" "$case_name: stage_fixed missing from lefthook config"
rm -rf "$workdir" rm -rf "$workdir"
@@ -1255,6 +1266,43 @@ run_mk_repo_lefthook_case() {
echo "[test] PASS: $case_name" >&2 echo "[test] PASS: $case_name" >&2
} }
run_mk_repo_treefmt_hook_case() {
local case_name="mkRepo configures treefmt and lefthook for dev shell hooks"
local workdir
workdir="$(mktemp -d)"
local repo_dir="$workdir/mk-repo-treefmt"
local system
local derivation_json="$workdir/treefmt-hook.drv.json"
local lefthook_yml_drv
local lefthook_yml_json="$workdir/treefmt-hook-yml.drv.json"
mkdir -p "$repo_dir"
write_mk_repo_flake "$repo_dir"
CURRENT_LOG="$workdir/mk-repo-treefmt.log"
init_git_repo "$repo_dir"
run_capture_ok "$case_name: treefmt should be available in shell" bash -c 'cd "$1" && nix develop --no-write-lock-file . -c sh -c '"'"'printf "%s\n" "$LEFTHOOK_BIN" && command -v treefmt'"'"'' _ "$repo_dir"
assert_contains 'lefthook-dumb-term' "$CURRENT_LOG" "$case_name: LEFTHOOK_BIN wrapper missing"
assert_contains '/bin/treefmt' "$CURRENT_LOG" "$case_name: treefmt missing from shell"
system="$(nix eval --raw --impure --expr 'builtins.currentSystem')"
run_capture_ok "$case_name: formatting check derivation show failed" bash -c 'nix derivation show "$1" >"$2"' _ "$repo_dir#checks.${system}.formatting-check" "$workdir/formatting-check.drv.json"
run_capture_ok "$case_name: lefthook derivation show failed" bash -c 'nix derivation show "$1" >"$2"' _ "$repo_dir#checks.${system}.lefthook-check" "$derivation_json"
lefthook_yml_drv="$(perl -0ne 'print "/nix/store/$1\n" if /"([a-z0-9]{32}-lefthook\.yml\.drv)"/' "$derivation_json")"
if [[ -z "$lefthook_yml_drv" ]]; then
fail "$case_name: could not locate lefthook.yml derivation"
fi
run_capture_ok "$case_name: lefthook.yml derivation show failed" bash -c 'nix derivation show "$1" >"$2"' _ "$lefthook_yml_drv" "$lefthook_yml_json"
assert_contains '--no-cache {staged_files}' "$lefthook_yml_json" "$case_name: treefmt hook missing staged-file format command"
assert_contains '\"stage_fixed\":true' "$lefthook_yml_json" "$case_name: treefmt hook should re-stage formatted files"
rm -rf "$workdir"
CURRENT_LOG=""
echo "[test] PASS: $case_name" >&2
}
run_mk_repo_tool_failure_case() { run_mk_repo_tool_failure_case() {
local case_name="mkRepo required tools fail shell startup" local case_name="mkRepo required tools fail shell startup"
local workdir local workdir
@@ -1370,6 +1418,7 @@ run_version_metadata_case
run_mk_repo_case run_mk_repo_case
run_mk_repo_command_tool_case run_mk_repo_command_tool_case
run_mk_repo_lefthook_case run_mk_repo_lefthook_case
run_mk_repo_treefmt_hook_case
run_mk_repo_tool_failure_case run_mk_repo_tool_failure_case
run_impure_bootstrap_validation_case run_impure_bootstrap_validation_case
run_legacy_api_eval_case run_legacy_api_eval_case