Skip to content

Comments

Changed member welcome email job to run based on config#25465

Merged
troyciesco merged 5 commits intomainfrom
NY-763_dev-null-email
Nov 18, 2025
Merged

Changed member welcome email job to run based on config#25465
troyciesco merged 5 commits intomainfrom
NY-763_dev-null-email

Conversation

@troyciesco
Copy link
Contributor

ref https://linear.app/ghost/issue/NY-763

  • Modifies the member welcome email job so it no longer references the welcomeEmails labs flag, and instead checks to ensure memberWelcomeEmailTestInbox is set in config
  • This will allow us to stress test a higher volume of emails than we'd get by manually turning on the labs flag for a few sites
  • By making sure the config exists before scheduling the job there won't be any unnecessary impact to self-hosted instances
  • Doesn't send the email to any real members, just to an internal (to Ghost) test inbox
  • The welcomeEmails lab flag itself isn't deleted yet - we'll likely use it for UI-related toggles in the future

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 17, 2025

Walkthrough

The PR replaces feature-flag checks for member welcome emails (previously labs.isSet('welcomeEmails')) with a configuration-driven check using config.get('memberWelcomeEmailTestInbox'). Changes touch the job scheduler and the member creation flow where the gating condition is evaluated. Unit and integration tests are updated to stub or set config.get/configUtils instead of mocking the labs service. No public APIs or function signatures were changed.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Consistent pattern: the same conditional check replacement across several files and tests.
  • Files/areas to double-check:
    • job scheduler: ensure the new config key is referenced correctly and respects environment guards.
    • MemberRepository create flow: validate the config lookup logic and any dependency removal (labs) doesn’t break DI expectations.
    • Tests: confirm config.get/configUtils stubbing is isolated and restored between tests to avoid cross-test contamination.
    • Global search: verify there are no remaining references to the welcomeEmails labs flag elsewhere in the codebase.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: replacing labs flag with config-based control for member welcome email job scheduling.
Description check ✅ Passed The description is directly related to the changeset, providing context, rationale, and implementation details about switching from labs flags to config-based control.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch NY-763_dev-null-email

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9cd835a and b2a9e91.

📒 Files selected for processing (1)
  • ghost/core/test/integration/services/member-welcome-emails.test.js (6 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25118
File: apps/portal/src/actions.js:160-173
Timestamp: 2025-10-09T15:31:06.587Z
Learning: When reviewing PRs that introduce feature-flagged changes (e.g., `labs?.membersSigninOTCAlpha`), avoid suggesting modifications to non-flagged code paths unless they're directly related to the PR's objectives. Keep the scope focused on the feature-flag-specific changes only.
Learnt from: troyciesco
Repo: TryGhost/Ghost PR: 25288
File: ghost/core/core/server/services/member-welcome-emails/jobs/lib/process-entries.js:46-64
Timestamp: 2025-11-10T23:10:17.470Z
Learning: In ghost/core/core/server/services/member-welcome-emails/jobs/lib/process-entries.js and the outbox processing flow, entries are marked as PROCESSING before being processed. If a failure occurs after email send but before deletion, the entry remains stuck in PROCESSING state (not reprocessed). This intentional design prevents duplicate emails. Handling stuck PROCESSING entries is planned for a separate PR.
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 23770
File: apps/admin-x-settings/src/components/settings/email/newsletters/NewsletterDetailModalLabs.tsx:435-450
Timestamp: 2025-06-10T11:07:10.800Z
Learning: In Ghost's newsletter customization features, when promoting a feature from alpha to beta status, the feature flag guards are updated to make the feature available under both the `emailCustomization` (beta) and `emailCustomizationAlpha` (alpha) flags. This is done by either removing conditional guards entirely when the component is already behind both flags, or by updating conditionals to check for either flag.
📚 Learning: 2025-06-10T11:07:10.800Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 23770
File: apps/admin-x-settings/src/components/settings/email/newsletters/NewsletterDetailModalLabs.tsx:435-450
Timestamp: 2025-06-10T11:07:10.800Z
Learning: In Ghost's newsletter customization features, when promoting a feature from alpha to beta status, the feature flag guards are updated to make the feature available under both the `emailCustomization` (beta) and `emailCustomizationAlpha` (alpha) flags. This is done by either removing conditional guards entirely when the component is already behind both flags, or by updating conditionals to check for either flag.

Applied to files:

  • ghost/core/test/integration/services/member-welcome-emails.test.js
📚 Learning: 2025-10-09T15:31:06.587Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25118
File: apps/portal/src/actions.js:160-173
Timestamp: 2025-10-09T15:31:06.587Z
Learning: When reviewing PRs that introduce feature-flagged changes (e.g., `labs?.membersSigninOTCAlpha`), avoid suggesting modifications to non-flagged code paths unless they're directly related to the PR's objectives. Keep the scope focused on the feature-flag-specific changes only.

Applied to files:

  • ghost/core/test/integration/services/member-welcome-emails.test.js
📚 Learning: 2025-10-30T17:13:26.190Z
Learnt from: sam-lord
Repo: TryGhost/Ghost PR: 25303
File: ghost/core/core/server/services/email-service/BatchSendingService.js:19-19
Timestamp: 2025-10-30T17:13:26.190Z
Learning: In ghost/core/core/server/services/email-service/BatchSendingService.js and similar files in the Ghost codebase, prefer using `{...options}` spread syntax without explicit guards like `...(options || {})` when spreading potentially undefined objects, as the maintainer prefers cleaner syntax over defensive patterns when the behavior is safe.

Applied to files:

  • ghost/core/test/integration/services/member-welcome-emails.test.js
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Legacy tests (Node 22.13.1, mysql8)
  • GitHub Check: Legacy tests (Node 22.13.1, sqlite3)
  • GitHub Check: Lint
  • GitHub Check: Ghost-CLI tests
  • GitHub Check: Acceptance tests (Node 22.13.1, sqlite3)
  • GitHub Check: Unit tests (Node 22.13.1)
  • GitHub Check: Acceptance tests (Node 22.13.1, mysql8)
  • GitHub Check: Build & Push
🔇 Additional comments (3)
ghost/core/test/integration/services/member-welcome-emails.test.js (3)

6-6: LGTM! Config utilities properly imported and cleaned up.

The addition of configUtils and the cleanup in afterEach ensure test isolation when manipulating configuration values.

Also applies to: 24-24


29-29: LGTM! Consistent config-based feature enablement.

The tests properly enable the welcome email feature using a test inbox email address, and the test cases appropriately verify both the happy path and edge cases (imported members, admin-created members).

Also applies to: 68-68, 83-83, 98-98


52-54: No issues found. Empty string correctly disables the feature.

The verification confirms both implementations use truthy checks on config.get('memberWelcomeEmailTestInbox'):

  • Job scheduler returns early if the config is falsy
  • Member repository skips the feature block if the config is falsy

Since empty string is falsy in JavaScript, setting the config to '' correctly disables the feature in both code paths. The test will work as intended.


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

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

@troyciesco troyciesco marked this pull request as ready for review November 17, 2025 21:29
Copy link
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: 0

🧹 Nitpick comments (1)
ghost/core/test/integration/services/member-welcome-emails.test.js (1)

30-36: Consider extracting the config stubbing pattern to reduce duplication.

The same config stubbing pattern is repeated across all five tests. While the current approach is correct and functional, extracting it to a reusable helper would improve maintainability.

For example, you could add a helper function:

function stubMemberWelcomeEmailConfig(enabled) {
    const originalGet = config.get.bind(config);
    sinon.stub(config, 'get').callsFake((key) => {
        if (key === 'memberWelcomeEmailTestInbox') {
            return enabled ? 'test-inbox@example.com' : undefined;
        }
        return originalGet(key);
    });
}

Then use it in each test:

-        const originalGet = config.get.bind(config);
-        sinon.stub(config, 'get').callsFake((key) => {
-            if (key === 'memberWelcomeEmailTestInbox') {
-                return 'test-inbox@example.com';
-            }
-            return originalGet(key);
-        });
+        stubMemberWelcomeEmailConfig(true);

Also applies to: 60-66, 81-87, 102-108, 123-129

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ad19ae7 and c8e5776.

📒 Files selected for processing (4)
  • ghost/core/core/server/services/member-welcome-emails/jobs/index.js (1 hunks)
  • ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js (2 hunks)
  • ghost/core/test/integration/services/member-welcome-emails.test.js (6 hunks)
  • ghost/core/test/unit/server/services/members/members-api/repositories/MemberRepository.test.js (6 hunks)
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: troyciesco
Repo: TryGhost/Ghost PR: 25288
File: ghost/core/core/server/services/member-welcome-emails/jobs/lib/process-entries.js:46-64
Timestamp: 2025-11-10T23:10:17.470Z
Learning: In ghost/core/core/server/services/member-welcome-emails/jobs/lib/process-entries.js and the outbox processing flow, entries are marked as PROCESSING before being processed. If a failure occurs after email send but before deletion, the entry remains stuck in PROCESSING state (not reprocessed). This intentional design prevents duplicate emails. Handling stuck PROCESSING entries is planned for a separate PR.
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 23770
File: apps/admin-x-settings/src/components/settings/email/newsletters/NewsletterDetailModalLabs.tsx:435-450
Timestamp: 2025-06-10T11:07:10.800Z
Learning: In Ghost's newsletter customization features, when promoting a feature from alpha to beta status, the feature flag guards are updated to make the feature available under both the `emailCustomization` (beta) and `emailCustomizationAlpha` (alpha) flags. This is done by either removing conditional guards entirely when the component is already behind both flags, or by updating conditionals to check for either flag.
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25118
File: apps/portal/src/actions.js:160-173
Timestamp: 2025-10-09T15:31:06.587Z
Learning: When reviewing PRs that introduce feature-flagged changes (e.g., `labs?.membersSigninOTCAlpha`), avoid suggesting modifications to non-flagged code paths unless they're directly related to the PR's objectives. Keep the scope focused on the feature-flag-specific changes only.
📚 Learning: 2025-06-10T11:07:10.800Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 23770
File: apps/admin-x-settings/src/components/settings/email/newsletters/NewsletterDetailModalLabs.tsx:435-450
Timestamp: 2025-06-10T11:07:10.800Z
Learning: In Ghost's newsletter customization features, when promoting a feature from alpha to beta status, the feature flag guards are updated to make the feature available under both the `emailCustomization` (beta) and `emailCustomizationAlpha` (alpha) flags. This is done by either removing conditional guards entirely when the component is already behind both flags, or by updating conditionals to check for either flag.

Applied to files:

  • ghost/core/test/integration/services/member-welcome-emails.test.js
  • ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js
  • ghost/core/core/server/services/member-welcome-emails/jobs/index.js
📚 Learning: 2025-10-09T15:31:06.587Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25118
File: apps/portal/src/actions.js:160-173
Timestamp: 2025-10-09T15:31:06.587Z
Learning: When reviewing PRs that introduce feature-flagged changes (e.g., `labs?.membersSigninOTCAlpha`), avoid suggesting modifications to non-flagged code paths unless they're directly related to the PR's objectives. Keep the scope focused on the feature-flag-specific changes only.

Applied to files:

  • ghost/core/test/integration/services/member-welcome-emails.test.js
  • ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js
  • ghost/core/core/server/services/member-welcome-emails/jobs/index.js
📚 Learning: 2025-11-10T23:10:17.470Z
Learnt from: troyciesco
Repo: TryGhost/Ghost PR: 25288
File: ghost/core/core/server/services/member-welcome-emails/jobs/lib/process-entries.js:46-64
Timestamp: 2025-11-10T23:10:17.470Z
Learning: In ghost/core/core/server/services/member-welcome-emails/jobs/lib/process-entries.js and the outbox processing flow, entries are marked as PROCESSING before being processed. If a failure occurs after email send but before deletion, the entry remains stuck in PROCESSING state (not reprocessed). This intentional design prevents duplicate emails. Handling stuck PROCESSING entries is planned for a separate PR.

Applied to files:

  • ghost/core/test/integration/services/member-welcome-emails.test.js
  • ghost/core/test/unit/server/services/members/members-api/repositories/MemberRepository.test.js
  • ghost/core/core/server/services/member-welcome-emails/jobs/index.js
📚 Learning: 2025-10-30T17:13:26.190Z
Learnt from: sam-lord
Repo: TryGhost/Ghost PR: 25303
File: ghost/core/core/server/services/email-service/BatchSendingService.js:19-19
Timestamp: 2025-10-30T17:13:26.190Z
Learning: In ghost/core/core/server/services/email-service/BatchSendingService.js and similar files in the Ghost codebase, prefer using `{...options}` spread syntax without explicit guards like `...(options || {})` when spreading potentially undefined objects, as the maintainer prefers cleaner syntax over defensive patterns when the behavior is safe.

Applied to files:

  • ghost/core/core/server/services/member-welcome-emails/jobs/index.js
🧬 Code graph analysis (4)
ghost/core/test/integration/services/member-welcome-emails.test.js (3)
ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js (3)
  • config (11-11)
  • require (6-6)
  • require (8-8)
ghost/core/core/server/services/member-welcome-emails/jobs/index.js (1)
  • config (3-3)
ghost/core/core/server/services/member-welcome-emails/jobs/lib/send-member-welcome-email.js (2)
  • config (4-4)
  • require (3-3)
ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js (5)
ghost/core/test/unit/server/services/members/members-api/repositories/MemberRepository.test.js (2)
  • config (7-7)
  • require (6-6)
ghost/core/core/server/services/member-welcome-emails/jobs/index.js (1)
  • config (3-3)
ghost/core/test/integration/services/member-welcome-emails.test.js (2)
  • config (6-6)
  • require (4-4)
ghost/core/core/server/services/member-welcome-emails/jobs/lib/send-member-welcome-email.js (2)
  • config (4-4)
  • require (3-3)
ghost/core/core/boot.js (1)
  • config (445-445)
ghost/core/test/unit/server/services/members/members-api/repositories/MemberRepository.test.js (1)
ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js (3)
  • config (11-11)
  • require (6-6)
  • require (8-8)
ghost/core/core/server/services/member-welcome-emails/jobs/index.js (2)
ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js (3)
  • config (11-11)
  • require (6-6)
  • require (8-8)
ghost/core/core/server/services/member-welcome-emails/jobs/lib/send-member-welcome-email.js (2)
  • config (4-4)
  • require (3-3)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: E2E Tests (Shard 1/2)
  • GitHub Check: Inspect Docker Image
  • GitHub Check: E2E Tests (Shard 2/2)
  • GitHub Check: Acceptance tests (Node 22.13.1, mysql8)
  • GitHub Check: Acceptance tests (Node 22.13.1, sqlite3)
  • GitHub Check: Ghost-CLI tests
  • GitHub Check: Legacy tests (Node 22.13.1, sqlite3)
  • GitHub Check: Unit tests (Node 22.13.1)
  • GitHub Check: Legacy tests (Node 22.13.1, mysql8)
🔇 Additional comments (5)
ghost/core/core/server/services/member-welcome-emails/jobs/index.js (2)

3-3: LGTM! Clean migration from labs flag to config.

The change successfully replaces the labs-based feature flag with a configuration-driven approach. The config key memberWelcomeEmailTestInbox clearly conveys its purpose, and the truthy check appropriately gates the job scheduling based on whether the test inbox is configured.

Also applies to: 11-11


6-6: LGTM! Comprehensive test updates for config-based gating.

The test updates consistently replace labs stubs with config stubs across all test cases. The pattern of wrapping the original config.get method ensures that other config keys remain accessible, and the tests properly cover both enabled (returns email address) and disabled (returns undefined) scenarios.

Also applies to: 30-36, 59-66, 81-87, 102-108, 123-129

ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js (1)

11-11: LGTM! Successful migration to config-based gating.

The change correctly replaces the labs service check with a direct config module call. This aligns with the PR's objective to enable stress testing via a configured test inbox rather than toggling labs flags across sites.

Note: The labsService remains in the constructor (line 94), which is expected as per the PR description—the labs flag may be retained for future UI-related toggles or other features.

Also applies to: 341-341

ghost/core/test/unit/server/services/members/members-api/repositories/MemberRepository.test.js (1)

7-7: LGTM! Well-structured test updates for config-based feature gating.

The unit test updates correctly replace labs service mocks with config stubs for the welcome email feature. The new "outbox integration" test suite (lines 465-632) properly excludes labsService from the constructor, while earlier tests retain it for testing other features—maintaining appropriate test isolation.

Also applies to: 530-530, 554-555, 571-572, 596-597, 615-616

ghost/core/test/integration/services/member-welcome-emails.test.js (1)

6-6: LGTM!

The config import is correctly added to support the new configuration-based gating approach.

@github-actions
Copy link
Contributor

E2E Tests Failed

To view the Playwright test report locally, run:

REPORT_DIR=$(mktemp -d) && gh run download 19445075834 -n playwright-report -D "$REPORT_DIR" && npx playwright show-report "$REPORT_DIR"

@troyciesco troyciesco requested a review from cmraible November 17, 2025 22:05
Copy link
Collaborator

@cmraible cmraible left a comment

Choose a reason for hiding this comment

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

No notes, nice one 👨‍🍳

So nice and easy to review 🙌

@troyciesco troyciesco merged commit d831441 into main Nov 18, 2025
31 checks passed
@troyciesco troyciesco deleted the NY-763_dev-null-email branch November 18, 2025 19:42
troyciesco added a commit that referenced this pull request Nov 18, 2025
ref https://linear.app/ghost/issue/NY-763

- Modifies the member welcome email job so it no longer references the
`welcomeEmails` labs flag, and instead checks to ensure
`memberWelcomeEmailTestInbox` is set in config
- This will allow us to stress test a higher volume of emails than we'd
get by manually turning on the labs flag for a few sites
- By making sure the config exists before scheduling the job there won't
be any unnecessary impact to self-hosted instances
- Doesn't send the email to any real members, just to an internal (to
Ghost) test inbox
- The `welcomeEmails` lab flag itself isn't deleted yet - we'll likely
use it for UI-related toggles in the future
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