Skip to content

Commit 652bc98

Browse files
jimish-gamitgjimishstancllukinovec
authored
Add --skip-tenants option to HasTenantOptions (#1436)
Adds a --skip-tenants option to all tenant artisan commands (`tenants:run`, `tenants:migrate`, `tenants:rollback`, `tenants:seed`, `tenants:up`, `tenants:down`). The option is the complement of the existing `--tenants` option instead of specifying which tenants to include, you specify which to exclude. --------- Co-authored-by: Jimish Gamit <unique.jimish@gmail.com> Co-authored-by: Samuel Stancl <samuel@archte.ch> Co-authored-by: lukinovec <lukinovec@gmail.com>
1 parent dfb0e1a commit 652bc98

3 files changed

Lines changed: 57 additions & 4 deletions

File tree

src/Commands/Run.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ class Run extends Command
1717
protected $description = 'Run a command for tenant(s)';
1818

1919
protected $signature = 'tenants:run {commandname : The artisan command.}
20-
{--tenants=* : The tenant(s) to run the command for. Default: all}';
20+
{--tenants=* : The tenant(s) to run the command for. Default: all}
21+
{--skip-tenants=* : The tenant(s) to skip}';
2122

2223
public function handle(): int
2324
{

src/Concerns/HasTenantOptions.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,16 @@
1010
use Symfony\Component\Console\Input\InputOption;
1111

1212
/**
13-
* Adds 'tenants' and 'with-pending' options.
13+
* Adds 'tenants', 'skip-tenants', and 'with-pending' options.
1414
*/
1515
trait HasTenantOptions
1616
{
1717
protected function getOptions()
1818
{
1919
return array_merge([
20-
new InputOption('tenants', null, InputOption::VALUE_IS_ARRAY|InputOption::VALUE_OPTIONAL, 'The tenants to run this command for. Leave empty for all tenants', null),
21-
new InputOption('with-pending', null, InputOption::VALUE_OPTIONAL, 'Include pending tenants in query if true/1, exclude if false/0. Defaults to the tenancy.pending.include_in_queries config value.'),
20+
new InputOption('tenants', null, InputOption::VALUE_IS_ARRAY|InputOption::VALUE_OPTIONAL, 'The tenants to run this command for. Leave empty for all tenants', null),
21+
new InputOption('skip-tenants', null, InputOption::VALUE_IS_ARRAY|InputOption::VALUE_OPTIONAL, 'The tenants to skip when running this command', null),
22+
new InputOption('with-pending', null, InputOption::VALUE_OPTIONAL, 'Include pending tenants in query if true/1, exclude if false/0. Defaults to the tenancy.pending.include_in_queries config value.'),
2223
], parent::getOptions());
2324
}
2425

@@ -42,6 +43,9 @@ protected function getTenantsQuery(?array $tenantKeys = null): Builder
4243
->when($this->option('tenants'), function ($query) {
4344
$query->whereIn(tenancy()->model()->getTenantKeyName(), $this->option('tenants'));
4445
})
46+
->when($this->option('skip-tenants'), function ($query) {
47+
$query->whereNotIn(tenancy()->model()->getTenantKeyName(), $this->option('skip-tenants'));
48+
})
4549
->when(tenancy()->model()::hasGlobalScope(PendingScope::class), function ($query) {
4650
$includePending = $this->input->hasParameterOption('--with-pending')
4751
? filter_var($this->option('with-pending') ?? true, FILTER_VALIDATE_BOOLEAN)

tests/CommandsTest.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,3 +515,51 @@
515515
expect($tenantHasDatabase($tenant))->toBe($shouldHaveDBAfterMigrateFresh);
516516
}
517517
})->with([true, false]);
518+
519+
test('migrate commands can skip specified tenants', function (string $command) {
520+
$tenant1 = Tenant::create();
521+
$tenant2 = Tenant::create();
522+
$tenant3 = Tenant::create();
523+
524+
pest()->artisan("{$command} --skip-tenants={$tenant1->getTenantKey()} --skip-tenants={$tenant2->getTenantKey()}");
525+
526+
tenancy()->initialize($tenant1);
527+
528+
expect(Schema::hasTable('users'))->toBeFalse();
529+
530+
tenancy()->initialize($tenant2);
531+
532+
expect(Schema::hasTable('users'))->toBeFalse();
533+
534+
tenancy()->initialize($tenant3);
535+
536+
expect(Schema::hasTable('users'))->toBeTrue();
537+
})->with([
538+
'tenants:migrate',
539+
'tenants:migrate-fresh',
540+
]);
541+
542+
test('run command can skip specified tenants', function () {
543+
$tenant1 = Tenant::create()->getTenantKey();
544+
$tenant2 = Tenant::create()->getTenantKey();
545+
$tenant3 = Tenant::create()->getTenantKey();
546+
547+
pest()->artisan("tenants:run --skip-tenants=$tenant1 --skip-tenants=$tenant2 'bar foo foo@bar foobar arg --option=option'")
548+
->doesntExpectOutputToContain("Tenant: $tenant1")
549+
->doesntExpectOutputToContain("Tenant: $tenant2")
550+
->expectsOutputToContain("Tenant: $tenant3")
551+
->assertExitCode(0);
552+
});
553+
554+
test('tenants and skip-tenants options can be used together', function () {
555+
$tenant1 = Tenant::create()->getTenantKey();
556+
$tenant2 = Tenant::create()->getTenantKey();
557+
$tenant3 = Tenant::create()->getTenantKey();
558+
559+
// Scope to tenant1+tenant2, then skip tenant2 — only tenant1 should run
560+
pest()->artisan("tenants:run --tenants=$tenant1 --tenants=$tenant2 --skip-tenants=$tenant2 'bar foo foo@bar foobar arg --option=option'")
561+
->expectsOutputToContain("Tenant: $tenant1")
562+
->doesntExpectOutputToContain("Tenant: $tenant2")
563+
->doesntExpectOutputToContain("Tenant: $tenant3")
564+
->assertExitCode(0);
565+
});

0 commit comments

Comments
 (0)