1
0
mirror of https://github.com/laravel/valet.git synced 2026-02-07 01:00:09 +01:00

Merge branch 'master' into feature/custom-site-stubs

This commit is contained in:
Jerry Price
2022-07-08 09:21:51 -04:00
13 changed files with 219 additions and 22 deletions

1
.gitattributes vendored
View File

@@ -19,4 +19,3 @@ phpunit.xml.dist export-ignore
UPGRADE.md export-ignore
/bin/ngrok -diff
/bin/ngrok-arm -diff

View File

@@ -11,9 +11,6 @@
Alternatively, try to reboot your machine first to see if it solves your current issue.-->
- Valet Version: #.#.#
- PHP Version: #.#.#
### Description:

12
.github/workflows/pull-requests.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
name: pull requests
on:
pull_request_target:
types: [opened]
permissions:
pull-requests: write
jobs:
uneditable:
uses: laravel/.github/.github/workflows/pull-requests.yml@main

Binary file not shown.

View File

@@ -28,7 +28,6 @@ class Diagnose
'curl --version',
'php --ri curl',
'~/.composer/vendor/laravel/valet/bin/ngrok version',
'~/.composer/vendor/laravel/valet/bin/ngrok-arm version',
'ls -al ~/.ngrok2',
'brew info nginx',
'brew info php',

View File

@@ -51,7 +51,7 @@ public function findHttpTunnelUrl($tunnels, $domain)
// find the one responding on HTTP. Each tunnel has an HTTP and a HTTPS address
// but for local dev purposes we just desire the plain HTTP URL endpoint.
foreach ($tunnels as $tunnel) {
if ($tunnel->proto === 'http' && strpos($tunnel->config->addr, $domain)) {
if ($tunnel->proto === 'http' && strpos($tunnel->config->addr, strtolower($domain))) {
return $tunnel->public_url;
}
}

View File

@@ -46,6 +46,8 @@ public function __construct(Brew $brew, CommandLine $cli, Filesystem $files, Con
*/
public function install()
{
info('Installing and configuring phpfpm...');
if (! $this->brew->hasInstalledPhp()) {
$this->brew->ensureInstalled('php', [], $this->taps);
}
@@ -324,7 +326,7 @@ public function symlinkPrimaryValetSock($phpVersion)
*/
public function normalizePhpVersion($version)
{
return preg_replace('/(?:php@?)?([0-9+])(?:.)?([0-9+])/i', 'php@$1.$2', $version);
return preg_replace('/(?:php@?)?([0-9+])(?:.)?([0-9+])/i', 'php@$1.$2', (string) $version);
}
/**

View File

@@ -7,6 +7,7 @@
class Site
{
public $brew;
public $config;
public $cli;
public $files;
@@ -14,12 +15,14 @@ class Site
/**
* Create a new Site instance.
*
* @param Brew $brew
* @param Configuration $config
* @param CommandLine $cli
* @param Filesystem $files
*/
public function __construct(Configuration $config, CommandLine $cli, Filesystem $files)
public function __construct(Brew $brew, Configuration $config, CommandLine $cli, Filesystem $files)
{
$this->brew = $brew;
$this->cli = $cli;
$this->files = $files;
$this->config = $config;
@@ -317,12 +320,14 @@ public function getSites($path, $certs)
})->map(function ($path, $site) use ($certs, $config) {
$secured = $certs->has($site);
$url = ($secured ? 'https' : 'http').'://'.$site.'.'.$config['tld'];
$phpVersion = $this->getPhpVersion($site.'.'.$config['tld']);
return [
'site' => $site,
'secured' => $secured ? ' X' : '',
'url' => $url,
'path' => $path,
'phpVersion' => $phpVersion,
];
});
}
@@ -356,6 +361,23 @@ public function pruneLinks()
$this->files->removeBrokenLinksAt($this->sitesPath());
}
/**
* Get the PHP version for the given site.
*
* @param string $url Site URL including the TLD
* @return string
*/
public function getPhpVersion($url)
{
$defaultPhpVersion = $this->brew->linkedPhp();
$phpVersion = PhpFpm::normalizePhpVersion($this->customPhpVersion($url));
if (empty($phpVersion)) {
$phpVersion = PhpFpm::normalizePhpVersion($defaultPhpVersion);
}
return $phpVersion;
}
/**
* Resecure all currently secured sites with a fresh configuration.
*
@@ -1049,6 +1071,24 @@ public function certificatesPath($url = null, $extension = null)
return $this->valetHomePath().'/Certificates'.$url.$extension;
}
/**
* Make the domain name based on parked domains or the internal TLD.
*
* @return string
*/
public function domain($domain)
{
// if ($this->parked()->pluck('site')->contains($domain)) {
// return $domain;
// }
// if ($parked = $this->parked()->where('path', getcwd())->first()) {
// return $parked['site'];
// }
return ($domain ?: $this->host(getcwd())).'.'.$this->config->read()['tld'];
}
/**
* Replace Loopback configuration line in Valet site configuration file contents.
*

View File

@@ -14,6 +14,8 @@
use Illuminate\Container\Container;
use Silly\Application;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use function Valet\info;
use function Valet\output;
@@ -32,7 +34,7 @@
*/
Container::setInstance(new Container);
$version = '3.1.1';
$version = '3.1.8';
$app = new Application('Laravel Valet', $version);
@@ -75,11 +77,21 @@
/**
* Get or set the TLD currently being used by Valet.
*/
$app->command('tld [tld]', function ($tld = null) {
$app->command('tld [tld]', function (InputInterface $input, OutputInterface $output, $tld = null) {
if ($tld === null) {
return output(Configuration::read()['tld']);
}
$helper = $this->getHelperSet()->get('question');
$question = new ConfirmationQuestion(
'Using a custom TLD is no longer officially supported and may lead to unexpected behavior. Do you wish to proceed? [y/N]',
false
);
if (false === $helper->ask($input, $output, $question)) {
return warning('No new Valet tld was set.');
}
DnsMasq::updateTld(
$oldTld = Configuration::read()['tld'],
$tld = trim($tld, '.')
@@ -166,7 +178,7 @@
$app->command('links', function () {
$links = Site::links();
table(['Site', 'SSL', 'URL', 'Path'], $links->all());
table(['Site', 'SSL', 'URL', 'Path', 'PHP Version'], $links->all());
})->descriptions('Display all of the registered Valet links');
/**
@@ -180,7 +192,7 @@
* Secure the given domain with a trusted TLS certificate.
*/
$app->command('secure [domain] [--expireIn=]', function ($domain = null, $expireIn = 368) {
$url = ($domain ?: Site::host(getcwd())).'.'.Configuration::read()['tld'];
$url = Site::domain($domain);
Site::secure($url, null, $expireIn);
@@ -201,7 +213,7 @@
return;
}
$url = ($domain ?: Site::host(getcwd())).'.'.Configuration::read()['tld'];
$url = Site::domain($domain);
Site::unsecure($url);
@@ -280,7 +292,7 @@
* Open the current or given directory in the browser.
*/
$app->command('open [domain]', function ($domain = null) {
$url = 'http://'.($domain ?: Site::host(getcwd())).'.'.Configuration::read()['tld'];
$url = 'http://'.Site::domain($domain);
CommandLine::runAsUser('open '.escapeshellarg($url));
})->descriptions('Open the site for the current (or specified) directory in your browser');
@@ -295,7 +307,7 @@
* Echo the currently tunneled URL.
*/
$app->command('fetch-share-url [domain]', function ($domain = null) {
output(Ngrok::currentTunnelUrl($domain ?: Site::host(getcwd()).'.'.Configuration::read()['tld']));
output(Ngrok::currentTunnelUrl(Site::domain($domain)));
})->descriptions('Get the URL to the current Ngrok tunnel');
/**

66
tests/NgrokTest.php Normal file
View File

@@ -0,0 +1,66 @@
<?php
use Illuminate\Container\Container;
use Valet\Ngrok;
use function Valet\user;
class NgrokTest extends Yoast\PHPUnitPolyfills\TestCases\TestCase
{
public function set_up()
{
$_SERVER['SUDO_USER'] = user();
Container::setInstance(new Container);
}
public function tear_down()
{
Mockery::close();
}
public function test_it_matches_correct_share_tunnel()
{
$tunnels = [
(object) [
'proto' => 'https',
'config' => (object) [
'addr' => 'http://mysite.test:80',
],
'public_url' => 'http://bad-proto.ngrok.io/',
],
(object) [
'proto' => 'http',
'config' => (object) [
'addr' => 'http://nottherightone.test:80',
],
'public_url' => 'http://bad-site.ngrok.io/',
],
(object) [
'proto' => 'http',
'config' => (object) [
'addr' => 'http://mysite.test:80',
],
'public_url' => 'http://right-one.ngrok.io/',
],
];
$ngrok = new Ngrok;
$this->assertEquals('http://right-one.ngrok.io/', $ngrok->findHttpTunnelUrl($tunnels, 'mysite'));
}
public function test_it_checks_against_lowercased_domain()
{
$tunnels = [
(object) [
'proto' => 'http',
'config' => (object) [
'addr' => 'http://mysite.test:80',
],
'public_url' => 'http://right-one.ngrok.io/',
],
];
$ngrok = new Ngrok;
$this->assertEquals('http://right-one.ngrok.io/', $ngrok->findHttpTunnelUrl($tunnels, 'MySite'));
}
}

View File

@@ -63,6 +63,8 @@ public function test_it_normalizes_php_versions()
$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'));
$this->assertEquals('', resolve(PhpFpm::class)->normalizePhpVersion(''));
$this->assertEquals('', resolve(PhpFpm::class)->normalizePhpVersion(null));
}
public function test_it_validates_php_versions_when_installed()
@@ -425,6 +427,8 @@ public function test_un_isolate_will_remove_isolation_for_a_site()
public function test_isolate_will_throw_if_site_is_not_parked_or_linked()
{
$brewMock = Mockery::mock(Brew::class);
$brewMock->shouldReceive('linkedPhp')->andReturn('php@7.4');
$configMock = Mockery::mock(Configuration::class);
$configMock->shouldReceive('read')->andReturn(['tld' => 'jamble', 'paths' => []]);

View File

@@ -1,6 +1,7 @@
<?php
use Illuminate\Container\Container;
use Valet\Brew;
use Valet\CommandLine;
use Valet\Configuration;
use Valet\Filesystem;
@@ -68,18 +69,25 @@ public function test_get_sites_will_return_if_secured()
$files->shouldReceive('ensureDirExists')
->once()
->with($dirPath, user());
$files->shouldReceive('exists')->andReturn(false);
$config = Mockery::mock(Configuration::class);
$config->shouldReceive('read')
->once()
->andReturn(['tld' => 'local']);
$brew = Mockery::mock(Brew::class);
$brew->shouldReceive('linkedPhp')->andReturn('php@8.1');
swap(Filesystem::class, $files);
swap(Configuration::class, $config);
swap(Brew::class, $brew);
/** @var Site $site */
$site = resolve(Site::class);
$phpVersion = $site->brew->linkedPhp();
$certs = Mockery::mock(\Illuminate\Support\Collection::class);
$certs->shouldReceive('has')
->twice()
@@ -96,12 +104,14 @@ public function test_get_sites_will_return_if_secured()
'secured' => '',
'url' => 'http://sitetwo.local',
'path' => $dirPath.'/sitetwo',
'phpVersion' => $phpVersion,
], $sites->first());
$this->assertSame([
'site' => 'sitethree',
'secured' => ' X',
'url' => 'https://sitethree.local',
'path' => $dirPath.'/sitethree',
'phpVersion' => $phpVersion,
], $sites->last());
}
@@ -125,18 +135,25 @@ public function test_get_sites_will_work_with_non_symlinked_path()
$files->shouldReceive('ensureDirExists')
->once()
->with($dirPath, user());
$files->shouldReceive('exists')->andReturn(false);
$config = Mockery::mock(Configuration::class);
$config->shouldReceive('read')
->once()
->andReturn(['tld' => 'local']);
$brew = Mockery::mock(Brew::class);
$brew->shouldReceive('linkedPhp')->andReturn('php@8.1');
swap(Filesystem::class, $files);
swap(Configuration::class, $config);
swap(Brew::class, $brew);
/** @var Site $site */
$site = resolve(Site::class);
$phpVersion = $site->brew->linkedPhp();
$sites = $site->getSites($dirPath, collect());
$this->assertCount(1, $sites);
$this->assertSame([
@@ -144,6 +161,7 @@ public function test_get_sites_will_work_with_non_symlinked_path()
'secured' => '',
'url' => 'http://sitetwo.local',
'path' => $dirPath.'/sitetwo',
'phpVersion' => $phpVersion,
], $sites->first());
}
@@ -162,18 +180,25 @@ public function test_get_sites_will_not_return_if_path_is_not_directory()
$files->shouldReceive('ensureDirExists')
->once()
->with($dirPath, user());
$files->shouldReceive('exists')->andReturn(false);
$config = Mockery::mock(Configuration::class);
$config->shouldReceive('read')
->once()
->andReturn(['tld' => 'local']);
$brew = Mockery::mock(Brew::class);
$brew->shouldReceive('linkedPhp')->andReturn('php@8.1');
swap(Filesystem::class, $files);
swap(Configuration::class, $config);
swap(Brew::class, $brew);
/** @var Site $site */
$site = resolve(Site::class);
$phpVersion = $site->brew->linkedPhp();
$sites = $site->getSites($dirPath, collect());
$this->assertCount(1, $sites);
$this->assertSame([
@@ -181,6 +206,7 @@ public function test_get_sites_will_not_return_if_path_is_not_directory()
'secured' => '',
'url' => 'http://siteone.local',
'path' => $dirPath.'/siteone',
'phpVersion' => $phpVersion,
], $sites->first());
}
@@ -204,18 +230,25 @@ public function test_get_sites_will_work_with_symlinked_path()
$files->shouldReceive('ensureDirExists')
->once()
->with($dirPath, user());
$files->shouldReceive('exists')->andReturn(false);
$config = Mockery::mock(Configuration::class);
$config->shouldReceive('read')
->once()
->andReturn(['tld' => 'local']);
$brew = Mockery::mock(Brew::class);
$brew->shouldReceive('linkedPhp')->andReturn('php@8.1');
swap(Filesystem::class, $files);
swap(Configuration::class, $config);
swap(Brew::class, $brew);
/** @var Site $site */
$site = resolve(Site::class);
$phpVersion = $site->brew->linkedPhp();
$sites = $site->getSites($dirPath, collect());
$this->assertCount(1, $sites);
$this->assertSame([
@@ -223,6 +256,7 @@ public function test_get_sites_will_work_with_symlinked_path()
'secured' => '',
'url' => 'http://siteone.local',
'path' => $linkedPath,
'phpVersion' => $phpVersion,
], $sites->first());
}
@@ -534,6 +568,7 @@ public function test_gets_site_url_from_directory()
swap(Configuration::class, $config);
$siteMock = Mockery::mock(Site::class, [
resolve(Brew::class),
resolve(Configuration::class),
resolve(CommandLine::class),
resolve(Filesystem::class),
@@ -585,6 +620,7 @@ public function test_it_throws_getting_nonexistent_site()
swap(Configuration::class, $config);
$siteMock = Mockery::mock(Site::class, [
resolve(Brew::class),
resolve(Configuration::class),
resolve(CommandLine::class),
resolve(Filesystem::class),
@@ -609,6 +645,7 @@ public function test_isolation_will_persist_when_adding_ssl_certificate()
$config = Mockery::mock(Configuration::class);
$siteMock = Mockery::mock(Site::class, [
resolve(Brew::class),
$config,
Mockery::mock(CommandLine::class),
$files,
@@ -641,6 +678,7 @@ public function test_isolation_will_persist_when_removing_ssl_certificate()
$cli = Mockery::mock(CommandLine::class);
$siteMock = Mockery::mock(Site::class, [
resolve(Brew::class),
$config,
$cli,
$files,
@@ -662,12 +700,40 @@ public function test_isolation_will_persist_when_removing_ssl_certificate()
resolve(Site::class)->unsecure('site2.test');
}
public function test_php_version_returns_correct_version_for_site()
{
$files = Mockery::mock(Filesystem::class);
$files->shouldReceive('exists')->andReturn(false);
$brew = Mockery::mock(Brew::class);
$brew->shouldReceive('linkedPhp')->andReturn('php@8.1');
swap(Brew::class, $brew);
$site = Mockery::mock(Site::class, [
resolve(Brew::class),
Mockery::mock(Configuration::class),
Mockery::mock(CommandLine::class),
$files,
])->makePartial();
$site->shouldReceive('customPhpVersion')->with('site1.test')->andReturn('73')->once();
$site->shouldReceive('customPhpVersion')->with('site2.test')->andReturn(null)->once();
swap(Site::class, $site);
$phpVersion = $site->brew->linkedPhp();
$this->assertEquals('php@7.3', $site->getPhpVersion('site1.test'));
$this->assertEquals($phpVersion, $site->getPhpVersion('site2.test'));
}
public function test_can_install_nginx_site_config_for_specific_php_version()
{
$files = Mockery::mock(Filesystem::class);
$config = Mockery::mock(Configuration::class);
$siteMock = Mockery::mock(Site::class, [
resolve(Brew::class),
$config,
resolve(CommandLine::class),
$files,
@@ -719,6 +785,7 @@ public function test_it_removes_isolation()
$files = Mockery::mock(Filesystem::class);
$siteMock = Mockery::mock(Site::class, [
resolve(Brew::class),
resolve(Configuration::class),
resolve(CommandLine::class),
$files,
@@ -744,6 +811,7 @@ public function test_retrieves_custom_php_version_from_nginx_config()
$files = Mockery::mock(Filesystem::class);
$siteMock = Mockery::mock(Site::class, [
resolve(Brew::class),
resolve(Configuration::class),
resolve(CommandLine::class),
$files,
@@ -829,6 +897,7 @@ public function test_it_can_read_php_rc_version()
swap(Filesystem::class, $files);
$siteMock = Mockery::mock(Site::class, [
resolve(Brew::class),
resolve(Configuration::class),
resolve(CommandLine::class),
resolve(Filesystem::class),

11
valet
View File

@@ -69,16 +69,13 @@ then
PORT=80
fi
# Lowercase the host to match how the rest of our domains are looked up
HOST=$(echo "$HOST" | tr '[:upper:]' '[:lower:]')
# Fetch Ngrok URL In Background...
bash "$DIR/cli/scripts/fetch-share-url.sh" "$HOST" &
ARCH=$(uname -m)
if [[ $ARCH == 'arm64' ]]; then
"$DIR/bin/ngrok-arm" http "$HOST.$TLD:$PORT" -host-header=rewrite $PARAMS
else
"$DIR/bin/ngrok" http "$HOST.$TLD:$PORT" -host-header=rewrite $PARAMS
fi
sudo -u "$USER" "$DIR/bin/ngrok" http "$HOST.$TLD:$PORT" --host-header=rewrite $PARAMS
exit