Skip to content

[4.x] Create pending tenants with pending_since, improve --with-pending#1458

Open
lukinovec wants to merge 10 commits intomasterfrom
pending-improvements
Open

[4.x] Create pending tenants with pending_since, improve --with-pending#1458
lukinovec wants to merge 10 commits intomasterfrom
pending-improvements

Conversation

@lukinovec
Copy link
Copy Markdown
Contributor

@lukinovec lukinovec commented Apr 28, 2026

Pending tenants aren't getting their pending_since set until they're created completely (e.g. their DB was created, migrated and seeded -- first, the tenant is created fully, and only after that, the tenant is updated to have pending_since). This is a problem if someone wants to e.g. add a job to the DatabaseCreated job pipeline that would check $this->tenant->pending(). Since at the point of DatabaseCreated, the tenant's pending_since isn't set yet, $this->tenant->pending() returns false, even for tenants created using createPending(). So instead of letting the pending tenant get fully created, and only after that, setting its pending_since (using update()), we now set pending_since in create(). CreatingPendingTenant is now dispatched from the static::creating hook, and PendingTenantCreated is dispatched from static::created for consistency.

Setting pending_since right in create() made the MigrateDatabase and SeedDatabase jobs exclude the pending tenants during their creation if the tenancy.pending.include_in_queries config was set to false -- in that case, these jobs would never migrate or seed the databases of pending tenants. So these jobs now pass --with-pending to their underlying commands, with the value set in their $includePending static property (true by default). This overrides the tenancy.pending.include_in_queries config -- unless the $includePending properties are set to false, these jobs will always include pending tenants.

The --with-pending tenant command option originally worked just to opt-in for including pending tenants in the command. Now, --with-pending can accept values (true/1 or false/0), so e.g.

  • tenants:run foo with --with-pending/--with-pending=true/--with-pending=1 includes pending tenants
  • tenants:run foo with --with-pending=false/--with-pending=0 excludes pending tenants (also --with-pending=foobar -- invalid input, considered false)

Passing --with-pending makes the command bypass the tenancy.pending.include_in_queries config (so e.g. if tenancy.pending.include_in_queries is set to true, and --with-pending=false is passed to a command, the command will exclude pending tenants). When --with-pending is not passed, the command will include or exclude pending tenants based on the tenancy.pending.include_in_queries config.

In tenancy-docs, I opened a PR with a note about the --with-pending and job changes (https://github.com/archtechx/tenancy-docs/pull/5).

  • Delete // todo@pending mention in docs from HasTenantOptions after the docs PR gets reviewed/merged

Summary by CodeRabbit

  • New Features

    • --with-pending accepts explicit boolean-like values; when omitted, existing configuration is used
    • Migration and seeding jobs add configurable flags to include/exclude pending tenants regardless of config
    • Pending tenants now record creation timestamp and emit lifecycle events consistently during creation
  • Tests

    • Expanded coverage for --with-pending parsing, job-driven migration/seeding for pending tenants, and lifecycle/job integration tests

lukinovec and others added 5 commits April 28, 2026 10:35
Pasing --with-pending, --with-pending=1 or --with-pending=true now makes tenant commands include pending tenants regardless of the include_in_queries config, and passing --with-pending=false, --with-pending=0 or --with-pending=foo makes the commands exclude pending tenants.
Cover that --with-pending can now accept values, and that the option takes precedence over include_in_queries config. Also simplify/improve existing assertions.
Instead of creating pending tenants without pending_since, letting job pipelines (e.g. TenantCreated) run, and only after that, setting the tenant's pending_since, set it while creating. This allows checking tenant's pending status accurately e.g. in the CreateDatabase job pipeline.
Now that tenants are created with pending_since right away, the migrate and seed database jobs need to include pending tenants for creating pending tenants to work fully. The jobs can still exclude pending tenants if $includePending is set to false.

Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 28, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3216177f-ae33-45ab-8c24-ac543e6b0a35

📥 Commits

Reviewing files that changed from the base of the PR and between 4764b99 and 0c463ea.

📒 Files selected for processing (1)
  • src/Concerns/HasTenantOptions.php

📝 Walkthrough

Walkthrough

--with-pending is now an optional boolean-like CLI option that, when present, overrides config; pending tenants get pending_since set at creation and their lifecycle events fire in model creating/created hooks when pending; migration/seed jobs include a static $includePending forwarded to Artisan; tests updated.

Changes

Cohort / File(s) Summary
Console option & tenant options
src/Concerns/HasTenantOptions.php
--with-pending changed from presence-only flag to an optional boolean-like parameter; when explicitly provided its parsed boolean value is used, otherwise falls back to tenancy.pending.include_in_queries.
Pending tenant lifecycle
src/Database/Concerns/HasPending.php
pending_since is included in attributes at creation time; dispatch of CreatingPendingTenant and PendingTenantCreated moved into model creating/created hooks and gated by pending().
Jobs: migrate & seed
src/Jobs/MigrateDatabase.php, src/Jobs/SeedDatabase.php
Added public static bool $includePending = true; jobs forward --with-pending to tenants:migrate / tenants:seed using that static flag.
Tests
tests/PendingTenantsTest.php
Refactored and expanded tests to cover explicit truthy/falsy --with-pending, default config behavior when omitted, job-level $includePending behavior, added integration scenarios and a PendingTenantJob test helper.

Sequence Diagram

sequenceDiagram
    participant CLI
    participant Job as JobPipeline
    participant Model as TenantModel
    participant Migrate as MigrateDatabase Job
    participant Seed as SeedDatabase Job
    participant DB as Database

    CLI->>Job: dispatch tenant lifecycle (with --with-pending)
    Job->>Model: create tenant (attributes include pending_since when pending)
    Model-->>Job: created (creating/created events fire if pending)
    Job->>Migrate: run (--with-pending = Migrate::$includePending)
    Migrate->>DB: run migrations
    Job->>Seed: run (--with-pending = Seed::$includePending)
    Seed->>DB: run seeders
    DB-->>CLI: tenant DB ready
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • stancl

Poem

🐇
I nibble flags and hop among,
Pending marks set right and strong.
Events wake as models spring,
Jobs march in and gardens sing.
A carrot cheer — migrations run! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: setting pending_since during tenant creation and improving the --with-pending option behavior.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pending-improvements

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 28, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.89%. Comparing base (9849119) to head (0c463ea).

Additional details and impacted files
@@             Coverage Diff              @@
##             master    #1458      +/-   ##
============================================
+ Coverage     85.84%   85.89%   +0.04%     
- Complexity     1163     1165       +2     
============================================
  Files           185      185              
  Lines          3399     3409      +10     
============================================
+ Hits           2918     2928      +10     
  Misses          481      481              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/PendingTenantsTest.php (1)

195-239: 🧹 Nitpick | 🔵 Trivial

Consider adding test coverage for invalid --with-pending values.

The current tests cover truthy (--with-pending, =true, =1) and falsy (=false, =0) values. Per the PR description, "invalid values treated as false" via filter_var. Consider adding a test case with an invalid value like --with-pending=invalid to document this behavior.

📝 Suggested test addition
test('commands exclude pending tenants when invalid --with-pending value is passed', function () {
    config(['tenancy.pending.include_in_queries' => true]);

    $pendingTenant = Tenant::createPending();
    $normalTenant = Tenant::create();

    // Invalid values are treated as false per filter_var behavior
    $command = pest()->artisan("tenants:run 'bar testing testing@test.test password foo' --with-pending=invalid");

    $command->expectsOutputToContain("Tenant: {$normalTenant->getTenantKey()}");
    $command->doesntExpectOutputToContain("Tenant: {$pendingTenant->getTenantKey()}");
    $command->assertSuccessful();
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/PendingTenantsTest.php` around lines 195 - 239, Add a new test in
PendingTenantsTest.php that verifies invalid --with-pending values are treated
as false: create one pending and one normal Tenant, set
config(['tenancy.pending.include_in_queries' => true]), run the tenants:run
command with the flag "--with-pending=invalid" (use pest()->artisan as in the
existing tests), and assert that the normal tenant appears in output while the
pending tenant does not; name the test similar to test('commands exclude pending
tenants when invalid --with-pending value is passed') to match existing test
style.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Database/Concerns/HasPending.php`:
- Around line 52-60: The CreatingPendingTenant event is being dispatched before
the model is persisted, so listeners (especially with the GeneratesIds trait)
see a tenant without an ID; move the event dispatch to after the model is saved
so the ID is generated first: create the tenant with static::make(...) and call
$tenant->save(), then call event(new CreatingPendingTenant($tenant));
references: static::make, static::getPendingAttributes, $tenant->save(), and the
CreatingPendingTenant event.

---

Outside diff comments:
In `@tests/PendingTenantsTest.php`:
- Around line 195-239: Add a new test in PendingTenantsTest.php that verifies
invalid --with-pending values are treated as false: create one pending and one
normal Tenant, set config(['tenancy.pending.include_in_queries' => true]), run
the tenants:run command with the flag "--with-pending=invalid" (use
pest()->artisan as in the existing tests), and assert that the normal tenant
appears in output while the pending tenant does not; name the test similar to
test('commands exclude pending tenants when invalid --with-pending value is
passed') to match existing test style.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 73bb6188-dcf8-449c-82e3-b0795c3952ca

📥 Commits

Reviewing files that changed from the base of the PR and between 9849119 and f309dcc.

📒 Files selected for processing (5)
  • src/Concerns/HasTenantOptions.php
  • src/Database/Concerns/HasPending.php
  • src/Jobs/MigrateDatabase.php
  • src/Jobs/SeedDatabase.php
  • tests/PendingTenantsTest.php

Comment thread src/Database/Concerns/HasPending.php Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Database/Concerns/HasPending.php`:
- Around line 64-68: The createPending() method currently uses array_merge([...
'pending_since' => now()->timestamp], static::getPendingAttributes($attributes),
$attributes) which allows callers to override 'pending_since' (e.g., passing
null) and produce a non-pending tenant; modify createPending() so the enforced
'pending_since' cannot be overwritten—either remove 'pending_since' from the
incoming $attributes before merging, or perform the merge so the timestamp is
applied last (or use array union + to prefer the existing timestamp), ensuring
createPending() always sets a non-null pending_since and thus always creates a
pending tenant; update any references to getPendingAttributes(...) if needed to
avoid reintroducing the override.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 208319f4-ed48-45b1-a11f-9a4cf977ffb7

📥 Commits

Reviewing files that changed from the base of the PR and between f309dcc and e3673f5.

📒 Files selected for processing (2)
  • src/Database/Concerns/HasPending.php
  • tests/PendingTenantsTest.php

Comment thread src/Database/Concerns/HasPending.php
Reverting the HasPending changes (in createPending(), create tenant without pending_since, and only after that, update the tenant to give it pending_since) makes the test fail.
…reation

Ensures that createPending always creates tenants with pending_since set to the current timestamp.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
src/Database/Concerns/HasPending.php (1)

32-35: ⚠️ Potential issue | 🟠 Major

CreatingPendingTenant now fires before the tenant is persisted.

Line 32 moves this public event into Eloquent’s creating phase, so listeners now run before the tenant row exists in storage. That is a behavioral break for any listener that queries the tenant, depends on DB-populated state, or expects the record to be readable by key. Please either keep this dispatch on the post-save path or document the timing change as a breaking change.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Database/Concerns/HasPending.php` around lines 32 - 35, The
CreatingPendingTenant event is now dispatched during Eloquent’s creating phase
(static::creating) which runs before the tenant row is persisted; to restore
previous behavior move the dispatch into the post-save lifecycle (e.g.,
static::created or static::saved) so listeners see a persisted record, i.e.
replace the static::creating(...) handler with a static::created(...) or
static::saved(...) handler that checks $tenant->pending() and fires event(new
CreatingPendingTenant($tenant)); if this timing change is intentional instead
update documentation/changelog to mark it as a breaking change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/Database/Concerns/HasPending.php`:
- Around line 32-35: The CreatingPendingTenant event is now dispatched during
Eloquent’s creating phase (static::creating) which runs before the tenant row is
persisted; to restore previous behavior move the dispatch into the post-save
lifecycle (e.g., static::created or static::saved) so listeners see a persisted
record, i.e. replace the static::creating(...) handler with a
static::created(...) or static::saved(...) handler that checks
$tenant->pending() and fires event(new CreatingPendingTenant($tenant)); if this
timing change is intentional instead update documentation/changelog to mark it
as a breaking change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1e6c14c2-cc7b-4baf-b8a6-44fa8e7f29db

📥 Commits

Reviewing files that changed from the base of the PR and between e3673f5 and 4764b99.

📒 Files selected for processing (2)
  • src/Database/Concerns/HasPending.php
  • tests/PendingTenantsTest.php

@lukinovec
Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 28, 2026

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Concerns/HasTenantOptions.php`:
- Line 21: Remove or resolve the inline TODO comment on the InputOption
declaration for '--with-pending' in HasTenantOptions.php: either delete the "//
todo@pending mention in docs" comment, replace it with a reference to the
documentation page or issue tracker (e.g., "see docs:
<doc-path-or-issue-number>"), or open and reference a new issue tracking the
docs update so the reminder is not left in source; update the comment text to
include the issue/PR number or documentation path next to the
InputOption('with-pending', ...) declaration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7d952e8d-aafd-440e-93c9-215d054af511

📥 Commits

Reviewing files that changed from the base of the PR and between 9849119 and 4764b99.

📒 Files selected for processing (5)
  • src/Concerns/HasTenantOptions.php
  • src/Database/Concerns/HasPending.php
  • src/Jobs/MigrateDatabase.php
  • src/Jobs/SeedDatabase.php
  • tests/PendingTenantsTest.php

Comment thread src/Concerns/HasTenantOptions.php Outdated
@stancl stancl self-assigned this May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants