From 0aa1b74599176ffd7ae8ba19fd96e7b138a212ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ci=C4=99=C5=BCarkiewicz?= Date: Fri, 24 Jul 2026 16:46:04 -0700 Subject: [PATCH] feat(git): add grouped commit integration opt-out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Summary Add a default-enabled `git.enable` umbrella so projects can disable all Flakebox commit-time Git integration with one option. When disabled, Flakebox omits generated pre-commit and commit-msg hooks, the commit template, their shell activation/configuration, the pre-commit timer package, and generated Just/GitHub consumers of the absent hook. Preserve the existing granular options for partial control. ### Details Gate the three existing generation and activation branches with `git.enable` while leaving contributed check configuration and each partial enable option unchanged. Gate the Just lint recipe/final-check dependency and GitHub CI lint job on effective pre-commit enablement, including the existing granular pre-commit option. This prevents future Flakebox generation, hook installation, template configuration, and dangling consumers without adding stale-state manifests or automatic deletion. Document manual cleanup of additive generated files, hooks under Git’s common directory after ownership confirmation, and the template setting only when it still equals Flakebox’s value. Add evaluation assertions for defaults, retained partial values, and package omission. Generated checks cover positive default artifacts/actions/consumers, umbrella-disabled output, and each granular artifact combination. ### Reviews An independent maintainability review initially found dangling Just/GitHub pre-commit consumers, incomplete default/granular coverage, and unsafe/incomplete manual cleanup documentation. The implementation gated consumers on effective pre-commit enablement, expanded generated-behavior coverage, and made cleanup instructions ownership- and value-aware. Follow-up review passed. ### Validation - `nix develop -c treefmt` - focused `gitHooks` Nix check - `nix develop -c selfci check` - `nix develop -c selfci check --candidate vtllymzy` --- checks/git-hooks.nix | 82 +++++++++++++++++++++++++++++++++++++++ docs/technical-details.md | 35 +++++++++++++++++ lib/modules/git.nix | 10 +++-- lib/modules/github.nix | 2 +- lib/modules/just.nix | 4 +- 5 files changed, 127 insertions(+), 6 deletions(-) diff --git a/checks/git-hooks.nix b/checks/git-hooks.nix index 6b147e2..f0e7071 100644 --- a/checks/git-hooks.nix +++ b/checks/git-hooks.nix @@ -68,6 +68,32 @@ let inherit (flakeboxLib.config.git.pre-commit.hooks) shellcheck; }; + gitDisabledLib = mkLib pkgs { + config = { + git.enable = false; + github.ci.enable = true; + }; + }; + + preCommitDisabledLib = mkLib pkgs { + config = { + git.pre-commit.enable = false; + github.ci.enable = true; + }; + }; + + commitMsgDisabledLib = mkLib pkgs { + config.git.commit-msg.enable = false; + }; + + commitTemplateDisabledLib = mkLib pkgs { + config.git.commit-template.enable = false; + }; + + gitEnabledCiLib = mkLib pkgs { + config.github.ci.enable = true; + }; + stashHooks = mkHookFixture { stash-probe = '' grep -qx staged tracked.txt @@ -134,6 +160,23 @@ let emptyHooks = mkHookFixture { }; in assert pkgs.lib.elem timer flakeboxLib.config.env.shellPackages; +assert flakeboxLib.config.git.enable; +assert gitDisabledLib.config.git.pre-commit.enable; +assert gitDisabledLib.config.git.commit-msg.enable; +assert gitDisabledLib.config.git.commit-template.enable; +assert !(pkgs.lib.elem timer gitDisabledLib.config.env.shellPackages); +assert + !(pkgs.lib.hasInfix "hooks/pre-commit" ( + builtins.concatStringsSep "\n" gitDisabledLib.config.env.shellHooks + )); +assert + !(pkgs.lib.hasInfix "hooks/commit-msg" ( + builtins.concatStringsSep "\n" gitDisabledLib.config.env.shellHooks + )); +assert + !(pkgs.lib.hasInfix "git config commit.template" ( + builtins.concatStringsSep "\n" gitDisabledLib.config.env.shellHooks + )); pkgs.runCommand "git-hooks-tests" { nativeBuildInputs = [ @@ -178,6 +221,45 @@ pkgs.runCommand "git-hooks-tests" fi bash -n "$commit_msg" + [ -e "${flakeboxLib.root}/misc/git-hooks/commit-template.txt" ] + grep -q 'git config commit.template misc/git-hooks/commit-template.txt' \ + "${flakeboxLib.root}/.config/flakebox/shellHook.sh" + grep -q 'hooks/pre-commit' "${flakeboxLib.root}/justfile" + grep -q 'misc/git-hooks/pre-commit' \ + "${gitEnabledCiLib.root}/.github/workflows/flakebox-ci.yml" + + # The grouped opt-out omits every generated commit integration artifact and + # every installer/configuration action and generated consumer. + [ ! -e ${gitDisabledLib.root}/misc/git-hooks/pre-commit ] + [ ! -e ${gitDisabledLib.root}/misc/git-hooks/commit-msg ] + [ ! -e ${gitDisabledLib.root}/misc/git-hooks/commit-template.txt ] + disabled_shell_hook="${gitDisabledLib.root}/.config/flakebox/shellHook.sh" + ! grep -q 'hooks/pre-commit' "$disabled_shell_hook" + ! grep -q 'hooks/commit-msg' "$disabled_shell_hook" + ! grep -q 'git config commit.template' "$disabled_shell_hook" + ! grep -q 'hooks/pre-commit' "${gitDisabledLib.root}/justfile" + ! grep -q 'misc/git-hooks/pre-commit' \ + "${gitDisabledLib.root}/.github/workflows/flakebox-ci.yml" + + # Existing granular options still suppress only their own integration, and + # pre-commit consumers follow the effective pre-commit setting. + [ ! -e ${preCommitDisabledLib.root}/misc/git-hooks/pre-commit ] + [ -e ${preCommitDisabledLib.root}/misc/git-hooks/commit-msg ] + [ -e ${preCommitDisabledLib.root}/misc/git-hooks/commit-template.txt ] + ! grep -q 'hooks/pre-commit' "${preCommitDisabledLib.root}/justfile" + ! grep -q 'misc/git-hooks/pre-commit' \ + "${preCommitDisabledLib.root}/.github/workflows/flakebox-ci.yml" + + [ -e ${commitMsgDisabledLib.root}/misc/git-hooks/pre-commit ] + [ ! -e ${commitMsgDisabledLib.root}/misc/git-hooks/commit-msg ] + [ -e ${commitMsgDisabledLib.root}/misc/git-hooks/commit-template.txt ] + + [ -e ${commitTemplateDisabledLib.root}/misc/git-hooks/pre-commit ] + [ -e ${commitTemplateDisabledLib.root}/misc/git-hooks/commit-msg ] + [ ! -e ${commitTemplateDisabledLib.root}/misc/git-hooks/commit-template.txt ] + ! grep -q 'git config commit.template' \ + "${commitTemplateDisabledLib.root}/.config/flakebox/shellHook.sh" + # The timer preserves success, failures, errexit, signals, and byte-exact # ordinary output when no warning is emitted. function check_output() { diff --git a/docs/technical-details.md b/docs/technical-details.md index 58f7a63..925fffd 100644 --- a/docs/technical-details.md +++ b/docs/technical-details.md @@ -67,6 +67,41 @@ value runs the checks normally. This does not affect hooks not generated by Flakebox. Git's `git commit --no-verify` is also available as a one-shot alternative. +### Disabling commit integration + +Set `git.enable = false` in the Flakebox configuration to disable the complete +Git commit integration. Flakebox then does not generate or install its +`pre-commit` or `commit-msg` hooks, generate its commit-message template, or set +Git's `commit.template` configuration. The existing `git.pre-commit.enable`, +`git.commit-msg.enable`, and `git.commit-template.enable` options remain +available for partial control when `git.enable` is true. + +This option does not clean up state installed by an earlier configuration. +After changing it, remove the old generated files: + +```console +rm -f misc/git-hooks/pre-commit \ + misc/git-hooks/commit-msg \ + misc/git-hooks/commit-template.txt +``` + +Remove installed hooks only after confirming they are Flakebox-owned: + +```console +hooks_dir="$(git rev-parse --git-common-dir)/hooks" +ls -l "$hooks_dir/pre-commit" "$hooks_dir/commit-msg" +rm -f "$hooks_dir/pre-commit" "$hooks_dir/commit-msg" +``` + +Finally, remove the template setting only when it still has the Flakebox value: + +```console +if [ "$(git config --get commit.template || true)" = \ + "misc/git-hooks/commit-template.txt" ]; then + git config --unset commit.template +fi +``` + ## Flakebox `lib` output Flakebox's Flake exposes a `lib` flake output which allows: diff --git a/lib/modules/git.nix b/lib/modules/git.nix index d9d984c..ef634e9 100644 --- a/lib/modules/git.nix +++ b/lib/modules/git.nix @@ -12,6 +12,10 @@ in { options.git = { + enable = lib.mkEnableOption "Flakebox Git commit hooks and commit template integration" // { + default = true; + }; + pre-commit = { enable = lib.mkEnableOption "git pre-commit hook" // { default = true; @@ -107,7 +111,7 @@ in ''; }) - (lib.mkIf config.git.commit-msg.enable { + (lib.mkIf (config.git.enable && config.git.commit-msg.enable) { rootDir."misc/git-hooks/commit-msg" = let content = ( @@ -168,7 +172,7 @@ in }) - (lib.mkIf config.git.pre-commit.enable { + (lib.mkIf (config.git.enable && config.git.pre-commit.enable) { rootDir."misc/git-hooks/pre-commit" = let indentString = @@ -280,7 +284,7 @@ in }) - (lib.mkIf config.git.commit-template.enable { + (lib.mkIf (config.git.enable && config.git.commit-template.enable) { rootDir."misc/git-hooks/commit-template.txt" = { source = pkgs.writeText "commit-template" ( lib.removeSuffix "\n" '' diff --git a/lib/modules/github.nix b/lib/modules/github.nix index c40348c..57208b0 100644 --- a/lib/modules/github.nix +++ b/lib/modules/github.nix @@ -184,7 +184,7 @@ in }) { - lint = { + lint = lib.mkIf (config.git.enable && config.git.pre-commit.enable) { name = "Lint"; runs-on = config.github.ci.runsOn; steps = [ diff --git a/lib/modules/just.nix b/lib/modules/just.nix index aa107e9..0bb41da 100644 --- a/lib/modules/just.nix +++ b/lib/modules/just.nix @@ -159,7 +159,7 @@ in ''; }; - lint = { + lint = lib.mkIf (config.git.enable && config.git.pre-commit.enable) { priority = 100; content = '' # run lints (git pre-commit hook) @@ -174,7 +174,7 @@ in priority = 100; content = '' # run all checks recommended before opening a PR - final-check: lint ${ + final-check: ${lib.optionalString (config.git.enable && config.git.pre-commit.enable) "lint"} ${ if config.just.rules ? clippy && config.just.rules.clippy.enable then "clippy" else "" } #!/usr/bin/env bash