Allow executing specific hook
When you have multiple pre-commit hooks, you can only use vendor/bin/captainhook pre-commit to execute all of them.
But I want to only execute a single hook on CI.
Use case: My pre-commit hook runs phpstan, php-cs-fixer, phpunit and a custom CaptainHook PHP implementation.
On CI I run phpstan, php-cs-fixer and phpunit separately. But the custom CaptainHook PHP implementation I want to run.
Ideally, I can name them, and then use vendor/bin/captainhook pre-commit the-name.
A workaround that you can use is to create captainhook.ci.json and in you captainhook.json you include it
"config": {
"includes": [
"captainhook.ci.json"
]
and in CI you run the Cap'n like this vendor/bin/captainhook pre-commit -c captainhook.ci.json.
The problem is that Actions currently do not have a unique identifier and generating one based on the action itself is tricky. At least I could not come up with a reliable solution so far that generates the same ID if you change the order of the Actions or change the Action. Without an unique identifier we would need to trigger the Action with the full "action": "THIS FULL TEXT THAT IS USED TO DEFINE THE ACTION" and I don't like that option because as soon as you change a tiny thing in your action you would need to update all direct executions.
A rough idea I have, is to add a config ID to Actions.
{
"action": "foo bar baz",
"config": {
"ID": "my-unique-id"
}
}
And if you define it you can run: vendor/bin/captainhook action my-unique-id .
But I'm not convinced that it is a viable solution and I don't think it solves the underlaying problem.
Why not allow this configuration format too:
{
"pre-commit": {
"enabled": true,
"actions": {
"phpstan": {
"action": "vendor/bin/phpstan"
},
"phpunit": {
"action": "vendor/bin/phpunit"
}
}
}
}
But adding id would also be good enough for me:
{
"pre-commit": {
"enabled": true,
"actions": [
{
"id": "phpstan",
"action": "vendor/bin/phpstan"
},
{
"id": "phpunit",
"action": "vendor/bin/phpunit"
}
]
}
}
When you specify an id, it should be unique (within the hook block).
Your suggestion would make sure it is unique but this would be a big BC break :/ And now you would have to configure an ID, because mixing ID and no-ID would not work.
My suggestion is to support 2 ways to declare it. If you use an object with keys in JSON, then you can use those as identifier.
For all existing configurations, they can't be triggered per action.
We can show an error if that is detected.
Basically, if it is a list, then show error when identifier is passed to the CLI.
This way, only people that opt in to the new format can trigger it, the rest keeps working as is.
The other option where we add an id to the action declaration can also work. Only those that have an id can be triggered per action.
Im not sure the Cap'n is the right tool to run code in CI.
The thing with the hook commands is, that they require specific inputs to function properly. For example pre-push needs data from stdIn in a specific format. So you just can't execute all Actions without the hook/git context. For the pre-commit hook Actions that mostly works but can't be guaranteed. That's why I'm hesitant to allow single Action execution. Nice for debugging, but...
It will most likely create more confusion than it provides benefit, if some Actions work and others fail.
My suggestion: I would extract your custom action code into a class/function and write a small wrapper
#!/bin/php
<?php
require "vendor/autoload.php";
$dependencies = new Dependencies();
$myClass = new MyClass;
$myClass->execute($dependencies);
Then your custom Cap'n Action looks like this
<?php
class MyAction implements Action
{
public function execute(Config $config, IO $io, Repository $repository, Config\Action $action) : void
{
$dependencies = new Dependencies();
$myClass = new MyClass;
$myClass->execute($dependencies);
}
}
And it can be executed in your custom hook, but also as a simple shell script
php bin/my-cool-action.php
Good idea, I was also thinking of separating it. Thanks for thinking about it.