diff --git a/cli/Valet/Nginx.php b/cli/Valet/Nginx.php index 0ab30d4cd..ea4f8b127 100644 --- a/cli/Valet/Nginx.php +++ b/cli/Valet/Nginx.php @@ -177,4 +177,17 @@ public function uninstall() $this->brew->uninstallFormula('nginx nginx-full'); $this->cli->quietly('rm -rf '.BREW_PREFIX.'/etc/nginx '.BREW_PREFIX.'/var/log/nginx'); } + + /** + * Return a list of all sites with explicit Nginx configurations. + * + * @return \Illuminate\Support\Collection + */ + public function configuredSites() + { + return collect($this->files->scandir(VALET_HOME_PATH.'/Nginx')) + ->reject(function ($file) { + return starts_with($file, '.'); + }); + } } diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index fe91ed10b..42ac1b097 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -52,9 +52,16 @@ public function install() $this->files->ensureDirExists(VALET_HOME_PATH.'/Log', user()); - $this->createConfigurationFiles(); + $phpVersion = $this->brew->linkedPhp(); + $this->createConfigurationFiles($phpVersion); + + // Remove old valet.sock + $this->files->unlink(VALET_HOME_PATH.'/valet.sock'); + $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/valet.sock'); $this->restart(); + + $this->symlinkPrimaryValetSock($phpVersion); } /** @@ -74,12 +81,12 @@ public function uninstall() * * Writes FPM config file, pointing to the correct .sock file, and log and ini files. * - * @param string|null $phpVersion + * @param string $phpVersion * @return void */ - public function createConfigurationFiles($phpVersion = null) + public function createConfigurationFiles($phpVersion) { - info(sprintf('Updating PHP configuration%s...', ($phpVersion ? ' for '.$phpVersion : ''))); + info("Updating PHP configuration for {$phpVersion}..."); $fpmConfigFile = $this->fpmConfigPath($phpVersion); @@ -87,13 +94,10 @@ public function createConfigurationFiles($phpVersion = null) // Create FPM Config File from stub $contents = str_replace( - ['VALET_USER', 'VALET_HOME_PATH'], - [user(), VALET_HOME_PATH], + ['VALET_USER', 'VALET_HOME_PATH', 'valet.sock'], + [user(), VALET_HOME_PATH, self::fpmSockName($phpVersion)], $this->files->get(__DIR__.'/../stubs/etc-phpfpm-valet.conf') ); - if ($phpVersion) { - $contents = str_replace('valet.sock', self::fpmSockName($phpVersion), $contents); - } $this->files->put($fpmConfigFile, $contents); // Create other config files from stubs @@ -210,7 +214,6 @@ public function isolateDirectory($directory, $version) $this->brew->ensureInstalled($version, [], $this->taps); $oldCustomPhpVersion = $this->site->customPhpVersion($site); // Example output: "74" - $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/'.$this->fpmSockName($oldCustomPhpVersion)); $this->createConfigurationFiles($version); $this->site->isolate($site, $version); @@ -245,6 +248,22 @@ public function unIsolateDirectory($directory) info(sprintf('The site [%s] is now using the default PHP version.', $site)); } + /** + * List all directories with PHP isolation configured. + * + * @return \Illuminate\Support\Collection + */ + public function isolatedDirectories() + { + $configuredSites = $this->nginx->configuredSites(); + + return $configuredSites->filter(function ($item) { + return strpos($this->files->get(VALET_HOME_PATH.'/Nginx/'.$item), ISOLATED_PHP_VERSION) !== false; + })->map(function ($item) { + return ['url' => $item, 'version' => $this->normalizePhpVersion($this->site->customPhpVersion($item))]; + }); + } + /** * Use a specific version of PHP globally. * @@ -269,15 +288,6 @@ public function useVersion($version, $force = false) // Unlink the current global PHP if there is one installed if ($this->brew->hasLinkedPhp()) { - $linkedPhp = $this->brew->linkedPhp(); - - // Update the old FPM to keep running, using a custom sock file, so existing isolated sites aren't broken - $this->createConfigurationFiles($linkedPhp); - - // Update existing custom Nginx config files; if they're using the old or new PHP version, - // update them to the new correct sock file location - $this->updateConfigurationForGlobalUpdate($version, $linkedPhp); - $currentVersion = $this->brew->getLinkedPhpFormula(); info(sprintf('Unlinking current version: %s', $currentVersion)); $this->brew->unlink($currentVersion); @@ -288,10 +298,6 @@ public function useVersion($version, $force = false) $this->stopRunning(); - // remove any orphaned valet.sock files that PHP didn't clean up due to version conflicts - $this->files->unlink(VALET_HOME_PATH.'/valet.sock'); - $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/valet*.sock'); - $this->install(); $newVersion = $version === 'php' ? $this->brew->determineAliasedVersion($version) : $version; @@ -304,16 +310,23 @@ public function useVersion($version, $force = false) return $newVersion; } + /** + * Symlink (Capistrano-style) a given Valet.sock file to be the primary valet.sock. + * + * @param string $phpVersion + * @return void + */ + public function symlinkPrimaryValetSock($phpVersion) + { + $this->files->symlinkAsUser(VALET_HOME_PATH.'/'.$this->fpmSockName($phpVersion), VALET_HOME_PATH.'/valet.sock'); + } + /** * If passed php7.4, or php74, 7.4, or 74 formats, normalize to php@7.4 format. */ public function normalizePhpVersion($version) { - if (strpos($version, 'php') === false) { - $version = 'php'.$version; - } - - return preg_replace('/(php)([0-9+])(?:.)?([0-9+])/i', '$1@$2.$3', $version); + return preg_replace('/(?:php@?)?([0-9+])(?:.)?([0-9+])/i', 'php@$1.$2', $version); } /** @@ -356,42 +369,6 @@ public static function fpmSockName($phpVersion = null) return "valet{$versionInteger}.sock"; } - /** - * Update all existing Nginx files when running a global PHP version update. - * - * If a given file is pointing to `valet.sock`, it's targeting the old global PHP version; - * update it to point to the new custom sock file for that version. - * - * If a given file is pointing the custom sock file for the new global version, that new - * version will now be hosted at `valet.sock`, so update the config file to point to that instead. - * - * @param string $newPhpVersion - * @param string $oldPhpVersion - * @return void - */ - public function updateConfigurationForGlobalUpdate($newPhpVersion, $oldPhpVersion) - { - collect($this->files->scandir(VALET_HOME_PATH.'/Nginx')) - ->reject(function ($file) { - return starts_with($file, '.'); - }) - ->each(function ($file) use ($newPhpVersion, $oldPhpVersion) { - $content = $this->files->get(VALET_HOME_PATH.'/Nginx/'.$file); - - if (! starts_with($content, '# Valet isolated PHP version')) { - return; - } - - if (strpos($content, self::fpmSockName($newPhpVersion)) !== false) { - info(sprintf('Updating site %s to keep using version: %s', $file, $newPhpVersion)); - $this->files->put(VALET_HOME_PATH.'/Nginx/'.$file, str_replace(self::fpmSockName($newPhpVersion), 'valet.sock', $content)); - } elseif (strpos($content, 'valet.sock') !== false) { - info(sprintf('Updating site %s to keep using version: %s', $file, $oldPhpVersion)); - $this->files->put(VALET_HOME_PATH.'/Nginx/'.$file, str_replace('valet.sock', self::fpmSockName($oldPhpVersion), $content)); - } - }); - } - /** * Get a list including the global PHP version and allPHP versions currently serving "isolated sites" (sites with * custom Nginx configs pointing them to a specific PHP version). @@ -404,23 +381,19 @@ public function utilizedPhpVersions() return self::fpmSockName($this->normalizePhpVersion($version)); })->unique(); - return collect($this->files->scandir(VALET_HOME_PATH.'/Nginx')) - ->reject(function ($file) { - return starts_with($file, '.'); - }) - ->map(function ($file) use ($fpmSockFiles) { - $content = $this->files->get(VALET_HOME_PATH.'/Nginx/'.$file); - - // Get the normalized PHP version for this config file, if it's defined - foreach ($fpmSockFiles as $sock) { - if (strpos($content, $sock) !== false) { - // Extract the PHP version number from a custom .sock path; - // for example, "valet74.sock" will output "php74" - $phpVersion = 'php'.str_replace(['valet', '.sock'], '', $sock); - - return $this->normalizePhpVersion($phpVersion); // Example output php@7.4 - } + return $this->nginx->configuredSites()->map(function ($file) use ($fpmSockFiles) { + $content = $this->files->get(VALET_HOME_PATH.'/Nginx/'.$file); + + // Get the normalized PHP version for this config file, if it's defined + foreach ($fpmSockFiles as $sock) { + if (strpos($content, $sock) !== false) { + // Extract the PHP version number from a custom .sock path; + // for example, "valet74.sock" will output "php74" + $phpVersion = 'php'.str_replace(['valet', '.sock'], '', $sock); + + return $this->normalizePhpVersion($phpVersion); // Example output php@7.4 } - })->merge([$this->brew->getLinkedPhpFormula()])->filter()->unique()->values()->toArray(); + } + })->merge([$this->brew->getLinkedPhpFormula()])->filter()->unique()->values()->toArray(); } } diff --git a/cli/Valet/Site.php b/cli/Valet/Site.php index 4f94c2072..660f68bac 100644 --- a/cli/Valet/Site.php +++ b/cli/Valet/Site.php @@ -517,7 +517,7 @@ public function secure($url, $siteConf = null, $certificateExpireInDays = 396, $ // If the user had isolated the PHP version for this site, swap out .sock file if ($phpVersion) { - $siteConf = $this->replaceSockFile($siteConf, "valet{$phpVersion}.sock", $phpVersion); + $siteConf = $this->replaceSockFile($siteConf, $phpVersion); } $this->files->putAsUser($this->nginxPath($url), $siteConf); @@ -706,16 +706,14 @@ public function buildSecureNginxServer($url, $siteConf = null) */ public function isolate($valetSite, $phpVersion) { - $fpmSockName = PhpFpm::fpmSockName($phpVersion); - if ($this->files->exists($this->nginxPath($valetSite))) { // Modify the existing config if it exists (likely because it's secured) $siteConf = $this->files->get($this->nginxPath($valetSite)); - $siteConf = $this->replaceSockFile($siteConf, $fpmSockName, $phpVersion); + $siteConf = $this->replaceSockFile($siteConf, $phpVersion); } else { $siteConf = str_replace( ['VALET_HOME_PATH', 'VALET_SERVER_PATH', 'VALET_STATIC_PREFIX', 'VALET_SITE', 'VALET_PHP_FPM_SOCKET', 'VALET_ISOLATED_PHP_VERSION'], - [VALET_HOME_PATH, VALET_SERVER_PATH, VALET_STATIC_PREFIX, $valetSite, $fpmSockName, $phpVersion], + [VALET_HOME_PATH, VALET_SERVER_PATH, VALET_STATIC_PREFIX, $valetSite, PhpFpm::fpmSockName($phpVersion), $phpVersion], $this->replaceLoopback($this->files->get(__DIR__.'/../stubs/site.valet.conf')) ); } @@ -1084,7 +1082,7 @@ public function customPhpVersion($url) if ($this->files->exists($this->nginxPath($url))) { $siteConf = $this->files->get($this->nginxPath($url)); - if (starts_with($siteConf, '# Valet isolated PHP version')) { + if (starts_with($siteConf, '# '.ISOLATED_PHP_VERSION)) { $firstLine = explode(PHP_EOL, $siteConf)[0]; return preg_replace("/[^\d]*/", '', $firstLine); // Example output: "74" or "81" @@ -1096,15 +1094,16 @@ public function customPhpVersion($url) * Replace .sock file in an Nginx site configuration file contents. * * @param string $siteConf - * @param string $sockFile * @param string $phpVersion * @return string */ - public function replaceSockFile($siteConf, $sockFile, $phpVersion) + public function replaceSockFile($siteConf, $phpVersion) { + $sockFile = PhpFpm::fpmSockName($phpVersion); + $siteConf = preg_replace('/valet[0-9]*.sock/', $sockFile, $siteConf); - $siteConf = preg_replace('/# Valet isolated PHP version.*\n/', '', $siteConf); // Remove `Valet isolated PHP version` line from config + $siteConf = preg_replace('/# '.ISOLATED_PHP_VERSION.'.*\n/', '', $siteConf); // Remove ISOLATED_PHP_VERSION line from config - return '# Valet isolated PHP version : '.$phpVersion.PHP_EOL.$siteConf; + return '# '.ISOLATED_PHP_VERSION.'='.$phpVersion.PHP_EOL.$siteConf; } } diff --git a/cli/includes/helpers.php b/cli/includes/helpers.php index 1daf74fec..352d867fb 100644 --- a/cli/includes/helpers.php +++ b/cli/includes/helpers.php @@ -23,6 +23,8 @@ define('BREW_PREFIX', (new CommandLine())->runAsUser('printf $(brew --prefix)')); +define('ISOLATED_PHP_VERSION', 'ISOLATED_PHP_VERSION'); + /** * Output the given text to the console. * diff --git a/cli/stubs/site.valet.conf b/cli/stubs/site.valet.conf index 26109aef4..9fb0a7939 100644 --- a/cli/stubs/site.valet.conf +++ b/cli/stubs/site.valet.conf @@ -1,4 +1,4 @@ -# Valet isolated PHP version : VALET_ISOLATED_PHP_VERSION +# ISOLATED_PHP_VERSION=VALET_ISOLATED_PHP_VERSION server { listen 127.0.0.1:80; server_name VALET_SITE www.VALET_SITE *.VALET_SITE; diff --git a/cli/valet.php b/cli/valet.php index 7679fa372..e009188e3 100755 --- a/cli/valet.php +++ b/cli/valet.php @@ -32,7 +32,7 @@ */ Container::setInstance(new Container); -$version = '2.18.9'; +$version = '2.18.10'; $app = new Application('Laravel Valet', $version); @@ -210,6 +210,17 @@ info('The ['.$url.'] site will now serve traffic over HTTP.'); })->descriptions('Stop serving the given domain over HTTPS and remove the trusted TLS certificate'); + /** + * Get all the current secured sites. + */ + $app->command('secured', function () { + $sites = collect(Site::secured())->map(function ($url) { + return ['Site' => $url]; + }); + + table(['Site'], $sites->all()); + }); + /** * Create an Nginx proxy config for the specified domain. */ @@ -491,9 +502,9 @@ ]); /** - * Allow the user to change the version of php valet uses. + * Allow the user to change the version of php Valet uses. */ - $app->command('use [phpVersion] [--force] [--site=]', function ($phpVersion, $force, $site) { + $app->command('use [phpVersion] [--force]', function ($phpVersion, $force) { if (! $phpVersion) { $path = getcwd().'/.valetphprc'; $linkedVersion = Brew::linkedPhp(); @@ -509,30 +520,35 @@ } } - PhpFpm::useVersion($phpVersion, $force, $site); - })->descriptions('Change the version of PHP used by valet', [ + PhpFpm::useVersion($phpVersion, $force); + })->descriptions('Change the version of PHP used by Valet', [ 'phpVersion' => 'The PHP version you want to use, e.g php@7.3', - '--site' => 'Isolate PHP version of a specific valet site. e.g: --site=site.test', ]); /** - * Allow the user to change the version of php valet uses to serve a given site. + * Allow the user to change the version of PHP Valet uses to serve the current site. */ - $app->command('isolate [site] [phpVersion] ', function ($site, $phpVersion) { - PhpFpm::isolateDirectory($site, $phpVersion); - })->descriptions('Change the version of PHP used by valet to serve a given site', [ - 'site' => 'The valet site (e.g. site.test) you want to isolate to a given PHP version', + $app->command('isolate [phpVersion] ', function ($phpVersion) { + PhpFpm::isolateDirectory(basename(getcwd()), $phpVersion); + })->descriptions('Change the version of PHP used by Valet to serve the current working directory', [ 'phpVersion' => 'The PHP version you want to use, e.g php@7.3', ]); /** - * Allow the user to un-do specifying the version of php valet uses to serve a given site. + * Allow the user to un-do specifying the version of PHP Valet uses to serve the current site. */ - $app->command('unisolate [site] ', function ($site) { - PhpFpm::unIsolateDirectory($site); - })->descriptions('Stop customizing the version of PHP used by valet to serve a given site', [ - 'site' => 'The valet site (e.g. site.test) you want to un-isolate', - ]); + $app->command('unisolate', function () { + PhpFpm::unIsolateDirectory(basename(getcwd())); + })->descriptions('Stop customizing the version of PHP used by Valet to serve the current working directory'); + + /** + * List isolated sites. + */ + $app->command('isolated', function () { + $sites = PhpFpm::isolatedDirectories(); + + table(['Path', 'PHP Version'], $sites->all()); + })->descriptions('List all sites using isolated versions of PHP.'); /** * Tail log file. diff --git a/tests/NginxTest.php b/tests/NginxTest.php index e2f780511..f05c39580 100644 --- a/tests/NginxTest.php +++ b/tests/NginxTest.php @@ -86,4 +86,26 @@ public function test_install_nginx_directories_rewrites_secure_nginx_files() $site->shouldHaveReceived('resecureForNewConfiguration', [$data, $data]); } + + public function test_it_gets_configured_sites() + { + $files = Mockery::mock(Filesystem::class); + + $files->shouldReceive('scandir') + ->once() + ->with(VALET_HOME_PATH.'/Nginx') + ->andReturn(['.gitkeep', 'isolated-site-71.test', 'isolated-site-72.test', 'isolated-site-73.test']); + + swap(Filesystem::class, $files); + swap(Configuration::class, $config = Mockery::spy(Configuration::class, ['read' => ['tld' => 'test', 'loopback' => VALET_LOOPBACK]])); + swap(Site::class, Mockery::mock(Site::class)); + + $nginx = resolve(Nginx::class); + $output = $nginx->configuredSites(); + + $this->assertEquals( + ['isolated-site-71.test', 'isolated-site-72.test', 'isolated-site-73.test'], + $output->values()->all() + ); + } } diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index d169731ef..0632c6741 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -35,13 +35,7 @@ public function test_fpm_is_configured_with_the_correct_user_group_and_port() copy(__DIR__.'/files/fpm.conf', __DIR__.'/output/fpm.conf'); mkdir(__DIR__.'/output/conf.d'); copy(__DIR__.'/files/php-memory-limits.ini', __DIR__.'/output/conf.d/php-memory-limits.ini'); - resolve(StubForUpdatingFpmConfigFiles::class)->createConfigurationFiles(); - $contents = file_get_contents(__DIR__.'/output/fpm.conf'); - $this->assertStringContainsString(sprintf("\nuser = %s", user()), $contents); - $this->assertStringContainsString("\ngroup = staff", $contents); - $this->assertStringContainsString("\nlisten = ".VALET_HOME_PATH.'/valet.sock', $contents); - // Passing specific version will change the .sock file resolve(StubForUpdatingFpmConfigFiles::class)->createConfigurationFiles('php@7.2'); $contents = file_get_contents(__DIR__.'/output/fpm.conf'); $this->assertStringContainsString(sprintf("\nuser = %s", user()), $contents); @@ -57,10 +51,25 @@ public function test_it_can_generate_sock_file_name_from_php_version() $this->assertEquals('valet72.sock', resolve(PhpFpm::class)->fpmSockName('72')); } + public function test_it_normalizes_php_versions() + { + $this->assertEquals('php@8.1', resolve(PhpFpm::class)->normalizePhpVersion('php@8.1')); + $this->assertEquals('php@8.1', resolve(PhpFpm::class)->normalizePhpVersion('php8.1')); + $this->assertEquals('php@8.1', resolve(PhpFpm::class)->normalizePhpVersion('php81')); + $this->assertEquals('php@8.1', resolve(PhpFpm::class)->normalizePhpVersion('8.1')); + $this->assertEquals('php@8.1', resolve(PhpFpm::class)->normalizePhpVersion('81')); + } + + public function test_it_installs() + { + $this->markTestIncomplete('todo'); + } + public function test_utilized_php_versions() { $fileSystemMock = Mockery::mock(Filesystem::class); $brewMock = Mockery::mock(Brew::class); + $nginxMock = Mockery::mock(Nginx::class); $phpFpmMock = Mockery::mock(PhpFpm::class, [ $brewMock, @@ -68,7 +77,7 @@ public function test_utilized_php_versions() $fileSystemMock, resolve(Configuration::class), Mockery::mock(Site::class), - Mockery::mock(Nginx::class), + $nginxMock, ])->makePartial(); swap(PhpFpm::class, $phpFpmMock); @@ -82,25 +91,22 @@ public function test_utilized_php_versions() $brewMock->shouldReceive('getLinkedPhpFormula')->andReturn('php@7.3'); - $fileSystemMock->shouldReceive('scandir') + $nginxMock->shouldReceive('configuredSites') ->once() - ->with(VALET_HOME_PATH.'/Nginx') - ->andReturn(['.gitkeep', 'isolated-site-71.test', 'isolated-site-72.test', 'isolated-site-73.test']); - - $fileSystemMock->shouldNotReceive('get')->with(VALET_HOME_PATH.'/Nginx/.gitkeep'); + ->andReturn(collect(['isolated-site-71.test', 'isolated-site-72.test', 'isolated-site-73.test'])); $sites = [ [ 'site' => 'isolated-site-71.test', - 'conf' => '# Valet isolated PHP version : 71'.PHP_EOL.'valet71.sock', + 'conf' => '# '.ISOLATED_PHP_VERSION.'=71'.PHP_EOL.'valet71.sock', ], [ 'site' => 'isolated-site-72.test', - 'conf' => '# Valet isolated PHP version : php@7.2'.PHP_EOL.'valet72.sock', + 'conf' => '# '.ISOLATED_PHP_VERSION.'=php@7.2'.PHP_EOL.'valet72.sock', ], [ 'site' => 'isolated-site-73.test', - 'conf' => '# Valet isolated PHP version : 73'.PHP_EOL.'valet.sock', + 'conf' => '# '.ISOLATED_PHP_VERSION.'=73'.PHP_EOL.'valet.sock', ], ]; @@ -111,79 +117,61 @@ public function test_utilized_php_versions() $this->assertEquals(['php@7.1', 'php@7.2', 'php@7.3'], resolve(PhpFpm::class)->utilizedPhpVersions()); } - public function test_global_php_version_update_will_swap_socks() + public function test_it_lists_isolated_directories() { $fileSystemMock = Mockery::mock(Filesystem::class); + $nginxMock = Mockery::mock(Nginx::class); + $site = Mockery::mock(Site::class); $phpFpmMock = Mockery::mock(PhpFpm::class, [ Mockery::mock(Brew::class), Mockery::mock(CommandLine::class), $fileSystemMock, resolve(Configuration::class), - Mockery::mock(Site::class), - Mockery::mock(Nginx::class), + $site, + $nginxMock, ])->makePartial(); swap(PhpFpm::class, $phpFpmMock); - $fileSystemMock->shouldReceive('scandir') - ->once() - ->with(VALET_HOME_PATH.'/Nginx') - ->andReturn([ - '.gitkeep', - 'isolated-site-71.test', - 'isolated-site-72.test', - 'isolated-site-73.test', - 'non-isolated-site.test', - ]); - - // Skip dotfiles - $fileSystemMock->shouldNotReceive('get')->with(VALET_HOME_PATH.'/Nginx/.gitkeep'); - - // Any isolated site running on php72 would be replaced with default valet.sock, - // as 72 will be the default version after the global PHP version switch - $fileSystemMock->shouldReceive('get') + $nginxMock->shouldReceive('configuredSites') ->once() - ->with(VALET_HOME_PATH.'/Nginx/isolated-site-72.test') - ->andReturn('# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }'); + ->andReturn(collect(['isolated-site-71.test', 'isolated-site-72.test', 'not-isolated-site.test'])); - $fileSystemMock->shouldReceive('put')->once()->withArgs([ - VALET_HOME_PATH.'/Nginx/isolated-site-72.test', - '# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet.sock }', - ]); - - // Any isolated site running on current PHP version (with valet.sock), - // should be still be running on the same version after the global version update - $fileSystemMock->shouldReceive('get') - ->once() - ->with(VALET_HOME_PATH.'/Nginx/isolated-site-71.test') - ->andReturn('# Valet isolated PHP version : 71'.PHP_EOL.'server { fastcgi_pass: valet.sock }'); + $site->shouldReceive('customPhpVersion')->with('isolated-site-71.test')->andReturn('71'); + $site->shouldReceive('customPhpVersion')->with('isolated-site-72.test')->andReturn('72'); + $site->shouldReceive('normalizePhpVersion')->with('71')->andReturn('php@7.1'); + $site->shouldReceive('normalizePhpVersion')->with('72')->andReturn('php@7.2'); - $fileSystemMock->shouldReceive('put')->once()->withArgs([ - VALET_HOME_PATH.'/Nginx/isolated-site-71.test', - '# Valet isolated PHP version : 71'.PHP_EOL.'server { fastcgi_pass: valet71.sock }', - ]); - - // PHP 7.3 sites won't be affected here - $fileSystemMock->shouldReceive('get') - ->once() - ->with(VALET_HOME_PATH.'/Nginx/isolated-site-73.test') - ->andReturn('# Valet isolated PHP version : 73'.PHP_EOL.'server { fastcgi_pass: valet73.sock }'); - - $fileSystemMock->shouldNotReceive('put')->withArgs([ - VALET_HOME_PATH.'/Nginx/isolated-site-73.test', - Mockery::any(), - ]); + $sites = [ + [ + 'site' => 'isolated-site-71.test', + 'conf' => '# '.ISOLATED_PHP_VERSION.'=71'.PHP_EOL.'valet71.sock', + ], + [ + 'site' => 'isolated-site-72.test', + 'conf' => '# '.ISOLATED_PHP_VERSION.'=php@7.2'.PHP_EOL.'valet72.sock', + ], + [ + 'site' => 'not-isolated-site.test', + 'conf' => 'This one is not isolated', + ], + ]; - // Nginx config that doesn't have the isolation header, It would not swap .sock files - $fileSystemMock->shouldReceive('get')->once()->with(VALET_HOME_PATH.'/Nginx/non-isolated-site.test')->andReturn('valet.sock'); - $fileSystemMock->shouldNotReceive('put')->withArgs([ - VALET_HOME_PATH.'/Nginx/non-isolated-site.test', - 'valet71.sock', - ]); + foreach ($sites as $site) { + $fileSystemMock->shouldReceive('get')->once()->with(VALET_HOME_PATH.'/Nginx/'.$site['site'])->andReturn($site['conf']); + } - // Switching from php7.1 to php7.2 - resolve(PhpFpm::class)->updateConfigurationForGlobalUpdate('php@7.2', 'php@7.1'); + $this->assertEquals([ + [ + 'url' => 'isolated-site-71.test', + 'version' => 'php@7.1', + ], + [ + 'url' => 'isolated-site-72.test', + 'version' => 'php@7.2', + ], + ], resolve(PhpFpm::class)->isolatedDirectories()->toArray()); } public function test_stop_unused_php_versions() @@ -250,11 +238,13 @@ public function test_use_version_will_convert_passed_php_version() $brewMock = Mockery::mock(Brew::class); $nginxMock = Mockery::mock(Nginx::class); $siteMock = Mockery::mock(Site::class); + $filesystem = Mockery::mock(Filesystem::class); + $cli = Mockery::mock(CommandLine::class); $phpFpmMock = Mockery::mock(PhpFpm::class, [ $brewMock, - resolve(CommandLine::class), - resolve(Filesystem::class), + $cli, + $filesystem, resolve(Configuration::class), $siteMock, $nginxMock, @@ -277,6 +267,10 @@ public function test_use_version_will_convert_passed_php_version() $nginxMock->shouldReceive('restart'); + $filesystem->shouldReceive('unlink')->with(VALET_HOME_PATH.'/valet.sock'); + + $cli->shouldReceive('quietly')->with('sudo rm '.VALET_HOME_PATH.'/valet.sock'); + // Test both non prefixed and prefixed $this->assertSame('php@7.2', $phpFpmMock->useVersion('php7.2')); $this->assertSame('php@7.2', $phpFpmMock->useVersion('php72')); @@ -302,24 +296,17 @@ public function test_use_version_if_already_linked_php_will_unlink_before_instal $brewMock = Mockery::mock(Brew::class); $nginxMock = Mockery::mock(Nginx::class); $siteMock = Mockery::mock(Site::class); - $cliMock = Mockery::mock(CommandLine::class); - $fileSystemMock = Mockery::mock(Filesystem::class); $phpFpmMock = Mockery::mock(PhpFpm::class, [ $brewMock, - $cliMock, - $fileSystemMock, + resolve(CommandLine::class), + resolve(Filesystem::class), resolve(Configuration::class), $siteMock, $nginxMock, ])->makePartial(); $phpFpmMock->shouldReceive('install'); - $cliMock->shouldReceive('quietly')->with('sudo rm '.VALET_HOME_PATH.'/valet*.sock')->once(); - $fileSystemMock->shouldReceive('unlink')->with(VALET_HOME_PATH.'/valet.sock')->once(); - - $phpFpmMock->shouldReceive('createConfigurationFiles')->with('php@7.1')->once(); - $phpFpmMock->shouldReceive('updateConfigurationForGlobalUpdate')->withArgs(['php@7.2', 'php@7.1'])->once(); $brewMock->shouldReceive('supportedPhpVersions')->andReturn(collect([ 'php@7.2', @@ -384,12 +371,11 @@ public function test_isolate_will_isolate_a_site() $brewMock->shouldNotReceive('unlink'); $phpFpmMock->shouldNotReceive('stopRunning'); $phpFpmMock->shouldNotReceive('install'); - $phpFpmMock->shouldNotReceive('updateConfigurationForGlobalUpdate'); $this->assertSame(null, $phpFpmMock->isolateDirectory('test', 'php@7.2')); } - public function test_un_isolate_can_remove_isolation_for_a_site() + public function test_un_isolate_will_remove_isolation_for_a_site() { $nginxMock = Mockery::mock(Nginx::class); $siteMock = Mockery::mock(Site::class); diff --git a/tests/SiteTest.php b/tests/SiteTest.php index 7db70ab5a..e8e03d41e 100644 --- a/tests/SiteTest.php +++ b/tests/SiteTest.php @@ -602,7 +602,7 @@ public function test_isolation_will_persist_when_adding_ssl_certificate() // If site has an isolated PHP version for the site, it would replace .sock file $siteMock->shouldReceive('customPhpVersion')->with('site1.test')->andReturn('73')->once(); - $siteMock->shouldReceive('replaceSockFile')->withArgs([Mockery::any(), 'valet73.sock', '73'])->once(); + $siteMock->shouldReceive('replaceSockFile')->withArgs([Mockery::any(), '73'])->once(); resolve(Site::class)->secure('site1.test'); // For sites without an isolated PHP version, nothing should be replaced @@ -659,13 +659,13 @@ public function test_can_install_nginx_site_config_for_specific_php_version() $files->shouldReceive('get') ->once() ->with($siteMock->nginxPath('site1.test')) - ->andReturn('# Valet isolated PHP version : php@7.4'.PHP_EOL.'server { fastcgi_pass: valet74.sock }'); + ->andReturn('# '.ISOLATED_PHP_VERSION.'=php@7.4'.PHP_EOL.'server { fastcgi_pass: valet74.sock }'); $files->shouldReceive('putAsUser') ->once() ->withArgs([ $siteMock->nginxPath('site1.test'), - '# Valet isolated PHP version : php@8.0'.PHP_EOL.'server { fastcgi_pass: valet80.sock }', + '# '.ISOLATED_PHP_VERSION.'=php@8.0'.PHP_EOL.'server { fastcgi_pass: valet80.sock }', ]); $siteMock->isolate('site1.test', 'php@8.0'); @@ -682,7 +682,7 @@ public function test_can_install_nginx_site_config_for_specific_php_version() ->withArgs([ $siteMock->nginxPath('site2.test'), Mockery::on(function ($argument) { - return preg_match('/^# Valet isolated PHP version : php@8.0/', $argument) + return preg_match('/^# '.ISOLATED_PHP_VERSION.'=php@8.0/', $argument) && preg_match('#fastcgi_pass "unix:.*/valet80.sock#', $argument) && strpos($argument, 'server_name site2.test www.site2.test *.site2.test;') !== false; }), @@ -733,7 +733,7 @@ public function test_retrieves_custom_php_version_from_nginx_config() $files->shouldReceive('get') ->once() ->with($siteMock->nginxPath('site1.test')) - ->andReturn('# Valet isolated PHP version : php@7.4'); + ->andReturn('# '.ISOLATED_PHP_VERSION.'=php@7.4'); $this->assertEquals('74', resolve(Site::class)->customPhpVersion('site1.test')); // Site without any custom nginx config @@ -757,30 +757,45 @@ public function test_replace_sock_file_in_nginx_config() // When switching to php71, valet71.sock should be replaced with valet.sock; // isolation header should be prepended $this->assertEquals( - '# Valet isolated PHP version : 71'.PHP_EOL.'server { fastcgi_pass: valet.sock }', - $site->replaceSockFile('server { fastcgi_pass: valet71.sock }', 'valet.sock', '71') + '# '.ISOLATED_PHP_VERSION.'=71'.PHP_EOL.'server { fastcgi_pass: valet71.sock }', + $site->replaceSockFile('server { fastcgi_pass: valet71.sock }', '71') ); // When switching to php72, valet.sock should be replaced with valet72.sock $this->assertEquals( - '# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }', - $site->replaceSockFile('server { fastcgi_pass: valet.sock }', 'valet72.sock', '72') + '# '.ISOLATED_PHP_VERSION.'=72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }', + $site->replaceSockFile('server { fastcgi_pass: valet.sock }', '72') ); // When switching to php73 from php72, valet72.sock should be replaced with valet73.sock; // isolation header should be updated to php@7.3 $this->assertEquals( - '# Valet isolated PHP version : 73'.PHP_EOL.'server { fastcgi_pass: valet73.sock }', - $site->replaceSockFile('# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }', 'valet73.sock', '73') + '# '.ISOLATED_PHP_VERSION.'=73'.PHP_EOL.'server { fastcgi_pass: valet73.sock }', + $site->replaceSockFile('# '.ISOLATED_PHP_VERSION.'=72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }', '73') ); // When switching to php72 from php74, valet72.sock should be replaced with valet74.sock; // isolation header should be updated to php@7.4 $this->assertEquals( - '# Valet isolated PHP version : php@7.4'.PHP_EOL.'server { fastcgi_pass: valet74.sock }', - $site->replaceSockFile('# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet.sock }', 'valet74.sock', 'php@7.4') + '# '.ISOLATED_PHP_VERSION.'=php@7.4'.PHP_EOL.'server { fastcgi_pass: valet74.sock }', + $site->replaceSockFile('# '.ISOLATED_PHP_VERSION.'=72'.PHP_EOL.'server { fastcgi_pass: valet.sock }', 'php@7.4') ); } + + public function test_it_returns_secured_sites() + { + $files = Mockery::mock(Filesystem::class); + $files->shouldReceive('scandir') + ->once() + ->andReturn(['helloworld.tld.crt']); + + swap(Filesystem::class, $files); + + $site = resolve(Site::class); + $sites = $site->secured(); + + $this->assertSame(['helloworld.tld'], $sites); + } } class CommandLineFake extends CommandLine