captainhookphp / captainhook

CaptainHook is a very flexible git hook manager for software developers that makes sharing git hooks with your team a breeze.
http://captainhook.info
MIT License
992 stars 86 forks source link

STAGED_FILES greedy when there is conditions #215

Closed CircleCode closed 1 year ago

CircleCode commented 1 year ago

imagine the following hook:

{
  "action": "cmd -- {$STAGED_FILES|of-type:php}"
  "conditions": [
    {
      "exec": "\\CaptainHook\\App\\Hook\\Condition\\FileStaged\\ThatIs",
      "args": [
        {
          "ofType": "php",
          "inDirectory": [
            "foo/",
            "bar"
          ]
        }
      ]
    }
  ]
}

and the following staged files:

the hook will call cmd with the 3 files, and there is no way to restrict this (since we would require $STAGED_FILES|of-type:php|in-dir with 2 directories

I imagine several solutions

  1. easy one: allow multivalued in-dir filter (coma separated?), but can be very verbose when there are a lot of dirs
  2. complex one: add a filter like matchFilesCondition that would pick all the files that have been matched by all the conditions applied on files (complicated because it creates a link between condition and command, and also because it should take boolean operator on conditions into account)

Side note: I could also split my hook into one command for each dir, but this increases a lot the time required to run the hook, and this is complicated when there are a lot of dirs involved.

CircleCode commented 1 year ago

I just found thanks to your tests that this can easily be achieved with multiple uses of the placeholder:

/tests/unit/Runner/Action/Cli/Command/FormatterTest.php#L70-L75

        $formatter = new Formatter($io, $config, $repo);
        $command1  = $formatter->format('cmd1 argument {$STAGED_FILES|in-dir:foo} {$STAGED_FILES|in-dir:baz}');
        $command2  = $formatter->format('cmd2 argument {$STAGED_FILES}');

        $this->assertEquals('cmd1 argument foo/file1.php baz/file3.php', $command1);
        $this->assertEquals('cmd2 argument foo/file1.php bar/file2.php baz/file3.php', $command2);

For my example, this would be:

{
  "action": "cmd -- {$STAGED_FILES|of-type:php|in-dir:foo/} {$STAGED_FILES|of-type:php|in-dir:bar/}"
  "conditions": [
    {
      "exec": "\\CaptainHook\\App\\Hook\\Condition\\FileStaged\\ThatIs",
      "args": [
        {
          "ofType": "php",
          "inDirectory": [
            "foo/",
            "bar/"
          ]
        }
      ]
    }
  ]
}

Thus closing this issue