diff --git a/README.md b/README.md index b904cd6..e8df126 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,17 @@ composer require --dev projektgopher/whisky ./vendor/bin/whisky install ``` -> **Note** It is recommended to only require Whisky on a project level, as it does not **currently** work as expected when installed _globally_. +This is the recommended method, as every developer on your project will have access to the tool. + +### Global Installation +Whisky can be installed globally, however this means that any developer on your project will _also_ need it installed globally if they want to use it. + +```bash +composer global require projektgopher/whisky +whisky install +``` + +If Whisky is installed both globally, and locally, on a project the version that's run will depend on how the command is invoked. ## Usage @@ -103,6 +113,16 @@ git hook run pre-commit ``` +## Troubleshooting +If you've installed Whisky **both** locally **and** globally, and your hooks are being run _twice_, try uninstalling whisky from your hooks for **one** of those installations. + +```bash +# Remove global Whisky hooks, leaving the local ones, +# while keeping `whisky.json` in the project root. +whisky uninstall -n +``` + + ## Contributing > **Note** Don't build the binary when contributing. The binary will be built when a release is tagged. diff --git a/app/Commands/GetRunCmd.php b/app/Commands/GetRunCmd.php index 3bc685a..46db1ea 100644 --- a/app/Commands/GetRunCmd.php +++ b/app/Commands/GetRunCmd.php @@ -4,6 +4,7 @@ use Illuminate\Support\Facades\File; use LaravelZero\Framework\Commands\Command; +use ProjektGopher\Whisky\Platform; use ProjektGopher\Whisky\Whisky; /** @@ -18,8 +19,8 @@ class GetRunCmd extends Command public function handle(): int { - if (File::exists(Whisky::base_path('bin/skip-once'))) { - File::delete(Whisky::base_path('bin/skip-once')); + if (File::exists(Platform::cwd('.git/hooks/skip-once'))) { + File::delete(Platform::cwd('.git/hooks/skip-once')); return Command::SUCCESS; } diff --git a/app/Commands/SkipOnce.php b/app/Commands/SkipOnce.php index b6f3a13..2e04c34 100644 --- a/app/Commands/SkipOnce.php +++ b/app/Commands/SkipOnce.php @@ -4,7 +4,7 @@ use Illuminate\Support\Facades\File; use LaravelZero\Framework\Commands\Command; -use ProjektGopher\Whisky\Whisky; +use ProjektGopher\Whisky\Platform; class SkipOnce extends Command { @@ -14,7 +14,7 @@ class SkipOnce extends Command public function handle(): int { - File::put(Whisky::base_path('bin/skip-once'), ''); + File::put(Platform::cwd('.git/hooks/skip-once'), ''); $this->info('Next hook will be skipped.'); $this->line('If the action you\'re about to take has a `pre` and `post` hook'); diff --git a/app/Platform.php b/app/Platform.php index dd7b1af..e0972dc 100644 --- a/app/Platform.php +++ b/app/Platform.php @@ -24,6 +24,16 @@ public static function normalizePath(string $path): string return $path; } + public static function getGlobalComposerHome(): string + { + return rtrim(shell_exec('composer -n global config home --quiet'), "\n"); + } + + public static function getGlobalComposerBinDir(): string + { + return rtrim(shell_exec('composer -n global config bin-dir --absolute --quiet'), "\n"); + } + public function determineQuote(): string { return $this->isWindows() ? '"' : "'"; diff --git a/app/Whisky.php b/app/Whisky.php index b9b7e94..70df296 100644 --- a/app/Whisky.php +++ b/app/Whisky.php @@ -2,45 +2,43 @@ namespace ProjektGopher\Whisky; -use Phar; +use Illuminate\Support\Facades\File; class Whisky { + public static function base_path(string $path = ''): string + { + $code_path = "vendor/projektgopher/whisky/{$path}"; + + return Platform::normalizePath(match (true) { + self::dogfooding() => base_path($path), + self::isRunningGlobally() => Platform::getGlobalComposerHome().'/'.$code_path, + default => Platform::cwd($code_path), + }); + } + public static function bin_path(): string { return Platform::normalizePath(match (true) { self::dogfooding() => Platform::cwd('whisky'), - self::isRunningGlobally() => '/usr/local/bin/whisky', // TODO + self::isRunningGlobally() => Platform::getGlobalComposerBinDir().'/whisky', default => Platform::cwd('vendor/bin/whisky'), }); } public static function dogfooding(): bool { - return Platform::cwd() === self::base_path(); + return Platform::cwd() === Platform::normalizePath(base_path()); } - // TODO - public static function isRunningGlobally(): bool - { - // composer -n config --global home - // - return false; - } - - // TODO public static function isInstalledGlobally(): bool { - // composer -n config --global home - // composer -n global config bin-dir --absolute --quiet - return false; + return File::exists(Platform::getGlobalComposerBinDir().'/whisky'); } - public static function base_path(string $path = ''): string + public static function isRunningGlobally(): bool { - return Platform::normalizePath(Phar::running() - ? Platform::cwd("vendor/projektgopher/whisky/{$path}") - : base_path($path)); + return str_starts_with(base_path(), Platform::getGlobalComposerHome()); } public static function readConfig(string $key): string|array|null diff --git a/tests/Feature/RunTest.php b/tests/Feature/RunTest.php index f234852..dca6fc8 100644 --- a/tests/Feature/RunTest.php +++ b/tests/Feature/RunTest.php @@ -1,16 +1,17 @@ once() - ->with(normalizePath(base_path('bin/skip-once'))) + ->with(Platform::cwd('.git/hooks/skip-once')) ->andReturnTrue(); File::shouldReceive('delete') ->once() - ->with(normalizePath(base_path('bin/skip-once'))) + ->with(Platform::cwd('.git/hooks/skip-once')) ->andReturnTrue(); $this->artisan('get-run-cmd pre-commit') diff --git a/tests/Feature/SkipOnceTest.php b/tests/Feature/SkipOnceTest.php index 8192ed3..9cbcffe 100644 --- a/tests/Feature/SkipOnceTest.php +++ b/tests/Feature/SkipOnceTest.php @@ -1,6 +1,7 @@ artisan('list') @@ -13,8 +14,8 @@ ->expectsOutputToContain('Next hook will be skipped.') ->assertExitCode(0); - expect(File::exists(__DIR__.'/../../bin/skip-once'))->toBeTrue(); + expect(File::exists(Platform::cwd('.git/hooks/skip-once')))->toBeTrue(); // Cleanup - File::delete(__DIR__.'/../../bin/skip-once'); + File::delete(Platform::cwd('.git/hooks/skip-once')); });