GithubHelp home page GithubHelp logo

captainhookphp / captainhook Goto Github PK

View Code? Open in Web Editor NEW
957.0 20.0 86.0 3.68 MB

CaptainHook is a very flexible git hook manager for software developers that makes sharing git hooks with your team a breeze.

Home Page: http://captainhook.info

License: MIT License

PHP 99.81% Shell 0.03% Dockerfile 0.16%
php git git-hooks hacktoberfest automation code-quality

captainhook's Introduction

Latest Stable Version Minimum PHP Version Downloads License Build Status Scrutinizer Code Quality Code Coverage Twitter

CaptainHook

CaptainHook logo

CaptainHook is an easy to use and very flexible git hook library for php developers. It enables you to configure your git hook actions in a simple json file.

You can use CaptainHook to validate or prepare your commit messages, ensure code quality or run unit tests before you commit or push changes to git. You can automatically clear local caches or install the latest composer dependencies after pulling the latest changes.

CaptainHook makes it easy to share hooks within your team and even can make sure that everybody in your team activates the hooks locally.

You can run cli commands, use some built in validators, or write your own PHP classes that get executed by CaptainHook. For more information have a look at the documentation.

Installation

The preferred method to install CaptainHook is to install the PHAR file. You can do so by using Phive or download the PHAR from the GitHub release page.

phive install captainhook

Or use Composer to install it.

composer require --dev captainhook/captainhook-phar

If you want to get the source code with all its dependencies you can use:

composer require --dev captainhook/captainhook

Setup

After installing CaptainHook you can use the captainhook executable to create a configuration.

vendor/bin/captainhook configure

After creating the captainhook.json configuration file you have to activate the hooks by installing them to your local .git directory. To do so just run the following CaptainHook command.

vendor/bin/captainhook install

Have a look at this short installation video.

Install demo

One of the goals of CaptainHook is to make it easy for a team to use the same git hooks. If you want to make sure everybody actually installs the hooks you can use the small Composer plugin hook-installer. It runs the captainhook install command everytime you run a Composer command.

composer require --dev captainhook/hook-installer

Off course teammates can still commit without executing the hooks, that's why you should run appropriate checks on the backend as well. But at least this way nobody can forget to install them "by accident".

Configuration

Here's an example captainhook.json configuration file.

{
  "commit-msg": {
    "enabled": true,
    "actions": [
      {
        "action": "\\CaptainHook\\App\\Hook\\Message\\Action\\Beams",
      }
    ]
  },
  "pre-commit": {
    "enabled": true,
    "actions": [
      {
        "action": "phpunit"
      },
      {
        "action": "phpcs --standard=psr2 src"
      }
    ]
  },
  "pre-push": {
    "enabled": false,
    "actions": []
  }
}

Contributing

So you'd like to contribute to the CaptainHook library? Excellent! Thank you very much. I can absolutely use your help.

Have a look at the contribution guidelines.

captainhook's People

Contributors

aboks avatar alexandrmazur96 avatar bcremer avatar be-heiglandreas avatar boesing avatar chriskapp avatar davidjeddy avatar fxedel avatar glensc avatar heiglandreas avatar hoogi91 avatar icanhazstring avatar iherak avatar iquito avatar localheinz avatar norgeindian avatar peter279k avatar purplebooth avatar pyrokar avatar ramsey avatar raphaelstolt avatar ruscon avatar sebastianfeldmann avatar shochdoerfer avatar spajxo avatar wirone avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

captainhook's Issues

[Feature] Adding `conditions` to `actions`?

I wanted to write an Action that executes composer install after a merge or a checkout if composer.json or composer.lock where changed.

First I created an Action called ...\Composer\Action\TriggerInstall, then I realized I could write it in a more generic way. ...\Change\Action\CmdTrigger where you could specify the list of files to watch and a cli command to execute.

But being limited to calling cli commands didn't feel right. So in order to allow PHP "commands" as well I could write something like ...\Change\Action\PHPTrigger.
But passing options to this "command" would create an action config in an action config and that feels even more strange.

To describe the problem in a very abstract way I want to to execute a certain action only under specific circumstances. So I thought about adding conditions to an action configuration.

This could look like this.

    "post-checkout": {
        "enabled": true,
        "actions": [
            {
                "action": "composer install",
                "options": [],
                "conditions": [
                    {
                        "class": "\\CaptainHook\\App\\Hook\\Condition\\FileChange",
                        "args": {
                            "files": [
                                "composer.json",
                                "composer.lock"
                            ]
                        }
                    }
                ]
            }
        ]
    }

This would blow up the configuration quite a bit but would be a very flexible solution. People could write their own conditions by implementing a simple one method interface.

Any feedback would be appreciated.

Local captainhook.json support

Feature Request

Hey there,

We are many developers and thus, some of us have a docker configuration, others may have vagrant and so on.

I would prefer having a way to create example local configurations, where our developers can re-configure the projects configuration to their environment.

Example

Project configuration

captainhook.json

{
	"config": {
		"verbosity": "normal"
	}
}

Developers own configuration which is excluded from VCS

captainhook.local.json

{
	"config": {
		"verbosity": "verbose",
		"run-mode": "docker",
		"run-exec": "docker exec whatever"
	}
}

The deal could be, that the local file is always next to the captainhook.json.
This might make the implementation quite easy.

What do you think about it?

Space in captainhook.json path leading to not found in 5.x

I tried to upgade from 4.x to 5.x today and my captainhook config file is not found anymore - this is the output:

CaptainHook Composer Plugin
  Using CaptainHook config: /home/andreas/X/2015 - Project/captainhook.json
sh: 1: /home/andreas/X/2015: not found

                                                                                       
  [RuntimeException]                                                                   
  Shiver me timbers! CaptainHook could not install yer git hooks! (invalid-exit-code)  

It seems sh is called in a way that is not safe with spaces?

Upgrade fails with missing class

After upgrading from CaptainHook 4.5.4 to 4.5.8, the following error appears on existing checkouts:

Fatal error: Uncaught Error: Class 'SebastianFeldmann\Camino\Path\Directory' not found in vendor/captainhook/captainhook/src/Hook/Template/Builder.php:60

The sebastianfeldmann/camino package is being installed as part of the update, and the autoloader has not yet updated, so the post-update hooks fail. This issue is breaking our builds and causing some developer confusion.

Relaunch editor if message is invalid or save to tempoarary file?

Currently if I type a commit message and it is rejected, then I have to commit again, and re-type everything (which could have been a significant amount of code).

Would be good to automatically respawn the editor (using the EDITOR env var f.e.) with an additional comment showing the validation failures.

Or, I guess, to simply save the commit message to a temporary file where it can be re-sourced.

Wrong path to captainhook-run with run-mode: docker

We're using run-mode: docker in our config and since v4.5.4, the hook scripts contain a wrong path to the captainhook-run binary.

Example commit-msg

#!/usr/bin/env bash
docker exec container ./absolute/path/to/vendor/bin/captainhook-run commit-msg "$@"

(Note the leading dot before the absolute path).

Before, it contained the correct relative path

#!/usr/bin/env bash
docker exec container ./vendor/bin/captainhook-run commit-msg "$@"

Error on empty commit message

I often use an empty commit message to cancel my commit as per the GIT commit help:

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.

I don't think captain hook is currently handling this case?

Action: \CaptainHook\App\Hook\Message\Action\Beams                                                                                                                                            
PHP Notice:  Undefined offset: 0 in /home/daniel/www/dantleech/maestro/vendor/sebastianfeldmann/git/src/CommitMessage.php on line 200
PHP Stack trace:                                                                
PHP   1. {main}() /home/daniel/www/dantleech/maestro/.git/hooks/commit-msg:0
PHP   2. CaptainHook\App\Console\Application\Hook->run() /home/daniel/www/dantleech/maestro/.git/hooks/commit-msg:14
PHP   3. CaptainHook\App\Console\Application\Hook->doRun() /home/daniel/www/dantleech/maestro/vendor/symfony/console/Application.php:149
PHP   4. CaptainHook\App\Console\Command\Hook\CommitMsg->run() /home/daniel/www/dantleech/maestro/vendor/captainhook/captainhook/src/Console/Application/Hook.php:96
PHP   5. CaptainHook\App\Console\Command\Hook\CommitMsg->execute() /home/daniel/www/dantleech/maestro/vendor/symfony/console/Command/Command.php:255
PHP   6. CaptainHook\App\Runner\Hook\CommitMsg->run() /home/daniel/www/dantleech/maestro/vendor/captainhook/captainhook/src/Console/Command/Hook.php:94
PHP   7. CaptainHook\App\Runner\Hook\CommitMsg->handleAction() /home/daniel/www/dantleech/maestro/vendor/captainhook/captainhook/src/Runner/Hook.php:123                                      
PHP   8. CaptainHook\App\Runner\Hook\CommitMsg->executePhpAction() /home/daniel/www/dantleech/maestro/vendor/captainhook/captainhook/src/Runner/Hook.php:147
PHP   9. CaptainHook\App\Runner\Action\PHP->execute() /home/daniel/www/dantleech/maestro/vendor/captainhook/captainhook/src/Runner/Hook.php:161
PHP  10. CaptainHook\App\Hook\Message\Action\Beams->execute() /home/daniel/www/dantleech/maestro/vendor/captainhook/captainhook/src/Runner/Action/PHP.php:48
PHP  11. CaptainHook\App\Hook\Message\Action\Beams->validate() /home/daniel/www/dantleech/maestro/vendor/captainhook/captainhook/src/Hook/Message/Action/Beams.php:46
PHP  12. CaptainHook\App\Hook\Message\RuleBook->validate() /home/daniel/www/dantleech/maestro/vendor/captainhook/captainhook/src/Hook/Message/Action/Book.php:59
PHP  13. CaptainHook\App\Hook\Message\Rule\LimitSubjectLength->pass() /home/daniel/www/dantleech/maestro/vendor/captainhook/captainhook/src/Hook/Message/RuleBook.php:69
PHP  14. SebastianFeldmann\Git\CommitMessage->getSubject() /home/daniel/www/dantleech/maestro/vendor/captainhook/captainhook/src/Hook/Message/Rule/LimitSubjectLength.php:50
                   
In PHP.php line 53:                                                             
               
  PHP Error:Return value of SebastianFeldmann\Git\CommitMessage::getSubject()
   must be of the type string, null returned                                                                                                                                                  

Post-pull hook

Hello,

I would like to have a post-pull hook in my project, so every time I execute a git pull it could clear the local cache, execute other developers database migrations, or so. Do I make a PR? I think it should be more or less as #22.

PHPStan runs forever as pre-commit hook

This might be similar to #35, but I opened a new issue to be more specific:

I have a reasonably large codebase with lots of legacy code, and am using PHPStan and Psalm for new code while ignoring the issues in the older code. I usually run PHPStan via composer (so I can just type in composer phpstan) and that works fine.

I attempted a few times to add the exact same command I use via composer scripts as a pre-commit hook with CaptainHook, but it seems PHPStan crashes without CaptainHook noticing, as the PHPStan command just runs forever and never returns: via composer it runs for maybe 15-20 seconds, but even after waiting for 10 minutes or longer via CaptainHook nothing happens. This has been an issue ever since I adopted PHPStan for the project (about 6 months ago) and is still occuring with the latest PHP 7.3 version and the latest CaptainHook and PHPStan versions.

Why I report this here instead of with PHPStan is that it does work via composer scripts, which should work similarly as CaptainHook (with spawning another process, running it and then reporting back), and because CaptainHook just waits forever on PHPStan and there is no error message or hint what actually happened to PHPStan, so I actually wouldn't know what problem to report, where it occurs and why.

This problem does not occur with a new 6-month-old codebase, so there is something in this legacy project that leads to the problem. Ideally there would be a way to show the output from PHPStan while running CaptainHook, or maybe something that composer scripts does can be added to CaptainHook to overcome this.

Wrong path to captainhook-run with run-mode: docker (v 4.5.7=

I have CaptainHook version 4.5.7 2019-11-24 running and run into the same problem as outlined in #61. The difference might be that the paths on the host and in the container differ a bit - not sure how the path to captainhook-run is determined.

Directory layout on the host:

./.git
./app/captainhook.json

Directory layout in container:

/var/www/.git
/var/www/html/captainhook.json

So basically everything stored locally in app get's stored in html in the container. Since I use a pre-built container I can't do much about it.

The generated bash script looks like this (WRONG) - was generated in the container:

#!/usr/bin/env bash
docker exec phpfpm ./html/vendor/bin/captainhook-run commit-msg "$@"

and should be:

#!/usr/bin/env bash
docker exec phpfpm ./vendor/bin/captainhook-run commit-msg "$@"

Maybe you want to define a base path in the config for some more "exotic" installations?

Hook execution not working for non standard project setup

Assume the following project structure

/path/to/project/.git
/path/to/project/subfolder/vendor/

Inside the folder /path/to/project/subfolder/ i will run the composer commands
composer require --dev sebastianfeldmann/captainhook:~1.0

What i get is this
/path/to/project/subfolder/bin/captainhook

Using this binary, i get the error that there is not .git folder available. Which is true because it is not inside the 'subfolder'. If i switch the folder to be beside the .git folder. The configure works fine. But the hooks itself won't work because of the hardcoded path to the vendor folder.

The hook path to vendor is always ../../vendor
Which should be ../../subfolder/vendor on my project.

Would be nice if the captainhook.json config can be given some kind of folder config for .git and vendor/ so the hooks can be configured in the right way.

Discussion - Force PHAR usage via sub package

Problem

Currently there are two ways to execute the Cap'n. The first is executing the PHP script installed via composer, the second one is via PHAR file. Both methods have some minor but significant differences that could lead to maintaining problems in the future.

Possible solution

To get back to a single way of executing the Cap'n the idea is to transform the main captainhook composer package into a PHAR container package only containing the PHAR files and move the source code and all to a new captainhook-app repository. As an example you can see something similar in the PHPStan repository.

Pro

  • Only one way of execution
  • Easier to maintain
  • Less bugs (hopefully)
  • Never any version collisions because of the isolated scoped PHAR file (this is HUGE)

Contra

  • Testing a dev-master state would get really complicated and will potentially stupidly increase the size of the PHAR container repository if we would commit a new PHAR for every push into the app repository.
  • Not important but I personally do not like the idea of committing binary files to a repository :)

Side effect

Doing this change would have a nice side effect. The main package could be converted into a composer plugin. This would make the handling of certain events easier (install/uninstall) and we could deprecate the plugin-composer package and always have the functionality build in from the get go.
If someone needs the pure variant without composer, they could always go for the PHAR only installation.

Things to consider

A possible migration could be challenging. Older versions should still be installable so we would have to "leave" the source code and all inside the main repository (at least in the git history) even if it is not needed there for the latest version. No biggy but then we would have 2 repositories with the full source code history until version 5 🤦

The release process would get massively more complicated

  • Push and tag app repository
  • Build PHAR
  • Copy PHAR to main repository
  • Commit PHAR into main repository
  • Tag main repository as well
  • Create release for main repository with PHAR and signature file

I'm happy to get feedback on this idea.

Changes via captainhook binary removes "config" entry from captainhook.json

Hey there,

using vendor/bin/captainhook to either enable, disable or add an action, the \CaptainHook\App\Config\Util::writeToDisk will only write the contents of \CaptainHook\App\Config::getJsonData.

This method only provides the configuration for known (valid) hooks but will drop the config section.

pre-commit hook - use new and modified files

Hi, is it possible to use a variable or something for all new and modified files in a commit? I would like to use codesniffer and pass the paths to these files to the codesniffer, instead of hardcoding a whole directory to sniff.

prepare-commit-msg hook prints a warning

Hey captainhook,

Got the 'prepare-commit-msg' hook installed through the plugin but there's a php notice (undefined var)... This notice prevents me to commit anything (console exit -1)... I've just removed the hooks for now but would be nice to have a fix.

captainhooks rocks !

PHP Notice:  Undefined index: prepare-commit-msg in vendor/captainhook/captainhook/src/Console/Application/Hook.php on line 133
PHP Stack trace:
PHP   1. {main}() ....git/hooks/prepare-commit-msg:0
PHP   2. CaptainHook\App\Console\Application\Hook->run() .../.git/hooks/prepare-commit-msg:18

FileChanged BC break 4.X => 5.X

Hey there,

as there was no migration path available for 4.X to 5.X, I recently realized that the FileChanged hook introduces a Constrained interface which massively slows down our workflow.

In 4.X, the FileChanged got executed as expected for any hook, in 5.X its only executed for post-merge and post-checkout.

As the FileChanged is not "applicable" for all those other hooks, any hook is executed even if no file changed.

What is the reason behind that decision?

[Feature] Running the Cap'n inside a docker container

After having mentioned the Cap'n in one of my talks, I was asked how to run git hooks when the application is running in a docker container and no php cli is available on the host. I think that is an interesting use-case, especially when you want to offer hooks for other frameworks & tools as many people these days have their own docker setup in place.

Letting the hooks run commands in a container could be a trivial thing, instead of the php based hooks, provide a shell script that would call the php hooks in docker. The container name to run would need to configurable, I guess.

However, the problem is, how to install the Cap'n without invoking Composer/Php on the host. You could potentially provide a 2nd way of installing the Cap'n via some Bash tooling then. Not sure though if it really is feasible to maintain 2 separate installers.

Prevent commits to specified branches

I know anyone can bypass commit hooks easily enough, but I'd like a rule that stops commits directly on the master branch for example.

I've come up with this so far, which seems sound but does not work:

{
    "action": "if [[ \"`git rev-parse --abbrev-ref HEAD`\" == \"master\" ]]; then exit 1; fi"
},

Am I creating the action right? Or is there a better way.

Thank you

Optimize path resolving

I am trying to run CaptainHookPHP in a Docker setup that might not be a usual setup but since the pre-built containers make some assumptions that differ from my use case I had to find a creative work-round.

Directory layout on the host:

./.git
./src/captainhook.json

Directory layout in container:

/var/www/.git
/var/www/html/captainhook.json

So basically everything stored locally in src get's mounted in html directory in the container. Since I use a pre-built container I can't do much about it. /var/www/html is defined as the working directory in the Dockerfile.

This is what the configuration in my captainhook.json file looks like:

{
    "config": {
        "run-mode": "docker",
        "run-exec": "docker-compose exec -w /var/www -T phpfpm",
        "git-directory": "/var/www/.git/",
        "run-path": "/var/www/html/vendor/bin/captainhook"
    }
}

I had to explictly change the working directory of Docker when invoking the Git Hooks because CaptainHook assumes that the config file is stored in html/captainhook.json not in captainhook.json (as the command gets to be executed in /var/www/html already thanks to the configured working directory in Docker). Interestingly also the hook install command get's triggered in /var/www/html which at first made me assume that CaptainHookPHP would know where things are located.

The same issue occurs when executing action commands, e.g. some tool located in vendor/bin, I have to add the html/ prefix as well:

{
    "action": "html/vendor/bin/phpcs --standard=Magento2 html/app/code/",
    "options": []
}

As you can see, I need to apply the html/ prefix not only for the command I want to execute but also to path I want phpcs to examine.

Long story short, I think we do not only need a git-directory config setting, but also a workdir-directory config setting so that guessing the work directory can be ommited in cases where its needed.

New 'add' command that adds a hook to the configuration

Create a CaptainHook command that allows adding commands to the configuration

$ vendor/bin/captainhook add pre-commit

Then CaptainHook should ask about the Action and the options.

Please provide the action to execute:
Do you want to add an option value (y/n): 

[Feature] Add action to stop passwords leaking

Via this blog post I came across this paper which contains a list of regex expressions to characterize potential passwords.

It would be cool to have an action which could check the modified files for potential passwords and report them. Not sure though how accurate the detection is since it's based on regex patterns. Maybe it's needed to define a whitelist of files that are "ok" to commit.

Not sure how many actions you want to provide out-of-the-box, maybe it makes sense to release this as a separate package.

Add option git-directory to configure command

In my project I have the following directory structure:
├── .git
├── directoryA
├── directoryB
│ ├── directory1
│ ├── directroy2
│ ├── vendor
│ ├── composer.json
│ ├── index.php
├── directoryB

The .git directory is in the parent directory of the directory with my composer.json and the vendor directory. The command "captainhook configure" fails because the class Repository checks if the directory from which I call the command has the .git directory. The Repository class constructor has the optional parameter $root.

It would be nice to add an option to the configure command to set a custom .git path like in the cinstall command. Maybe it would be great to save the custom path in the captionhook.json.

[Bug] Running CaptainHookPhp installer in Docker container ignores run-mode

This might be an edge-case no one so far thought of, sorry for that.

Situation is: I want to use the Captain in a frontend project where not all team members have a PHP/Composer setup running. Since the Captain supports Docker this should work fine.

This is what I tried:

  1. Install the Captain via a Docker container
docker run --rm -v $(pwd):/app -w /app prooph/composer:7.2 require --dev captainhook/captainhook
  1. Run Captain install
docker run --rm -v $(pwd):/app -w /app php:7.2-cli /app/vendor/bin/captainhook install --run-mode=docker --run-exec="docker exec php"

As a result the git hooks are stored as PHP scripts not as shell scripts, which is what I have expected. If I run the commands locally without docker, things are working fine, the git hooks are stored as shell scripts as expected.

Are there any checks if the run mode is valid which might not work in this Docker setup?

Wrong path to autoload.php in hooks if composer dependencies are not managed in root directory

Great tool! Sadly there is an issue if the composer dependencies are not managed in the project's root directory.

Let's suppose the following structure:

[...]

  • ./.git
  • ./src
  • ./tests
  • ./libs/bower
  • ./libs/composer

[...]

Now let's install CaptainHook:

cd ./libs/composer && composer require --dev captainhook/plugin-composer

Configuring CaptainHook works fine:

cd ../../ && ./libs/composer/vendor/bin/captainhook configure

The captainhook.json file is now located in the project's root directory. So far, so good.

Problem: If I now install the hooks via ...

./libs/composer/vendor/bin/captainhook install

..., the path to the composer autoloader is wrong:

#!/usr/bin/env php
<?php
$autoLoader = __DIR__ . '/../../vendor/autoload.php';

if (!file_exists($autoLoader)) {
    fwrite(STDERR, 'Composer autoload.php could not be found');
    exit(1);
}
require $autoLoader;
$config = realpath(__DIR__ . '/../../captainhook.json');
$app    = new CaptainHook\App\Console\Application\Hook();
$app->setHook('commit-msg');
$app->setConfigFile($config);
$app->run();

Determined path:

$autoLoader = __DIR__ . '/../../vendor/autoload.php';

Correct path:

$autoLoader = __DIR__ . '/../../libs/composer/vendor/autoload.php';

Doesnt't work with phpstan newer than version 0.10.8

With phpstan newer than version 0.10.8 runs captainhook very long (one hour or more).

    "pre-commit": {
        "enabled": true,
        "actions": [
            {
                "action": "php ./vendor/phpstan/phpstan/bin/phpstan analyse -l 7 -c phpstan.neon ./"
            }
        ]
    },

This ist my captainhook.json

Migration guide

Write an version 4 to version 5 migration guide (migration.html)

[Feature] Allow HookAction to run only for specific hooks

For most HookActions it's probably irrelevant to which Git hook they belong. For some HookActions like captainhook-rejectpush a specific hook needs to be configured to make sure the HookAction works as intended.

I'd love to see a method in the HookAction that will be used by the Capt'n to check which hooks are valid for this action. When running the Capt'n each action configuration for the current Git hook needs to be checked and fail in case an ActionHook is used that "does not work" in the current Git hook configuration.

Basically I see two ways to accomplish this:

  • Extend the existing CaptainHook\App\Hook\Action with a parent method that would allow the HookAction to be executed in all Git hooks (as it works now)
  • Add a new marker interface with one specific method that HookActions need to implement. If the object instance does not implement the interface it would mean execute in all Git hooks (as it works now)

[Feature] Parallel execution of actions with symfony/process in a subprocess

I am having some hooks in my captainhook configuration.
Actually, every action takes for example X seconds which all are getting summed up to the execution time of the hook.

With asynchronous handling of actions, it would be possible to minimize the execution time of each hook to the maximum execution time of the slowest action.

Using symfony/process with a new console command action for example (which would execute a single action only) could run any action in a subprocess which could be asynchronously handled by the main hook command.
After this, any action output (stderr, stdout) could be merged together and provided to the consumer.

This would even provide any failure and not just the first which failed. Therefore, any failure can be fixed at once instead of fixing one by one.

Disable the ansi output when hook runs

When running the pre-commit hook, I get the following output:

image

This makes it unreadable as you can see. My configuration is the following for this hook:

image

As you can also see, running captainhook run pre-commit --no-ansi works fine:

image

So, is this a but or do I have to specify a configuration option somewhere?

The minimal required PHP version badge should be changed

As title.

After looking at the latest commit, it looks like the future package version will drop php-7.0 support.

The minimal required PHP version badge in README.md should be changed into this https://img.shields.io/badge/php-%3E%3D%207.1-8892BF.svg link.

.git directory not in composer folder

Hi Sebastian, great repro.

Sadly we do have a setup that requires us to have our composer part of the application setup in a parent directory.

I there an option to install git-hooks in a different ".git" directory than "./.git" ?

The error I am getting is:

$ vendor/bin/captainhook install -v

[RuntimeException]
Invalid git repository: /Users/cc/www/PROJECT/sub-folder-with-composer-setup

Missing MatchesRegularExpression rule

Hi,
here https://captainhookphp.github.io/captainhook/extend.html is stated that:

For example the regular expression validation is using a RuleBook with a single rule called MatchesRegularExpression.

But I'm not able to find this MatchesRegularExpression rule. I understand that I can use the \CaptainHook\App\Hook\Message\Action\Regex action but from what I see using the plain action is slightly different.

Indeed I'd like to validate commit messages against a regex but I don't want such validation on merge commits. From what I see here: https://github.com/CaptainHookPhp/captainhook/blob/f3f48a78549c8aad7095cbbb594cb520938d3010/src/Hook/Message/Action/Book.php#L55 the rule book already have this behavior. So I'd like to configure the commit-msg hook with something like that:

"commit-msg": {
  "enabled": true,
  "actions": [
    {
      "action": "\\CaptainHook\\App\\Hook\\Message\\Action\\Rules",
      "options": [
        "\\CaptainHook\\App\\Hook\\Message\\Rule\\MatchesRegularExpression"
      ]
    }
  ]

But as I said there is no MatchesRegularExpression rule.

Should I provide a PR with that "missing" MatchesRegularExpression rule?

Issue with 5.1.2 version

Hi,

I get the following error on 5.1.2 version, which is not present on 5.1.1:

~/www/xxx/htdocs> git commit --cleanup=whitespace --allow-empty --file=/var/folders/9j/cdpx8gks7r18f1pscsnybcsm0000gn/T/smartgit-17824646918419494257tmp/commit-3531327082774907137.tmp
�[32mNo syntax errors detected�[39m
Fatal error: Uncaught Error: Call to undefined method Symfony\Component\Process\Process::fromShellCommandline() in /Users/antoine/www/xxx/htdocs/vendor/sebastianfeldmann/cli/src/Processor/Symfony.php:36
Stack trace:
#0 /Users/antoine/www/~/www/xxx/htdocs> git commit --cleanup=whitespace --allow-empty --file=/var/folders/9j/cdpx8gks7r18f1pscsnybcsm0000gn/T/smartgit-17824646918419494257tmp/commit-3531327082774907137.tmp
�[32mNo syntax errors detected�[39m
Fatal error: Uncaught Error: Call to undefined method Symfony\Component\Process\Process::fromShellCommandline() in /Users/antoine/www/xxx/htdocs/vendor/sebastianfeldmann/cli/src/Processor/Symfony.php:36
Stack trace:
#0 /Users/antoine/www/xxx/htdocs/vendor/captainhook/captainhook/src/Runner/Action/Cli.php(51): SebastianFeldmann\Cli\Processor\Symfony->run('vendor/bin/phpc...')
#1 /Users/antoine/www/xxx/htdocs/vendor/captainhook/captainhook/src/Runner/Hook.php(160): CaptainHook\App\Runner\Action\Cli->execute(Object(CaptainHook\App\Console\IO\DefaultIO), Object(SebastianFeldmann\Git\Repository), Object(CaptainHook\App\Config\Action))
#2 /Users/antoine/www/xxx/htdocs/vendor/captainhook/captainhook/src/Runner/Hook.php(129): CaptainHook\App\Runner\Hook->executeCliAction(Object(CaptainHook\App\Config\Action))
#3 /Users/antoine/www/xxx/htdocs/vendor/captainhook/captainhook/src/Runner/Hook.php(103): CaptainHook\App\Runner\Hook->handleAction(Ob in /Users/antoine/www/xxx/htdocs/vendor/sebastianfeldmann/cli/src/Processor/Symfony.php on line 36
/htdocs/vendor/captainhook/captainhook/src/Runner/Action/Cli.php(51): SebastianFeldmann\Cli\Processor\Symfony->run('vendor/bin/phpc...')
#1 /Users/antoine/www/xxx/htdocs/vendor/captainhook/captainhook/src/Runner/Hook.php(160): CaptainHook\App\Runner\Action\Cli->execute(Object(CaptainHook\App\Console\IO\DefaultIO), Object(SebastianFeldmann\Git\Repository), Object(CaptainHook\App\Config\Action))
#2 /Users/antoine/www/xxx/htdocs/vendor/captainhook/captainhook/src/Runner/Hook.php(129): CaptainHook\App\Runner\Hook->executeCliAction(Object(CaptainHook\App\Config\Action))
#3 /Users/antoine/www/xxx/htdocs/vendor/captainhook/captainhook/src/Runner/Hook.php(103): CaptainHook\App\Runner\Hook->handleAction(Ob in /Users/antoine/www/xxx/htdocs/vendor/sebastianfeldmann/cli/src/Processor/Symfony.php on line 36

Maybe the best way to support of more range of Symfony version would be to do something like the following:

if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) {
        $process = Process::fromShellCommandline($command);
} else {
        $process = new Process($command);
}

Thank you in advance for your help

Diff in `git commit -v` interpreted as part of the body, causing validation failure.

When commiting with git commit -v

If I enter the commit message with only a subject and a new line, the validator passes:

Fix CS on commit

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Mon Jun 10 09:24:29 2019 +0100

If I enter the commit message with only a subject, the validator fails:

Foobar
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#   (use "git push" to publish your local commits)

I would guess this is because -v shows a diff after the commted text in the message, which GIT ignores, but I guess the Captain just strips the commted text? (?)

Full message with git commit -v from above:

Foobar

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Mon Jun 10 09:28:40 2019 +0100
#
# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.
#   (use "git push" to publish your local commits)
#
# Changes to be committed:
#	modified:   captainhook.json
#
# Untracked files:
#	.php_cs.cache
#	.phpunit.result.cache
#	STDERR
#	dot
#	dot.dot
#	example/
#	lsp-client.log
#	maestro.log
#	out
#	out.png
#	out.ps
#	phpactor.log
#	replay.json
#
# ------------------------ >8 ------------------------
# Do not modify or remove the line above.
# Everything below it will be ignored.
diff --git a/captainhook.json b/captainhook.json
index 97b181f..a6a48ff 100644
--- a/captainhook.json
+++ b/captainhook.json
@@ -12,7 +12,7 @@
     "enabled": true,
     "actions": [
       {
-        "action": "./vendor/bin/php-cs-fixer fix"
+        "action": "./vendor/bin/php-cs-fixer fix --dry-run"
       },
       {
         "action": "./vendor/bin/phpstan analyse --level=7 lib"

Docker error configuration with own images (or how to configure with cap'n image)

I'm trying to configure captainhook to run inside my docker container with my custom docker image with PHP 7.2

# run inside my container
cd /var/ww/html/project && vendor/bin/captainhook install -f --container <my_container> -r docker

( /var/www/html/project is a docker shared folder with my git project)

If I check the git hooks configurations I found this (example)

FILE: .git/hooks/commit-msg

#!/usr/bin/env bash
docker exec <my_container> ./ndor/bin/captainhook-run commit-msg "$@"%  

And the problem seems in this file: src/Hook/Template/Builder.php because the "vendor path configuration" is based on captainhook docker images.

Question: how do you configure captainhook with your images?

Parameters passed to Git hook should be available in Action

I might be wrong but I could not find a way to access the parameters passed to the Git hook itself. Like, I am currently trying to implement a pre-push hook and need to know the remote where the push will happen to. Does Captain Hook expose that information?

Included configuration not working

If you include a configuration with actions for a hook and the local configuration does not contain a configuration for this hook the actions are not executed because the default behavior for a hook configuration is disabled.

Is it possible to disable captainhook inside docker?

Hi there, thanks for the awesome package!

We use this in our project and we have one problem, maybe you can help us to configure it correctly.

Our repository contains a docker-compose.yml with some Docker images as well as the project's source code.

The structure looks like this:

tree -d -L 2 .
.
├── ci
├── deploy
│   └── ansible
├── docker
│   ├── apache
│   ├── db
│   └── php
├── source
│   ├── config
│   ├── src
│   ├── var
│   ├── tests
│   └── vendor
└── scripts

The .git folder is at the very top level, next to ci, deploy, etc. Our vendor folder is in source/vendor. We mounted the source folder to our PHP Docker Container to /var/www/source/.

The hooks on our host-machine are working as expected, but since they are not mounted on our docker-machine, we see some error message like this:

CaptainHook Composer Plugin
  Using CaptainHook config: captainhook.json
                                              
  [RuntimeException]                          
  Invalid git repository: /var/www/source

Questions:

  1. Do you think mounting the .git directory to the PHP container is a good idea? Or do you have a better suggestion?
  2. I've already configured the git-directory, but I can't see, where this setting is stored. I would expect it in captainhook.json.
  3. Is it possible to have different git-directory configured for our host-machines and for the PHP Docker Container?

How to hide the execute hook output from CaptainHook?

Hi there,

I'm wondering if anyone else feels the same but the following message is quite annoying to me

Screenshot 2019-07-30 16 57 15

When I execute a git command, I know exactly what hook will be run after that, I also know what commands run because I can read captainhook.json.

Adding an option to captainhook.json to turn those messages off would be very helpful so the end-user can focus on the final output (in my case from GrumPHP) only.

Regards,
Toan

Conditions should accept regexes or wildcards

To make the pre-commit hooks faster when editing non php files, I'd love to execute CodeSniffer only when PHP files have been changed. The implemented conditions seem only to accept full filenames and no wildcards or regex expressions.

Any chance we could add support for this? Any pointers on how to tackle this? E.g. extend the current condition implementation or add separate condition classes?

Post commit hooks

I'am tried to use the post-commit hook but I can't unfortunately. This may be a new feature ?

Do not overwrite hooks that are installed by CaptainHook

In case you append something to your hooks like LFS support the hooks should not be overwritten.

  1. Write a comment in every hook script
# created by CaptainHook 5.0.0
  1. Search for the comment and compare the current with the version that installed the hook
  2. If the version differs install the hook with a warning that any customization will be lost
  3. If the major version is still the same don't overwrite the hook

Stream binary output instead of buffering

During binary execution the output of any binary is currently buffered and released to stdOut after the binary is finished.

It would be a bit nicer if the stdOut of any binary would be streamed to the default stdOut directly

git lfs cannot be installed when using captainhook

$ git lfs install
Hook already exists: pre-push

	#!/usr/bin/env php
	<?php
	$autoLoader = __DIR__ . '/../../vendor/autoload.php';
	
	if (!file_exists($autoLoader)) {
	fwrite(STDERR, 'Composer autoload.php could not be found');
	exit(1);
	}
	require $autoLoader;
	$config = realpath(__DIR__ . '/../../captainhook.json');
	$app    = new CaptainHook\App\Console\Application\Hook();
	$app->setHook('pre-push');
	$app->setConfigFile($config);
	$app->setRepositoryPath(dirname(dirname(__DIR__)));
	$app->run();

To resolve this, either:
  1: run `git lfs update --manual` for instructions on how to merge hooks.
  2: run `git lfs update --force` to overwrite your hook.

So I called

$ git lfs update --manual
Add the following to .git/hooks/pre-push:

	#!/bin/sh
	command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/pre-push.\n"; exit 2; }
	git lfs pre-push "$@"

But how can I merge a shell script with a PHP script?

Passing a different $length to LimitSubjectLength

I want to use the LimitSubjectLength rule but with a 60 character limit instead of the default 50. How can I pass this value to the rule?

    "commit-msg": {
        "enabled": true,
        "actions": [
            {
              "action": "\\CaptainHook\\App\\Hook\\Message\\Action\\Rules",
              "options": [
                "\\CaptainHook\\App\\Hook\\Message\\Rule\\MsgNotEmpty",
                "\\CaptainHook\\App\\Hook\\Message\\Rule\\LimitSubjectLength",
                "\\CaptainHook\\App\\Hook\\Message\\Rule\\LimitBodyLineLength"
              ]
            }
        ]
    },

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.