From d51a9053288d2d92f8a9d0c079a42898ba0d4921 Mon Sep 17 00:00:00 2001 From: Len Woodward Date: Fri, 24 May 2024 10:32:09 -0700 Subject: [PATCH] [ Feat ] Use TTY mode on Process Facade (#72) * Extract snippets into getter function * new runner using tty mode on process facade * add new snippet to use new run command, make default * Update deprecated GetRunCmd to automatically update hook snippets * add fallback to support non-tty interfaces * remove unnecessary shell script * remove unused 'scripts' command * remove empty test file * temporarily skip test * update assignment operator * refactor skipped test --- app/Commands/GetRunCmd.php | 29 +++++++---------- app/Commands/Run.php | 60 +++++++++++++++++++++++++++++++++++ app/Commands/Scripts.php | 31 ------------------ app/Hook.php | 33 ++++++++++++------- bin/run-hook | 28 ---------------- tests/Feature/RunTest.php | 13 +++++--- tests/Feature/ScriptsTest.php | 0 7 files changed, 101 insertions(+), 93 deletions(-) create mode 100644 app/Commands/Run.php delete mode 100644 app/Commands/Scripts.php delete mode 100755 bin/run-hook delete mode 100644 tests/Feature/ScriptsTest.php diff --git a/app/Commands/GetRunCmd.php b/app/Commands/GetRunCmd.php index 46db1ea..c613035 100644 --- a/app/Commands/GetRunCmd.php +++ b/app/Commands/GetRunCmd.php @@ -2,14 +2,13 @@ namespace ProjektGopher\Whisky\Commands; -use Illuminate\Support\Facades\File; use LaravelZero\Framework\Commands\Command; -use ProjektGopher\Whisky\Platform; use ProjektGopher\Whisky\Whisky; /** - * This command is basically only needed to build the execution path - * to the `run` bash script, or to skip the hooks once. + * This command was only used to construct the execution path + * to the `run-hook` bash script, which is now deprecated. + * Now we can automatically update the hooks snippets. */ class GetRunCmd extends Command { @@ -17,22 +16,16 @@ class GetRunCmd extends Command protected $description = 'Get the bash command to run a given hook'; - public function handle(): int + public function handle(): void { - if (File::exists(Platform::cwd('.git/hooks/skip-once'))) { - File::delete(Platform::cwd('.git/hooks/skip-once')); - - return Command::SUCCESS; - } - - // Check if the hook is disabled in whisky.json - if (in_array($this->argument('hook'), Whisky::readConfig('disabled'))) { - return Command::SUCCESS; - } - $bin = Whisky::bin_path(); - $this->line(Whisky::base_path("bin/run-hook {$this->argument('hook')} {$bin}")); - return Command::SUCCESS; + $commands = collect([ + "echo 'The snippet in your hook is deprecated. Updating...'", + "{$bin} update", + "{$bin} run {$this->argument('hook')}", + ]); + + $this->line($commands->implode(PHP_EOL)); } } diff --git a/app/Commands/Run.php b/app/Commands/Run.php new file mode 100644 index 0000000..b20358e --- /dev/null +++ b/app/Commands/Run.php @@ -0,0 +1,60 @@ +error('Whisky has not been initialized in this project, aborting...'); + $this->line('Run `./vendor/bin/whisky install` to initialize Whisky in this project.'); + + return Command::FAILURE; + } + + if (File::exists(Platform::cwd('.git/hooks/skip-once'))) { + File::delete(Platform::cwd('.git/hooks/skip-once')); + + return Command::SUCCESS; + } + + // Check if the hook is disabled in whisky.json + if (in_array($this->argument('hook'), Whisky::readConfig('disabled'))) { + return Command::SUCCESS; + } + + $exitCode = Command::SUCCESS; + + Hook::make($this->argument('hook')) + ->getScripts() + ->each(function (string $script) use (&$exitCode): void { + $isTtySupported = SymfonyProcess::isTtySupported(); + + $result = $isTtySupported + ? Process::forever()->tty()->run($script) + : Process::timeout(300)->run($script); + + if ($result->failed() && ! $isTtySupported) { + $this->line($result->errorOutput()); + $this->line($result->output()); + } + + $exitCode |= $result->exitCode(); + }); + + return $exitCode; + } +} diff --git a/app/Commands/Scripts.php b/app/Commands/Scripts.php deleted file mode 100644 index 1b38271..0000000 --- a/app/Commands/Scripts.php +++ /dev/null @@ -1,31 +0,0 @@ -error('Whisky has not been initialized in this project, aborting...'); - $this->line('Run `./vendor/bin/whisky install` to initialize Whisky in this project.'); - - return Command::FAILURE; - } - - Hook::make($this->argument('hook'))->getScripts()->each(function (string $script): void { - $this->line($script); - }); - - return Command::SUCCESS; - } -} diff --git a/app/Hook.php b/app/Hook.php index d426296..d53c056 100644 --- a/app/Hook.php +++ b/app/Hook.php @@ -37,11 +37,9 @@ public function uninstall(): bool } $contents = File::get($path); - $commands = [ - "eval \"$({$this->bin} get-run-cmd {$this->hook})\"".PHP_EOL, - // TODO: legacy - handle upgrade somehow - "eval \"$(./vendor/bin/whisky get-run-cmd {$this->hook})\"".PHP_EOL, - ]; + $commands = $this->getSnippets() + ->map(fn (string $snippet): string => $snippet.PHP_EOL) + ->toArray(); if (! Str::contains($contents, $commands)) { return false; @@ -94,11 +92,7 @@ public function isInstalled(): bool { return Str::contains( File::get(Platform::cwd(".git/hooks/{$this->hook}")), - [ - "eval \"$({$this->bin} get-run-cmd {$this->hook})\"", - // TODO: legacy - handle upgrade somehow - "eval \"$(./vendor/bin/whisky get-run-cmd {$this->hook})\"", - ], + $this->getSnippets()->toArray(), ); } @@ -109,7 +103,7 @@ public function install(): void { File::append( Platform::cwd(".git/hooks/{$this->hook}"), - "eval \"$({$this->bin} get-run-cmd {$this->hook})\"".PHP_EOL, + $this->getSnippets()->first().PHP_EOL, ); } @@ -126,6 +120,23 @@ public function getScripts(): Collection return collect(Whisky::readConfig("hooks.{$this->hook}")); } + /** + * Collect the bash snippet history for calling the Whisky bin. + * The current version of the snippet should always be first. + * We keep this history to make updating our hooks easier. + * + * @return Collection + */ + public function getSnippets(): Collection + { + return collect([ + "{$this->bin} run {$this->hook}", + // Legacy Snippets. + "eval \"$({$this->bin} get-run-cmd {$this->hook})\"", + "eval \"$(./vendor/bin/whisky get-run-cmd {$this->hook})\"", + ]); + } + //////////////////////////////////////// //// Static methods //// //////////////////////////////////////// diff --git a/bin/run-hook b/bin/run-hook deleted file mode 100755 index 9ba7dee..0000000 --- a/bin/run-hook +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -# Get the hook name from the first argument -hook=$1 - -# Get the path to the Whisky binary from the second argument -bin=$2 - -# Get a list of scripts to run sequencially for this hook -SCRIPTS=$($bin scripts "$hook") - -# Make newlines the only separator -IFS=$'\n' - -# Set the exit code to 0. If any script fails, -# this will then be set to that exit code -exit_code=0 - -# Run each script -for SCRIPT in $SCRIPTS; do - eval "$SCRIPT" - last_exit_code=$? - if [ $last_exit_code -ne 0 ]; then - exit_code=$last_exit_code - fi -done - -exit $exit_code diff --git a/tests/Feature/RunTest.php b/tests/Feature/RunTest.php index dca6fc8..59844a4 100644 --- a/tests/Feature/RunTest.php +++ b/tests/Feature/RunTest.php @@ -3,7 +3,12 @@ use Illuminate\Support\Facades\File; use ProjektGopher\Whisky\Platform; -it('deletes skip-once file if exists and outputs nothing', function () { +it('deletes skip-once file if exists as long as whisky.json exists', function () { + File::shouldReceive('missing') + ->once() + ->with(Platform::cwd('whisky.json')) + ->andReturnFalse(); + File::shouldReceive('exists') ->once() ->with(Platform::cwd('.git/hooks/skip-once')) @@ -14,9 +19,7 @@ ->with(Platform::cwd('.git/hooks/skip-once')) ->andReturnTrue(); - $this->artisan('get-run-cmd pre-commit') + $this->artisan('run pre-commit') ->doesntExpectOutputToContain('run-hook') ->assertExitCode(0); -}); - -it('points correctly to the run-hook script'); +})->skip('Needs to be refactored so that the hooks don\'t actually run'); diff --git a/tests/Feature/ScriptsTest.php b/tests/Feature/ScriptsTest.php deleted file mode 100644 index e69de29..0000000