From e059ecdb596ab593e386a14b3bb9c19364df2056 Mon Sep 17 00:00:00 2001 From: SebSept Date: Sat, 8 May 2021 23:45:10 +0200 Subject: [PATCH 1/9] Documentation for pre-commit utility. --- README.md | 52 +++++++++++++++++---------- src/Command/SebSept/PrecommitHook.php | 19 ++++++++++ 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 7e84351..6aa40d4 100644 --- a/README.md +++ b/README.md @@ -24,10 +24,10 @@ This is just a starting point. - Code formating : [php-cs-fixer](https://github.com/FriendsOfPhp/PHP-CS-Fixer) configured using prestashop standard, ready to use out of the box. - Code analysis : [phpstan](https://phpstan.org/) almost ready to use with Prestashop standard, it asks a question then you're ready. - `fill-indexes` command, to add required index.php files. (see below for details) +- git pre-commit hook installer (details below) More tools will come - [prestashop/header-stamp](https://github.com/PrestaShopCorp/header-stamp/) (update license header in files) -- a tool to install a precommit hook to ensure everything is ok before commiting. - GitHub actions - ... @@ -42,23 +42,10 @@ You can even take an additionnal step by [defining an alias](https://duckduckgo. ## Provided commands -* psdt:php-cs-fixer -* psdt:phpstan -* psdt:fill-indexes - -### fill-indexes - -`composer psdt:fill-indexes` - -Add the missing index.php files on each folder. -Existing index.php files are not overriden. - -This is a security requirement of Prestashop to avoid the contents to be listed. - -More information [on the official documentation](https://devdocs.prestashop.com/1.7/modules/sell/techvalidation-checklist/#a-file-indexphp-exists-in-each-folder). - -I can't include [prestashop/autoindex](https://github.com/PrestaShopCorp/autoindex) because [it targets php 5.6](https://github.com/PrestaShopCorp/autoindex/blob/92e10242f94a99163dece280f6bd7b7c2b79c158/composer.json#L23) and has other issues. -My replacement is simpler and doesn't require additionnal dependencies. +* [psdt:php-cs-fixer](#fill-indexes) +* [psdt:phpstan](#phpstan) +* [psdt:fill-indexes](#fill-indexes) +* [psdt:install-precommit-hook](#git-pre-commit-hook-installer) (not supported on Windows yet) ### php-cs-fixer @@ -92,6 +79,35 @@ Autoinstallation provided by this package. Allows complying with the [Prestashop standards](https://devdocs.prestashop.com/1.7/development/coding-standards/). + +### fill-indexes + +`composer psdt:fill-indexes` + +Add the missing index.php files on each folder. +Existing index.php files are not overriden. + +This is a security requirement of Prestashop to avoid the contents to be listed. + +More information [on the official documentation](https://devdocs.prestashop.com/1.7/modules/sell/techvalidation-checklist/#a-file-indexphp-exists-in-each-folder). + +I can't include [prestashop/autoindex](https://github.com/PrestaShopCorp/autoindex) because [it targets php 5.6](https://github.com/PrestaShopCorp/autoindex/blob/92e10242f94a99163dece280f6bd7b7c2b79c158/composer.json#L23) and has other issues. +My replacement is simpler and doesn't require additionnal dependencies. + +### Git Pre-commit hook installer + +This command need to be run only once. +It does : +- add a composer script `pre-commit` +- add file `precommit.sh` +- make it executable +- symlink it to .git/hooks/pre-commit + +So before a commit is can be performed the composer script `pre-commit` must succeed (return 0). + +You can tweak the script by just editing the composer script. +You can run the `pre-commit` at any time `composer + ## Installation `composer require --dev sebsept/ps_dev_base` diff --git a/src/Command/SebSept/PrecommitHook.php b/src/Command/SebSept/PrecommitHook.php index 5e14362..a8acd2d 100644 --- a/src/Command/SebSept/PrecommitHook.php +++ b/src/Command/SebSept/PrecommitHook.php @@ -84,6 +84,19 @@ protected function execute(InputInterface $input, OutputInterface $output): int ? $this->getIO()->write(sprintf('%s is executable.', $preCommitHookFileRelativePath)) : $this->makePrecommitFileExecutable(); + $this->getIO()->write( + <<<'INFOS' +If everything is ok, before the next commit on this repository, the git precommit hook will be triggered. +If the script is ok, commit will be performed. Otherwise the commit will be aborted. +In case, you don't see the precommit script messages to see what needs to be fixed, you can run +composer psdt:pre-commit. + +You can also run this command at any time, before processing the commit, stashing changes for example. + +You can edit the script content by editing the script entry pre-commit in composer.json. +INFOS + ); + return 0; } catch (Exception $exception) { $this->getIO()->error(sprintf('%s failed : %s', $this->getComposerScriptName(), $exception->getMessage())); @@ -92,6 +105,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } + /** + * Name of composer script. + * In case it change, it also needs to be changed in the information text displayed. + * + * @see execute() + */ public function getComposerScriptName(): string { return 'pre-commit'; From f739199235d05b911fe93dd2eb89e9bffa49357e Mon Sep 17 00:00:00 2001 From: SebSept Date: Sat, 8 May 2021 23:47:29 +0200 Subject: [PATCH 2/9] fix scripts included in composer 'pre-commit' (not tested) --- src/Command/SebSept/PrecommitHook.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Command/SebSept/PrecommitHook.php b/src/Command/SebSept/PrecommitHook.php index a8acd2d..e850e77 100644 --- a/src/Command/SebSept/PrecommitHook.php +++ b/src/Command/SebSept/PrecommitHook.php @@ -131,9 +131,9 @@ private function installComposerScript(): void private function getComposerScripts(): array { $scripts = ['composer validate']; - (new PrestashopDevToolsCsFixer())->isToolConfigured() + !(new PrestashopDevToolsCsFixer())->isToolConfigured() ?: array_push($scripts, 'vendor/bin/php-cs-fixer fix --dry-run --ansi'); - (new PrestashopDevToolsPhpStan())->isToolConfigured() + !(new PrestashopDevToolsPhpStan())->isToolConfigured() ?: array_push($scripts, '@phpstan --ansi'); return $scripts; From 2ed74d81cd0e0a34a8a8f55feda6870a78ca4e46 Mon Sep 17 00:00:00 2001 From: SebSept Date: Mon, 10 May 2021 20:58:28 +0200 Subject: [PATCH 3/9] simplify code + description --- src/Command/SebSept/PrecommitHook.php | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/Command/SebSept/PrecommitHook.php b/src/Command/SebSept/PrecommitHook.php index e850e77..a8657c2 100644 --- a/src/Command/SebSept/PrecommitHook.php +++ b/src/Command/SebSept/PrecommitHook.php @@ -45,17 +45,17 @@ final protected function configure(): void $this->setHelp( $this->getDescription() . <<<'HELP' + * creates file precommit.sh that trigger composer script pre-commit * adds a composer script pre-commit - * creates file precommit.sh - * symlinks precommit.sh to .git/hooks/precommit + * symlinks precommit.sh to .git/hooks/precommit * next runs will trigger the composer script pre-commit -The composer scripts by default triggers the other scripts @phpstan @csfix (dry-run) and composer validate. -This is the default, you can edit the content of the script. +The composer scripts by default triggers the other scripts @phpstan, @csfix (dry-run) and composer validate. +This is the default, you can edit the content of the script in composer.json The --reconfigure allows to resetup, rerun the 3 first steps and override contents. -This is tested on GNU/Linux, it probably works fine on MacOS. Probably not on Windows (?). +This is tested on GNU/Linux, it probably works fine on MacOS. Probably not on Windows (feedback and fix are welcome). HELP ); @@ -70,7 +70,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->isComposerScriptDefined() ? $this->getIO()->write(sprintf('Composer script %s is installed.', $this->getComposerScriptName())) - : $this->installComposerScript(); + : $this->addComposerScript($this->getComposerScripts()); $this->precommitFileExists() ? $this->getIO()->write(sprintf('Precommit file %s is present.', self::PRECOMMIT_FILE)) @@ -116,13 +116,6 @@ public function getComposerScriptName(): string return 'pre-commit'; } - private function installComposerScript(): void - { - $this->getIO()->write('Installing composer script : ', false); - $this->addComposerScript($this->getComposerScripts()); - $this->getIO()->write('Ok'); - } - /** * Composer scripts to launch depending if tools are configured. * From b526be86a67d6863cb4e0567b02b8caee4046acf Mon Sep 17 00:00:00 2001 From: SebSept Date: Mon, 10 May 2021 21:46:43 +0200 Subject: [PATCH 4/9] commands runs the composer script when ready. --- src/Command/SebSept/PrecommitHook.php | 46 ++++++++++++++++++--------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/Command/SebSept/PrecommitHook.php b/src/Command/SebSept/PrecommitHook.php index a8657c2..258bafb 100644 --- a/src/Command/SebSept/PrecommitHook.php +++ b/src/Command/SebSept/PrecommitHook.php @@ -67,35 +67,33 @@ protected function execute(InputInterface $input, OutputInterface $output): int try { $preCommitHookFileRelativePath = str_replace(__DIR__ . DIRECTORY_SEPARATOR, '', self::PRECOMMIT_HOOK_FILE); + $composerScriptIsDefined = $this->isComposerScriptDefined(); + $precommitFileExists = $this->precommitFileExists(); + $precommitFileIsSymlinked = $this->isPrecommitFileSymlinked(); + $precommitFileIsExecutable = $this->isPrecommitFileExecutable(); + $readyToRun = $composerScriptIsDefined && $precommitFileExists && $precommitFileIsSymlinked && $precommitFileIsExecutable; - $this->isComposerScriptDefined() + $composerScriptIsDefined ? $this->getIO()->write(sprintf('Composer script %s is installed.', $this->getComposerScriptName())) : $this->addComposerScript($this->getComposerScripts()); - $this->precommitFileExists() + $precommitFileExists ? $this->getIO()->write(sprintf('Precommit file %s is present.', self::PRECOMMIT_FILE)) : $this->copyPrecommitFile(); - $this->isPrecommitFileSymlinked() + $precommitFileIsSymlinked ? $this->getIO()->write(sprintf('%s is symlinked to %s', self::PRECOMMIT_FILE, $preCommitHookFileRelativePath)) : $this->symLinkPrecommitFile(); - $this->isPrecommitFileExecutable() + $precommitFileIsExecutable ? $this->getIO()->write(sprintf('%s is executable.', $preCommitHookFileRelativePath)) : $this->makePrecommitFileExecutable(); - $this->getIO()->write( - <<<'INFOS' -If everything is ok, before the next commit on this repository, the git precommit hook will be triggered. -If the script is ok, commit will be performed. Otherwise the commit will be aborted. -In case, you don't see the precommit script messages to see what needs to be fixed, you can run -composer psdt:pre-commit. + $readyToRun + ? $this->runComposerScript($output) + : $this->getIO()->write(sprintf('run %s command again to run composer script %s', $this->getName(), $this->getComposerScriptName())); -You can also run this command at any time, before processing the commit, stashing changes for example. - -You can edit the script content by editing the script entry pre-commit in composer.json. -INFOS - ); + $this->getIO()->write($this->getAdditionnalHelp()); return 0; } catch (Exception $exception) { @@ -139,7 +137,9 @@ private function precommitFileExists(): bool private function copyPrecommitFile(): void { + $this->getIO()->write('Copying pre-commit script file ...', false); $this->fs->copy(self::SOURCE_PRECOMMIT_FILE, self::PRECOMMIT_FILE, true); + $this->getIO()->write('OK'); } private function isPrecommitFileSymlinked(): bool @@ -172,6 +172,22 @@ private function isPrecommitFileExecutable(): bool private function makePrecommitFileExecutable(): void { + $this->getIO()->write('Make pre-commit script file executable ...', false); $this->fs->chmod(self::PRECOMMIT_FILE, 0755); + $this->getIO()->write('OK'); + } + + private function getAdditionnalHelp(): string + { + return <<<'INFOS' +If everything is ok, before the next commit on this repository, the git precommit hook will be triggered. +If the script is ok, commit will be performed. Otherwise the commit will be aborted. +In case, you don't see the precommit script messages to see what needs to be fixed, you can run +composer psdt:pre-commit. + +You can also run this command at any time, before processing the commit, stashing changes for example. + +You can edit the script content by editing the script entry pre-commit in composer.json. +INFOS; } } From 0a6443f3bf01ee0cc773b256d7819b6bb8c1a08f Mon Sep 17 00:00:00 2001 From: SebSept Date: Tue, 11 May 2021 23:19:30 +0200 Subject: [PATCH 5/9] rollback deleted precommit.sh source script --- resources/precommit.sh | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 resources/precommit.sh diff --git a/resources/precommit.sh b/resources/precommit.sh new file mode 100644 index 0000000..011ec90 --- /dev/null +++ b/resources/precommit.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env sh +# this file must be symlinked in .git/hooks with the name "pre-commit" +# it fire composer script "pre-commit" which launch phpstan + phpcsfix +# +# install with `ln -s $(pwd)/precommit.sh .git/hooks/pre-commit` + +(cd "./" && echo "start pre-commit hook ..." & exec 'composer' 'run-script' 'pre-commit') \ No newline at end of file From 026b53c2007f0e15d1657b281a489bbb61296263 Mon Sep 17 00:00:00 2001 From: SebSept Date: Tue, 11 May 2021 23:19:43 +0200 Subject: [PATCH 6/9] reregister Precommit command --- src/Composer/PsDevToolsCommandProvider.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Composer/PsDevToolsCommandProvider.php b/src/Composer/PsDevToolsCommandProvider.php index 820eb86..02e7da0 100644 --- a/src/Composer/PsDevToolsCommandProvider.php +++ b/src/Composer/PsDevToolsCommandProvider.php @@ -25,6 +25,7 @@ use SebSept\PsDevToolsPlugin\Command\PrestashopDevTools\PrestashopDevToolsPhpStan; use SebSept\PsDevToolsPlugin\Command\SebSept\HelloCommand; use SebSept\PsDevToolsPlugin\Command\SebSept\IndexPhpFiller; +use SebSept\PsDevToolsPlugin\Command\SebSept\PrecommitHook; final class PsDevToolsCommandProvider implements CommandProvider { @@ -35,6 +36,7 @@ public function getCommands(): array new PrestashopDevToolsPhpStan(), new PrestashopDevToolsCsFixer(), new IndexPhpFiller(), + new PrecommitHook(), ]; } } From ccf890a78272421417961e5009b8310b9c59eb2e Mon Sep 17 00:00:00 2001 From: SebSept Date: Tue, 11 May 2021 23:20:20 +0200 Subject: [PATCH 7/9] runScript announce itself --- src/Command/BaseCommand.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Command/BaseCommand.php b/src/Command/BaseCommand.php index dd415f8..c66cb1e 100644 --- a/src/Command/BaseCommand.php +++ b/src/Command/BaseCommand.php @@ -90,6 +90,8 @@ final protected function isComposerScriptDefined(): bool */ final protected function runComposerScript(OutputInterface $output): void { + $output->write(sprintf('Now running composer script %s : ', $this->getComposerScriptName())); + $this->getApplication()->find('run-script')->run( new ArrayInput([ 'script' => $this->getComposerScriptName(), From c93eed7e862becfda27b36daafbe9330153cae14 Mon Sep 17 00:00:00 2001 From: SebSept Date: Tue, 11 May 2021 23:21:27 +0200 Subject: [PATCH 8/9] implemented --reconfigure option (not tested) --- src/Command/SebSept/PrecommitHook.php | 37 ++++++++++++++++----------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/Command/SebSept/PrecommitHook.php b/src/Command/SebSept/PrecommitHook.php index 258bafb..a73aa0a 100644 --- a/src/Command/SebSept/PrecommitHook.php +++ b/src/Command/SebSept/PrecommitHook.php @@ -26,6 +26,7 @@ use SebSept\PsDevToolsPlugin\Command\ScriptCommand; use SplFileInfo; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Filesystem\Filesystem; @@ -42,6 +43,7 @@ final protected function configure(): void { $this->setName('install-precommit-hook'); $this->setDescription('Install a git pre-commit hook'); + $this->addOption('reconfigure', null, InputOption::VALUE_NONE, 'rerun configuration and file installations.'); $this->setHelp( $this->getDescription() . <<<'HELP' @@ -63,15 +65,22 @@ final protected function configure(): void protected function execute(InputInterface $input, OutputInterface $output): int { - $this->fs = new Filesystem(); - try { + $this->fs = new Filesystem(); + /** @var bool $reconfigure */ + $reconfigure = $input->getOption('reconfigure'); $preCommitHookFileRelativePath = str_replace(__DIR__ . DIRECTORY_SEPARATOR, '', self::PRECOMMIT_HOOK_FILE); - $composerScriptIsDefined = $this->isComposerScriptDefined(); - $precommitFileExists = $this->precommitFileExists(); - $precommitFileIsSymlinked = $this->isPrecommitFileSymlinked(); - $precommitFileIsExecutable = $this->isPrecommitFileExecutable(); - $readyToRun = $composerScriptIsDefined && $precommitFileExists && $precommitFileIsSymlinked && $precommitFileIsExecutable; + + if ($reconfigure) { + $composerScriptIsDefined = $precommitFileExists = $precommitFileIsSymlinked = $precommitFileIsExecutable = $readyToRun + = false; + } else { + $composerScriptIsDefined = $this->isComposerScriptDefined(); + $precommitFileExists = $this->precommitFileExists(); + $precommitFileIsSymlinked = $this->isPrecommitFileSymlinked(); + $precommitFileIsExecutable = $this->isPrecommitFileExecutable(); + $readyToRun = $composerScriptIsDefined && $precommitFileExists && $precommitFileIsSymlinked && $precommitFileIsExecutable; + } $composerScriptIsDefined ? $this->getIO()->write(sprintf('Composer script %s is installed.', $this->getComposerScriptName())) @@ -89,12 +98,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int ? $this->getIO()->write(sprintf('%s is executable.', $preCommitHookFileRelativePath)) : $this->makePrecommitFileExecutable(); + $reconfigure && $this->getIO()->write($this->getAdditionnalHelp()); + $readyToRun ? $this->runComposerScript($output) : $this->getIO()->write(sprintf('run %s command again to run composer script %s', $this->getName(), $this->getComposerScriptName())); - $this->getIO()->write($this->getAdditionnalHelp()); - return 0; } catch (Exception $exception) { $this->getIO()->error(sprintf('%s failed : %s', $this->getComposerScriptName(), $exception->getMessage())); @@ -180,13 +189,11 @@ private function makePrecommitFileExecutable(): void private function getAdditionnalHelp(): string { return <<<'INFOS' -If everything is ok, before the next commit on this repository, the git precommit hook will be triggered. -If the script is ok, commit will be performed. Otherwise the commit will be aborted. -In case, you don't see the precommit script messages to see what needs to be fixed, you can run -composer psdt:pre-commit. - +Before the next commit the git precommit hook will be triggered. +If the pre-commit script return 0 (success), commit will be performed, otherwise aborted. +In case, you can't read the precommit script output and find what's wrong +just run composer psdt:pre-commit . You can also run this command at any time, before processing the commit, stashing changes for example. - You can edit the script content by editing the script entry pre-commit in composer.json. INFOS; } From eb5ec957b07ac3f5f938db871c6d1088f91fb1d9 Mon Sep 17 00:00:00 2001 From: SebSept Date: Wed, 12 May 2021 22:12:53 +0200 Subject: [PATCH 9/9] fix precommit command. --- src/Command/SebSept/PrecommitHook.php | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/Command/SebSept/PrecommitHook.php b/src/Command/SebSept/PrecommitHook.php index a73aa0a..03d3978 100644 --- a/src/Command/SebSept/PrecommitHook.php +++ b/src/Command/SebSept/PrecommitHook.php @@ -134,7 +134,7 @@ private function getComposerScripts(): array !(new PrestashopDevToolsCsFixer())->isToolConfigured() ?: array_push($scripts, 'vendor/bin/php-cs-fixer fix --dry-run --ansi'); !(new PrestashopDevToolsPhpStan())->isToolConfigured() - ?: array_push($scripts, '@phpstan --ansi'); + ?: array_push($scripts, '@phpstan'); return $scripts; } @@ -162,15 +162,23 @@ private function isPrecommitFileSymlinked(): bool private function symLinkPrecommitFile(): void { + $gitLink = getcwd() . DIRECTORY_SEPARATOR . self::PRECOMMIT_HOOK_FILE; + $precommitScript = getcwd() . DIRECTORY_SEPARATOR . self::PRECOMMIT_FILE; + + // remove existing git file + if (file_exists($gitLink)) { + $this->getIO()->write('Removing git hook...', false); + if (!unlink($gitLink)) { + throw new Exception('Failed to remove existing pre-commit file ' . $gitLink); + } + $this->getIO()->write(' OK'); + } + + // create symlink $this->getIO()->write('Symlink to precommit hook...', false); - if (!symlink( - getcwd() . DIRECTORY_SEPARATOR . self::PRECOMMIT_FILE, - getcwd() . DIRECTORY_SEPARATOR . self::PRECOMMIT_HOOK_FILE - )) { + if (!symlink($precommitScript, $gitLink)) { throw new Exception('Failed to symlink.'); } - // this does nothing (?), no error neither ... -// $this->fs->symlink(self::PRECOMMIT_FILE, self::PRECOMMIT_HOOK_FILE); $this->getIO()->write(' OK'); } @@ -189,10 +197,12 @@ private function makePrecommitFileExecutable(): void private function getAdditionnalHelp(): string { return <<<'INFOS' + Before the next commit the git precommit hook will be triggered. If the pre-commit script return 0 (success), commit will be performed, otherwise aborted. In case, you can't read the precommit script output and find what's wrong just run composer psdt:pre-commit . + You can also run this command at any time, before processing the commit, stashing changes for example. You can edit the script content by editing the script entry pre-commit in composer.json. INFOS;