numtide / treefmt

one CLI to format your repo [maintainers=@zimbatm,@brianmcgee]
https://treefmt.com
MIT License
592 stars 37 forks source link

Advice for how to use `treefmt` as a pre-commit hook #164

Open ocharles opened 2 years ago

ocharles commented 2 years ago

Is your feature request related to a problem? Please describe.

treefmt looks like a great choice for a pre-commit hook. I'd like to know the options to do this.

Describe the solution you'd like

A wiki entry/example pre-commit hook script.

Describe alternatives you've considered

A bit of Googling how to write pre-commit hooks in general.

zimbatm commented 2 years ago

Related to https://github.com/numtide/treefmt/issues/78

blaggacao commented 2 years ago

https://github.com/numtide/treefmt/blob/master/contrib/pre-commit

thenonameguy commented 2 years ago

https://github.com/cachix/pre-commit-hooks.nix Seems to be an obvious candidate, composing the above library that provides the changed files to arbitrary cli scripts/binaries (like treefmt).

Using https://github.com/cachix/pre-commit-hooks.nix#nix-flakes-support as a basis, just do:

checks = {
  pre-commit-check = pre-commit-hooks.lib."${system}".run {
    src = ./.;
    hooks = {
      treefmt = {
        name = "treefmt";
        enable = true;
        description = "One CLI to format the code tree.";
        types = [ "file" ];
        pass_filenames = true;
        entry = "${pkgs.treefmt}/bin/treefmt";
      };
    };
  };
};

I guess this could be added trivially, to the existing set of modules, almost verbatim: https://github.com/cachix/pre-commit-hooks.nix/blob/master/modules/hooks.nix#L327

With this I would consider this issue resolved, works well for our use-case.

justinrubek commented 1 year ago

I'm using https://github.com/cachix/pre-commit-hooks.nix, but I had to make one change to the above. treefmt won't be able to access any of its formatters if they aren't already on PATH which causes the check to fail. It can still function as a devShell's shellHook, but I had to use makeWrapper to provide the path if I wanted it to function as a check.

    formatters = [
      pkgs.alejandra
      pkgs.rustfmt
    ];

    # wrap treefmt to provide the correct PATH with all formatters
    treefmt = pkgs.stdenv.mkDerivation {
      name = "treefmt";
      buildInputs = [pkgs.makeWrapper];
      buildCommand = ''
        makeWrapper \
          ${pkgs.treefmt}/bin/treefmt \
          $out/bin/treefmt \
          --prefix PATH : ${lib.makeBinPath formatters}
      '';
    };

Using this treefmt in the hook's entry line works for both checks and devShells.

edit: Even better, after writing this comment I looked in to it and they already have treefmt support and an example to use it. It looks much cleaner using writeShellApplication instead of makeWrapper https://github.com/cachix/pre-commit-hooks.nix/blob/fb58866e20af98779017134319b5663b8215d912/modules/hooks.nix#L386

brianmcgee commented 1 month ago

Related to https://github.com/numtide/treefmt/issues/311