├── LICENSE ├── bin └── captainhook ├── composer.json ├── phive.xml ├── phpcs.xml └── src ├── CH.php ├── Config.php ├── Config ├── Action.php ├── Condition.php ├── Factory.php ├── Hook.php ├── Options.php ├── Plugin.php ├── Run.php └── Util.php ├── Console ├── Application.php ├── Command.php ├── Command │ ├── Add.php │ ├── ConfigAware.php │ ├── Configuration.php │ ├── Disable.php │ ├── Enable.php │ ├── Hook.php │ ├── Hook │ │ ├── CommitMsg.php │ │ ├── PostCheckout.php │ │ ├── PostCommit.php │ │ ├── PostMerge.php │ │ ├── PostRewrite.php │ │ ├── PreCommit.php │ │ ├── PrePush.php │ │ └── PrepareCommitMsg.php │ ├── Info.php │ ├── Install.php │ ├── RepositoryAware.php │ └── Uninstall.php ├── IO.php ├── IO │ ├── Base.php │ ├── CollectorIO.php │ ├── ComposerIO.php │ ├── DefaultIO.php │ ├── Message.php │ └── NullIO.php ├── IOUtil.php └── Runtime │ └── Resolver.php ├── Event.php ├── Event ├── Dispatcher.php ├── Factory.php ├── Handler.php ├── Hook.php ├── HookFailed.php └── HookSucceeded.php ├── Exception ├── ActionFailed.php ├── CaptainHookException.php ├── InvalidHookName.php └── InvalidPlugin.php ├── Git ├── ChangedFiles │ ├── Detecting.php │ ├── Detector.php │ └── Detector │ │ ├── Factory.php │ │ ├── Fallback.php │ │ ├── PostRewrite.php │ │ └── PrePush.php ├── Diff │ └── FilterUtil.php ├── Range.php ├── Range │ ├── Detecting.php │ ├── Detector │ │ ├── Fallback.php │ │ ├── PostRewrite.php │ │ └── PrePush.php │ ├── Generic.php │ └── PrePush.php ├── Rev.php └── Rev │ ├── Generic.php │ ├── PrePush.php │ └── Util.php ├── Hook ├── Action.php ├── Branch │ └── Action │ │ ├── BlockFixupAndSquashCommits.php │ │ └── EnsureNaming.php ├── Cli │ └── Command.php ├── Composer │ └── Action │ │ └── CheckLockFile.php ├── Condition.php ├── Condition │ ├── Branch │ │ ├── Files.php │ │ ├── Name.php │ │ ├── NotOn.php │ │ ├── NotOnMatching.php │ │ ├── On.php │ │ └── OnMatching.php │ ├── Cli.php │ ├── Config.php │ ├── Config │ │ ├── CustomValueIsFalsy.php │ │ └── CustomValueIsTruthy.php │ ├── ConfigDependant.php │ ├── File.php │ ├── FileChanged.php │ ├── FileChanged │ │ ├── All.php │ │ ├── Any.php │ │ └── OfType.php │ ├── FileStaged.php │ ├── FileStaged │ │ ├── All.php │ │ ├── Any.php │ │ ├── InDirectory.php │ │ ├── OfType.php │ │ └── ThatIs.php │ ├── Logic.php │ ├── Logic │ │ ├── LogicAnd.php │ │ └── LogicOr.php │ └── OnBranch.php ├── Constrained.php ├── Debug.php ├── Debug │ ├── Failure.php │ └── Success.php ├── Diff │ └── Action │ │ └── BlockSecrets.php ├── EventSubscriber.php ├── File │ └── Action │ │ ├── Check.php │ │ ├── DoesNotContainRegex.php │ │ ├── Emptiness.php │ │ ├── Exists.php │ │ ├── IsEmpty.php │ │ ├── IsNotEmpty.php │ │ └── MaxSize.php ├── FileList.php ├── Message │ ├── Action │ │ ├── Beams.php │ │ ├── Book.php │ │ ├── CacheOnFail.php │ │ ├── InjectIssueKeyFromBranch.php │ │ ├── Prepare.php │ │ ├── PrepareFromFile.php │ │ ├── Regex.php │ │ └── Rules.php │ ├── EventHandler │ │ └── WriteCacheFile.php │ ├── Rule.php │ ├── Rule │ │ ├── Base.php │ │ ├── Blacklist.php │ │ ├── CapitalizeSubject.php │ │ ├── LimitBodyLineLength.php │ │ ├── LimitSubjectLength.php │ │ ├── MsgNotEmpty.php │ │ ├── NoPeriodOnSubjectEnd.php │ │ ├── SeparateSubjectFromBodyWithBlankLine.php │ │ └── UseImperativeMood.php │ ├── RuleBook.php │ └── RuleBook │ │ └── RuleSet.php ├── Notify │ ├── Action │ │ ├── IntegrateBeforePush.php │ │ └── Notify.php │ ├── Extractor.php │ └── Notification.php ├── PHP │ ├── Action │ │ ├── Linting.php │ │ └── TestCoverage.php │ ├── CoverageResolver.php │ └── CoverageResolver │ │ ├── CloverXML.php │ │ └── PHPUnit.php ├── Restriction.php ├── Template.php ├── Template │ ├── Builder.php │ ├── Docker.php │ ├── Inspector.php │ ├── Local.php │ ├── Local │ │ ├── PHP.php │ │ ├── Shell.php │ │ └── WSL.php │ └── PathInfo.php ├── UserInput │ ├── AskConfirmation.php │ └── EventHandler │ │ └── AskConfirmation.php └── Util.php ├── Hooks.php ├── Plugin ├── CaptainHook.php ├── Hook.php └── Hook │ ├── Base.php │ └── PreserveWorkingTree.php ├── Runner.php ├── Runner ├── Action.php ├── Action │ ├── Cli.php │ ├── Cli │ │ └── Command │ │ │ ├── Formatter.php │ │ │ ├── Placeholder.php │ │ │ └── Placeholder │ │ │ ├── Arg.php │ │ │ ├── BranchFiles.php │ │ │ ├── ChangedFiles.php │ │ │ ├── Config.php │ │ │ ├── Env.php │ │ │ ├── Foundation.php │ │ │ ├── StagedFiles.php │ │ │ └── StdIn.php │ ├── Log.php │ └── PHP.php ├── Bootstrap │ └── Util.php ├── Condition.php ├── Config │ ├── Change.php │ ├── Change │ │ ├── AddAction.php │ │ ├── DisableHook.php │ │ ├── EnableHook.php │ │ └── Hook.php │ ├── Creator.php │ ├── Editor.php │ ├── Reader.php │ ├── Setup.php │ └── Setup │ │ ├── Advanced.php │ │ ├── Express.php │ │ └── Guided.php ├── Files.php ├── Hook.php ├── Hook │ ├── Arg.php │ ├── CommitMsg.php │ ├── Log.php │ ├── PostCheckout.php │ ├── PostCommit.php │ ├── PostMerge.php │ ├── PostRewrite.php │ ├── PreCommit.php │ ├── PrePush.php │ ├── PrepareCommitMsg.php │ └── Printer.php ├── Installer.php ├── RepositoryAware.php ├── Uninstaller.php └── Util.php └── Storage ├── File.php └── File ├── Json.php └── Xml.php /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Sebastian Feldmann 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "captainhook/captainhook", 3 | "type": "library", 4 | "description": "PHP git hook manager", 5 | "keywords": ["git", "hooks", "pre-commit", "pre-push", "commit-msg", "prepare-commit-msg", "post-merge"], 6 | "homepage": "http://php.captainhook.info/", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Sebastian Feldmann", 11 | "email": "sf@sebastian-feldmann.info" 12 | } 13 | ], 14 | "support": { 15 | "issues": "https://github.com/captainhook-git/captainhook/issues" 16 | }, 17 | "funding": [ 18 | { 19 | "type": "github", 20 | "url": "https://github.com/sponsors/sebastianfeldmann" 21 | } 22 | ], 23 | "autoload": { 24 | "psr-4": { 25 | "CaptainHook\\App\\": "src/" 26 | } 27 | }, 28 | "autoload-dev": { 29 | "psr-4": { 30 | "CaptainHook\\App\\": "tests/unit/", 31 | "CaptainHook\\App\\Integration\\": "tests/integration/" 32 | } 33 | }, 34 | "require": { 35 | "php": ">=8.0", 36 | "ext-json": "*", 37 | "ext-spl": "*", 38 | "ext-xml": "*", 39 | "captainhook/secrets": "^0.9.4", 40 | "sebastianfeldmann/camino": "^0.9.2", 41 | "sebastianfeldmann/cli": "^3.3", 42 | "sebastianfeldmann/git": "^3.14", 43 | "symfony/console": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0", 44 | "symfony/filesystem": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0", 45 | "symfony/process": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0" 46 | }, 47 | "require-dev": { 48 | "composer/composer": "~1 || ^2.0", 49 | "mikey179/vfsstream": "~1" 50 | }, 51 | "bin": [ 52 | "bin/captainhook" 53 | ], 54 | "extra": { 55 | "branch-alias": { 56 | "dev-main": "6.0.x-dev" 57 | }, 58 | "captainhook": { 59 | "config": "captainhook.json" 60 | } 61 | }, 62 | "replace" : { 63 | "sebastianfeldmann/captainhook": "*" 64 | }, 65 | "config": { 66 | "sort-packages": true 67 | }, 68 | "scripts": { 69 | "post-install-cmd": "tools/phive install --force-accept-unsigned", 70 | "tools": "tools/phive install --force-accept-unsigned", 71 | "compile": "tools/box compile", 72 | "test": "tools/phpunit --testsuite UnitTests", 73 | "test:integration": "tools/phpunit --testsuite IntegrationTests --no-coverage", 74 | "static": "tools/phpstan analyse", 75 | "style": "tools/phpcs --standard=psr12 src tests" 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /phive.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | src 9 | tests 10 | 11 | -------------------------------------------------------------------------------- /src/CH.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace CaptainHook\App; 15 | 16 | /** 17 | * Class CH 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 0.9.0 23 | */ 24 | final class CH 25 | { 26 | /** 27 | * Current CaptainHook version 28 | */ 29 | public const VERSION = '5.25.4'; 30 | 31 | /** 32 | * Release date of the current version 33 | */ 34 | public const RELEASE_DATE = '2025-06-01'; 35 | 36 | /** 37 | * Default configuration file 38 | */ 39 | public const CONFIG = 'captainhook.json'; 40 | 41 | /** 42 | * Minimal required version for the installer 43 | */ 44 | public const MIN_REQ_INSTALLER = '5.22.0'; 45 | } 46 | -------------------------------------------------------------------------------- /src/Config/Condition.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Config; 13 | 14 | /** 15 | * Class Action 16 | * 17 | * @package CaptainHook 18 | * @author Sebastian Feldmann 19 | * @link https://github.com/captainhook-git/captainhook 20 | * @since Class available since Release 4.2.0 21 | * @internal 22 | */ 23 | class Condition 24 | { 25 | /** 26 | * Condition executable 27 | * 28 | * @var string 29 | */ 30 | private $exec; 31 | 32 | /** 33 | * Condition arguments 34 | * 35 | * @var array 36 | */ 37 | private $args; 38 | 39 | /** 40 | * Condition constructor 41 | * 42 | * @param string $exec 43 | * @param array $args 44 | */ 45 | public function __construct(string $exec, array $args = []) 46 | { 47 | $this->exec = $exec; 48 | $this->args = $args; 49 | } 50 | 51 | /** 52 | * Exec getter 53 | * 54 | * @return string 55 | */ 56 | public function getExec(): string 57 | { 58 | return $this->exec; 59 | } 60 | 61 | /** 62 | * Args getter 63 | * 64 | * @return array 65 | */ 66 | public function getArgs(): array 67 | { 68 | return $this->args; 69 | } 70 | 71 | /** 72 | * Return config data 73 | * 74 | * @return array 75 | */ 76 | public function getJsonData(): array 77 | { 78 | return [ 79 | 'exec' => $this->exec, 80 | 'args' => $this->args, 81 | ]; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Config/Options.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Config; 13 | 14 | /** 15 | * Class Options 16 | * 17 | * @package CaptainHook 18 | * @author Sebastian Feldmann 19 | * @link https://github.com/captainhook-git/captainhook 20 | * @since Class available since Release 1.0.0 21 | */ 22 | class Options 23 | { 24 | /** 25 | * Map of options 26 | * 27 | * @var array 28 | */ 29 | private $options; 30 | 31 | /** 32 | * Options constructor 33 | * 34 | * @param array $options 35 | */ 36 | public function __construct(array $options) 37 | { 38 | $this->options = $options; 39 | } 40 | 41 | /** 42 | * Return a option value 43 | * 44 | * @template ProvidedDefault 45 | * @param string $name 46 | * @param ProvidedDefault $default 47 | * @return ProvidedDefault|mixed 48 | */ 49 | public function get(string $name, $default = null) 50 | { 51 | return $this->options[$name] ?? $default; 52 | } 53 | 54 | /** 55 | * Return all options 56 | * 57 | * @return array 58 | */ 59 | public function getAll(): array 60 | { 61 | return $this->options; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Config/Plugin.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Config; 13 | 14 | use CaptainHook\App\Exception\InvalidPlugin; 15 | use CaptainHook\App\Plugin\CaptainHook; 16 | 17 | /** 18 | * Class Plugin 19 | * 20 | * @package CaptainHook 21 | * @author Sebastian Feldmann 22 | * @link https://github.com/captainhook-git/captainhook 23 | * @since Class available since Release 5.9.0 24 | */ 25 | class Plugin 26 | { 27 | /** 28 | * Plugin class 29 | * 30 | * @var string 31 | */ 32 | private $plugin; 33 | 34 | /** 35 | * Map of options name => value 36 | * 37 | * @var Options 38 | */ 39 | private $options; 40 | 41 | /** 42 | * Plugin constructor 43 | * 44 | * @param string $plugin 45 | * @param array $options 46 | */ 47 | public function __construct(string $plugin, array $options = []) 48 | { 49 | if (!is_a($plugin, CaptainHook::class, true)) { 50 | throw new InvalidPlugin("{$plugin} is not a valid CaptainHook plugin."); 51 | } 52 | 53 | $this->plugin = $plugin; 54 | $this->setupOptions($options); 55 | } 56 | 57 | /** 58 | * Setup options 59 | * 60 | * @param array $options 61 | */ 62 | private function setupOptions(array $options): void 63 | { 64 | $this->options = new Options($options); 65 | } 66 | 67 | /** 68 | * Plugin class name getter 69 | * 70 | * @return string 71 | */ 72 | public function getPlugin(): string 73 | { 74 | return $this->plugin; 75 | } 76 | 77 | /** 78 | * Return option map 79 | * 80 | * @return Options 81 | */ 82 | public function getOptions(): Options 83 | { 84 | return $this->options; 85 | } 86 | 87 | /** 88 | * Return config data 89 | * 90 | * @return array 91 | */ 92 | public function getJsonData(): array 93 | { 94 | return [ 95 | 'plugin' => $this->plugin, 96 | 'options' => $this->options->getAll(), 97 | ]; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/Console/Command.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Console; 13 | 14 | use CaptainHook\App\Console\Runtime\Resolver; 15 | use Symfony\Component\Console\Command\Command as SymfonyCommand; 16 | use Symfony\Component\Console\Input\InputInterface; 17 | use Symfony\Component\Console\Output\OutputInterface; 18 | 19 | /** 20 | * Class Command 21 | * 22 | * @package CaptainHook 23 | * @author Sebastian Feldmann 24 | * @link https://github.com/captainhook-git/captainhook 25 | * @since Class available since Release 5.0.0 26 | */ 27 | abstract class Command extends SymfonyCommand 28 | { 29 | /** 30 | * Input output handler 31 | * 32 | * @var \CaptainHook\App\Console\IO 33 | */ 34 | private $io; 35 | 36 | /** 37 | * Runtime resolver 38 | * 39 | * @var \CaptainHook\App\Console\Runtime\Resolver 40 | */ 41 | protected Resolver $resolver; 42 | 43 | /** 44 | * Command constructor 45 | * 46 | * @param \CaptainHook\App\Console\Runtime\Resolver $resolver 47 | */ 48 | public function __construct(Resolver $resolver) 49 | { 50 | $this->resolver = $resolver; 51 | parent::__construct(); 52 | } 53 | 54 | /** 55 | * IO setter 56 | * 57 | * @param \CaptainHook\App\Console\IO $io 58 | */ 59 | public function setIO(IO $io): void 60 | { 61 | $this->io = $io; 62 | } 63 | 64 | /** 65 | * IO interface getter 66 | * 67 | * @param \Symfony\Component\Console\Input\InputInterface $input 68 | * @param \Symfony\Component\Console\Output\OutputInterface $output 69 | * @return \CaptainHook\App\Console\IO 70 | */ 71 | public function getIO(InputInterface $input, OutputInterface $output): IO 72 | { 73 | if (null === $this->io) { 74 | $this->io = new IO\DefaultIO($input, $output, $this->getHelperSet()); 75 | } 76 | return $this->io; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Console/Command/Add.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Console\Command; 13 | 14 | use CaptainHook\App\Console\IOUtil; 15 | use CaptainHook\App\Runner\Config\Editor; 16 | use Symfony\Component\Console\Input\InputArgument; 17 | use Symfony\Component\Console\Input\InputInterface; 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | 20 | /** 21 | * Class Add 22 | * 23 | * @package CaptainHook 24 | * @author Sebastian Feldmann 25 | * @link https://github.com/captainhook-git/captainhook 26 | * @since Class available since Release 4.2.0 27 | */ 28 | class Add extends ConfigAware 29 | { 30 | /** 31 | * Configure the command 32 | * 33 | * @return void 34 | */ 35 | protected function configure(): void 36 | { 37 | parent::configure(); 38 | $this->setName('config:add') 39 | ->setAliases(['add']) 40 | ->setDescription('Add an action to your hook configuration') 41 | ->setHelp('Add an action to your hook configuration') 42 | ->addArgument('hook', InputArgument::REQUIRED, 'Hook you want to add the action to'); 43 | } 44 | 45 | /** 46 | * Execute the command 47 | * 48 | * @param \Symfony\Component\Console\Input\InputInterface $input 49 | * @param \Symfony\Component\Console\Output\OutputInterface $output 50 | * @return int 51 | * @throws \CaptainHook\App\Exception\InvalidHookName 52 | * @throws \Exception 53 | */ 54 | protected function execute(InputInterface $input, OutputInterface $output): int 55 | { 56 | $io = $this->getIO($input, $output); 57 | $config = $this->createConfig($input, true); 58 | 59 | $editor = new Editor($io, $config); 60 | $editor->setHook(IOUtil::argToString($input->getArgument('hook'))) 61 | ->setChange('AddAction') 62 | ->run(); 63 | 64 | return 0; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Console/Command/Disable.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Console\Command; 13 | 14 | use CaptainHook\App\Console\IOUtil; 15 | use CaptainHook\App\Runner\Config\Editor; 16 | use Symfony\Component\Console\Input\InputArgument; 17 | use Symfony\Component\Console\Input\InputInterface; 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | 20 | /** 21 | * Class Add 22 | * 23 | * @package CaptainHook 24 | * @author Sebastian Feldmann 25 | * @link https://github.com/captainhook-git/captainhook 26 | * @since Class available since Release 4.2.0 27 | */ 28 | class Disable extends ConfigAware 29 | { 30 | /** 31 | * Configure the command 32 | * 33 | * @return void 34 | */ 35 | protected function configure(): void 36 | { 37 | parent::configure(); 38 | $this->setName('config:disable') 39 | ->setAliases(['disable']) 40 | ->setDescription('Disable the handling for a hook in your configuration') 41 | ->setHelp('Disable the handling for a hook in your configuration') 42 | ->addArgument('hook', InputArgument::REQUIRED, 'Hook you want to disable'); 43 | } 44 | 45 | /** 46 | * Execute the command 47 | * 48 | * @param \Symfony\Component\Console\Input\InputInterface $input 49 | * @param \Symfony\Component\Console\Output\OutputInterface $output 50 | * @return int 51 | * @throws \CaptainHook\App\Exception\InvalidHookName 52 | * @throws \Exception 53 | */ 54 | protected function execute(InputInterface $input, OutputInterface $output): int 55 | { 56 | $io = $this->getIO($input, $output); 57 | $config = $this->createConfig($input, true); 58 | 59 | $editor = new Editor($io, $config); 60 | $editor->setHook(IOUtil::argToString($input->getArgument('hook'))) 61 | ->setChange('DisableHook') 62 | ->run(); 63 | 64 | return 0; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Console/Command/Enable.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Console\Command; 13 | 14 | use CaptainHook\App\Console\IOUtil; 15 | use CaptainHook\App\Runner\Config\Editor; 16 | use Symfony\Component\Console\Input\InputArgument; 17 | use Symfony\Component\Console\Input\InputInterface; 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | 20 | /** 21 | * Class Add 22 | * 23 | * @package CaptainHook 24 | * @author Sebastian Feldmann 25 | * @link https://github.com/captainhook-git/captainhook 26 | * @since Class available since Release 4.2.0 27 | */ 28 | class Enable extends ConfigAware 29 | { 30 | /** 31 | * Configure the command 32 | * 33 | * @return void 34 | */ 35 | protected function configure(): void 36 | { 37 | parent::configure(); 38 | $this->setName('config:enable') 39 | ->setAliases(['enable']) 40 | ->setDescription('Enable the handling for a hook in your configuration') 41 | ->setHelp('Enable the handling for a hook in your configuration') 42 | ->addArgument('hook', InputArgument::REQUIRED, 'Hook you want to enable'); 43 | } 44 | 45 | /** 46 | * Execute the command 47 | * 48 | * @param \Symfony\Component\Console\Input\InputInterface $input 49 | * @param \Symfony\Component\Console\Output\OutputInterface $output 50 | * @return int 51 | * @throws \CaptainHook\App\Exception\InvalidHookName 52 | * @throws \Exception 53 | */ 54 | protected function execute(InputInterface $input, OutputInterface $output): int 55 | { 56 | $io = $this->getIO($input, $output); 57 | $config = $this->createConfig($input, true); 58 | 59 | $editor = new Editor($io, $config); 60 | $editor->setHook(IOUtil::argToString($input->getArgument('hook'))) 61 | ->setChange('EnableHook') 62 | ->run(); 63 | 64 | return 0; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Console/Command/Hook/CommitMsg.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Console\Command\Hook; 13 | 14 | use CaptainHook\App\Console\Command\Hook; 15 | use CaptainHook\App\Hooks; 16 | use Symfony\Component\Console\Input\InputArgument; 17 | 18 | /** 19 | * Class CommitMessage 20 | * 21 | * @package CaptainHook 22 | * @author Sebastian Feldmann 23 | * @link https://github.com/captainhook-git/captainhook 24 | * @since Class available since Release 0.9.0 25 | */ 26 | class CommitMsg extends Hook 27 | { 28 | /** 29 | * Hook to execute 30 | * 31 | * @var string 32 | */ 33 | protected string $hookName = Hooks::COMMIT_MSG; 34 | 35 | /** 36 | * Configure the command 37 | * 38 | * @return void 39 | */ 40 | protected function configure(): void 41 | { 42 | parent::configure(); 43 | $this->addArgument(Hooks::ARG_MESSAGE_FILE, InputArgument::REQUIRED, 'File containing the commit message.'); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Console/Command/Hook/PostCheckout.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Console\Command\Hook; 13 | 14 | use CaptainHook\App\Console\Command\Hook; 15 | use CaptainHook\App\Hooks; 16 | use Symfony\Component\Console\Input\InputArgument; 17 | 18 | /** 19 | * Class PostCheckout 20 | * 21 | * @package CaptainHook 22 | * @author Sebastian Feldmann 23 | * @link https://github.com/captainhook-git/captainhook 24 | * @since Class available since Release 4.1.0 25 | */ 26 | class PostCheckout extends Hook 27 | { 28 | /** 29 | * Hook to execute. 30 | * 31 | * @var string 32 | */ 33 | protected string $hookName = Hooks::POST_CHECKOUT; 34 | 35 | /** 36 | * Configure the command 37 | * 38 | * @return void 39 | */ 40 | protected function configure(): void 41 | { 42 | parent::configure(); 43 | $this->addArgument(Hooks::ARG_PREVIOUS_HEAD, InputArgument::OPTIONAL, 'Previous HEAD'); 44 | $this->addArgument(Hooks::ARG_NEW_HEAD, InputArgument::OPTIONAL, 'New HEAD'); 45 | $this->addArgument(Hooks::ARG_MODE, InputArgument::OPTIONAL, 'Checkout mode 1 branch 0 file'); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Console/Command/Hook/PostCommit.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Console\Command\Hook; 13 | 14 | use CaptainHook\App\Console\Command\Hook; 15 | use CaptainHook\App\Hooks; 16 | 17 | /** 18 | * Class PostCommit 19 | * 20 | * @package CaptainHook 21 | * @author Sebastian Feldmann 22 | * @link https://github.com/captainhook-git/captainhook 23 | * @since Class available since Release 0.9.0 24 | */ 25 | class PostCommit extends Hook 26 | { 27 | /** 28 | * Hook to execute. 29 | * 30 | * @var string 31 | */ 32 | protected string $hookName = Hooks::POST_COMMIT; 33 | } 34 | -------------------------------------------------------------------------------- /src/Console/Command/Hook/PostMerge.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Console\Command\Hook; 13 | 14 | use CaptainHook\App\Console\Command\Hook; 15 | use CaptainHook\App\Hooks; 16 | use Symfony\Component\Console\Input\InputArgument; 17 | 18 | /** 19 | * Class PostMerge 20 | * 21 | * @package CaptainHook 22 | * @author Sebastian Feldmann 23 | * @link https://github.com/captainhook-git/captainhook 24 | * @since Class available since Release 4.0.1 25 | */ 26 | class PostMerge extends Hook 27 | { 28 | /** 29 | * Hook to execute. 30 | * 31 | * @var string 32 | */ 33 | protected string $hookName = Hooks::POST_MERGE; 34 | 35 | /** 36 | * Configure the command 37 | * 38 | * @return void 39 | */ 40 | protected function configure(): void 41 | { 42 | parent::configure(); 43 | $this->addArgument(Hooks::ARG_SQUASH, InputArgument::OPTIONAL, 'Merge was done with a squash merge.'); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Console/Command/Hook/PostRewrite.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Console\Command\Hook; 13 | 14 | use CaptainHook\App\Console\Command\Hook; 15 | use CaptainHook\App\Hooks; 16 | use Symfony\Component\Console\Input\InputArgument; 17 | 18 | /** 19 | * Class PostRewrite 20 | * 21 | * @package CaptainHook 22 | * @author Sebastian Feldmann 23 | * @link https://github.com/captainhook-git/captainhook 24 | * @since Class available since Release 5.4.0 25 | */ 26 | class PostRewrite extends Hook 27 | { 28 | /** 29 | * Hook to execute. 30 | * 31 | * @var string 32 | */ 33 | protected string $hookName = Hooks::POST_REWRITE; 34 | 35 | /** 36 | * Configure the command 37 | * 38 | * @return void 39 | */ 40 | protected function configure(): void 41 | { 42 | parent::configure(); 43 | $this->addArgument(Hooks::ARG_GIT_COMMAND, InputArgument::OPTIONAL, 'Executed command'); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Console/Command/Hook/PreCommit.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Console\Command\Hook; 13 | 14 | use CaptainHook\App\Console\Command\Hook; 15 | use CaptainHook\App\Hooks; 16 | 17 | /** 18 | * Class PreCommit 19 | * 20 | * @package CaptainHook 21 | * @author Sebastian Feldmann 22 | * @link https://github.com/captainhook-git/captainhook 23 | * @since Class available since Release 0.9.0 24 | */ 25 | class PreCommit extends Hook 26 | { 27 | /** 28 | * Hook to execute. 29 | * 30 | * @var string 31 | */ 32 | protected string $hookName = Hooks::PRE_COMMIT; 33 | } 34 | -------------------------------------------------------------------------------- /src/Console/Command/Hook/PrePush.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Console\Command\Hook; 13 | 14 | use CaptainHook\App\Console\Command\Hook; 15 | use CaptainHook\App\Hooks; 16 | use Symfony\Component\Console\Input\InputArgument; 17 | 18 | /** 19 | * Class PrePush 20 | * 21 | * @package CaptainHook 22 | * @author Sebastian Feldmann 23 | * @link https://github.com/captainhook-git/captainhook 24 | * @since Class available since Release 0.9.0 25 | */ 26 | class PrePush extends Hook 27 | { 28 | /** 29 | * Hook to execute. 30 | * 31 | * @var string 32 | */ 33 | protected string $hookName = Hooks::PRE_PUSH; 34 | 35 | /** 36 | * Configure the command 37 | * 38 | * @return void 39 | */ 40 | protected function configure(): void 41 | { 42 | parent::configure(); 43 | $this->addArgument(Hooks::ARG_TARGET, InputArgument::OPTIONAL, 'Target repository name'); 44 | $this->addArgument(Hooks::ARG_URL, InputArgument::OPTIONAL, 'Target repository url'); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Console/Command/Hook/PrepareCommitMsg.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Console\Command\Hook; 13 | 14 | use CaptainHook\App\Console\Command\Hook; 15 | use CaptainHook\App\Hooks; 16 | use Symfony\Component\Console\Input\InputArgument; 17 | 18 | /** 19 | * Class PrepareCommitMessage 20 | * 21 | * @package CaptainHook 22 | * @author Sebastian Feldmann 23 | * @link https://github.com/captainhook-git/captainhook 24 | * @since Class available since Release 3.1.0 25 | */ 26 | class PrepareCommitMsg extends Hook 27 | { 28 | /** 29 | * Hook to execute 30 | * 31 | * @var string 32 | */ 33 | protected string $hookName = Hooks::PREPARE_COMMIT_MSG; 34 | 35 | /** 36 | * Configure the command 37 | * 38 | * @return void 39 | */ 40 | protected function configure(): void 41 | { 42 | parent::configure(); 43 | $this->addArgument(Hooks::ARG_MESSAGE_FILE, InputArgument::REQUIRED, 'File containing the commit log message'); 44 | $this->addArgument(Hooks::ARG_MODE, InputArgument::OPTIONAL, 'Current commit mode'); 45 | $this->addArgument(Hooks::ARG_HASH, InputArgument::OPTIONAL, 'Given commit hash'); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Console/Command/RepositoryAware.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Console\Command; 13 | 14 | use CaptainHook\App\Console\Runtime\Resolver; 15 | use SebastianFeldmann\Git\Repository; 16 | use Symfony\Component\Console\Input\InputOption; 17 | 18 | /** 19 | * Trait RepositoryAware 20 | * 21 | * Trait for all commands that needs to be aware of the git repository. 22 | * 23 | * @package CaptainHook\App\Console\Command 24 | */ 25 | class RepositoryAware extends ConfigAware 26 | { 27 | /** 28 | * Configure method to set up the git-directory command option 29 | * 30 | * @return void 31 | */ 32 | protected function configure(): void 33 | { 34 | parent::configure(); 35 | 36 | $this->addOption( 37 | 'git-directory', 38 | 'g', 39 | InputOption::VALUE_OPTIONAL, 40 | 'Path to your .git directory' 41 | ); 42 | } 43 | 44 | /** 45 | * Create a new git repository representation 46 | * 47 | * @param string $path 48 | * @return \SebastianFeldmann\Git\Repository 49 | */ 50 | protected function createRepository(string $path): Repository 51 | { 52 | return Repository::createVerified($path); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Console/IO/Base.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Console\IO; 13 | 14 | use CaptainHook\App\Console\IO; 15 | 16 | /** 17 | * Class Base 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 0.9.0 23 | */ 24 | abstract class Base implements IO 25 | { 26 | /** 27 | * Return the original cli arguments 28 | * 29 | * @return array 30 | */ 31 | public function getArguments(): array 32 | { 33 | return []; 34 | } 35 | 36 | /** 37 | * Return the original cli argument or a given default 38 | * 39 | * @param string $name 40 | * @param string $default 41 | * @return string 42 | */ 43 | public function getArgument(string $name, string $default = ''): string 44 | { 45 | return $default; 46 | } 47 | 48 | /** 49 | * Return the piped in standard input 50 | * 51 | * @return string[] 52 | */ 53 | public function getStandardInput(): array 54 | { 55 | return []; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Console/IO/Message.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Console\IO; 13 | 14 | /** 15 | * Class Message 16 | * 17 | * @package CaptainHook 18 | * @author Sebastian Feldmann 19 | * @link https://github.com/captainhook-git/captainhook 20 | * @since Class available since Release 5.19.0 21 | */ 22 | class Message 23 | { 24 | /** 25 | * Message, either a string or list of string for multiple lines 26 | * 27 | * @var string|array 28 | */ 29 | private string|array $message; 30 | 31 | /** 32 | * Should message be ended with a new line character 33 | * 34 | * @var bool 35 | */ 36 | private bool $newLine; 37 | 38 | /** 39 | * Current application verbosity 40 | * 41 | * @var int 42 | */ 43 | private int $verbosity; 44 | 45 | /** 46 | * Constructor 47 | * 48 | * @param string|array $message 49 | * @param bool $newLine 50 | * @param int $verbosity 51 | */ 52 | public function __construct(string|array $message, bool $newLine, int $verbosity) 53 | { 54 | $this->message = $message; 55 | $this->newLine = $newLine; 56 | $this->verbosity = $verbosity; 57 | } 58 | 59 | /** 60 | * Returns the message to print 61 | * 62 | * @return string|array 63 | */ 64 | public function message(): string|array 65 | { 66 | return $this->message; 67 | } 68 | 69 | /** 70 | * If true message should end with a new line 71 | * 72 | * @return bool 73 | */ 74 | public function newLine(): bool 75 | { 76 | return $this->newLine; 77 | } 78 | 79 | /** 80 | * Minimum verbosity this message should be displayed at 81 | * 82 | * @return int 83 | */ 84 | public function verbosity(): int 85 | { 86 | return $this->verbosity; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Console/IO/NullIO.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Console\IO; 13 | 14 | /** 15 | * Class NullIO 16 | * 17 | * @package CaptainHook 18 | * @author Sebastian Feldmann 19 | * @link https://github.com/captainhook-git/captainhook 20 | * @since Class available since Release 0.9.0 21 | */ 22 | class NullIO extends Base 23 | { 24 | /** 25 | * {@inheritDoc} 26 | */ 27 | public function isInteractive() 28 | { 29 | return false; 30 | } 31 | 32 | /** 33 | * {@inheritDoc} 34 | */ 35 | public function isVerbose() 36 | { 37 | return false; 38 | } 39 | 40 | /** 41 | * {@inheritDoc} 42 | */ 43 | public function isVeryVerbose() 44 | { 45 | return false; 46 | } 47 | 48 | /** 49 | * {@inheritDoc} 50 | */ 51 | public function isDebug() 52 | { 53 | return false; 54 | } 55 | 56 | /** 57 | * {@inheritDoc} 58 | */ 59 | public function write($messages, $newline = true, $verbosity = self::NORMAL) 60 | { 61 | } 62 | 63 | /** 64 | * {@inheritDoc} 65 | */ 66 | public function writeError($messages, $newline = true, $verbosity = self::NORMAL) 67 | { 68 | } 69 | 70 | /** 71 | * {@inheritDoc} 72 | */ 73 | public function ask($question, $default = null) 74 | { 75 | return (string) $default; 76 | } 77 | 78 | /** 79 | * {@inheritDoc} 80 | */ 81 | public function askConfirmation($question, $default = true) 82 | { 83 | return $default; 84 | } 85 | 86 | /** 87 | * {@inheritDoc} 88 | */ 89 | public function askAndValidate($question, $validator, $attempts = null, $default = null) 90 | { 91 | return $default; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Console/Runtime/Resolver.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Console\Runtime; 13 | 14 | /** 15 | * Class Resolver 16 | * 17 | * @package CaptainHook\App 18 | */ 19 | class Resolver 20 | { 21 | /** 22 | * PHAR flag, replaced by box during PHAR building 23 | * 24 | * @var string 25 | */ 26 | private string $runtime = '@runtime@'; 27 | 28 | /** 29 | * Path to the currently executed 'binary' 30 | * 31 | * @var string 32 | */ 33 | private string $executable; 34 | 35 | /** 36 | * Resolver constructor. 37 | * 38 | * @param string $executable 39 | */ 40 | public function __construct(string $executable = 'bin/vendor/captainhook') 41 | { 42 | $this->executable = $executable; 43 | } 44 | 45 | /** 46 | * Return current executed 'binary' 47 | * 48 | * @return string 49 | */ 50 | public function getExecutable(): string 51 | { 52 | return $this->executable; 53 | } 54 | 55 | /** 56 | * Check if the current runtime is executed via PHAR 57 | * 58 | * @return bool 59 | */ 60 | public function isPharRelease(): bool 61 | { 62 | return $this->runtime === 'PHAR'; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Event.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App; 13 | 14 | use CaptainHook\App\Console\IO; 15 | use SebastianFeldmann\Git\Repository; 16 | 17 | /** 18 | * Event interface 19 | * 20 | * Allows event handlers to do output access the app setup or the repository. 21 | * 22 | * @package CaptainHook 23 | * @author Sebastian Feldmann 24 | * @link https://github.com/captainhook-git/captainhook 25 | * @since Class available since Release 5.11.0 26 | */ 27 | interface Event 28 | { 29 | /** 30 | * Returns the event trigger name 31 | * 32 | * @return string 33 | */ 34 | public function name(): string; 35 | 36 | /** 37 | * Returns the captainhook config, most likely needed to access any original command line arguments 38 | * 39 | * @return \CaptainHook\App\Config 40 | */ 41 | public function config(): Config; 42 | 43 | /** 44 | * Returns IO to do some output 45 | * 46 | * @return \CaptainHook\App\Console\IO 47 | */ 48 | public function io(): IO; 49 | 50 | /** 51 | * Returns the git repository 52 | * 53 | * @return \SebastianFeldmann\Git\Repository 54 | */ 55 | public function repository(): Repository; 56 | } 57 | -------------------------------------------------------------------------------- /src/Event/Handler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Event; 13 | 14 | use CaptainHook\App\Event; 15 | 16 | /** 17 | * Interface EventListener 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 5.11.0 23 | */ 24 | interface Handler 25 | { 26 | /** 27 | * Executes the handler to handle the given event 28 | * 29 | * @param \CaptainHook\App\Event $event 30 | * @return void 31 | * @throws \Exception 32 | */ 33 | public function handle(Event $event); 34 | } 35 | -------------------------------------------------------------------------------- /src/Event/Hook.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Event; 13 | 14 | use CaptainHook\App\Config; 15 | use CaptainHook\App\Console\IO; 16 | use CaptainHook\App\Event; 17 | use SebastianFeldmann\Git\Repository; 18 | 19 | /** 20 | * Basic event class 21 | * 22 | * Makes sure the handler has access to the output the current app setup and the repository. 23 | * 24 | * @package CaptainHook 25 | * @author Sebastian Feldmann 26 | * @link https://github.com/captainhook-git/captainhook 27 | * @since Class available since Release 5.11.0 28 | */ 29 | abstract class Hook implements Event 30 | { 31 | /** 32 | * @var string 33 | */ 34 | protected $name; 35 | 36 | /** 37 | * @var \CaptainHook\App\Console\IO 38 | */ 39 | protected $io; 40 | 41 | /** 42 | * @var \CaptainHook\App\Config 43 | */ 44 | protected $config; 45 | 46 | /** 47 | * @var \SebastianFeldmann\Git\Repository 48 | */ 49 | protected $repository; 50 | 51 | /** 52 | * Event 53 | * 54 | * @param \CaptainHook\App\Console\IO $io 55 | * @param \CaptainHook\App\Config $config 56 | * @param \SebastianFeldmann\Git\Repository $repository 57 | */ 58 | public function __construct(IO $io, Config $config, Repository $repository) 59 | { 60 | $this->io = $io; 61 | $this->config = $config; 62 | $this->repository = $repository; 63 | } 64 | 65 | /** 66 | * @return string 67 | */ 68 | public function name(): string 69 | { 70 | return $this->name; 71 | } 72 | 73 | /** 74 | * @return \CaptainHook\App\Config 75 | */ 76 | public function config(): Config 77 | { 78 | return $this->config; 79 | } 80 | 81 | /** 82 | * @return \CaptainHook\App\Console\IO 83 | */ 84 | public function io(): IO 85 | { 86 | return $this->io; 87 | } 88 | 89 | /** 90 | * @return \SebastianFeldmann\Git\Repository 91 | */ 92 | public function repository(): Repository 93 | { 94 | return $this->repository; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/Event/HookFailed.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Event; 13 | 14 | /** 15 | * Hook failed event 16 | * 17 | * @package CaptainHook 18 | * @author Sebastian Feldmann 19 | * @link https://github.com/captainhook-git/captainhook 20 | * @since Class available since Release 5.11.0 21 | */ 22 | class HookFailed extends Hook 23 | { 24 | protected $name = 'onHookFailure'; 25 | } 26 | -------------------------------------------------------------------------------- /src/Event/HookSucceeded.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Event; 13 | 14 | /** 15 | * Hook succeeded event 16 | * 17 | * @package CaptainHook 18 | * @author Sebastian Feldmann 19 | * @link https://github.com/captainhook-git/captainhook 20 | * @since Class available since Release 5.11.0 21 | */ 22 | class HookSucceeded extends Hook 23 | { 24 | protected $name = 'onHookSuccess'; 25 | } 26 | -------------------------------------------------------------------------------- /src/Exception/ActionFailed.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Exception; 13 | 14 | use Exception; 15 | 16 | /** 17 | * Class ActionFailed 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 0.9.0 23 | */ 24 | class ActionFailed extends Exception implements CaptainHookException 25 | { 26 | } 27 | -------------------------------------------------------------------------------- /src/Exception/CaptainHookException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Exception; 13 | 14 | use Throwable; 15 | 16 | /** 17 | * CaptainHookException interface 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 5.9.0. 23 | */ 24 | interface CaptainHookException extends Throwable 25 | { 26 | } 27 | -------------------------------------------------------------------------------- /src/Exception/InvalidHookName.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Exception; 13 | 14 | use Exception; 15 | 16 | /** 17 | * Class InvalidHookName 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 0.9.0 23 | */ 24 | class InvalidHookName extends Exception implements CaptainHookException 25 | { 26 | } 27 | -------------------------------------------------------------------------------- /src/Exception/InvalidPlugin.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Exception; 13 | 14 | use RuntimeException; 15 | 16 | /** 17 | * Class InvalidPlugin 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 5.9.0 23 | */ 24 | class InvalidPlugin extends RuntimeException implements CaptainHookException 25 | { 26 | } 27 | -------------------------------------------------------------------------------- /src/Git/ChangedFiles/Detecting.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Git\ChangedFiles; 13 | 14 | /** 15 | * Detector interface 16 | * 17 | * Interface to detect changed files for the different hooks. 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 5.20.0 23 | */ 24 | interface Detecting 25 | { 26 | /** 27 | * Returns a list of changed files 28 | * 29 | * @param array $filter 30 | * @return array 31 | */ 32 | public function getChangedFiles(array $filter = []): array; 33 | } 34 | -------------------------------------------------------------------------------- /src/Git/ChangedFiles/Detector.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Git\ChangedFiles; 13 | 14 | use CaptainHook\App\Console\IO; 15 | use SebastianFeldmann\Git\Repository; 16 | 17 | /** 18 | * Class Detector 19 | * 20 | * Base class for all ChangedFiles Detecting implementations. 21 | * 22 | * @package CaptainHook 23 | * @author Sebastian Feldmann 24 | * @link https://github.com/captainhook-git/captainhook 25 | * @since Class available since Release 5.20.0 26 | */ 27 | abstract class Detector implements Detecting 28 | { 29 | /** 30 | * Input output handling 31 | * 32 | * @var \CaptainHook\App\Console\IO 33 | */ 34 | protected IO $io; 35 | 36 | /** 37 | * Git repository 38 | * 39 | * @var \SebastianFeldmann\Git\Repository 40 | */ 41 | protected Repository $repository; 42 | 43 | /** 44 | * Constructor 45 | * 46 | * @param \CaptainHook\App\Console\IO $io 47 | * @param \SebastianFeldmann\Git\Repository $repository 48 | */ 49 | public function __construct(IO $io, Repository $repository) 50 | { 51 | $this->io = $io; 52 | $this->repository = $repository; 53 | } 54 | 55 | /** 56 | * Returns a list of changed files 57 | * 58 | * @param array $filter 59 | * @return array 60 | */ 61 | abstract public function getChangedFiles(array $filter = []): array; 62 | } 63 | -------------------------------------------------------------------------------- /src/Git/ChangedFiles/Detector/Factory.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Git\ChangedFiles\Detector; 13 | 14 | use CaptainHook\App\Console\IO; 15 | use CaptainHook\App\Git\ChangedFiles\Detecting; 16 | use CaptainHook\App\Hooks; 17 | use SebastianFeldmann\Git\Repository; 18 | 19 | /** 20 | * Factory class 21 | * 22 | * Responsible for finding the previous - current ranges in every scenario 23 | * 24 | * @package CaptainHook 25 | * @author Sebastian Feldmann 26 | * @link https://github.com/captainhook-git/captainhook 27 | * @since Class available since Release 5.15.0 28 | */ 29 | class Factory 30 | { 31 | /** 32 | * List of available range detectors 33 | * 34 | * @var array 35 | */ 36 | private static array $detectors = [ 37 | 'hook:pre-push' => '\\CaptainHook\\App\\Git\\ChangedFiles\\Detector\\PrePush', 38 | 'hook:post-rewrite' => '\\CaptainHook\\App\\Git\\ChangedFiles\\Detector\\PostRewrite', 39 | ]; 40 | 41 | /** 42 | * Returns a ChangedFiles Detector 43 | * 44 | * @param \CaptainHook\App\Console\IO $io 45 | * @param \SebastianFeldmann\Git\Repository $repository 46 | * @return \CaptainHook\App\Git\ChangedFiles\Detecting 47 | */ 48 | public function getDetector(IO $io, Repository $repository): Detecting 49 | { 50 | $command = $io->getArgument(Hooks::ARG_COMMAND); 51 | 52 | /** @var \CaptainHook\App\Git\ChangedFiles\Detecting $class */ 53 | $class = self::$detectors[$command] ?? '\\CaptainHook\\App\\Git\\ChangedFiles\\Detector\\Fallback'; 54 | return new $class($io, $repository); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Git/ChangedFiles/Detector/Fallback.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Git\ChangedFiles\Detector; 13 | 14 | use CaptainHook\App\Git\ChangedFiles\Detector; 15 | use CaptainHook\App\Hooks; 16 | 17 | /** 18 | * Class Fallback 19 | * 20 | * This class should not be used it is just a fallback if the `pre-push` or `post-rewrite` 21 | * variants are somehow not applicable. 22 | * 23 | * @package CaptainHook 24 | * @author Sebastian Feldmann 25 | * @link https://github.com/captainhook-git/captainhook 26 | * @since Class available since Release 5.20.0 27 | */ 28 | class Fallback extends Detector 29 | { 30 | /** 31 | * Returns the list of changed files in a best-guess kind of way 32 | * 33 | * @param array $filter 34 | * @return array 35 | */ 36 | public function getChangedFiles(array $filter = []): array 37 | { 38 | return $this->repository->getDiffOperator()->getChangedFiles( 39 | $this->io->getArgument(Hooks::ARG_PREVIOUS_HEAD, 'HEAD@{1}'), 40 | 'HEAD', 41 | $filter 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Git/ChangedFiles/Detector/PostRewrite.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Git\ChangedFiles\Detector; 13 | 14 | use CaptainHook\App\Git\ChangedFiles\Detector; 15 | use CaptainHook\App\Git\Range\Detector\PostRewrite as RangeDetector; 16 | 17 | /** 18 | * Class PostRewrite 19 | * 20 | * @package CaptainHook 21 | * @author Sebastian Feldmann 22 | * @link https://github.com/captainhook-git/captainhook 23 | * @since Class available since Release 5.20.0 24 | */ 25 | class PostRewrite extends Detector 26 | { 27 | /** 28 | * Returns a list of changed files 29 | * 30 | * @param array $filter 31 | * @return array 32 | */ 33 | public function getChangedFiles(array $filter = []): array 34 | { 35 | $detector = new RangeDetector(); 36 | $ranges = $detector->getRanges($this->io); 37 | $old = $ranges[0]->from()->id(); 38 | $new = $ranges[0]->to()->id(); 39 | 40 | return $this->repository->getDiffOperator()->getChangedFiles($old, $new, $filter); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Git/Diff/FilterUtil.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Git\Diff; 13 | 14 | abstract class FilterUtil 15 | { 16 | /** 17 | * Converts a value into a valid diff filter array 18 | * 19 | * @param mixed $value 20 | * @return array 21 | */ 22 | public static function filterFromConfigValue($value): array 23 | { 24 | return self::sanitize( 25 | is_array($value) ? $value : str_split((string) strtoupper($value === null ? '' : $value)) 26 | ); 27 | } 28 | 29 | /** 30 | * Remove all invalid filter options 31 | * 32 | * @param array $data 33 | * @return array 34 | */ 35 | public static function sanitize(array $data): array 36 | { 37 | return array_filter($data, fn($e) => in_array($e, ['A', 'C', 'D', 'M', 'R', 'T', 'U', 'X', 'B', '*'])); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Git/Range.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Git; 13 | 14 | /** 15 | * Range class 16 | * 17 | * Represents a git range with a starting ref and an end ref. 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 5.15.0 23 | */ 24 | interface Range 25 | { 26 | /** 27 | * Returns the start ref 28 | * 29 | * @return \CaptainHook\App\Git\Rev 30 | */ 31 | public function from(): Rev; 32 | 33 | /** 34 | * Returns the end ref 35 | * 36 | * @return \CaptainHook\App\Git\Rev 37 | */ 38 | public function to(): Rev; 39 | } 40 | -------------------------------------------------------------------------------- /src/Git/Range/Detecting.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Git\Range; 13 | 14 | use CaptainHook\App\Console\IO; 15 | 16 | /** 17 | * Detecting interface 18 | * 19 | * Interface to gathering the previous state to current state ranges. 20 | * To handle gathering the ranges for pre-push, post-rewrite, post-checkout separately. 21 | * 22 | * @package CaptainHook 23 | * @author Sebastian Feldmann 24 | * @link https://github.com/captainhook-git/captainhook 25 | * @since Class available since Release 5.15.0 26 | */ 27 | interface Detecting 28 | { 29 | /** 30 | * Returns a list of ranges marking before and after points to collect the changes happening in between 31 | * 32 | * @param \CaptainHook\App\Console\IO $io 33 | * @return array<\CaptainHook\App\Git\Range> 34 | */ 35 | public function getRanges(IO $io): array; 36 | } 37 | -------------------------------------------------------------------------------- /src/Git/Range/Detector/Fallback.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Git\Range\Detector; 13 | 14 | use CaptainHook\App\Console\IO; 15 | use CaptainHook\App\Git\Range; 16 | use CaptainHook\App\Git\Range\Detecting; 17 | use CaptainHook\App\Git\Rev; 18 | use CaptainHook\App\Hooks; 19 | 20 | /** 21 | * Fallback Detector 22 | * 23 | * If no detection strategy matches the fallback detector is used to find the right range. 24 | * 25 | * @package CaptainHook 26 | * @author Sebastian Feldmann 27 | * @link https://github.com/captainhook-git/captainhook 28 | * @since Class available since Release 5.15.0 29 | */ 30 | class Fallback implements Detecting 31 | { 32 | /** 33 | * Returns the fallback range 34 | * 35 | * @param \CaptainHook\App\Console\IO $io 36 | * @return \CaptainHook\App\Git\Range\Generic[] 37 | */ 38 | public function getRanges(IO $io): array 39 | { 40 | return [ 41 | new Range\Generic( 42 | new Rev\Generic($io->getArgument(Hooks::ARG_PREVIOUS_HEAD, 'HEAD@{1}')), 43 | new Rev\Generic('HEAD') 44 | ) 45 | ]; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Git/Range/Detector/PostRewrite.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Git\Range\Detector; 13 | 14 | use CaptainHook\App\Console\IO; 15 | use CaptainHook\App\Git\Range\Detecting; 16 | use CaptainHook\App\Git\Range\Generic as Range; 17 | use CaptainHook\App\Git\Rev\Generic as Rev; 18 | 19 | /** 20 | * Class to access the pre-push stdIn data 21 | * 22 | * @package CaptainHook 23 | * @author Sebastian Feldmann 24 | * @link https://github.com/captainhook-git/captainhook 25 | * @since Class available since Release 5.15.0 26 | */ 27 | class PostRewrite implements Detecting 28 | { 29 | /** 30 | * Returns list of refs 31 | * 32 | * @param \CaptainHook\App\Console\IO $io 33 | * @return \CaptainHook\App\Git\Range[] 34 | */ 35 | public function getRanges(IO $io): array 36 | { 37 | return $this->createFromStdIn($io->getStandardInput()); 38 | } 39 | 40 | /** 41 | * Create ranges from stdIn 42 | * 43 | * @param array $stdIn 44 | * @return array<\CaptainHook\App\Git\Range> 45 | */ 46 | private function createFromStdIn(array $stdIn): array 47 | { 48 | $ranges = []; 49 | foreach ($stdIn as $line) { 50 | if (!empty($line)) { 51 | $parts = explode(' ', trim($line)); 52 | $from = new Rev(!empty($parts[1]) ? $parts[1] . '^' : 'HEAD@{1}'); 53 | $to = new Rev('HEAD'); 54 | $ranges[] = new Range($from, $to); 55 | } 56 | } 57 | return $ranges; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Git/Range/Detector/PrePush.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Git\Range\Detector; 13 | 14 | use CaptainHook\App\Console\IO; 15 | use CaptainHook\App\Git\Range\Detecting; 16 | use CaptainHook\App\Git\Range\PrePush as Range; 17 | use CaptainHook\App\Git\Rev\PrePush as Rev; 18 | use CaptainHook\App\Git\Rev\Util; 19 | 20 | /** 21 | * Class to access the pre-push stdIn data 22 | * 23 | * @package CaptainHook 24 | * @author Sebastian Feldmann 25 | * @link https://github.com/captainhook-git/captainhook 26 | * @since Class available since Release 5.15.0 27 | */ 28 | class PrePush implements Detecting 29 | { 30 | /** 31 | * Returns list of refs 32 | * 33 | * @param \CaptainHook\App\Console\IO $io 34 | * @return array<\CaptainHook\App\Git\Range\PrePush> 35 | */ 36 | public function getRanges(IO $io): array 37 | { 38 | return $this->createFromStdIn($io->getStandardInput()); 39 | } 40 | 41 | /** 42 | * Factory method 43 | * 44 | * @param array $stdIn 45 | * @return array<\CaptainHook\App\Git\Range\PrePush> 46 | */ 47 | private function createFromStdIn(array $stdIn): array 48 | { 49 | $ranges = []; 50 | foreach ($stdIn as $line) { 51 | if (empty($line)) { 52 | continue; 53 | } 54 | 55 | [$localRef, $localHash, $remoteRef, $remoteHash] = explode(' ', trim($line)); 56 | 57 | $from = new Rev($remoteRef, $remoteHash, Util::extractBranchInfo($remoteRef)['branch']); 58 | $to = new Rev($localRef, $localHash, Util::extractBranchInfo($localRef)['branch']); 59 | $ranges[] = new Range($from, $to); 60 | } 61 | return $ranges; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Git/Range/Generic.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Git\Range; 13 | 14 | use CaptainHook\App\Git\Range; 15 | use CaptainHook\App\Git\Rev; 16 | 17 | /** 18 | * Generic range implementation 19 | * 20 | * Most simple range implementation 21 | * 22 | * @package CaptainHook 23 | * @author Sebastian Feldmann 24 | * @link https://github.com/captainhook-git/captainhook 25 | * @since Class available since Release 5.15.0 26 | */ 27 | class Generic implements Range 28 | { 29 | /** 30 | * Starting reference 31 | * 32 | * @var \CaptainHook\App\Git\Rev 33 | */ 34 | private Rev $from; 35 | 36 | /** 37 | * Ending reference 38 | * 39 | * @var \CaptainHook\App\Git\Rev 40 | */ 41 | private Rev $to; 42 | 43 | /** 44 | * Constructor 45 | * 46 | */ 47 | public function __construct(Rev $from, Rev $to) 48 | { 49 | $this->from = $from; 50 | $this->to = $to; 51 | } 52 | 53 | /** 54 | * Return the git reference 55 | * 56 | * @return \CaptainHook\App\Git\Rev 57 | */ 58 | public function from(): Rev 59 | { 60 | return $this->from; 61 | } 62 | 63 | /** 64 | * @return \CaptainHook\App\Git\Rev 65 | */ 66 | public function to(): Rev 67 | { 68 | return $this->to; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Git/Range/PrePush.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Git\Range; 13 | 14 | use CaptainHook\App\Git; 15 | use CaptainHook\App\Git\Rev\PrePush as Rev; 16 | 17 | /** 18 | * Class 19 | * 20 | * @package CaptainHook 21 | * @author Sebastian Feldmann 22 | * @link https://github.com/captainhook-git/captainhook 23 | * @since Class available since Release 5.15.0 24 | */ 25 | class PrePush implements Git\Range 26 | { 27 | /** 28 | * @var \CaptainHook\App\Git\Rev\PrePush 29 | */ 30 | private Rev $from; 31 | 32 | /** 33 | * @var \CaptainHook\App\Git\Rev\PrePush 34 | */ 35 | private Rev $to; 36 | 37 | /** 38 | * Constructor 39 | * 40 | * @param \CaptainHook\App\Git\Rev\PrePush $from 41 | * @param \CaptainHook\App\Git\Rev\PrePush $to 42 | */ 43 | public function __construct(Rev $from, Rev $to) 44 | { 45 | $this->from = $from; 46 | $this->to = $to; 47 | } 48 | 49 | /** 50 | * Returns the start ref 51 | * 52 | * @return \CaptainHook\App\Git\Rev\PrePush 53 | */ 54 | public function from(): Rev 55 | { 56 | return $this->from; 57 | } 58 | 59 | /** 60 | * Returns the end ref 61 | * 62 | * @return \CaptainHook\App\Git\Rev\PrePush 63 | */ 64 | public function to(): Rev 65 | { 66 | return $this->to; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Git/Rev.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Git; 13 | 14 | /** 15 | * Ref interface 16 | * 17 | * Git references can be used in git commands to identify positions in the git history. 18 | * For example: HEAD, 4FD60E21, 19 | * 20 | * @package CaptainHook 21 | * @author Sebastian Feldmann 22 | * @link https://github.com/captainhook-git/captainhook 23 | * @since Class available since Release 5.15.0 24 | */ 25 | interface Rev 26 | { 27 | /** 28 | * Returns the ref id that can be used in a git command 29 | * 30 | * This can be completely a hash, branch name, ref-log position... 31 | * 32 | * @return string 33 | */ 34 | public function id(): string; 35 | } 36 | -------------------------------------------------------------------------------- /src/Git/Rev/Generic.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Git\Rev; 13 | 14 | use CaptainHook\App\Git\Rev; 15 | 16 | /** 17 | * Generic range implementation 18 | * 19 | * The simplest imaginable range implementation without any extra information. 20 | * 21 | * @package CaptainHook 22 | * @author Sebastian Feldmann 23 | * @link https://github.com/captainhook-git/captainhook 24 | * @since Class available since Release 5.15.0 25 | */ 26 | class Generic implements Rev 27 | { 28 | /** 29 | * Referencing a git state 30 | * 31 | * @var string 32 | */ 33 | private string $id; 34 | 35 | /** 36 | * Constructor 37 | * 38 | * @param string $id 39 | */ 40 | public function __construct(string $id) 41 | { 42 | $this->id = $id; 43 | } 44 | 45 | /** 46 | * Return the git reference 47 | * 48 | * @return string 49 | */ 50 | public function id(): string 51 | { 52 | return $this->id; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Git/Rev/PrePush.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Git\Rev; 13 | 14 | use CaptainHook\App\Git\Rev; 15 | 16 | /** 17 | * Git pre-push reference 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 5.15.0 23 | */ 24 | class PrePush implements Rev 25 | { 26 | /** 27 | * Head path - refs/heads/main 28 | * 29 | * @var string 30 | */ 31 | private string $head; 32 | 33 | /** 34 | * Git hash 35 | * 36 | * @var string 37 | */ 38 | private string $hash; 39 | 40 | /** 41 | * Branch name 42 | * 43 | * @var string 44 | */ 45 | private string $branch; 46 | 47 | /** 48 | * Constructor 49 | * 50 | * @param string $head 51 | * @param string $hash 52 | * @param string $branch 53 | */ 54 | public function __construct(string $head, string $hash, string $branch) 55 | { 56 | $this->head = $head; 57 | $this->hash = $hash; 58 | $this->branch = $branch; 59 | } 60 | 61 | /** 62 | * Head getter 63 | * 64 | * @return string 65 | */ 66 | public function head(): string 67 | { 68 | return $this->head; 69 | } 70 | 71 | /** 72 | * Hash getter 73 | * 74 | * @return string 75 | */ 76 | public function hash(): string 77 | { 78 | return $this->hash; 79 | } 80 | 81 | /** 82 | * Branch getter 83 | * 84 | * @return string 85 | */ 86 | public function branch(): string 87 | { 88 | return $this->branch; 89 | } 90 | 91 | /** 92 | * Returns the ref id that can be used in a git command 93 | * 94 | * This can be completely different thing hash, branch name, ref-log position... 95 | * 96 | * @return string 97 | */ 98 | public function id(): string 99 | { 100 | return $this->hash; 101 | } 102 | 103 | /** 104 | * Is this a git dummy hash 105 | * 106 | * @return bool 107 | */ 108 | public function isZeroRev(): bool 109 | { 110 | return Util::isZeroHash($this->hash); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/Git/Rev/Util.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Git\Rev; 13 | 14 | /** 15 | * Util class 16 | * 17 | * Does some simple format and validation stuff 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 5.15.0 23 | */ 24 | abstract class Util 25 | { 26 | /** 27 | * Indicates if commit hash is a zero hash 0000000000000000000000000000000000000000 28 | * 29 | * @param string $hash 30 | * @return bool 31 | */ 32 | public static function isZeroHash(string $hash): bool 33 | { 34 | return (bool) preg_match('/^0+$/', $hash); 35 | } 36 | 37 | /** 38 | * Splits remote and branch 39 | * 40 | * origin/main => ['remote' => 'origin', 'branch' => 'main'] 41 | * main => ['remote' => 'origin', 'branch' => 'main'] 42 | * ref/origin/main => ['remote' => 'origin', 'branch' => 'main'] 43 | * 44 | * @param string $ref 45 | * @return array 46 | */ 47 | public static function extractBranchInfo(string $ref): array 48 | { 49 | $ref = (string) preg_replace('#^refs/#', '', $ref); 50 | $parts = explode('/', $ref); 51 | 52 | return [ 53 | 'remote' => count($parts) > 1 ? array_shift($parts) : 'origin', 54 | 'branch' => implode('/', $parts), 55 | ]; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Hook/Action.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook; 13 | 14 | use CaptainHook\App\Config; 15 | use CaptainHook\App\Console\IO; 16 | use SebastianFeldmann\Git\Repository; 17 | 18 | /** 19 | * Interface Action 20 | * 21 | * @package CaptainHook 22 | * @author Sebastian Feldmann 23 | * @link https://github.com/captainhook-git/captainhook 24 | * @since Class available since Release 0.9.0 25 | */ 26 | interface Action 27 | { 28 | /** 29 | * Executes the action 30 | * 31 | * @param \CaptainHook\App\Config $config 32 | * @param \CaptainHook\App\Console\IO $io 33 | * @param \SebastianFeldmann\Git\Repository $repository 34 | * @param \CaptainHook\App\Config\Action $action 35 | * @return void 36 | * @throws \Exception 37 | */ 38 | public function execute(Config $config, IO $io, Repository $repository, Config\Action $action): void; 39 | } 40 | -------------------------------------------------------------------------------- /src/Hook/Cli/Command.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Cli; 13 | 14 | use CaptainHook\App\Config; 15 | use CaptainHook\App\Console\IO; 16 | use CaptainHook\App\Hook\Action; 17 | use SebastianFeldmann\Git\Repository; 18 | 19 | /** 20 | * Class Notify 21 | * 22 | * @package CaptainHook 23 | * @author Sebastian Feldmann 24 | * @link https://github.com/captainhook-git/captainhook 25 | * @since Class available since Release 5.23.1 26 | */ 27 | class Command implements Action 28 | { 29 | /** 30 | * Executes the action 31 | * 32 | * @param \CaptainHook\App\Config $config 33 | * @param \CaptainHook\App\Console\IO $io 34 | * @param \SebastianFeldmann\Git\Repository $repository 35 | * @param \CaptainHook\App\Config\Action $action 36 | * @return void 37 | * @throws \Exception 38 | */ 39 | public function execute(Config $config, IO $io, Repository $repository, Config\Action $action): void 40 | { 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Hook/Condition.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook; 13 | 14 | use CaptainHook\App\Console\IO; 15 | use SebastianFeldmann\Git\Repository; 16 | 17 | /** 18 | * Interface Conditions 19 | * 20 | * @package CaptainHook 21 | * @author Sebastian Feldmann 22 | * @link https://github.com/captainhook-git/captainhook 23 | * @since Class available since Release 4.2.0 24 | */ 25 | interface Condition 26 | { 27 | /** 28 | * Evaluates a condition 29 | * 30 | * @param \CaptainHook\App\Console\IO $io 31 | * @param \SebastianFeldmann\Git\Repository $repository 32 | * @return bool 33 | */ 34 | public function isTrue(IO $io, Repository $repository): bool; 35 | } 36 | -------------------------------------------------------------------------------- /src/Hook/Condition/Branch/Files.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace CaptainHook\App\Hook\Condition\Branch; 15 | 16 | use CaptainHook\App\Console\IO; 17 | use CaptainHook\App\Hook\Condition; 18 | use CaptainHook\App\Hook\FileList; 19 | use SebastianFeldmann\Git\Repository; 20 | 21 | /** 22 | * Files condition 23 | * 24 | * Example configuration: 25 | * 26 | * "action": "some-action" 27 | * "conditions": [ 28 | * {"exec": "\\CaptainHook\\App\\Hook\\Condition\\Branch\\Files", 29 | * "args": [ 30 | * {"compare-to": "main", "of-type": "php"} 31 | * ]} 32 | * ] 33 | * 34 | * @package CaptainHook 35 | * @author Sebastian Feldmann 36 | * @link https://github.com/captainhook-git/captainhook 37 | * @since Class available since Release 5.21.0 38 | */ 39 | class Files implements Condition 40 | { 41 | /** 42 | * Options 43 | * - compare-to: source branch if known, otherwise the reflog is used to figure it out 44 | * - in-directory: only check for files in given directory 45 | * - of-type: only check for files of given type 46 | * 47 | * @var array 48 | */ 49 | private array $options; 50 | 51 | /** 52 | * Constructor 53 | * 54 | * @param array $options 55 | */ 56 | public function __construct(array $options = []) 57 | { 58 | $this->options = $options; 59 | } 60 | 61 | /** 62 | * Check if the current branch contains changes to files 63 | * 64 | * @param \CaptainHook\App\Console\IO $io 65 | * @param \SebastianFeldmann\Git\Repository $repository 66 | * @return bool 67 | */ 68 | public function isTrue(IO $io, Repository $repository): bool 69 | { 70 | $branch = $repository->getInfoOperator()->getCurrentBranch(); 71 | $start = $this->options['compared-to'] ?? $repository->getLogOperator()->getBranchRevFromRefLog($branch); 72 | 73 | if (empty($start)) { 74 | return false; 75 | } 76 | 77 | $files = $repository->getLogOperator()->getChangedFilesSince($start, ['A', 'C', 'M', 'R']); 78 | 79 | return count(FileList::filter($files, $this->options)) > 0; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Hook/Condition/Branch/Name.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace CaptainHook\App\Hook\Condition\Branch; 15 | 16 | use CaptainHook\App\Console\IO; 17 | use CaptainHook\App\Hook\Condition; 18 | use SebastianFeldmann\Git\Repository; 19 | 20 | /** 21 | * OnBranch condition 22 | * 23 | * @package CaptainHook 24 | * @author Sebastian Feldmann 25 | * @link https://github.com/captainhook-git/captainhook 26 | * @since Class available since Release 5.0.0 27 | */ 28 | abstract class Name implements Condition 29 | { 30 | /** 31 | * Branch name to compare 32 | * 33 | * @var string 34 | */ 35 | protected string $name; 36 | 37 | /** 38 | * OnBranch constructor. 39 | * 40 | * @param string $name 41 | */ 42 | public function __construct(string $name) 43 | { 44 | $this->name = $name; 45 | } 46 | 47 | /** 48 | * Check is the current branch is equal to the configured one 49 | * 50 | * @param \CaptainHook\App\Console\IO $io 51 | * @param \SebastianFeldmann\Git\Repository $repository 52 | * @return bool 53 | */ 54 | abstract public function isTrue(IO $io, Repository $repository): bool; 55 | } 56 | -------------------------------------------------------------------------------- /src/Hook/Condition/Branch/NotOn.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace CaptainHook\App\Hook\Condition\Branch; 15 | 16 | use CaptainHook\App\Console\IO; 17 | use CaptainHook\App\Hook\Condition; 18 | use SebastianFeldmann\Git\Repository; 19 | 20 | /** 21 | * NotOn condition 22 | * 23 | * @package CaptainHook 24 | * @author Sebastian Feldmann 25 | * @link https://github.com/captainhook-git/captainhook 26 | * @since Class available since Release 5.20.2 27 | */ 28 | class NotOn extends Name 29 | { 30 | /** 31 | * Check is the current branch is not equal to the configured one 32 | * 33 | * @param \CaptainHook\App\Console\IO $io 34 | * @param \SebastianFeldmann\Git\Repository $repository 35 | * @return bool 36 | */ 37 | public function isTrue(IO $io, Repository $repository): bool 38 | { 39 | return trim($repository->getInfoOperator()->getCurrentBranch()) !== $this->name; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Hook/Condition/Branch/NotOnMatching.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace CaptainHook\App\Hook\Condition\Branch; 15 | 16 | use CaptainHook\App\Console\IO; 17 | use CaptainHook\App\Hook\Condition; 18 | use SebastianFeldmann\Git\Repository; 19 | 20 | /** 21 | * NotOnMatching condition 22 | * 23 | * @package CaptainHook 24 | * @author Sebastian Feldmann 25 | * @link https://github.com/captainhook-git/captainhook 26 | * @since Class available since Release 5.20.2 27 | */ 28 | class NotOnMatching extends Name 29 | { 30 | /** 31 | * Check is the current branch is not matched by the configured regex 32 | * 33 | * @param \CaptainHook\App\Console\IO $io 34 | * @param \SebastianFeldmann\Git\Repository $repository 35 | * @return bool 36 | */ 37 | public function isTrue(IO $io, Repository $repository): bool 38 | { 39 | return preg_match($this->name, trim($repository->getInfoOperator()->getCurrentBranch())) === 0; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Hook/Condition/Branch/On.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace CaptainHook\App\Hook\Condition\Branch; 15 | 16 | use CaptainHook\App\Console\IO; 17 | use CaptainHook\App\Hook\Condition; 18 | use SebastianFeldmann\Git\Repository; 19 | 20 | /** 21 | * On condition 22 | * 23 | * @package CaptainHook 24 | * @author Sebastian Feldmann 25 | * @link https://github.com/captainhook-git/captainhook 26 | * @since Class available since Release 5.20.2 27 | */ 28 | class On extends Name 29 | { 30 | /** 31 | * Check is the current branch is equal to the configured one 32 | * 33 | * @param \CaptainHook\App\Console\IO $io 34 | * @param \SebastianFeldmann\Git\Repository $repository 35 | * @return bool 36 | */ 37 | public function isTrue(IO $io, Repository $repository): bool 38 | { 39 | return trim($repository->getInfoOperator()->getCurrentBranch()) === $this->name; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Hook/Condition/Branch/OnMatching.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace CaptainHook\App\Hook\Condition\Branch; 15 | 16 | use CaptainHook\App\Console\IO; 17 | use CaptainHook\App\Hook\Condition; 18 | use SebastianFeldmann\Git\Repository; 19 | 20 | /** 21 | * OnMatching condition 22 | * 23 | * @package CaptainHook 24 | * @author Sebastian Feldmann 25 | * @link https://github.com/captainhook-git/captainhook 26 | * @since Class available since Release 5.20.2 27 | */ 28 | class OnMatching extends Name 29 | { 30 | /** 31 | * Check is the current branch is matched by the configured regex 32 | * 33 | * @param \CaptainHook\App\Console\IO $io 34 | * @param \SebastianFeldmann\Git\Repository $repository 35 | * @return bool 36 | */ 37 | public function isTrue(IO $io, Repository $repository): bool 38 | { 39 | return preg_match($this->name, trim($repository->getInfoOperator()->getCurrentBranch())) === 1; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Hook/Condition/Cli.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Condition; 13 | 14 | use CaptainHook\App\Console\IO; 15 | use CaptainHook\App\Hook\Condition; 16 | use SebastianFeldmann\Cli\Processor; 17 | use SebastianFeldmann\Git\Repository; 18 | 19 | /** 20 | * Class Cli 21 | * 22 | * @package CaptainHook 23 | * @author Sebastian Feldmann 24 | * @link https://github.com/captainhook-git/captainhook 25 | * @since Class available since Release 4.2.0 26 | */ 27 | class Cli implements Condition 28 | { 29 | /** 30 | * Binary executor 31 | * 32 | * @var \SebastianFeldmann\Cli\Processor 33 | */ 34 | private $processor; 35 | 36 | /** 37 | * @var string 38 | */ 39 | private $command; 40 | 41 | /** 42 | * Cli constructor. 43 | * 44 | * @param \SebastianFeldmann\Cli\Processor $processor 45 | * @param string $command 46 | */ 47 | public function __construct(Processor $processor, string $command) 48 | { 49 | $this->processor = $processor; 50 | $this->command = $command; 51 | } 52 | 53 | /** 54 | * Evaluates a condition 55 | * 56 | * @param \CaptainHook\App\Console\IO $io 57 | * @param \SebastianFeldmann\Git\Repository $repository 58 | * @return bool 59 | */ 60 | public function isTrue(IO $io, Repository $repository): bool 61 | { 62 | $result = $this->processor->run($this->command); 63 | 64 | return $result->isSuccessful(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Hook/Condition/Config.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Condition; 13 | 14 | use CaptainHook\App\Config as AppConfig; 15 | use CaptainHook\App\Console\IO; 16 | use CaptainHook\App\Hook\Condition; 17 | use RuntimeException; 18 | use SebastianFeldmann\Git\Repository; 19 | 20 | /** 21 | * Class FileChange 22 | * 23 | * @package CaptainHook 24 | * @author Sebastian Feldmann 25 | * @link https://github.com/captainhook-git/captainhook 26 | * @since Class available since Release 4.2.0 27 | */ 28 | abstract class Config implements ConfigDependant, Condition 29 | { 30 | /** 31 | * @var \CaptainHook\App\Config|null 32 | */ 33 | protected ?AppConfig $config = null; 34 | 35 | /** 36 | * Config setter 37 | * 38 | * @param \CaptainHook\App\Config $config 39 | * @return void 40 | */ 41 | public function setConfig(AppConfig $config): void 42 | { 43 | $this->config = $config; 44 | } 45 | 46 | /** 47 | * Check if the customer value exists and return izs boolish value 48 | * 49 | * @param string $value 50 | * @param bool $default 51 | * @return bool 52 | */ 53 | protected function checkCustomValue(string $value, bool $default): bool 54 | { 55 | if (null === $this->config) { 56 | throw new RuntimeException('config not set'); 57 | } 58 | $customSettings = $this->config->getCustomSettings(); 59 | $valueToCheck = $customSettings[$value] ?? $default; 60 | return filter_var($valueToCheck, FILTER_VALIDATE_BOOL); 61 | } 62 | 63 | /** 64 | * Evaluates a condition 65 | * 66 | * @param \CaptainHook\App\Console\IO $io 67 | * @param \SebastianFeldmann\Git\Repository $repository 68 | * @return bool 69 | */ 70 | abstract public function isTrue(IO $io, Repository $repository): bool; 71 | } 72 | -------------------------------------------------------------------------------- /src/Hook/Condition/Config/CustomValueIsFalsy.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Condition\Config; 13 | 14 | use CaptainHook\App\Console\IO; 15 | use CaptainHook\App\Hook\Condition; 16 | use CaptainHook\App\Hooks; 17 | use SebastianFeldmann\Git\Repository; 18 | 19 | /** 20 | * Class CustomValueIsFalsy 21 | * 22 | * Example configuration: 23 | * 24 | * "action": "some-action" 25 | * "conditions": [ 26 | * {"exec": "\\CaptainHook\\App\\Hook\\Condition\\Config\\CustomValueIsFalsy", 27 | * "args": [ 28 | * "NAME_OF_CUSTOM_VALUE" 29 | * ]} 30 | * ] 31 | * 32 | * @package CaptainHook 33 | * @author Sebastian Feldmann 34 | * @link https://github.com/captainhook-git/captainhook 35 | * @since Class available since Release 5.17.2 36 | */ 37 | class CustomValueIsFalsy extends Condition\Config 38 | { 39 | /** 40 | * Custom config value to check 41 | * 42 | * @var string 43 | */ 44 | private string $value; 45 | 46 | /** 47 | * CustomValueIsFalsy constructor 48 | * 49 | * @param string $value 50 | */ 51 | public function __construct(string $value) 52 | { 53 | $this->value = $value; 54 | } 55 | 56 | /** 57 | * Evaluates the condition 58 | * 59 | * @param \CaptainHook\App\Console\IO $io 60 | * @param \SebastianFeldmann\Git\Repository $repository 61 | * @return bool 62 | */ 63 | public function isTrue(IO $io, Repository $repository): bool 64 | { 65 | return !$this->checkCustomValue($this->value, false); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Hook/Condition/Config/CustomValueIsTruthy.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Condition\Config; 13 | 14 | use CaptainHook\App\Console\IO; 15 | use CaptainHook\App\Hook\Condition; 16 | use CaptainHook\App\Hooks; 17 | use SebastianFeldmann\Git\Repository; 18 | 19 | /** 20 | * Class CustomValueIsTruthy 21 | * 22 | * Example configuration: 23 | * 24 | * "action": "some-action" 25 | * "conditions": [ 26 | * {"exec": "\\CaptainHook\\App\\Hook\\Condition\\Config\\CustomValueIsTruthy", 27 | * "args": [ 28 | * "NAME_OF_CUSTOM_VALUE" 29 | * ]} 30 | * ] 31 | * 32 | * @package CaptainHook 33 | * @author Sebastian Feldmann 34 | * @link https://github.com/captainhook-git/captainhook 35 | * @since Class available since Release 5.17.2 36 | */ 37 | class CustomValueIsTruthy extends Condition\Config 38 | { 39 | /** 40 | * Custom config value to check 41 | * 42 | * @var string 43 | */ 44 | private string $value; 45 | 46 | /** 47 | * CustomValueIsTruthy constructor 48 | * 49 | * @param string $value 50 | */ 51 | public function __construct(string $value) 52 | { 53 | $this->value = $value; 54 | } 55 | 56 | /** 57 | * Evaluates the condition 58 | * 59 | * @param \CaptainHook\App\Console\IO $io 60 | * @param \SebastianFeldmann\Git\Repository $repository 61 | * @return bool 62 | */ 63 | public function isTrue(IO $io, Repository $repository): bool 64 | { 65 | return $this->checkCustomValue($this->value, false); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Hook/Condition/ConfigDependant.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Condition; 13 | 14 | use CaptainHook\App\Config; 15 | 16 | /** 17 | * Interface Conditions 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 5.17.2 23 | */ 24 | interface ConfigDependant 25 | { 26 | /** 27 | * Evaluates a condition 28 | * 29 | * This will be deprecated in version 6.0.0 30 | * In version 6.0.0 the condition interface should change to include the Config 31 | * 32 | * @param \CaptainHook\App\Config $config 33 | * @return void 34 | */ 35 | public function setConfig(Config $config): void; 36 | } 37 | -------------------------------------------------------------------------------- /src/Hook/Condition/FileChanged/All.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Condition\FileChanged; 13 | 14 | use CaptainHook\App\Console\IO; 15 | use CaptainHook\App\Hook\Condition\FileChanged; 16 | use SebastianFeldmann\Git\Repository; 17 | 18 | /** 19 | * Class All 20 | * 21 | * The FileChange condition is applicable for `post-merge` and `post-checkout` hooks. 22 | * It checks if all configured files are updated within the last change set. 23 | * 24 | * @package CaptainHook 25 | * @author Sebastian Feldmann 26 | * @link https://github.com/captainhook-git/captainhook 27 | * @since Class available since Release 4.2.0 28 | */ 29 | class All extends FileChanged 30 | { 31 | /** 32 | * Check if all the configured files were changed within the applied change set 33 | * 34 | * IMPORTANT: If no files are configured this condition is always true. 35 | * 36 | * @param \CaptainHook\App\Console\IO $io 37 | * @param \SebastianFeldmann\Git\Repository $repository 38 | * @return bool 39 | */ 40 | public function isTrue(IO $io, Repository $repository): bool 41 | { 42 | return $this->allFilesInHaystack($this->filesToWatch, $this->getChangedFiles($io, $repository)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Hook/Condition/FileChanged/Any.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Condition\FileChanged; 13 | 14 | use CaptainHook\App\Console\IO; 15 | use CaptainHook\App\Hook\Condition\FileChanged; 16 | use SebastianFeldmann\Git\Repository; 17 | 18 | /** 19 | * Class Any 20 | * 21 | * The FileChange condition is applicable for `post-merge` and `post-checkout` hooks. 22 | * For example it can be used to trigger an automatic composer install if the composer.json 23 | * or composer.lock file is changed during a checkout or merge. 24 | * 25 | * Example configuration: 26 | * 27 | * "action": "composer install" 28 | * "conditions": [ 29 | * {"exec": "\\CaptainHook\\App\\Hook\\Condition\\FileChange\\Any", 30 | * "args": [ 31 | * [ 32 | * "composer.json", 33 | * "composer.lock" 34 | * ] 35 | * ]} 36 | * ] 37 | * 38 | * @package CaptainHook 39 | * @author Sebastian Feldmann 40 | * @link https://github.com/captainhook-git/captainhook 41 | * @since Class available since Release 4.2.0 42 | */ 43 | class Any extends FileChanged 44 | { 45 | /** 46 | * Check if any of the configured files was changed within the applied change set 47 | * 48 | * IMPORTANT: If no files are configured this condition is always false. 49 | * 50 | * @param \CaptainHook\App\Console\IO $io 51 | * @param \SebastianFeldmann\Git\Repository $repository 52 | * @return bool 53 | */ 54 | public function isTrue(IO $io, Repository $repository): bool 55 | { 56 | return $this->anyFileInHaystack($this->filesToWatch, $this->getChangedFiles($io, $repository)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Hook/Condition/FileChanged/OfType.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Condition\FileChanged; 13 | 14 | use CaptainHook\App\Console\IO; 15 | use CaptainHook\App\Git; 16 | use CaptainHook\App\Hook\Condition; 17 | use CaptainHook\App\Hook\Constrained; 18 | use CaptainHook\App\Hook\FileList; 19 | use CaptainHook\App\Hook\Restriction; 20 | use CaptainHook\App\Hooks; 21 | use SebastianFeldmann\Git\Repository; 22 | 23 | /** 24 | * Class OfType 25 | * 26 | * Example configuration: 27 | * 28 | * "action": "some-action" 29 | * "conditions": [ 30 | * {"exec": "\\CaptainHook\\App\\Hook\\Condition\\FileChanged\\OfType", 31 | * "args": [ 32 | * "php" 33 | * ]} 34 | * ] 35 | * 36 | * @package CaptainHook 37 | * @author Sebastian Feldmann 38 | * @link https://github.com/captainhook-git/captainhook 39 | * @since Class available since Release 5.0.0 40 | */ 41 | class OfType implements Condition, Constrained 42 | { 43 | /** 44 | * File type to check e.g. 'php' or 'html' 45 | * 46 | * @var string 47 | */ 48 | private string $suffix; 49 | 50 | /** 51 | * OfType constructor 52 | * 53 | * @param string $type 54 | */ 55 | public function __construct(string $type) 56 | { 57 | $this->suffix = $type; 58 | } 59 | 60 | /** 61 | * Return the hook restriction information 62 | * 63 | * @return \CaptainHook\App\Hook\Restriction 64 | */ 65 | public static function getRestriction(): Restriction 66 | { 67 | return Restriction::fromArray([Hooks::PRE_PUSH, Hooks::POST_CHECKOUT, Hooks::POST_MERGE, Hooks::POST_REWRITE]); 68 | } 69 | 70 | /** 71 | * Evaluates the condition 72 | * 73 | * @param \CaptainHook\App\Console\IO $io 74 | * @param \SebastianFeldmann\Git\Repository $repository 75 | * @return bool 76 | */ 77 | public function isTrue(IO $io, Repository $repository): bool 78 | { 79 | $factory = new Git\ChangedFiles\Detector\Factory(); 80 | $detector = $factory->getDetector($io, $repository); 81 | 82 | $files = $detector->getChangedFiles(['A', 'C', 'M', 'R']); 83 | $files = FileList::filterByType($files, ['of-type' => $this->suffix]); 84 | 85 | if (count($files) > 0) { 86 | return true; 87 | } 88 | return false; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Hook/Condition/FileStaged.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Condition; 13 | 14 | use CaptainHook\App\Console\IO; 15 | use CaptainHook\App\Git\Diff\FilterUtil; 16 | use CaptainHook\App\Hook\Restriction; 17 | use CaptainHook\App\Hooks; 18 | use SebastianFeldmann\Git\Repository; 19 | 20 | /** 21 | * Class FileChange 22 | * 23 | * @package CaptainHook 24 | * @author Sebastian Feldmann 25 | * @link https://github.com/captainhook-git/captainhook 26 | * @since Class available since Release 5.2.0 27 | */ 28 | abstract class FileStaged extends File 29 | { 30 | /** 31 | * List of file to watch 32 | * 33 | * @var array 34 | */ 35 | protected array $filesToWatch; 36 | 37 | /** 38 | * --diff-filter options 39 | * 40 | * @var array 41 | */ 42 | protected array $diffFilter; 43 | 44 | /** 45 | * FileStaged constructor 46 | * 47 | * @param mixed $files 48 | * @param mixed $diffFilter 49 | */ 50 | public function __construct($files, $diffFilter = []) 51 | { 52 | $this->filesToWatch = is_array($files) ? $files : explode(',', (string) $files); 53 | $this->diffFilter = FilterUtil::filterFromConfigValue($diffFilter); 54 | } 55 | 56 | /** 57 | * Return the hook restriction information 58 | * 59 | * @return \CaptainHook\App\Hook\Restriction 60 | */ 61 | public static function getRestriction(): Restriction 62 | { 63 | return Restriction::fromArray([Hooks::PRE_COMMIT]); 64 | } 65 | 66 | /** 67 | * Evaluates a condition 68 | * 69 | * @param \CaptainHook\App\Console\IO $io 70 | * @param \SebastianFeldmann\Git\Repository $repository 71 | * @return bool 72 | */ 73 | abstract public function isTrue(IO $io, Repository $repository): bool; 74 | 75 | /** 76 | * Use 'diff-index --cached' to find the staged files before the commit 77 | * 78 | * @param \SebastianFeldmann\Git\Repository $repository 79 | * @return array 80 | */ 81 | protected function getStagedFiles(Repository $repository): array 82 | { 83 | return $repository->getIndexOperator()->getStagedFiles($this->diffFilter); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Hook/Condition/FileStaged/All.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Condition\FileStaged; 13 | 14 | use CaptainHook\App\Console\IO; 15 | use CaptainHook\App\Hook\Condition\FileStaged; 16 | use SebastianFeldmann\Git\Repository; 17 | 18 | /** 19 | * Class All 20 | * 21 | * The FileStaged condition is applicable for `pre-commit` hooks. 22 | * It checks if all configured files are staged for commit. 23 | * 24 | * Example configuration: 25 | * 26 | * "action": "some-action" 27 | * "conditions": [ 28 | * {"exec": "\\CaptainHook\\App\\Hook\\Condition\\FileStaged\\All", 29 | * "args": [ 30 | * ["file1", "file2", "file3"] 31 | * ]} 32 | * ] 33 | * 34 | * The file list can also be defined as comma seperated string "file1,file2,file3" 35 | * 36 | * @package CaptainHook 37 | * @author Sebastian Feldmann 38 | * @link https://github.com/captainhook-git/captainhook 39 | * @since Class available since Release 5.2.0 40 | */ 41 | class All extends FileStaged 42 | { 43 | /** 44 | * Check if all the configured files are staged for commit 45 | * 46 | * @param \CaptainHook\App\Console\IO $io 47 | * @param \SebastianFeldmann\Git\Repository $repository 48 | * @return bool 49 | */ 50 | public function isTrue(IO $io, Repository $repository): bool 51 | { 52 | return $this->allFilesInHaystack($this->filesToWatch, $this->getStagedFiles($repository)); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Hook/Condition/FileStaged/Any.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Condition\FileStaged; 13 | 14 | use CaptainHook\App\Console\IO; 15 | use CaptainHook\App\Hook\Condition\FileStaged; 16 | use SebastianFeldmann\Git\Repository; 17 | 18 | /** 19 | * Class Any 20 | * 21 | * The FileStaged condition is applicable for `pre-commit hooks. 22 | * 23 | * Example configuration: 24 | * 25 | * "action": "some-action" 26 | * "conditions": [ 27 | * {"exec": "\\CaptainHook\\App\\Hook\\Condition\\FileStaged\\Any", 28 | * "args": [ 29 | * ["file1", "file2", "file3"] 30 | * ]} 31 | * ] 32 | * 33 | * The file list can also be defined as comma seperated string "file1,file2,file3" 34 | * 35 | * @package CaptainHook 36 | * @author Sebastian Feldmann 37 | * @link https://github.com/captainhook-git/captainhook 38 | * @since Class available since Release 5.2.0 39 | */ 40 | class Any extends FileStaged 41 | { 42 | /** 43 | * Check if any of the configured files is staged for commit 44 | * 45 | * @param \CaptainHook\App\Console\IO $io 46 | * @param \SebastianFeldmann\Git\Repository $repository 47 | * @return bool 48 | */ 49 | public function isTrue(IO $io, Repository $repository): bool 50 | { 51 | return $this->anyFileInHaystack($this->filesToWatch, $this->getStagedFiles($repository)); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Hook/Condition/Logic.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace CaptainHook\App\Hook\Condition; 15 | 16 | use CaptainHook\App\Hook\Condition; 17 | 18 | /** 19 | * Logical condition base class 20 | * 21 | * @package CaptainHook 22 | * @author Sebastian Feldmann 23 | * @author Andreas Heigl 24 | * @link https://github.com/captainhook-git/captainhook 25 | * @since Class available since Release 5.7.0 26 | */ 27 | abstract class Logic implements Condition 28 | { 29 | /** 30 | * List of conditions to logically connect 31 | * 32 | * @var \CaptainHook\App\Hook\Condition[] 33 | */ 34 | protected array $conditions = []; 35 | 36 | final private function __construct(Condition ...$conditions) 37 | { 38 | $this->conditions = $conditions; 39 | } 40 | 41 | /** 42 | * Create a logic condition 43 | * 44 | * @param array $conditions 45 | * @return \CaptainHook\App\Hook\Condition 46 | */ 47 | public static function fromConditionsArray(array $conditions): Condition 48 | { 49 | $realConditions = []; 50 | foreach ($conditions as $condition) { 51 | if (! $condition instanceof Condition) { 52 | continue; 53 | } 54 | $realConditions[] = $condition; 55 | } 56 | 57 | return new static(...$realConditions); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Hook/Condition/Logic/LogicAnd.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace CaptainHook\App\Hook\Condition\Logic; 15 | 16 | use CaptainHook\App\Console\IO; 17 | use CaptainHook\App\Hook\Condition\Logic; 18 | use SebastianFeldmann\Git\Repository; 19 | 20 | /** 21 | * Connects multiple conditions with 'and' 22 | * 23 | * @package CaptainHook 24 | * @author Sebastian Feldmann 25 | * @author Andreas Heigl 26 | * @link https://github.com/captainhook-git/captainhook 27 | * @since Class available since Release 5.7.0 28 | */ 29 | final class LogicAnd extends Logic 30 | { 31 | public function isTrue(IO $io, Repository $repository): bool 32 | { 33 | foreach ($this->conditions as $condition) { 34 | if (false === $condition->isTrue($io, $repository)) { 35 | return false; 36 | } 37 | } 38 | return true; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Hook/Condition/Logic/LogicOr.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace CaptainHook\App\Hook\Condition\Logic; 15 | 16 | use CaptainHook\App\Console\IO; 17 | use CaptainHook\App\Hook\Condition\Logic; 18 | use SebastianFeldmann\Git\Repository; 19 | 20 | /** 21 | * Connects multiple conditions with 'or' 22 | * 23 | * @package CaptainHook 24 | * @author Sebastian Feldmann 25 | * @author Andreas Heigl 26 | * @link https://github.com/captainhook-git/captainhook 27 | * @since Class available since Release 5.7.0 28 | */ 29 | final class LogicOr extends Logic 30 | { 31 | public function isTrue(IO $io, Repository $repository): bool 32 | { 33 | foreach ($this->conditions as $condition) { 34 | if (true === $condition->isTrue($io, $repository)) { 35 | return true; 36 | } 37 | } 38 | return false; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Hook/Condition/OnBranch.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace CaptainHook\App\Hook\Condition; 15 | 16 | use CaptainHook\App\Console\IO; 17 | use CaptainHook\App\Hook\Condition; 18 | use SebastianFeldmann\Git\Repository; 19 | 20 | /** 21 | * OnBranch condition 22 | * 23 | * @package CaptainHook 24 | * @author Sebastian Feldmann 25 | * @link https://github.com/captainhook-git/captainhook 26 | * @since Class available since Release 5.0.0 27 | * @deprecated Replaced be CaptainHook\App\Hook\Condition\Branch\CurrentlyOn 28 | */ 29 | class OnBranch extends Condition\Branch\On 30 | { 31 | } 32 | -------------------------------------------------------------------------------- /src/Hook/Constrained.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace CaptainHook\App\Hook; 15 | 16 | /** 17 | * Interface Constrained 18 | * 19 | * If your action is only applicable for a certain set of hooks you can limit its execution to specific hooks by 20 | * implementing this interface and returning a restriction value object. 21 | * 22 | * @package CaptainHook 23 | * @author Sebastian Feldmann 24 | * @link https://github.com/captainhook-git/captainhook 25 | * @since Class available since Release 5.0.0 26 | */ 27 | interface Constrained 28 | { 29 | /** 30 | * Returns the list of hooks where this action is applicable 31 | * 32 | * @return \CaptainHook\App\Hook\Restriction 33 | */ 34 | public static function getRestriction(): Restriction; 35 | } 36 | -------------------------------------------------------------------------------- /src/Hook/Debug.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook; 13 | 14 | use CaptainHook\App\Config; 15 | use CaptainHook\App\Console\IO; 16 | use CaptainHook\App\Exception\ActionFailed; 17 | use SebastianFeldmann\Git\Repository; 18 | 19 | /** 20 | * Debug hook to test hook triggering 21 | * 22 | * @package CaptainHook 23 | * @author Sebastian Feldmann 24 | * @link https://github.com/captainhook-git/captainhook 25 | * @since Class available since Release 4.0.4 26 | */ 27 | abstract class Debug implements Action 28 | { 29 | /** 30 | * Executes the action 31 | * 32 | * @param \CaptainHook\App\Config $config 33 | * @param \CaptainHook\App\Console\IO $io 34 | * @param \SebastianFeldmann\Git\Repository $repository 35 | * @param \CaptainHook\App\Config\Action $action 36 | * @return void 37 | * @throws \Exception 38 | */ 39 | abstract public function execute(Config $config, IO $io, Repository $repository, Config\Action $action): void; 40 | 41 | /** 42 | * Generate some debug output 43 | * 44 | * @param \CaptainHook\App\Console\IO $io 45 | * @param \SebastianFeldmann\Git\Repository $repository 46 | * @return void 47 | */ 48 | protected function debugOutput(IO $io, Repository $repository): void 49 | { 50 | $originalHookArguments = $io->getArguments(); 51 | $currentGitTag = $repository->getInfoOperator()->getCurrentTag(); 52 | 53 | $io->write(['', '']); 54 | $io->write('Executing Dummy action'); 55 | $io->write($this->getArgumentOutput($originalHookArguments)); 56 | $io->write(' Current git-tag: ' . $currentGitTag . ''); 57 | $io->write(' StandardInput: ' . PHP_EOL . ' ' . implode(PHP_EOL . ' ', $io->getStandardInput())); 58 | } 59 | 60 | /** 61 | * Format output to display original hook arguments 62 | * 63 | * @param array $args 64 | * @return string 65 | */ 66 | protected function getArgumentOutput(array $args): string 67 | { 68 | $out = ' Original arguments:' . PHP_EOL; 69 | foreach ($args as $name => $value) { 70 | $out .= ' ' . $name . ' => ' . $value . '' . PHP_EOL; 71 | } 72 | return trim($out); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Hook/Debug/Failure.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Debug; 13 | 14 | use CaptainHook\App\Config; 15 | use CaptainHook\App\Console\IO; 16 | use CaptainHook\App\Exception\ActionFailed; 17 | use CaptainHook\App\Hook\Debug; 18 | use SebastianFeldmann\Git\Repository; 19 | 20 | /** 21 | * Debug hook to test hook triggering that fails the hook execution 22 | * 23 | * @package CaptainHook 24 | * @author Sebastian Feldmann 25 | * @link https://github.com/captainhook-git/captainhook 26 | * @since Class available since Release 5.20.1 27 | */ 28 | class Failure extends Debug 29 | { 30 | /** 31 | * Executes the action 32 | * 33 | * @param \CaptainHook\App\Config $config 34 | * @param \CaptainHook\App\Console\IO $io 35 | * @param \SebastianFeldmann\Git\Repository $repository 36 | * @param \CaptainHook\App\Config\Action $action 37 | * @return void 38 | * @throws \Exception 39 | */ 40 | public function execute(Config $config, IO $io, Repository $repository, Config\Action $action): void 41 | { 42 | $this->debugOutput($io, $repository); 43 | 44 | throw new ActionFailed( 45 | 'The \'Debug\' action is only for debugging purposes, ' 46 | . 'please remove the \'Debug\' action from your config' 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Hook/Debug/Success.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Debug; 13 | 14 | use CaptainHook\App\Config; 15 | use CaptainHook\App\Console\IO; 16 | use CaptainHook\App\Hook\Debug; 17 | use SebastianFeldmann\Git\Repository; 18 | 19 | /** 20 | * Debug hook to test hook triggering that allows the hook to pass 21 | * 22 | * @package CaptainHook 23 | * @author Sebastian Feldmann 24 | * @link https://github.com/captainhook-git/captainhook 25 | * @since Class available since Release 4.0.4 26 | */ 27 | class Success extends Debug 28 | { 29 | /** 30 | * Executes the action 31 | * 32 | * @param \CaptainHook\App\Config $config 33 | * @param \CaptainHook\App\Console\IO $io 34 | * @param \SebastianFeldmann\Git\Repository $repository 35 | * @param \CaptainHook\App\Config\Action $action 36 | * @return void 37 | * @throws \Exception 38 | */ 39 | public function execute(Config $config, IO $io, Repository $repository, Config\Action $action): void 40 | { 41 | $this->debugOutput($io, $repository); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Hook/EventSubscriber.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook; 13 | 14 | use CaptainHook\App\Config\Action as ActionConfig; 15 | 16 | /** 17 | * Interface EventSubscriber 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 5.11.0 23 | */ 24 | interface EventSubscriber 25 | { 26 | /** 27 | * Returns a list of event handlers 28 | * 29 | * @param \CaptainHook\App\Config\Action $action 30 | * @return array> 31 | * @throws \Exception 32 | */ 33 | public static function getEventHandlers(ActionConfig $action): array; 34 | } 35 | -------------------------------------------------------------------------------- /src/Hook/File/Action/IsEmpty.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\File\Action; 13 | 14 | use SebastianFeldmann\Git\Repository; 15 | 16 | /** 17 | * Class IsEmpty 18 | * 19 | * @package CaptainHook 20 | * @author Felix Edelmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 5.4.0 23 | */ 24 | class IsEmpty extends Emptiness 25 | { 26 | /** 27 | * Actual action name for better error messages 28 | * 29 | * @var string 30 | */ 31 | protected string $actionName = 'IsEmpty'; 32 | 33 | /** 34 | * Checks if the file is valid or not 35 | * 36 | * @param \SebastianFeldmann\Git\Repository $repository 37 | * @param string $file 38 | * @return bool 39 | */ 40 | protected function isValid(Repository $repository, string $file): bool 41 | { 42 | return $this->isEmpty($file); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Hook/File/Action/IsNotEmpty.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\File\Action; 13 | 14 | use SebastianFeldmann\Git\Repository; 15 | 16 | /** 17 | * Class IsNotEmpty 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 5.4.1 23 | */ 24 | class IsNotEmpty extends Emptiness 25 | { 26 | /** 27 | * Actual action name for better error messages 28 | * 29 | * @var string 30 | */ 31 | protected string $actionName = 'IsNotEmpty'; 32 | 33 | /** 34 | * Checks if the file is valid or not 35 | * 36 | * @param \SebastianFeldmann\Git\Repository $repository 37 | * @param string $file 38 | * @return bool 39 | */ 40 | protected function isValid(Repository $repository, string $file): bool 41 | { 42 | return !$this->isEmpty($file); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Hook/Message/Action/Beams.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace CaptainHook\App\Hook\Message\Action; 15 | 16 | use CaptainHook\App\Config; 17 | use CaptainHook\App\Console\IO; 18 | use CaptainHook\App\Hook\Message\RuleBook; 19 | use SebastianFeldmann\Git\Repository; 20 | 21 | /** 22 | * Class Beams 23 | * 24 | * @package CaptainHook 25 | * @author Sebastian Feldmann 26 | * @link https://github.com/captainhook-git/captainhook 27 | * @since Class available since Release 0.9.0 28 | */ 29 | class Beams extends Book 30 | { 31 | /** 32 | * Execute the configured action 33 | * 34 | * @param \CaptainHook\App\Config $config 35 | * @param \CaptainHook\App\Console\IO $io 36 | * @param \SebastianFeldmann\Git\Repository $repository 37 | * @param \CaptainHook\App\Config\Action $action 38 | * @return void 39 | * @throws \Exception 40 | */ 41 | public function execute(Config $config, IO $io, Repository $repository, Config\Action $action): void 42 | { 43 | $options = $action->getOptions(); 44 | $book = new RuleBook(); 45 | $book->setRules(RuleBook\RuleSet::beams( 46 | (int) $options->get('subjectLength', 50), 47 | (int) $options->get('bodyLineLength', 72), 48 | (bool) $options->get('checkImperativeBeginningOnly', false) 49 | )); 50 | 51 | $this->validate($book, $repository, $io); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Hook/Message/Action/CacheOnFail.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace CaptainHook\App\Hook\Message\Action; 15 | 16 | use CaptainHook\App\Config; 17 | use CaptainHook\App\Console\IO; 18 | use CaptainHook\App\Exception\ActionFailed; 19 | use CaptainHook\App\Hook\Action; 20 | use CaptainHook\App\Hook\EventSubscriber; 21 | use CaptainHook\App\Hook\Message\EventHandler\WriteCacheFile; 22 | use SebastianFeldmann\Git\Repository; 23 | 24 | /** 25 | * Class FailedStore 26 | * 27 | * @package CaptainHook 28 | * @author Sebastian Feldmann 29 | * @link https://github.com/captainhook-git/captainhook 30 | * @since Class available since Release 5.11.0 31 | */ 32 | class CacheOnFail implements Action, EventSubscriber 33 | { 34 | /** 35 | * Execute the configured action 36 | * 37 | * @param \CaptainHook\App\Config $config 38 | * @param \CaptainHook\App\Console\IO $io 39 | * @param \SebastianFeldmann\Git\Repository $repository 40 | * @param \CaptainHook\App\Config\Action $action 41 | * @return void 42 | * @throws \Exception 43 | */ 44 | public function execute(Config $config, IO $io, Repository $repository, Config\Action $action): void 45 | { 46 | // this action is just registering some event handler, so nothing to see here 47 | } 48 | 49 | /** 50 | * Returns a list of event handlers 51 | * 52 | * @param \CaptainHook\App\Config\Action $action 53 | * @return array> 54 | * @throws \Exception 55 | */ 56 | public static function getEventHandlers(Config\Action $action): array 57 | { 58 | // make sure the cache file is configured 59 | if (empty($action->getOptions()->get('file', ''))) { 60 | throw new ActionFailed('CacheOnFail requires \'file\' option'); 61 | } 62 | return [ 63 | 'onHookFailure' => [new WriteCacheFile($action->getOptions()->get('file', ''))] 64 | ]; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Hook/Message/Action/Prepare.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Message\Action; 13 | 14 | use CaptainHook\App\Config; 15 | use CaptainHook\App\Console\IO; 16 | use CaptainHook\App\Hook\Action; 17 | use SebastianFeldmann\Git\CommitMessage; 18 | use SebastianFeldmann\Git\Repository; 19 | 20 | /** 21 | * Class Prepare 22 | * 23 | * @package CaptainHook 24 | * @author Sebastian Feldmann 25 | * @link https://github.com/captainhook-git/captainhook 26 | * @since Class available since Release 3.1.0 27 | */ 28 | class Prepare implements Action 29 | { 30 | /** 31 | * Executes the action 32 | * 33 | * @param \CaptainHook\App\Config $config 34 | * @param \CaptainHook\App\Console\IO $io 35 | * @param \SebastianFeldmann\Git\Repository $repository 36 | * @param \CaptainHook\App\Config\Action $action 37 | * @return void 38 | * @throws \Exception 39 | */ 40 | public function execute(Config $config, IO $io, Repository $repository, Config\Action $action): void 41 | { 42 | $options = $action->getOptions(); 43 | $oldMsg = $repository->getCommitMsg(); 44 | 45 | if (!$repository->isMerging()) { 46 | $repository->setCommitMsg(new CommitMessage($options->get('message', ''), $oldMsg->getCommentCharacter())); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Hook/Message/Action/PrepareFromFile.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace CaptainHook\App\Hook\Message\Action; 15 | 16 | use CaptainHook\App\Config; 17 | use CaptainHook\App\Console\IO; 18 | use CaptainHook\App\Exception\ActionFailed; 19 | use CaptainHook\App\Hook\Action; 20 | use SebastianFeldmann\Git\CommitMessage; 21 | use SebastianFeldmann\Git\Repository; 22 | 23 | /** 24 | * Class PrepareFromFile 25 | * 26 | * Example configuration: 27 | * { 28 | * "action": "\\CaptainHook\\App\\Hook\\Message\\Action\\PrepareFromFile" 29 | * "options": { 30 | * "file": ".git/CH_MSG_CACHE" 31 | * } 32 | * } 33 | * 34 | * @package CaptainHook 35 | * @author Sebastian Feldmann 36 | * @link https://github.com/captainhook-git/captainhook 37 | * @since Class available since Release 5.11.0 38 | */ 39 | class PrepareFromFile implements Action 40 | { 41 | /** 42 | * Execute the configured action 43 | * 44 | * @param \CaptainHook\App\Config $config 45 | * @param \CaptainHook\App\Console\IO $io 46 | * @param \SebastianFeldmann\Git\Repository $repository 47 | * @param \CaptainHook\App\Config\Action $action 48 | * @return void 49 | * @throws \Exception 50 | */ 51 | public function execute(Config $config, IO $io, Repository $repository, Config\Action $action): void 52 | { 53 | $options = $action->getOptions(); 54 | $cacheFile = $repository->getRoot() . '/' . $options->get('file', ''); 55 | if (empty($options->get('file', ''))) { 56 | throw new ActionFailed('PrepareFromFile requires \'file\' option'); 57 | } 58 | 59 | if (!is_file($cacheFile)) { 60 | return; 61 | } 62 | 63 | // if there is a commit message don't do anything just delete the file 64 | if ($repository->getCommitMsg()->isEmpty()) { 65 | $msg = (string)file_get_contents($cacheFile); 66 | $repository->setCommitMsg( 67 | new CommitMessage($msg, $repository->getCommitMsg()->getCommentCharacter()) 68 | ); 69 | } 70 | 71 | if (!$options->get('keep', false)) { 72 | unlink($cacheFile); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Hook/Message/EventHandler/WriteCacheFile.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Message\EventHandler; 13 | 14 | use CaptainHook\App\Event; 15 | use CaptainHook\App\Event\Handler; 16 | 17 | /** 18 | * Writes to commit message cache file to load it for a later commit 19 | * 20 | * @package CaptainHook 21 | * @author Sebastian Feldmann 22 | * @link https://github.com/captainhook-git/captainhook 23 | * @since Class available since Release 5.11.0 24 | */ 25 | class WriteCacheFile implements Handler 26 | { 27 | /** 28 | * Path to the commit message cache file 29 | * 30 | * @var string 31 | */ 32 | private $file; 33 | 34 | /** 35 | * @param string $file 36 | */ 37 | public function __construct(string $file) 38 | { 39 | $this->file = $file; 40 | } 41 | /** 42 | * Writes the commit message to a cache file to reuse it for the next commit 43 | * 44 | * @return void 45 | */ 46 | public function handle(Event $event) 47 | { 48 | $msg = $event->repository()->getCommitMsg()->getRawContent(); 49 | $path = $event->repository()->getRoot() . '/' . $this->file; 50 | file_put_contents($path, $msg); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Hook/Message/Rule.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Message; 13 | 14 | use SebastianFeldmann\Git\CommitMessage; 15 | 16 | /** 17 | * Interface Rule 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 0.9.0 23 | */ 24 | interface Rule 25 | { 26 | /** 27 | * Return a hint how to pass the rule. 28 | * 29 | * @return string 30 | */ 31 | public function getHint(): string; 32 | 33 | /** 34 | * Checks if a commit message passes the rule. 35 | * 36 | * @param \SebastianFeldmann\Git\CommitMessage $msg 37 | * @return bool 38 | */ 39 | public function pass(CommitMessage $msg): bool; 40 | } 41 | -------------------------------------------------------------------------------- /src/Hook/Message/Rule/Base.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Message\Rule; 13 | 14 | use SebastianFeldmann\Git\CommitMessage; 15 | use CaptainHook\App\Hook\Message\Rule; 16 | 17 | /** 18 | * Class Base 19 | * 20 | * @package CaptainHook 21 | * @author Sebastian Feldmann 22 | * @link https://github.com/captainhook-git/captainhook 23 | * @since Class available since Release 0.9.0 24 | */ 25 | abstract class Base implements Rule 26 | { 27 | /** 28 | * Rule hint. 29 | * 30 | * @var string 31 | */ 32 | protected $hint; 33 | 34 | /** 35 | * @return string 36 | */ 37 | public function getHint(): string 38 | { 39 | return $this->hint; 40 | } 41 | 42 | /** 43 | * @param \SebastianFeldmann\Git\CommitMessage $msg 44 | * @return bool 45 | */ 46 | abstract public function pass(CommitMessage $msg): bool; 47 | } 48 | -------------------------------------------------------------------------------- /src/Hook/Message/Rule/CapitalizeSubject.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Message\Rule; 13 | 14 | use SebastianFeldmann\Git\CommitMessage; 15 | 16 | /** 17 | * Class CapitalizeSubject 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 0.9.0 23 | */ 24 | class CapitalizeSubject extends Base 25 | { 26 | /** 27 | * Constructor 28 | */ 29 | public function __construct() 30 | { 31 | $this->hint = 'Subject line has to start with an upper case letter'; 32 | } 33 | 34 | /** 35 | * Check if commit message starts with upper case letter 36 | * 37 | * @param \SebastianFeldmann\Git\CommitMessage $msg 38 | * @return bool 39 | */ 40 | public function pass(CommitMessage $msg): bool 41 | { 42 | if (!$msg->isEmpty()) { 43 | $firstLetter = substr($msg->getSubject(), 0, 1); 44 | return $firstLetter === strtoupper($firstLetter); 45 | } 46 | return false; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Hook/Message/Rule/LimitBodyLineLength.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Message\Rule; 13 | 14 | use SebastianFeldmann\Git\CommitMessage; 15 | 16 | /** 17 | * Class LimitBodyLineLength 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 0.9.0 23 | */ 24 | class LimitBodyLineLength extends Base 25 | { 26 | /** 27 | * Length limit 28 | * 29 | * @var int 30 | */ 31 | protected $maxLength; 32 | 33 | /** 34 | * Constructor 35 | * 36 | * @param int $length 37 | */ 38 | public function __construct($length = 72) 39 | { 40 | $this->hint = 'Body lines should not exceed ' . $length . ' characters'; 41 | $this->maxLength = $length; 42 | } 43 | 44 | /** 45 | * Check if a body line doesn't exceed the max length limit 46 | * 47 | * @param \SebastianFeldmann\Git\CommitMessage $msg 48 | * @return bool 49 | */ 50 | public function pass(CommitMessage $msg): bool 51 | { 52 | $lineNr = 1; 53 | foreach ($msg->getBodyLines() as $line) { 54 | if (mb_strlen($line) > $this->maxLength) { 55 | $this->hint .= PHP_EOL . 'Line ' . $lineNr . ' of your body exceeds the max line length'; 56 | return false; 57 | } 58 | $lineNr++; 59 | } 60 | return true; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Hook/Message/Rule/LimitSubjectLength.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Message\Rule; 13 | 14 | use SebastianFeldmann\Git\CommitMessage; 15 | 16 | /** 17 | * Class LimitSubjectLength 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 0.9.0 23 | */ 24 | class LimitSubjectLength extends Base 25 | { 26 | /** 27 | * Length limit 28 | * 29 | * @var int 30 | */ 31 | protected $maxLength; 32 | 33 | /** 34 | * Constructor 35 | * 36 | * @param int $length 37 | */ 38 | public function __construct(int $length = 50) 39 | { 40 | $this->hint = 'Subject line should not exceed ' . $length . ' characters'; 41 | $this->maxLength = $length; 42 | } 43 | 44 | /** 45 | * Check if commit message doesn't exceeed the max length 46 | * 47 | * @param \SebastianFeldmann\Git\CommitMessage $msg 48 | * @return bool 49 | */ 50 | public function pass(CommitMessage $msg): bool 51 | { 52 | $subjectLength = mb_strlen($msg->getSubject()); 53 | if ($subjectLength > $this->maxLength) { 54 | $this->hint .= ' (' . $subjectLength . ')'; 55 | return false; 56 | } 57 | return true; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Hook/Message/Rule/MsgNotEmpty.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Message\Rule; 13 | 14 | use SebastianFeldmann\Git\CommitMessage; 15 | 16 | /** 17 | * Class MsgNotEmpty 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 0.9.0 23 | */ 24 | class MsgNotEmpty extends Base 25 | { 26 | /** 27 | * SubjectStartsUpperCase constructor 28 | */ 29 | public function __construct() 30 | { 31 | $this->hint = 'Commit message can not be empty'; 32 | } 33 | 34 | /** 35 | * Check if commit message is not empty 36 | * 37 | * @param \SebastianFeldmann\Git\CommitMessage $msg 38 | * @return bool 39 | */ 40 | public function pass(CommitMessage $msg): bool 41 | { 42 | return !$msg->isEmpty(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Hook/Message/Rule/NoPeriodOnSubjectEnd.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Message\Rule; 13 | 14 | use SebastianFeldmann\Git\CommitMessage; 15 | 16 | /** 17 | * Class NoPeriodOnSubjectEnd 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 0.9.0 23 | */ 24 | class NoPeriodOnSubjectEnd extends Base 25 | { 26 | /** 27 | * Constructor 28 | */ 29 | public function __construct() 30 | { 31 | $this->hint = 'Subject should not end with a period'; 32 | } 33 | 34 | /** 35 | * Check if commit message doesn't end with a period 36 | * 37 | * @param \SebastianFeldmann\Git\CommitMessage $msg 38 | * @return bool 39 | */ 40 | public function pass(CommitMessage $msg): bool 41 | { 42 | return substr(trim($msg->getSubject()), -1) !== '.'; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Hook/Message/Rule/SeparateSubjectFromBodyWithBlankLine.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Message\Rule; 13 | 14 | use SebastianFeldmann\Git\CommitMessage; 15 | 16 | /** 17 | * Class SeparateSubjectFromBodyWithBlankLine 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 0.9.0 23 | */ 24 | class SeparateSubjectFromBodyWithBlankLine extends Base 25 | { 26 | /** 27 | * Constructor 28 | */ 29 | public function __construct() 30 | { 31 | $this->hint = 'Subject and body have to be separated by a blank line'; 32 | } 33 | 34 | /** 35 | * Check if subject and body are separated by a blank line 36 | * 37 | * @param \SebastianFeldmann\Git\CommitMessage $msg 38 | * @return bool 39 | */ 40 | public function pass(CommitMessage $msg): bool 41 | { 42 | return $msg->getContentLineCount() < 2 || empty($msg->getContentLine(1)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Hook/Message/Rule/UseImperativeMood.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Message\Rule; 13 | 14 | /** 15 | * Class UseImperativeMood 16 | * 17 | * @package CaptainHook 18 | * @author Sebastian Feldmann 19 | * @link https://github.com/captainhook-git/captainhook 20 | * @since Class available since Release 0.9.0 21 | */ 22 | class UseImperativeMood extends Blacklist 23 | { 24 | /** 25 | * Constructor 26 | * 27 | * @param bool $checkOnlyBeginning 28 | */ 29 | public function __construct(bool $checkOnlyBeginning = false) 30 | { 31 | parent::__construct(); 32 | 33 | $this->hint = 'A commit message subject should always complete the following sentence.' . PHP_EOL . 34 | 'This commit will [YOUR COMMIT MESSAGE].'; 35 | 36 | $this->setSubjectBlacklist( 37 | [ 38 | 'added', 39 | 'changed', 40 | 'created', 41 | 'deleted', 42 | 'fixed', 43 | 'reformatted', 44 | 'removed', 45 | 'updated', 46 | 'uploaded' 47 | ] 48 | ); 49 | 50 | if ($checkOnlyBeginning) { 51 | // overwrite the detection logic to only check the beginning og the string 52 | $this->stringDetection = function (string $content, string $term): bool { 53 | return strpos($content, $term) === 0; 54 | }; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Hook/Message/RuleBook.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Message; 13 | 14 | use SebastianFeldmann\Git\CommitMessage; 15 | 16 | /** 17 | * Class RuleBook 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 0.9.0 23 | */ 24 | class RuleBook 25 | { 26 | /** 27 | * List of rules to check 28 | * 29 | * @var \CaptainHook\App\Hook\Message\Rule[] 30 | */ 31 | private $rules = []; 32 | 33 | /** 34 | * Set rules to check 35 | * 36 | * @param \CaptainHook\App\Hook\Message\Rule[] $rules 37 | * @return \CaptainHook\App\Hook\Message\RuleBook 38 | */ 39 | public function setRules(array $rules): RuleBook 40 | { 41 | $this->rules = $rules; 42 | return $this; 43 | } 44 | 45 | /** 46 | * Add a rule to the list 47 | * 48 | * @param \CaptainHook\App\Hook\Message\Rule $rule 49 | * @return \CaptainHook\App\Hook\Message\RuleBook 50 | */ 51 | public function addRule(Rule $rule): RuleBook 52 | { 53 | $this->rules[] = $rule; 54 | return $this; 55 | } 56 | 57 | /** 58 | * Validates all rules 59 | * 60 | * Returns a list of problems found checking the commit message. 61 | * If the list is empty the message is valid. 62 | * 63 | * @param \SebastianFeldmann\Git\CommitMessage $msg 64 | * @return array 65 | */ 66 | public function validate(CommitMessage $msg): array 67 | { 68 | $problems = []; 69 | foreach ($this->rules as $rule) { 70 | if (!$rule->pass($msg)) { 71 | $problems[] = $rule->getHint(); 72 | } 73 | } 74 | return $problems; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/Hook/Message/RuleBook/RuleSet.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Message\RuleBook; 13 | 14 | use CaptainHook\App\Hook\Message\Rule; 15 | 16 | /** 17 | * Class RuleSet 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 2.1.0 23 | */ 24 | abstract class RuleSet 25 | { 26 | /** 27 | * Return Beams rule set 28 | * 29 | * @param int $subjectLength 30 | * @param int $bodyLineLength 31 | * @param bool $checkImperativeBeginningOnly 32 | * @return \CaptainHook\App\Hook\Message\Rule[] 33 | */ 34 | public static function beams( 35 | int $subjectLength = 50, 36 | int $bodyLineLength = 72, 37 | bool $checkImperativeBeginningOnly = false 38 | ): array { 39 | return [ 40 | new Rule\CapitalizeSubject(), 41 | new Rule\LimitSubjectLength($subjectLength), 42 | new Rule\NoPeriodOnSubjectEnd(), 43 | new Rule\UseImperativeMood($checkImperativeBeginningOnly), 44 | new Rule\LimitBodyLineLength($bodyLineLength), 45 | new Rule\SeparateSubjectFromBodyWithBlankLine() 46 | ]; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Hook/Notify/Action/IntegrateBeforePush.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Notify\Action; 13 | 14 | use CaptainHook\App\Config; 15 | use CaptainHook\App\Console\IO; 16 | use CaptainHook\App\Exception\ActionFailed; 17 | use CaptainHook\App\Hook\Action; 18 | use CaptainHook\App\Hook\Constrained; 19 | use CaptainHook\App\Hook\Restriction; 20 | use CaptainHook\App\Git\Rev\Util as RevUtil; 21 | use CaptainHook\App\Hooks; 22 | use SebastianFeldmann\Git\Repository; 23 | 24 | /** 25 | * Class IntegrateBeforePush 26 | * 27 | * @package CaptainHook 28 | * @author Sebastian Feldmann 29 | * @link https://github.com/captainhook-git/captainhook 30 | * @since Class available since Release 5.19.1 31 | */ 32 | class IntegrateBeforePush implements Action, Constrained 33 | { 34 | /** 35 | * Returns a list of applicable hooks 36 | * 37 | * @return \CaptainHook\App\Hook\Restriction 38 | */ 39 | public static function getRestriction(): Restriction 40 | { 41 | return Restriction::fromArray([Hooks::PRE_PUSH]); 42 | } 43 | 44 | /** 45 | * Executes the action 46 | * 47 | * @param \CaptainHook\App\Config $config 48 | * @param \CaptainHook\App\Console\IO $io 49 | * @param \SebastianFeldmann\Git\Repository $repository 50 | * @param \CaptainHook\App\Config\Action $action 51 | * @return void 52 | * @throws \Exception 53 | */ 54 | public function execute(Config $config, IO $io, Repository $repository, Config\Action $action): void 55 | { 56 | $trigger = $action->getOptions()->get('trigger', '[merge]'); 57 | $branchToWatch = $action->getOptions()->get('branch', 'origin/main'); 58 | $branchInfo = RevUtil::extractBranchInfo($branchToWatch); 59 | 60 | $repository->getRemoteOperator()->fetchBranch($branchInfo['remote'], $branchInfo['branch']); 61 | 62 | foreach ($repository->getLogOperator()->getCommitsBetween('HEAD', $branchToWatch) as $commit) { 63 | $message = $commit->getSubject() . PHP_EOL . $commit->getBody(); 64 | if (str_contains($message, $trigger)) { 65 | throw new ActionFailed('integrate ' . $branchInfo['branch'] . ' before you push!'); 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Hook/Notify/Extractor.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\Notify; 13 | 14 | /** 15 | * Class Extractor 16 | * 17 | * @package CaptainHook 18 | * @author Sebastian Feldmann 19 | * @link https://github.com/captainhook-git/captainhook 20 | * @since Class available since Release 5.4.5 21 | */ 22 | class Extractor 23 | { 24 | /** 25 | * Find the notification inside a commit message and return a Notification model 26 | * 27 | * @param string $message 28 | * @param string $prefix 29 | * @return \CaptainHook\App\Hook\Notify\Notification 30 | */ 31 | public static function extractNotification(string $message, string $prefix = 'git-notify:'): Notification 32 | { 33 | return new Notification(self::getLines($message, $prefix)); 34 | } 35 | 36 | /** 37 | * @param string $message 38 | * @param string $prefix 39 | * @return array 40 | */ 41 | private static function getLines(string $message, string $prefix): array 42 | { 43 | $matches = []; 44 | if (preg_match('#' . $prefix . '(.*)#is', $message, $matches)) { 45 | $split = preg_split("/\r\n|\n|\r/", $matches[1]); 46 | 47 | return is_array($split) ? array_map('trim', $split) : []; 48 | } 49 | return []; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Hook/PHP/CoverageResolver.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\PHP; 13 | 14 | /** 15 | * Interface CoverageResolver 16 | * 17 | * @package CaptainHook 18 | * @author Sebastian Feldmann 19 | * @link https://github.com/captainhook-git/captainhook 20 | * @since Class available since Release 1.2.0 21 | */ 22 | interface CoverageResolver 23 | { 24 | /** 25 | * Return test coverage in percent. 26 | * 27 | * @return int 28 | */ 29 | public function getCoverage(): int; 30 | } 31 | -------------------------------------------------------------------------------- /src/Hook/PHP/CoverageResolver/PHPUnit.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\PHP\CoverageResolver; 13 | 14 | use RuntimeException; 15 | use CaptainHook\App\Hook\PHP\CoverageResolver; 16 | use SebastianFeldmann\Cli\Processor\ProcOpen as Processor; 17 | 18 | /** 19 | * Class PHPUnit 20 | * 21 | * @package CaptainHook 22 | * @author Sebastian Feldmann 23 | * @link https://github.com/captainhook-git/captainhook 24 | * @since Class available since Release 1.2.0 25 | */ 26 | class PHPUnit implements CoverageResolver 27 | { 28 | /** 29 | * Path to phpunit 30 | * 31 | * @var string 32 | */ 33 | private $phpUnit; 34 | 35 | /** 36 | * PHPUnit constructor. 37 | * 38 | * @param string $pathToPHPUnit 39 | */ 40 | public function __construct(string $pathToPHPUnit) 41 | { 42 | $this->phpUnit = $pathToPHPUnit; 43 | } 44 | 45 | /** 46 | * Run PHPUnit to calculate code coverage. 47 | * Shamelessly ripped from bruli/php-git-hooks. 48 | * 49 | * @author Pablo Braulio 50 | * @return int 51 | */ 52 | public function getCoverage(): int 53 | { 54 | $processor = new Processor(); 55 | $result = $processor->run($this->phpUnit . ' --coverage-text|grep Classes|cut -d " " -f 4|cut -d "%" -f 1'); 56 | $output = $result->getStdOut(); 57 | if (!$result->isSuccessful() || empty($output)) { 58 | throw new RuntimeException('Error while executing PHPUnit: ' . $result->getStdErr()); 59 | } 60 | return (int) ceil((float) $output); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Hook/Template.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook; 13 | 14 | /** 15 | * Template interface 16 | * 17 | * Templates generate the hook sourcecode to place in .git/hooks/* to execute CaptainHook. 18 | * There are 3 types of templates: 19 | * - SHELL Writes a shell script, this is the recommended way for all unix or linux based systems. 20 | * - PHP Writes a PHP script, this is useful if you are running windows and shell scripts aren't an option. 21 | * - DOCKER Writes a shell script that executes captainhook inside a docker container. This is useful if you 22 | * don't want to install PHP locally. 23 | * 24 | * @package CaptainHook 25 | * @author Sebastian Feldmann 26 | * @link https://github.com/captainhook-git/captainhook 27 | * @since Class available since Release 4.3.0 28 | */ 29 | interface Template 30 | { 31 | public const SHELL = 'shell'; 32 | public const PHP = 'php'; 33 | public const DOCKER = 'docker'; 34 | public const WSL = 'wsl'; 35 | 36 | /** 37 | * Return the code for the git hook scripts 38 | * 39 | * @param string $hook Name of the hook to generate the sourcecode for 40 | * @return string 41 | */ 42 | public function getCode(string $hook): string; 43 | } 44 | -------------------------------------------------------------------------------- /src/Hook/Template/Builder.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace CaptainHook\App\Hook\Template; 15 | 16 | use CaptainHook\App\Config; 17 | use CaptainHook\App\Console\Runtime\Resolver; 18 | use CaptainHook\App\Hook\Template; 19 | use CaptainHook\App\Hook\Template\Local\PHP; 20 | use CaptainHook\App\Hook\Template\Local\Shell; 21 | use CaptainHook\App\Hook\Template\Local\WSL; 22 | use CaptainHook\App\Runner\Bootstrap\Util; 23 | use RuntimeException; 24 | use SebastianFeldmann\Git\Repository; 25 | 26 | /** 27 | * Builder class 28 | * 29 | * Creates git hook Template objects regarding some provided input. 30 | * 31 | * @package CaptainHook 32 | * @author Sebastian Feldmann 33 | * @link https://github.com/captainhook-git/captainhook 34 | * @since Class available since Release 4.3.0 35 | */ 36 | abstract class Builder 37 | { 38 | /** 39 | * Creates a template that is responsible for the git hook sourcecode 40 | * 41 | * @param \CaptainHook\App\Config $config 42 | * @param \SebastianFeldmann\Git\Repository $repository 43 | * @param \CaptainHook\App\Console\Runtime\Resolver $resolver 44 | * @return \CaptainHook\App\Hook\Template 45 | */ 46 | public static function build(Config $config, Repository $repository, Resolver $resolver): Template 47 | { 48 | $pathInfo = new PathInfo( 49 | $repository->getRoot(), 50 | $config->getPath(), 51 | $resolver->getExecutable(), 52 | $resolver->isPharRelease() 53 | ); 54 | Util::validateBootstrapPath($resolver->isPharRelease(), $config); 55 | 56 | switch ($config->getRunConfig()->getMode()) { 57 | case Template::DOCKER: 58 | return new Docker($pathInfo, $config); 59 | case Template::PHP: 60 | return new PHP($pathInfo, $config); 61 | case Template::WSL: 62 | return new WSL($pathInfo, $config); 63 | default: 64 | return new Shell($pathInfo, $config); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Hook/Template/Local.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace CaptainHook\App\Hook\Template; 15 | 16 | use CaptainHook\App\Config; 17 | use CaptainHook\App\Hook\Template; 18 | use CaptainHook\App\Runner\Bootstrap\Util; 19 | 20 | abstract class Local implements Template 21 | { 22 | /** 23 | * All template related path information 24 | * 25 | * @var \CaptainHook\App\Hook\Template\PathInfo 26 | */ 27 | protected PathInfo $pathInfo; 28 | 29 | /** 30 | * CaptainHook configuration 31 | * 32 | * @var \CaptainHook\App\Config 33 | */ 34 | protected Config $config; 35 | 36 | /** 37 | * Local constructor 38 | * 39 | * @param \CaptainHook\App\Hook\Template\PathInfo $pathInfo 40 | * @param \CaptainHook\App\Config $config 41 | */ 42 | public function __construct(PathInfo $pathInfo, Config $config) 43 | { 44 | $this->pathInfo = $pathInfo; 45 | $this->config = $config; 46 | } 47 | 48 | /** 49 | * Return the code for the git hook scripts 50 | * 51 | * @param string $hook Name of the hook to generate the sourcecode for 52 | * @return string 53 | */ 54 | public function getCode(string $hook): string 55 | { 56 | return implode(PHP_EOL, $this->getHookLines($hook)) . PHP_EOL; 57 | } 58 | 59 | /** 60 | * Returns the bootstrap option depending on the current runtime (can be empty) 61 | * 62 | * @return string 63 | */ 64 | public function getBootstrapCmdOption(): string 65 | { 66 | return Util::bootstrapCmdOption($this->pathInfo->isPhar(), $this->config); 67 | } 68 | 69 | /** 70 | * Return the code for the git hook scripts 71 | * 72 | * @param string $hook Name of the hook to generate the sourcecode for 73 | * @return array 74 | */ 75 | abstract protected function getHookLines(string $hook): array; 76 | } 77 | -------------------------------------------------------------------------------- /src/Hook/Template/Local/WSL.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace CaptainHook\App\Hook\Template\Local; 15 | 16 | /** 17 | * WSL class 18 | * 19 | * Generates the sourcecode for the php hook scripts in .git/hooks/*. 20 | * 21 | * @package CaptainHook 22 | * @author Sebastian Feldmann 23 | * @author Christoph Kappestein 24 | * @link https://github.com/captainhook-git/captainhook 25 | * @since Class available since Release 5.23.0 26 | */ 27 | class WSL extends Shell 28 | { 29 | protected function getExecutable(): string 30 | { 31 | return 'wsl.exe ' . parent::getExecutable(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Hook/UserInput/AskConfirmation.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\UserInput; 13 | 14 | use CaptainHook\App\Config; 15 | use CaptainHook\App\Console\IO; 16 | use CaptainHook\App\Hook\Action; 17 | use CaptainHook\App\Hook\EventSubscriber; 18 | use SebastianFeldmann\Git\Repository; 19 | 20 | /** 21 | * Debug hook to test hook triggering that fails the hook execution 22 | * 23 | * @package CaptainHook 24 | * @author Sebastian Feldmann 25 | * @link https://github.com/captainhook-git/captainhook 26 | * @since Class available since Release 5.20.1 27 | */ 28 | class AskConfirmation implements Action, EventSubscriber 29 | { 30 | /** 31 | * Default question to ask the user 32 | * 33 | * @var string 34 | */ 35 | private static string $defaultMessage = 'Do you want to continue? [yes|no]'; 36 | 37 | /** 38 | * Executes the action 39 | * 40 | * @param \CaptainHook\App\Config $config 41 | * @param \CaptainHook\App\Console\IO $io 42 | * @param \SebastianFeldmann\Git\Repository $repository 43 | * @param \CaptainHook\App\Config\Action $action 44 | * @return void 45 | * @throws \Exception 46 | */ 47 | public function execute(Config $config, IO $io, Repository $repository, Config\Action $action): void 48 | { 49 | // this action is just registering some event handler, so nothing to see here 50 | } 51 | 52 | /** 53 | * Returns a list of event handlers 54 | * 55 | * @param \CaptainHook\App\Config\Action $action 56 | * @return array> 57 | * @throws \Exception 58 | */ 59 | public static function getEventHandlers(Config\Action $action): array 60 | { 61 | $msg = $action->getOptions()->get('message', self::$defaultMessage); 62 | $default = (bool) $action->getOptions()->get('default', false); 63 | return [ 64 | 'onHookSuccess' => [new EventHandler\AskConfirmation($msg, $default)] 65 | ]; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Hook/UserInput/EventHandler/AskConfirmation.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Hook\UserInput\EventHandler; 13 | 14 | use CaptainHook\App\Console\IOUtil; 15 | use CaptainHook\App\Event; 16 | use CaptainHook\App\Event\Handler; 17 | use CaptainHook\App\Exception\ActionFailed; 18 | 19 | /** 20 | * Writes to commit message cache file to load it for a later commit 21 | * 22 | * @package CaptainHook 23 | * @author Sebastian Feldmann 24 | * @link https://github.com/captainhook-git/captainhook 25 | * @since Class available since Release 5.11.0 26 | */ 27 | class AskConfirmation implements Handler 28 | { 29 | /** 30 | * Question to ask 31 | * 32 | * @var string 33 | */ 34 | private string $question; 35 | 36 | /** 37 | * No input ok or not 38 | * 39 | * @var bool 40 | */ 41 | private bool $default; 42 | 43 | /** 44 | * @param string $question 45 | * @param bool $default 46 | */ 47 | public function __construct(string $question, bool $default = false) 48 | { 49 | $this->question = $question; 50 | $this->default = $default; 51 | } 52 | 53 | /** 54 | * Writes the commit message to a cache file to reuse it for the next commit 55 | * 56 | * @param \CaptainHook\App\Event $event 57 | * @return void 58 | * @throws \CaptainHook\App\Exception\ActionFailed 59 | */ 60 | public function handle(Event $event): void 61 | { 62 | if (!IOUtil::answerToBool($event->io()->ask(PHP_EOL . $this->question . ' ', $this->default ? 'y' : 'n'))) { 63 | throw new ActionFailed('no confirmation, abort!'); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Plugin/CaptainHook.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Plugin; 13 | 14 | /** 15 | * CaptainHook plugin interface 16 | * 17 | * @package CaptainHook 18 | * @author Sebastian Feldmann 19 | * @link https://github.com/captainhook-git/captainhook 20 | * @since Class available since Release 5.9.0. 21 | */ 22 | interface CaptainHook 23 | { 24 | } 25 | -------------------------------------------------------------------------------- /src/Plugin/Hook.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Plugin; 13 | 14 | use CaptainHook\App\Config; 15 | use CaptainHook\App\Console\IO; 16 | use CaptainHook\App\Runner\Hook as RunnerHook; 17 | use SebastianFeldmann\Git\Repository; 18 | 19 | /** 20 | * Runner plugin interface 21 | * 22 | * @package CaptainHook 23 | * @author Sebastian Feldmann 24 | * @link https://github.com/captainhook-git/captainhook 25 | * @since Class available since Release 5.9.0. 26 | */ 27 | interface Hook extends CaptainHook 28 | { 29 | /** 30 | * Configure the runner plugin. 31 | * 32 | * @param Config $config 33 | * @param IO $io 34 | * @param Repository $repository 35 | * @param Config\Plugin $plugin 36 | * @return void 37 | */ 38 | public function configure(Config $config, IO $io, Repository $repository, Config\Plugin $plugin): void; 39 | 40 | /** 41 | * Execute before all actions 42 | * 43 | * @param RunnerHook $hook 44 | * @return void 45 | */ 46 | public function beforeHook(RunnerHook $hook): void; 47 | 48 | /** 49 | * Execute before each action 50 | * 51 | * @param RunnerHook $hook 52 | * @param Config\Action $action 53 | * @return void 54 | */ 55 | public function beforeAction(RunnerHook $hook, Config\Action $action): void; 56 | 57 | /** 58 | * Execute after each action 59 | * 60 | * @param RunnerHook $hook 61 | * @param Config\Action $action 62 | * @return void 63 | */ 64 | public function afterAction(RunnerHook $hook, Config\Action $action): void; 65 | 66 | /** 67 | * Execute after all actions 68 | * 69 | * @param RunnerHook $hook 70 | * @return void 71 | */ 72 | public function afterHook(RunnerHook $hook): void; 73 | } 74 | -------------------------------------------------------------------------------- /src/Plugin/Hook/Base.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Plugin\Hook; 13 | 14 | use CaptainHook\App\Config; 15 | use CaptainHook\App\Console\IO; 16 | use CaptainHook\App\Plugin; 17 | use SebastianFeldmann\Git\Repository; 18 | 19 | /** 20 | * Base runner plugin abstract class 21 | * 22 | * @package CaptainHook 23 | * @author Sebastian Feldmann 24 | * @link https://github.com/captainhook-git/captainhook 25 | * @since Class available since Release 5.9.0. 26 | */ 27 | abstract class Base implements Plugin\Hook 28 | { 29 | /** 30 | * @var Config 31 | */ 32 | protected $config; 33 | 34 | /** 35 | * @var IO 36 | */ 37 | protected $io; 38 | 39 | /** 40 | * @var Repository 41 | */ 42 | protected $repository; 43 | 44 | /** 45 | * @var Config\Plugin 46 | */ 47 | protected $plugin; 48 | 49 | public function configure(Config $config, IO $io, Repository $repository, Config\Plugin $plugin): void 50 | { 51 | $this->config = $config; 52 | $this->io = $io; 53 | $this->repository = $repository; 54 | $this->plugin = $plugin; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Runner.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App; 13 | 14 | use CaptainHook\App\Console\IO; 15 | 16 | /** 17 | * Class Runner 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 0.9.0 23 | */ 24 | abstract class Runner 25 | { 26 | /** 27 | * @var \CaptainHook\App\Console\IO 28 | */ 29 | protected $io; 30 | 31 | /** 32 | * @var \CaptainHook\App\Config 33 | */ 34 | protected $config; 35 | 36 | /** 37 | * Installer constructor. 38 | * 39 | * @param \CaptainHook\App\Console\IO $io 40 | * @param \CaptainHook\App\Config $config 41 | */ 42 | public function __construct(IO $io, Config $config) 43 | { 44 | $this->io = $io; 45 | $this->config = $config; 46 | } 47 | 48 | /** 49 | * Executes the Runner. 50 | */ 51 | abstract public function run(): void; 52 | } 53 | -------------------------------------------------------------------------------- /src/Runner/Action.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner; 13 | 14 | use CaptainHook\App\Config; 15 | use CaptainHook\App\Console\IO; 16 | use SebastianFeldmann\Git\Repository; 17 | 18 | /** 19 | * Interface Action 20 | * 21 | * @package CaptainHook 22 | * @author Sebastian Feldmann 23 | * @link https://github.com/captainhook-git/captainhook 24 | * @since Class available since Release 5.19.0 25 | */ 26 | interface Action 27 | { 28 | /** 29 | * Executes the action 30 | * 31 | * @param \CaptainHook\App\Config $config 32 | * @param \CaptainHook\App\Console\IO $io 33 | * @param \SebastianFeldmann\Git\Repository $repository 34 | * @param \CaptainHook\App\Config\Action $action 35 | * @return void 36 | * @throws \Exception 37 | */ 38 | public function execute(Config $config, IO $io, Repository $repository, Config\Action $action): void; 39 | } 40 | -------------------------------------------------------------------------------- /src/Runner/Action/Cli/Command/Placeholder.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Action\Cli\Command; 13 | 14 | use CaptainHook\App\Config; 15 | use CaptainHook\App\Console\IO; 16 | use SebastianFeldmann\Git\Repository; 17 | 18 | /** 19 | * Interface Placeholder 20 | * 21 | * @package CaptainHook 22 | * @author Sebastian Feldmann 23 | * @link https://github.com/captainhook-git/captainhook 24 | * @since Class available since Release 5.0.0 25 | */ 26 | interface Placeholder 27 | { 28 | /** 29 | * Placeholder constructor 30 | * 31 | * @param \CaptainHook\App\Console\IO $io 32 | * @param \CaptainHook\App\Config $config 33 | * @param \SebastianFeldmann\Git\Repository $repository 34 | */ 35 | public function __construct(IO $io, Config $config, Repository $repository); 36 | 37 | /** 38 | * Return the replacement value for this placeholder 39 | * 40 | * @param array $options 41 | * @return string 42 | */ 43 | public function replacement(array $options): string; 44 | } 45 | -------------------------------------------------------------------------------- /src/Runner/Action/Cli/Command/Placeholder/Arg.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Action\Cli\Command\Placeholder; 13 | 14 | /** 15 | * Class Arg 16 | * 17 | * @package CaptainHook 18 | * @author Sebastian Feldmann 19 | * @link https://github.com/captainhook-git/captainhook 20 | * @since Class available since Release 5.19.0 21 | */ 22 | class Arg extends Foundation 23 | { 24 | /** 25 | * Return the requested command ARGUMENT or a given default, returns empty string by default 26 | * 27 | * @param array $options 28 | * @return string 29 | */ 30 | public function replacement(array $options): string 31 | { 32 | $var = $options['value-of'] ?? '_'; 33 | $default = $options['default'] ?? ''; 34 | 35 | return $this->io->getArgument(self::toArgument($var), $default); 36 | } 37 | 38 | /** 39 | * Converts an argument name to a placeholder string 40 | * 41 | * @param string $arg 42 | * @return string 43 | */ 44 | public static function toPlaceholder(string $arg): string 45 | { 46 | return str_replace('-', '_', strtoupper($arg)); 47 | } 48 | 49 | /** 50 | * Converts a placeholder string to an argument name 51 | * 52 | * @param string $placeholder 53 | * @return string 54 | */ 55 | public static function toArgument(string $placeholder): string 56 | { 57 | return str_replace('_', '-', strtolower($placeholder)); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Runner/Action/Cli/Command/Placeholder/BranchFiles.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Action\Cli\Command\Placeholder; 13 | 14 | use CaptainHook\App\Git; 15 | use CaptainHook\App\Hook\FileList; 16 | 17 | /** 18 | * Changed Files Placeholder 19 | * 20 | * This placeholder only works for pre-push, post-rewrite, post-checkout and post-merge actions. 21 | * If it is used in a pre-push hook and multiple refs are pushed the placeholder will contain 22 | * all changed files for all refs. 23 | * 24 | * Usage examples: 25 | * - {$BRANCH_FILES|compare-to:main|separated-by:,} 26 | * - {$BRANCH_FILES|in-dir:foo/bar} 27 | * - {$BRANCH_FILES|of-type:php} 28 | * 29 | * @package CaptainHook 30 | * @author Sebastian Feldmann 31 | * @link https://github.com/captainhook-git/captainhook 32 | * @since Class available since Release 5.21.0 33 | */ 34 | class BranchFiles extends Foundation 35 | { 36 | /** 37 | * @param array $options 38 | * @return string 39 | */ 40 | public function replacement(array $options): string 41 | { 42 | $branch = $this->repository->getInfoOperator()->getCurrentBranch(); 43 | $start = $options['compared-to'] ?? $this->repository->getLogOperator()->getBranchRevFromRefLog($branch); 44 | 45 | if (empty($start)) { 46 | $this->io->write('could not find branch start'); 47 | return ''; 48 | } 49 | $files = $this->repository->getLogOperator()->getChangedFilesSince($start, ['A', 'C', 'M', 'R']); 50 | 51 | return implode(($options['separated-by'] ?? ' '), FileList::filter($files, $options)); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Runner/Action/Cli/Command/Placeholder/ChangedFiles.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Action\Cli\Command\Placeholder; 13 | 14 | use CaptainHook\App\Git; 15 | use CaptainHook\App\Hook\FileList; 16 | 17 | /** 18 | * Changed Files Placeholder 19 | * 20 | * This placeholder only works for pre-push, post-rewrite, post-checkout and post-merge actions. 21 | * If it is used in a pre-push hook and multiple refs are pushed the placeholder will contain 22 | * all changed files for all refs. 23 | * 24 | * Usage examples: 25 | * - {$CHANGED_FILES|separated-by:,} 26 | * - {$CHANGED_FILES|in-dir:foo/bar} 27 | * - {$CHANGED_FILES|of-type:php} 28 | * 29 | * @package CaptainHook 30 | * @author Sebastian Feldmann 31 | * @link https://github.com/captainhook-git/captainhook 32 | * @since Class available since Release 5.15.3 33 | */ 34 | class ChangedFiles extends Foundation 35 | { 36 | /** 37 | * @param array $options 38 | * @return string 39 | */ 40 | public function replacement(array $options): string 41 | { 42 | $factory = new Git\ChangedFiles\Detector\Factory(); 43 | $detector = $factory->getDetector($this->io, $this->repository); 44 | 45 | $files = $detector->getChangedFiles(['A', 'C', 'M', 'R']); 46 | 47 | return implode(($options['separated-by'] ?? ' '), FileList::filter($files, $options)); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Runner/Action/Cli/Command/Placeholder/Config.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Action\Cli\Command\Placeholder; 13 | 14 | /** 15 | * Class Config 16 | * 17 | * @package CaptainHook 18 | * @author Sebastian Feldmann 19 | * @link https://github.com/captainhook-git/captainhook 20 | * @since Class available since Release 5.6.0 21 | */ 22 | class Config extends Foundation 23 | { 24 | /** 25 | * Maps the config value names to actual methods that have to be called to retrieve the value 26 | * 27 | * @var array 28 | */ 29 | private $valueToMethod = [ 30 | 'bootstrap' => 'getBootstrap', 31 | 'git-directory' => 'getGitDirectory', 32 | 'php-path' => 'getPhpPath', 33 | ]; 34 | 35 | /** 36 | * @param array $options 37 | * @return string 38 | */ 39 | public function replacement(array $options): string 40 | { 41 | if (!isset($options['value-of'])) { 42 | return ''; 43 | } 44 | 45 | return $this->getConfigValueFor($options['value-of']); 46 | } 47 | 48 | /** 49 | * Returns the config value '' by default if value is unknown 50 | * 51 | * @param string $value 52 | * @return string 53 | */ 54 | private function getConfigValueFor(string $value): string 55 | { 56 | if (strpos($value, 'custom>>') === 0) { 57 | $key = substr($value, 8); 58 | $custom = $this->config->getCustomSettings(); 59 | return $custom[$key] ?? ''; 60 | } 61 | if (!isset($this->valueToMethod[$value])) { 62 | return ''; 63 | } 64 | 65 | $method = $this->valueToMethod[$value]; 66 | return $this->config->$method(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Runner/Action/Cli/Command/Placeholder/Env.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Action\Cli\Command\Placeholder; 13 | 14 | /** 15 | * Class Env 16 | * 17 | * @package CaptainHook 18 | * @author Sebastian Feldmann 19 | * @link https://github.com/captainhook-git/captainhook 20 | * @since Class available since Release 5.8.0 21 | */ 22 | class Env extends Foundation 23 | { 24 | /** 25 | * Return the requested ENVIRONMENT variable or a given default, returns empty string by default 26 | * 27 | * @param array $options 28 | * @return string 29 | */ 30 | public function replacement(array $options): string 31 | { 32 | if (!isset($options['value-of'])) { 33 | return ''; 34 | } 35 | 36 | $var = $options['value-of']; 37 | $default = $options['default'] ?? ''; 38 | 39 | return (string) ($_ENV[$var] ?? $default); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Runner/Action/Cli/Command/Placeholder/Foundation.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Action\Cli\Command\Placeholder; 13 | 14 | use CaptainHook\App\Config; 15 | use CaptainHook\App\Console\IO; 16 | use CaptainHook\App\Runner\Action\Cli\Command\Placeholder as PlaceholderInterface; 17 | use SebastianFeldmann\Git\Repository; 18 | 19 | /** 20 | * Class Foundation 21 | * 22 | * @package CaptainHook 23 | * @author Sebastian Feldmann 24 | * @link https://github.com/captainhook-git/captainhook 25 | * @since Class available since Release 5.6.0 26 | */ 27 | abstract class Foundation implements PlaceholderInterface 28 | { 29 | /** 30 | * Input Output handler 31 | * 32 | * @var \CaptainHook\App\Console\IO 33 | */ 34 | protected IO $io; 35 | 36 | /** 37 | * CaptainHook configuration 38 | * 39 | * @var \CaptainHook\App\Config 40 | */ 41 | protected Config $config; 42 | 43 | /** 44 | * Git repository 45 | * 46 | * @var \SebastianFeldmann\Git\Repository 47 | */ 48 | protected Repository $repository; 49 | 50 | /** 51 | * StagedFile constructor 52 | * 53 | * @param \CaptainHook\App\Console\IO $io 54 | * @param \CaptainHook\App\Config $config 55 | * @param \SebastianFeldmann\Git\Repository $repository 56 | */ 57 | public function __construct(IO $io, Config $config, Repository $repository) 58 | { 59 | $this->io = $io; 60 | $this->config = $config; 61 | $this->repository = $repository; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Runner/Action/Cli/Command/Placeholder/StagedFiles.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Action\Cli\Command\Placeholder; 13 | 14 | use CaptainHook\App\Hook\FileList; 15 | 16 | /** 17 | * Class UpdatedFiles 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 5.0.0 23 | */ 24 | class StagedFiles extends Foundation 25 | { 26 | /** 27 | * @param array $options 28 | * @return string 29 | */ 30 | public function replacement(array $options): string 31 | { 32 | $filter = isset($options['diff-filter']) ? str_split($options['diff-filter']) : ['A', 'C', 'M', 'R']; 33 | $files = isset($options['of-type']) 34 | ? $this->repository->getIndexOperator()->getStagedFilesOfType($options['of-type'], $filter) 35 | : $this->repository->getIndexOperator()->getStagedFiles($filter); 36 | 37 | $files = FileList::filterByDirectory($files, $options); 38 | $files = FileList::replaceInAll($files, $options); 39 | 40 | return implode(($options['separated-by'] ?? ' '), $files); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Runner/Action/Cli/Command/Placeholder/StdIn.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Action\Cli\Command\Placeholder; 13 | 14 | /** 15 | * Class StdIn 16 | * 17 | * @package CaptainHook 18 | * @author Sebastian Feldmann 19 | * @link https://github.com/captainhook-git/captainhook 20 | * @since Class available since Release 5.23.5 21 | */ 22 | class StdIn extends Foundation 23 | { 24 | /** 25 | * Return the original hook stdIn (shell escaped) 26 | * 27 | * Returns at least '' 28 | * 29 | * @param array $options 30 | * @return string 31 | */ 32 | public function replacement(array $options): string 33 | { 34 | return escapeshellarg(implode(PHP_EOL, $this->io->getStandardInput())); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Runner/Bootstrap/Util.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Bootstrap; 13 | 14 | use CaptainHook\App\Config; 15 | use RuntimeException; 16 | 17 | /** 18 | * Bootstrap Util 19 | * 20 | * @package CaptainHook 21 | * @author Sebastian Feldmann 22 | * @link https://github.com/captainhook-git/captainhook 23 | * @since Class available since Release 5.23.3 24 | */ 25 | class Util 26 | { 27 | /** 28 | * Return the bootstrap file to load (can be empty) 29 | * 30 | * @param bool $isPhar 31 | * @param \CaptainHook\App\Config $config 32 | * @return string 33 | */ 34 | public static function validateBootstrapPath(bool $isPhar, Config $config): string 35 | { 36 | $bootstrapFile = dirname($config->getPath()) . '/' . $config->getBootstrap(); 37 | if (!file_exists($bootstrapFile)) { 38 | // since the phar has its own autoloader we don't need to do anything 39 | // if the bootstrap file is not actively set 40 | if ($isPhar && empty($config->getBootstrap(''))) { 41 | return ''; 42 | } 43 | throw new RuntimeException('bootstrap file not found'); 44 | } 45 | return $bootstrapFile; 46 | } 47 | 48 | /** 49 | * Returns the bootstrap command option (can be empty) 50 | * 51 | * @param bool $isPhar 52 | * @param \CaptainHook\App\Config $config 53 | * @return string 54 | */ 55 | public static function bootstrapCmdOption(bool $isPhar, Config $config): string 56 | { 57 | // nothing to load => no option 58 | if ($isPhar && empty($config->getBootstrap(''))) { 59 | return ''; 60 | } 61 | return ' --bootstrap=' . $config->getBootstrap(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Runner/Config/Change.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Config\Change; 13 | 14 | use CaptainHook\App\Config; 15 | use CaptainHook\App\Runner\Config\Setup\Advanced; 16 | 17 | /** 18 | * Class AddAction 19 | * 20 | * @package CaptainHook 21 | * @author Sebastian Feldmann 22 | * @link https://github.com/captainhook-git/captainhook 23 | * @since Class available since Release 4.2.0 24 | */ 25 | class AddAction extends Hook 26 | { 27 | /** 28 | * Apply changes to the given config 29 | * 30 | * @param \CaptainHook\App\Config $config 31 | * @return void 32 | * @throws \Exception 33 | */ 34 | public function applyTo(Config $config): void 35 | { 36 | $hookConfig = $config->getHookConfig($this->hookToChange); 37 | $setup = new Advanced($this->io); 38 | $actionConfig = $setup->getActionConfig(); 39 | 40 | $hookConfig->addAction($actionConfig); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Runner/Config/Change/DisableHook.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Config\Change; 13 | 14 | use CaptainHook\App\Config; 15 | 16 | /** 17 | * Class AddAction 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 4.2.0 23 | */ 24 | class DisableHook extends Hook 25 | { 26 | /** 27 | * Apply changes to the given config 28 | * 29 | * @param \CaptainHook\App\Config $config 30 | * @return void 31 | * @throws \Exception 32 | */ 33 | public function applyTo(Config $config): void 34 | { 35 | $config->getHookConfig($this->hookToChange)->setEnabled(false); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Runner/Config/Change/EnableHook.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Config\Change; 13 | 14 | use CaptainHook\App\Config; 15 | 16 | /** 17 | * Class AddAction 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 4.2.0 23 | */ 24 | class EnableHook extends Hook 25 | { 26 | /** 27 | * Apply changes to the given config 28 | * 29 | * @param \CaptainHook\App\Config $config 30 | * @return void 31 | * @throws \Exception 32 | */ 33 | public function applyTo(Config $config): void 34 | { 35 | $config->getHookConfig($this->hookToChange)->setEnabled(true); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Runner/Config/Change/Hook.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Config\Change; 13 | 14 | use CaptainHook\App\Config; 15 | use CaptainHook\App\Console\IO; 16 | use CaptainHook\App\Runner\Config\Change; 17 | 18 | /** 19 | * Class AddAction 20 | * 21 | * @package CaptainHook 22 | * @author Sebastian Feldmann 23 | * @link https://github.com/captainhook-git/captainhook 24 | * @since Class available since Release 4.2.0 25 | */ 26 | abstract class Hook implements Change 27 | { 28 | /** 29 | * @var \CaptainHook\App\Console\IO 30 | */ 31 | protected $io; 32 | 33 | /** 34 | * Name of the hook to add the action to 35 | * 36 | * @var string 37 | */ 38 | protected $hookToChange; 39 | 40 | /** 41 | * AddAction constructor 42 | * 43 | * @param \CaptainHook\App\Console\IO $io 44 | * @param string $hookToChange 45 | */ 46 | public function __construct(IO $io, string $hookToChange) 47 | { 48 | $this->io = $io; 49 | $this->hookToChange = $hookToChange; 50 | } 51 | 52 | /** 53 | * Apply changes to the given config 54 | * 55 | * @param \CaptainHook\App\Config $config 56 | * @return void 57 | * @throws \Exception 58 | */ 59 | abstract public function applyTo(Config $config): void; 60 | } 61 | -------------------------------------------------------------------------------- /src/Runner/Config/Setup.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Config; 13 | 14 | use CaptainHook\App\Config; 15 | 16 | /** 17 | * Interface Setup 18 | * 19 | * @package CaptainHook 20 | * @author Sebastian Feldmann 21 | * @link https://github.com/captainhook-git/captainhook 22 | * @since Class available since Release 2.1.3 23 | */ 24 | interface Setup 25 | { 26 | /** 27 | * Setup hook configurations by asking some questions 28 | * 29 | * @param \CaptainHook\App\Config $config 30 | * @return void 31 | */ 32 | public function configureHooks(Config $config): void; 33 | } 34 | -------------------------------------------------------------------------------- /src/Runner/Config/Setup/Guided.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Config\Setup; 13 | 14 | use CaptainHook\App\Console\IO; 15 | use Exception; 16 | 17 | /** 18 | * Class Guided 19 | * 20 | * @package CaptainHook 21 | * @author Sebastian Feldmann 22 | * @link https://github.com/captainhook-git/captainhook 23 | * @since Class available since Release 2.2.0 24 | */ 25 | abstract class Guided 26 | { 27 | /** 28 | * @var \CaptainHook\App\Console\IO 29 | */ 30 | protected $io; 31 | 32 | /** 33 | * Guided constructor 34 | * 35 | * @param \CaptainHook\App\Console\IO $io 36 | */ 37 | public function __construct(IO $io) 38 | { 39 | $this->io = $io; 40 | } 41 | 42 | /** 43 | * PHP action option validation 44 | * 45 | * @param string $option 46 | * @return string 47 | * @throws \Exception 48 | */ 49 | public static function isPHPActionOptionValid(string $option): string 50 | { 51 | if (count(explode(':', $option)) !== 2) { 52 | throw new Exception('Invalid option, use "key:value"'); 53 | } 54 | return $option; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Runner/Hook/Arg.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Hook; 13 | 14 | use CaptainHook\App\Exception\InvalidHookName; 15 | 16 | /** 17 | * Hook argument for lots of commands 18 | * 19 | * - install pre-push,pre-commit 20 | * - info commit-message 21 | */ 22 | class Arg 23 | { 24 | /** 25 | * List of hooks 26 | * 27 | * @var array 28 | */ 29 | private array $hooks = []; 30 | 31 | /** 32 | * @param string $hook 33 | * @param callable $hookValidation 34 | * @throws \CaptainHook\App\Exception\InvalidHookName 35 | */ 36 | public function __construct(string $hook, callable $hookValidation) 37 | { 38 | if (empty($hook)) { 39 | return; 40 | } 41 | 42 | /** @var array $hooks */ 43 | $hooks = explode(',', $hook); 44 | $hooks = array_map('trim', $hooks); 45 | 46 | if (!empty(($invalidHooks = array_filter($hooks, $hookValidation)))) { 47 | throw new InvalidHookName( 48 | 'Invalid hook name \'' . implode('\', \'', $invalidHooks) . '\'' 49 | ); 50 | } 51 | $this->hooks = $hooks; 52 | } 53 | 54 | /** 55 | * Return the list of hooks provided as an argument 56 | * 57 | * @return array 58 | */ 59 | public function hooks(): array 60 | { 61 | return $this->hooks; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Runner/Hook/CommitMsg.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Hook; 13 | 14 | use CaptainHook\App\Hooks; 15 | use CaptainHook\App\Runner\Hook; 16 | use SebastianFeldmann\Git; 17 | 18 | /** 19 | * CommitMsg 20 | * 21 | * @package CaptainHook 22 | * @author Sebastian Feldmann 23 | * @link https://github.com/captainhook-git/captainhook 24 | * @since Class available since Release 3.1.0 25 | */ 26 | class CommitMsg extends Hook 27 | { 28 | /** 29 | * Hook to execute 30 | * 31 | * @var string 32 | */ 33 | protected $hook = Hooks::COMMIT_MSG; 34 | 35 | /** 36 | * Read the commit message from file 37 | */ 38 | public function beforeHook(): void 39 | { 40 | $commentChar = $this->repository->getConfigOperator()->getSettingSafely('core.commentchar', '#'); 41 | $commitMsg = Git\CommitMessage::createFromFile( 42 | $this->io->getArgument(Hooks::ARG_MESSAGE_FILE, ''), 43 | $commentChar 44 | ); 45 | 46 | $this->repository->setCommitMsg($commitMsg); 47 | 48 | parent::beforeHook(); 49 | } 50 | 51 | /** 52 | * Makes sure we do not run commit message validation for fixup commits 53 | * 54 | * @return void 55 | * @throws \Exception 56 | */ 57 | protected function runHook(): void 58 | { 59 | $msg = $this->repository->getCommitMsg(); 60 | if ($msg->isFixup()) { 61 | $this->io->write(' - no commit message validation for fixup commits: skipping all actions'); 62 | return; 63 | } 64 | parent::runHook(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Runner/Hook/Log.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Hook; 13 | 14 | use CaptainHook\App\Runner\Action\Log as ActionLog; 15 | 16 | class Log 17 | { 18 | /** 19 | * List if all Action Logs 20 | * 21 | * @var array<\CaptainHook\App\Runner\Action\Log> 22 | */ 23 | private array $logs = []; 24 | 25 | /** 26 | * Adds an action log to the hook log 27 | * 28 | * @param \CaptainHook\App\Runner\Action\Log $actionLog 29 | * @return void 30 | */ 31 | public function addActionLog(ActionLog $actionLog): void 32 | { 33 | $this->logs[] = $actionLog; 34 | } 35 | 36 | /** 37 | * Checks if any of the collected action logs has a message to display 38 | * 39 | * @param int $verbosity 40 | * @return bool 41 | */ 42 | public function hasMessageForVerbosity(int $verbosity): bool 43 | { 44 | foreach ($this->logs as $actionLog) { 45 | if ($actionLog->hasMessageForVerbosity($verbosity)) { 46 | return true; 47 | } 48 | } 49 | return false; 50 | } 51 | 52 | /** 53 | * Returns all collected action logs 54 | * 55 | * @return array<\CaptainHook\App\Runner\Action\Log> 56 | */ 57 | public function logs(): array 58 | { 59 | return $this->logs; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Runner/Hook/PostCheckout.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Hook; 13 | 14 | use CaptainHook\App\Hooks; 15 | use CaptainHook\App\Runner\Hook; 16 | 17 | /** 18 | * Hook 19 | * 20 | * @package CaptainHook 21 | * @author Sebastian Feldmann 22 | * @link https://github.com/captainhook-git/captainhook 23 | * @since Class available since Release 4.1.0 24 | */ 25 | class PostCheckout extends Hook 26 | { 27 | /** 28 | * Hook to execute 29 | * 30 | * @var string 31 | */ 32 | protected $hook = Hooks::POST_CHECKOUT; 33 | } 34 | -------------------------------------------------------------------------------- /src/Runner/Hook/PostCommit.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Hook; 13 | 14 | use CaptainHook\App\Hooks; 15 | use CaptainHook\App\Runner\Hook; 16 | 17 | /** 18 | * Hook 19 | * 20 | * @package CaptainHook 21 | * @author Sebastian Feldmann 22 | * @link https://github.com/captainhook-git/captainhook 23 | * @since Class available since Release 3.1.0 24 | */ 25 | class PostCommit extends Hook 26 | { 27 | /** 28 | * Hook to execute 29 | * 30 | * @var string 31 | */ 32 | protected $hook = Hooks::POST_COMMIT; 33 | } 34 | -------------------------------------------------------------------------------- /src/Runner/Hook/PostMerge.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Hook; 13 | 14 | use CaptainHook\App\Hooks; 15 | use CaptainHook\App\Runner\Hook; 16 | 17 | /** 18 | * Hook 19 | * 20 | * @package CaptainHook 21 | * @author Sebastian Feldmann 22 | * @link https://github.com/captainhook-git/captainhook 23 | * @since Class available since Release 3.1.0 24 | */ 25 | class PostMerge extends Hook 26 | { 27 | /** 28 | * Hook to execute 29 | * 30 | * @var string 31 | */ 32 | protected $hook = Hooks::POST_MERGE; 33 | } 34 | -------------------------------------------------------------------------------- /src/Runner/Hook/PostRewrite.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Hook; 13 | 14 | use CaptainHook\App\Hooks; 15 | use CaptainHook\App\Runner\Hook; 16 | 17 | /** 18 | * Hook 19 | * 20 | * @package CaptainHook 21 | * @author Sebastian Feldmann 22 | * @link https://github.com/captainhook-git/captainhook 23 | * @since Class available since Release 5.4.0 24 | */ 25 | class PostRewrite extends Hook 26 | { 27 | /** 28 | * Hook to execute 29 | * 30 | * @var string 31 | */ 32 | protected $hook = Hooks::POST_REWRITE; 33 | } 34 | -------------------------------------------------------------------------------- /src/Runner/Hook/PreCommit.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Hook; 13 | 14 | use CaptainHook\App\Hooks; 15 | use CaptainHook\App\Runner\Hook; 16 | 17 | /** 18 | * Hook 19 | * 20 | * @package CaptainHook 21 | * @author Sebastian Feldmann 22 | * @link https://github.com/captainhook-git/captainhook 23 | * @since Class available since Release 3.1.0 24 | */ 25 | class PreCommit extends Hook 26 | { 27 | /** 28 | * Hook to execute 29 | * 30 | * @var string 31 | */ 32 | protected $hook = Hooks::PRE_COMMIT; 33 | } 34 | -------------------------------------------------------------------------------- /src/Runner/Hook/PrePush.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner\Hook; 13 | 14 | use CaptainHook\App\Hooks; 15 | use CaptainHook\App\Runner\Hook; 16 | 17 | /** 18 | * Hook 19 | * 20 | * @package CaptainHook 21 | * @author Sebastian Feldmann 22 | * @link https://github.com/captainhook-git/captainhook 23 | * @since Class available since Release 3.1.0 24 | */ 25 | class PrePush extends Hook 26 | { 27 | /** 28 | * Hook to execute 29 | * 30 | * @var string 31 | */ 32 | protected $hook = Hooks::PRE_PUSH; 33 | } 34 | -------------------------------------------------------------------------------- /src/Runner/RepositoryAware.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner; 13 | 14 | use CaptainHook\App\Config; 15 | use CaptainHook\App\Console\IO; 16 | use CaptainHook\App\Runner; 17 | use SebastianFeldmann\Git\Repository; 18 | 19 | /** 20 | * Class HookHandler 21 | * 22 | * @package CaptainHook 23 | * @author Sebastian Feldmann 24 | * @link https://github.com/captainhook-git/captainhook 25 | * @since Class available since Release 0.9.0 26 | */ 27 | abstract class RepositoryAware extends Runner 28 | { 29 | /** 30 | * Git repository. 31 | * 32 | * @var \SebastianFeldmann\Git\Repository 33 | */ 34 | protected $repository; 35 | 36 | /** 37 | * HookHandler constructor. 38 | * 39 | * @param \CaptainHook\App\Console\IO $io 40 | * @param \CaptainHook\App\Config $config 41 | * @param \SebastianFeldmann\Git\Repository $repository 42 | */ 43 | public function __construct(IO $io, Config $config, Repository $repository) 44 | { 45 | parent::__construct($io, $config); 46 | $this->repository = $repository; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Runner/Util.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Runner; 13 | 14 | /** 15 | * Class Util 16 | * 17 | * @package CaptainHook\App\Runner 18 | */ 19 | final class Util 20 | { 21 | /** 22 | * List of valid action types 23 | * 24 | * @var array 25 | */ 26 | private static $validTypes = ['php' => true, 'cli' => true]; 27 | 28 | 29 | /** 30 | * Check the validity of a exec type 31 | * 32 | * @param string $type 33 | * @return bool 34 | */ 35 | public static function isTypeValid(string $type): bool 36 | { 37 | return isset(self::$validTypes[$type]); 38 | } 39 | 40 | /** 41 | * Return action type 42 | * 43 | * @param string $action 44 | * @return string 45 | */ 46 | public static function getExecType(string $action): string 47 | { 48 | return substr($action, 0, 1) === '\\' ? 'php' : 'cli'; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Storage/File/Json.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Storage\File; 13 | 14 | use CaptainHook\App\Storage\File; 15 | use RuntimeException; 16 | use stdClass; 17 | 18 | /** 19 | * Class Json 20 | * 21 | * @package CaptainHook 22 | * @author Sebastian Feldmann 23 | * @link https://github.com/captainhook-git/captainhook 24 | * @since Class available since Release 0.9.0 25 | */ 26 | final class Json extends File 27 | { 28 | /** 29 | * Read and decode the json file 30 | * 31 | * @param bool $assoc 32 | * @return \stdClass|array|null 33 | */ 34 | public function read(bool $assoc = false): array|stdClass|null 35 | { 36 | $json = json_decode(parent::read(), $assoc); 37 | if (json_last_error() !== JSON_ERROR_NONE) { 38 | throw new RuntimeException('Invalid json file'); 39 | } 40 | return $json; 41 | } 42 | 43 | /** 44 | * Read the file and decode to assoc array 45 | * 46 | * @return array 47 | */ 48 | public function readAssoc(): array 49 | { 50 | return (array) ($this->read(true) ?? []); 51 | } 52 | 53 | /** 54 | * Encode content to json and write to disk 55 | * 56 | * @param mixed $content 57 | * @param int $options 58 | * @return void 59 | */ 60 | public function write($content, $options = 448): void 61 | { 62 | $json = json_encode($content, $options) . ($options & JSON_PRETTY_PRINT ? "\n" : ''); 63 | parent::write($json); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Storage/File/Xml.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CaptainHook\App\Storage\File; 13 | 14 | use CaptainHook\App\Storage\File; 15 | use RuntimeException; 16 | 17 | /** 18 | * Class Xml 19 | * 20 | * @package CaptainHook 21 | * @author Sebastian Feldmann 22 | * @link https://github.com/captainhook-git/captainhook 23 | * @since Class available since Release 1.2.0 24 | */ 25 | final class Xml extends File 26 | { 27 | /** 28 | * Read the xml file and return a SimpleXML object. 29 | * 30 | * @return \SimpleXMLElement 31 | */ 32 | public function read() 33 | { 34 | $old = libxml_use_internal_errors(true); 35 | $xml = simplexml_load_file($this->path); 36 | $errors = libxml_get_errors(); 37 | libxml_use_internal_errors($old); 38 | 39 | if (count($errors) || $xml === false) { 40 | throw new RuntimeException('xml file \'' . $this->path . '\': ' . $errors[0]->message); 41 | } 42 | return $xml; 43 | } 44 | } 45 | --------------------------------------------------------------------------------