gitpowershellpre-commit-hookpre-commitpre-commit.com

Using pre-commit tool, is there a way to pass filenames one by one to the `entry` program?


Using pre-commit, I'm trying to invoke PSScriptAnalyzer tool as a static checker for PowerShell scripts. Since there is no pre-commit language for PowerShell and I don't want to add an additional script to the repository for this simple task, I have to resort to system language and call pwsh as a pre-installed system command.

I also don't want to run the checker as PSScriptAnalyzer -Recurse -Path . because I don't want git-ignored files or files which are not modified and are not part of the changeset to also be checked.

So I have come up with the following snippet in my .pre-commit-config.yaml file:

- repo: local
  hooks:
    - id: PSScriptAnalyzer
      name: Check Powershell scripts with PSScriptAnalyzer
      language: system
      entry: pwsh -NoProfile -NonInteractive -Command Invoke-ScriptAnalyzer -EnableExit -Path 
      files: ^.*\.ps1$
      pass_filenames: true

The problem is this command can only handle one argument being passed to it but pre-commit passes any matching file at the end of the command as arguments, resulting in an error.

pre-commit does not seem to have an option to change this behavior and pass the files individually. The host is Linux and latest versions of pre-commit and pwsh are installed inside.

How can I achieve this?


Solution

  • pre-commit intentionally does not support one-file-at-a-time because it is grossly inefficient (starting and stopping a process (or more) per file is quite slow).

    ideally the other tool (PSScriptAnalyzer) would be adjusted to support passing multiple arguments (since this will have benefits outside of pre-commit, such as usage with xargs)

    that said, you can hack around this deficiency in whatever tool you're trying to use with pre-commit via a little bit of xargs -- converting the sequence of arguments into individual calls

    here is the oldest duplicate in the issue tracker and outlines the solution (you can probably adapt the bash solution to powershell or utilize xargs -n1 if you don't care about spaces):

        entry: bash -c 'for x in "$@"; do ... "$x"; done' --
    

    disclaimer: I wrote pre-commit