Skip to content

Commit 1f0c668

Browse files
committed
Merge branch 'master' into august
2 parents a4309fd + e806825 commit 1f0c668

File tree

6 files changed

+121
-40
lines changed

6 files changed

+121
-40
lines changed

src/Commands/Migrate.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,24 @@ public function handle(): int
5151
return 1;
5252
}
5353

54+
$originalTemplateConnection = config('tenancy.database.template_tenant_connection');
55+
56+
if ($database = $this->input->getOption('database')) {
57+
config(['tenancy.database.template_tenant_connection' => $database]);
58+
}
59+
5460
if ($this->getProcesses() > 1) {
55-
return $this->runConcurrently($this->getTenantChunks()->map(function ($chunk) {
61+
$code = $this->runConcurrently($this->getTenantChunks()->map(function ($chunk) {
5662
return $this->getTenants($chunk);
5763
}));
64+
} else {
65+
$code = $this->migrateTenants($this->getTenants()) ? 0 : 1;
5866
}
5967

60-
return $this->migrateTenants($this->getTenants()) ? 0 : 1;
68+
// Reset the template tenant connection to the original one
69+
config(['tenancy.database.template_tenant_connection' => $originalTemplateConnection]);
70+
71+
return $code;
6172
}
6273

6374
protected function childHandle(mixed ...$args): bool

src/Commands/MigrateFresh.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Stancl\Tenancy\Commands;
66

7+
use Illuminate\Console\ConfirmableTrait;
78
use Illuminate\Database\Console\Migrations\BaseCommand;
89
use Illuminate\Database\QueryException;
910
use Illuminate\Support\LazyCollection;
@@ -17,7 +18,7 @@
1718

1819
class MigrateFresh extends BaseCommand
1920
{
20-
use HasTenantOptions, DealsWithMigrations, ParallelCommand;
21+
use HasTenantOptions, DealsWithMigrations, ParallelCommand, ConfirmableTrait;
2122

2223
protected $description = 'Drop all tables and re-run all migrations for tenant(s)';
2324

@@ -27,13 +28,18 @@ public function __construct()
2728

2829
$this->addOption('drop-views', null, InputOption::VALUE_NONE, 'Drop views along with tenant tables.', null);
2930
$this->addOption('step', null, InputOption::VALUE_NONE, 'Force the migrations to be run so they can be rolled back individually.');
31+
$this->addOption('force', null, InputOption::VALUE_NONE, 'Force the command to run when in production.', null);
3032
$this->addProcessesOption();
3133

3234
$this->setName('tenants:migrate-fresh');
3335
}
3436

3537
public function handle(): int
3638
{
39+
if (! $this->confirmToProceed()) {
40+
return 1;
41+
}
42+
3743
$success = true;
3844

3945
if ($this->getProcesses() > 1) {

src/Features/ViteBundler.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
namespace Stancl\Tenancy\Features;
66

77
use Illuminate\Foundation\Application;
8+
use Illuminate\Support\Facades\Vite;
89
use Stancl\Tenancy\Contracts\Feature;
9-
use Stancl\Tenancy\Overrides\Vite;
1010
use Stancl\Tenancy\Tenancy;
1111

1212
class ViteBundler implements Feature
@@ -21,6 +21,8 @@ public function __construct(Application $app)
2121

2222
public function bootstrap(Tenancy $tenancy): void
2323
{
24-
$this->app->singleton(\Illuminate\Foundation\Vite::class, Vite::class);
24+
Vite::createAssetPathsUsing(function ($path, $secure = null) {
25+
return global_asset($path);
26+
});
2527
}
2628
}

src/Overrides/Vite.php

Lines changed: 0 additions & 22 deletions
This file was deleted.

tests/CommandsTest.php

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper;
2828
use Stancl\Tenancy\Database\Exceptions\TenantDatabaseDoesNotExistException;
2929
use function Stancl\Tenancy\Tests\pest;
30+
use Stancl\Tenancy\Events\MigratingDatabase;
3031

3132
beforeEach(function () {
3233
if (file_exists($schemaPath = 'tests/Etc/tenant-schema-test.dump')) {
@@ -95,6 +96,60 @@
9596
expect(Schema::hasTable('users'))->toBeTrue();
9697
});
9798

99+
test('migrate command uses the passed database option as the template tenant connection', function () {
100+
$originalTemplateConnection = config('tenancy.database.template_tenant_connection');
101+
102+
// Add a custom connection that will be used as the template for the tenant connection
103+
// Identical to the default (mysql), just with different charset and collation
104+
config(['database.connections.custom_connection' => [
105+
"driver" => "mysql",
106+
"url" => "",
107+
"host" => "mysql",
108+
"port" => "3306",
109+
"database" => "main",
110+
"username" => "root",
111+
"password" => "password",
112+
"unix_socket" => "",
113+
"charset" => "latin1", // Different from the default (utf8mb4)
114+
"collation" => "latin1_swedish_ci", // Different from the default (utf8mb4_unicode_ci)
115+
"prefix" => "",
116+
"prefix_indexes" => true,
117+
"strict" => true,
118+
"engine" => null,
119+
"options" => []
120+
]]);
121+
122+
$templateConnectionDuringMigration = null;
123+
$tenantConnectionDuringMigration = null;
124+
125+
Event::listen(MigratingDatabase::class, function() use (&$templateConnectionDuringMigration, &$tenantConnectionDuringMigration) {
126+
$templateConnectionDuringMigration = config('tenancy.database.template_tenant_connection');
127+
$tenantConnectionDuringMigration = DB::connection('tenant')->getConfig();
128+
});
129+
130+
// The original tenant template connection config remains default
131+
expect(config('tenancy.database.template_tenant_connection'))->toBe($originalTemplateConnection);
132+
133+
Tenant::create();
134+
135+
// The original template connection is used when the --database option is not passed
136+
pest()->artisan('tenants:migrate');
137+
expect($templateConnectionDuringMigration)->toBe($originalTemplateConnection);
138+
139+
Tenant::create();
140+
141+
// The migrate command temporarily uses the connection passed in the --database option
142+
pest()->artisan('tenants:migrate', ['--database' => 'custom_connection']);
143+
expect($templateConnectionDuringMigration)->toBe('custom_connection');
144+
145+
// The tenant connection during migration actually used custom_connection's config
146+
expect($tenantConnectionDuringMigration['charset'])->toBe('latin1');
147+
expect($tenantConnectionDuringMigration['collation'])->toBe('latin1_swedish_ci');
148+
149+
// The tenant template connection config is restored to the original after migrating
150+
expect(config('tenancy.database.template_tenant_connection'))->toBe($originalTemplateConnection);
151+
});
152+
98153
test('migrate command only throws exceptions if skip-failing is not passed', function() {
99154
Tenant::create();
100155

@@ -311,6 +366,21 @@
311366
expect(DB::table('users')->exists())->toBeFalse();
312367
});
313368

369+
test('migrate fresh command respects force option in production', function () {
370+
// Set environment to production
371+
app()->detectEnvironment(fn() => 'production');
372+
373+
Tenant::create();
374+
375+
// Without --force in production, command should prompt for confirmation
376+
pest()->artisan('tenants:migrate-fresh')
377+
->expectsConfirmation('Are you sure you want to run this command?');
378+
379+
// With --force, command should succeed without prompting
380+
pest()->artisan('tenants:migrate-fresh', ['--force' => true])
381+
->assertSuccessful();
382+
});
383+
314384
test('run command with array of tenants works', function () {
315385
$tenantId1 = Tenant::create()->getTenantKey();
316386
$tenantId2 = Tenant::create()->getTenantKey();

tests/Features/ViteBundlerTest.php

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,41 @@
33
declare(strict_types=1);
44

55
use Illuminate\Foundation\Vite;
6-
use Stancl\Tenancy\Tests\Etc\Tenant;
7-
use Stancl\Tenancy\Overrides\Vite as StanclVite;
6+
use Illuminate\Support\Facades\File;
7+
use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper;
88
use Stancl\Tenancy\Features\ViteBundler;
9+
use Stancl\Tenancy\Tests\Etc\Tenant;
910

10-
test('vite helper uses our custom class', function() {
11-
$vite = app(Vite::class);
12-
13-
expect($vite)->toBeInstanceOf(Vite::class);
14-
expect($vite)->not()->toBeInstanceOf(StanclVite::class);
11+
use function Stancl\Tenancy\Tests\withBootstrapping;
1512

13+
beforeEach(function () {
1614
config([
17-
'tenancy.features' => [ViteBundler::class],
15+
'tenancy.filesystem.asset_helper_override' => true,
16+
'tenancy.bootstrappers' => [FilesystemTenancyBootstrapper::class],
1817
]);
1918

20-
$tenant = Tenant::create();
19+
File::ensureDirectoryExists(dirname($manifestPath = public_path('build/manifest.json')));
20+
File::put($manifestPath, json_encode([
21+
'foo' => [
22+
'file' => 'assets/foo-AbC123.js',
23+
'src' => 'js/foo.js',
24+
],
25+
]));
26+
});
27+
28+
test('vite bundler ensures vite assets use global_asset when asset_helper_override is enabled', function () {
29+
config(['tenancy.features' => [ViteBundler::class]]);
30+
31+
withBootstrapping();
2132

22-
tenancy()->initialize($tenant);
33+
tenancy()->initialize(Tenant::create());
2334

24-
app()->forgetInstance(Vite::class);
35+
// Not what we want
36+
expect(asset('foo'))->toBe(route('stancl.tenancy.asset', ['path' => 'foo']));
2537

26-
$vite = app(Vite::class);
38+
$viteAssetUrl = app(Vite::class)->asset('foo');
39+
$expectedGlobalUrl = global_asset('build/assets/foo-AbC123.js');
2740

28-
expect($vite)->toBeInstanceOf(StanclVite::class);
41+
expect($viteAssetUrl)->toBe($expectedGlobalUrl);
42+
expect($viteAssetUrl)->toBe('http://localhost/build/assets/foo-AbC123.js');
2943
});

0 commit comments

Comments
 (0)