Skip to content

feat(cli): add app domain commands#33

Merged
luanvdw merged 7 commits into
mainfrom
aman/app-domain-cli
May 27, 2026
Merged

feat(cli): add app domain commands#33
luanvdw merged 7 commits into
mainfrom
aman/app-domain-cli

Conversation

@AmanVarshney01
Copy link
Copy Markdown
Member

Summary

  • add prisma-cli app domain commands for add, show, remove, retry, and wait
  • wire the commands to the Management API custom-domain endpoints
  • document the domain command/error contract and cover the key flows in tests

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 25, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR implements end-to-end custom domain management for preview apps. Changes span public specification documents, CLI type contracts, preview-provider APIs, command handlers with polling, presenters, and comprehensive test coverage across unit, controller, and CLI help tests.

Changes

Custom Domain Management Feature

Layer / File(s) Summary
Public Specification and Error Codes
docs/product/command-principles.md, docs/product/command-spec.md, docs/product/error-conventions.md
domain is added as a stable noun; wait becomes a stable verb. The app domain command group (add/show/remove/retry/wait) is fully documented with production-branch enforcement, idempotency, confirmation requirements, polling semantics, and exit codes. Seven custom-domain error codes (invalid hostname, DNS not configured, quota exceeded, not found, retry not eligible, verification failed, timeout) are registered with meanings.
Domain Type Contracts
packages/cli/src/types/app.ts
Introduces AppDomainStatus (lifecycle states), AppDomainFailureCategory (dns/acme/storage), AppDomainDnsRecord, and AppDomainSummary (full domain shape with status, failure, cert expiry, timestamps, DNS records). Defines shared AppDomainTarget (workspace/project/branch/app) and typed result interfaces for add/show/remove/retry operations.
Preview Provider Domain APIs
packages/cli/src/lib/app/preview-provider.ts
Extends PreviewAppProvider with listDomains, addDomain (handles 409 conflict via hostname normalization), showDomain, removeDomain, retryDomain. Exports PreviewDomainStatus, PreviewDomainDnsRecord, PreviewDomainRecord, and PreviewDomainApiError. Normalizes raw API responses and maps HTTP failures into typed errors.
Domain Failure Guidance
packages/cli/src/lib/app/domain-guidance.ts
Implements formatDomainFailureFix to generate category-specific guidance (dns with optional DNS record fields, acme, storage, generic retry fallback) for failed domain states.
Command Wiring and Entry Points
packages/cli/src/commands/app/index.ts
Registers app domain group and subcommands (add/show/remove/retry/wait); wires hostname argument and shared target options (\--app, \--project, \--branch); connects synchronous commands to controllers and wait to streaming handler with \--timeout (default 15m).
Domain Command Handlers
packages/cli/src/controllers/app.ts
Implements runAppDomainAdd/Show/Remove/Retry/Wait; normalizes/validates hostnames; resolves production-eligible app target; calls provider APIs; maps provider errors to CliError with specific codes. runAppDomainWait includes timeout parsing, polling interval selection, JSON/human status emission, failure details with guidance, and timeout instructions.
Output Presenters
packages/cli/src/presenters/app.ts
Adds renderAppDomainAdd/Show/Remove/Retry and serializers; renders target context, hostname, status with tone, DNS records or placeholder, failure details, optional "fix" guidance, cert expiration (UTC or "-"), and operation-specific fields (existing flag, removed indicator).
Command Descriptors
packages/cli/src/shell/command-meta.ts
Registers command descriptors for prisma app domain and all subcommands with IDs, paths, descriptions, and example usage.
Feature Tests
packages/cli/tests/app-controller.test.ts, packages/cli/tests/app-presenter.test.ts, packages/cli/tests/app-provider.test.ts, packages/cli/tests/app.test.ts
Adds provider idempotency test (409 handling with existing domain); controller tests (DNS missing→DOMAIN_DNS_NOT_CONFIGURED, quota conflict→DOMAIN_QUOTA_EXCEEDED, retry eligibility, wait timeout/poll-once modes); presenter tests (DNS placeholder rendering, failure guidance); CLI help tests for domain subcommands.

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(cli): add app domain commands' directly and concisely describes the main change: adding new app domain commands to the CLI.
Description check ✅ Passed The description provides a clear summary of the PR's objectives: adding app domain commands, wiring them to the Management API, documenting the contract, and adding test coverage.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch aman/app-domain-cli
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch aman/app-domain-cli

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

Copy link
Copy Markdown

@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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/cli/src/controllers/app.ts`:
- Line 822: The domain lookup failure message is hardcoded to use
domainCommandError("show", ...) which mislabels failures for other actions;
update all calls that currently pass the literal "show" (e.g., the call after
resolveDomainByHostname and the occurrences at lines referenced) to pass the
actual command name variable used by the surrounding handler (e.g., command,
cmdName, or actionName) so domainCommandError receives the real operation
(remove/retry/wait/list/etc.) instead of "show"; search for
domainCommandError("show", ...) and replace the first argument with the correct
operation variable in the surrounding function (and ensure that variable is in
scope or add a parameter if needed) so error messages accurately reflect the
attempted command.

In `@packages/cli/src/presenters/app.ts`:
- Around line 535-545: The current domainFixFields function always returns DNS
remediation text whenever domain.failureReason exists, which can mislead users
for non-DNS failures; update domainFixFields (the function named
domainFixFields) to first check that the failure reason/category indicates a
DNS-related failure (e.g., domain.failureReason.category === "dns" or
domain.failureReason.type === "dns" depending on the domain shape) and only then
construct the DNS instruction using domain.dnsRecords[0] (falling back to {
type: "CNAME", name: domain.hostname, value: "edge.prisma.app" }); for any other
failure category return an empty array. Ensure you reference
domain.failureReason and domain.dnsRecords in the conditional so non-DNS
failures don't get DNS remediation text.

In `@packages/cli/tests/app.test.ts`:
- Around line 68-85: The test currently calls executeCli for "app domain
--help", "app domain add --help", and "app domain wait --help" but misses the
other domain subcommands; update the tests to also invoke executeCli for "app
domain show --help", "app domain remove --help", and "app domain retry --help"
so help output for those commands is validated; add the same three executeCli
calls in the second help block (the one around the 165-176 region) to keep both
help assertion groups symmetric, referencing the executeCli helper and the argv
arrays to locate where to add the new calls.
🪄 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: 7a5f37da-8826-41eb-ad71-ac5f3bd4560a

📥 Commits

Reviewing files that changed from the base of the PR and between b3c4e13 and ce20c9f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (13)
  • docs/product/command-principles.md
  • docs/product/command-spec.md
  • docs/product/error-conventions.md
  • packages/cli/package.json
  • packages/cli/src/commands/app/index.ts
  • packages/cli/src/controllers/app.ts
  • packages/cli/src/lib/app/preview-provider.ts
  • packages/cli/src/presenters/app.ts
  • packages/cli/src/shell/command-meta.ts
  • packages/cli/src/types/app.ts
  • packages/cli/tests/app-controller.test.ts
  • packages/cli/tests/app-provider.test.ts
  • packages/cli/tests/app.test.ts

Comment thread packages/cli/src/controllers/app.ts Outdated
Comment thread packages/cli/src/presenters/app.ts
Comment thread packages/cli/tests/app.test.ts
Copy link
Copy Markdown

@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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/cli/src/controllers/app.ts`:
- Around line 1662-1678: The code unconditionally emits a concrete CNAME
remediation when DNS errors occur; change the logic so that when
isDomainDnsError(error) is true you first inspect the error for a
provider-reported CNAME target (or any extractable target) and only call
domainDnsNotConfiguredError(hostname, error) / include a CNAME-specific
nextSteps if that target exists; otherwise return a generic CliError (using
CliError with code "NO_DEPLOYMENTS", domain "app", summary/why/fix/debug via
formatDebugDetails(error)) that omits the CNAME instruction and provides a
generic DNS remediation and non-actionable nextSteps; apply the same conditional
handling in the other similar block (the section around the other occurrence
noted in the review).
🪄 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: 7a45098d-c7a2-40bf-a28b-c61c4b52dd3c

📥 Commits

Reviewing files that changed from the base of the PR and between a110465 and 6539087.

📒 Files selected for processing (4)
  • docs/product/command-spec.md
  • docs/product/error-conventions.md
  • packages/cli/src/controllers/app.ts
  • packages/cli/tests/app-controller.test.ts

Comment thread packages/cli/src/controllers/app.ts Outdated
Copy link
Copy Markdown
Member

@luanvdw luanvdw left a comment

Choose a reason for hiding this comment

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

Thanks @AmanVarshney01, the CLI shape is looking good!

Can we do an additional pass on DNS guidance? where possible, the CLI must always give a truthful next step after app domain add/show. IIUC right now it can omit records when the API omits dnsRecords, and it can print CNAME fixes for non-CNAME/non-DNS failures. Can we either rely on authoritative dnsRecords from the API, or make the fallback a tested provider contract?

I’d also fix the hardcoded "show" error label in shared hostname lookup. After that I think this achieves the J20 CLI objective without expanding scope. wdyt?

Copy link
Copy Markdown

@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.

Caution

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

⚠️ Outside diff range comments (1)
packages/cli/src/presenters/app.ts (1)

320-320: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Align failure tone with failure category presence.

Line 320 still uses failureReason only for tone, but Line 535 now returns failureCategory even when reason is absent. That can render a real failure as dim.

Proposed fix
-        { key: "failure", value: formatDomainFailure(result.domain), tone: result.domain.failureReason ? "error" : "dim" },
+        {
+          key: "failure",
+          value: formatDomainFailure(result.domain),
+          tone: (result.domain.failureCategory || result.domain.failureReason) ? "error" : "dim",
+        },

Also applies to: 533-536

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/presenters/app.ts` at line 320, The tone for the "failure"
field currently checks only result.domain.failureReason which misses cases where
failureCategory is present; update the tone logic where the object uses
formatDomainFailure(result.domain) (and the other occurrence around the block
that previously checked failureReason at the same area) to use failureCategory
OR failureReason (e.g., tone set when result.domain.failureCategory ||
result.domain.failureReason) so any real failure indicated by failureCategory
renders as "error" instead of "dim".
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/cli/src/presenters/app.ts`:
- Line 320: The tone for the "failure" field currently checks only
result.domain.failureReason which misses cases where failureCategory is present;
update the tone logic where the object uses formatDomainFailure(result.domain)
(and the other occurrence around the block that previously checked failureReason
at the same area) to use failureCategory OR failureReason (e.g., tone set when
result.domain.failureCategory || result.domain.failureReason) so any real
failure indicated by failureCategory renders as "error" instead of "dim".

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 62f3aab1-9f35-458e-b1c0-da4b6a2bb0fe

📥 Commits

Reviewing files that changed from the base of the PR and between 6539087 and 17618f5.

📒 Files selected for processing (6)
  • docs/product/command-spec.md
  • packages/cli/src/controllers/app.ts
  • packages/cli/src/lib/app/domain-guidance.ts
  • packages/cli/src/presenters/app.ts
  • packages/cli/tests/app-controller.test.ts
  • packages/cli/tests/app-presenter.test.ts

Copy link
Copy Markdown

@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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/product/command-spec.md`:
- Line 860: Update the documented exit codes so the timeout uses the
runtime-failure code instead of the usage/config code: change the sentence
"exits 0 on `active`, 1 on terminal `failed`, and 2 on timeout" so that timeout
returns 1 (e.g., "exits 0 on `active`, 1 on terminal `failed` and on timeout;
reserve 2 for usage/config errors"). Also scan nearby examples or tables in this
spec to ensure any other mentions of timeout exit code are updated to 1.
🪄 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: 1cc6d0da-c302-4126-bd29-3430250bad36

📥 Commits

Reviewing files that changed from the base of the PR and between 17618f5 and 10d7672.

📒 Files selected for processing (14)
  • docs/product/command-principles.md
  • docs/product/command-spec.md
  • docs/product/error-conventions.md
  • packages/cli/src/commands/app/index.ts
  • packages/cli/src/controllers/app.ts
  • packages/cli/src/lib/app/domain-guidance.ts
  • packages/cli/src/lib/app/preview-provider.ts
  • packages/cli/src/presenters/app.ts
  • packages/cli/src/shell/command-meta.ts
  • packages/cli/src/types/app.ts
  • packages/cli/tests/app-controller.test.ts
  • packages/cli/tests/app-presenter.test.ts
  • packages/cli/tests/app-provider.test.ts
  • packages/cli/tests/app.test.ts

Comment thread docs/product/command-spec.md Outdated
@AmanVarshney01 AmanVarshney01 requested a review from luanvdw May 26, 2026 17:54
luanvdw
luanvdw previously approved these changes May 27, 2026
Copy link
Copy Markdown
Member

@luanvdw luanvdw left a comment

Choose a reason for hiding this comment

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

@AmanVarshney01 thanks for the follow-up changes, this is in a great shape!

Would you take a look at the below feedback, and see if we can either include it in this PR, or tackle as follow up work? I'm approving the PR so long, as these are non-blocking changes.

  • Can we handle the domain already registered elsewhere as a more guided error path?
    addDomain currently treats 409 as idempotent if the hostname is found on the selected app, which is good. But if the hostname is registered on a different app/project/workspace, it falls through to the generic “custom domain add failed” path and suggests app domain show <hostname>. Since show resolves within the selected app, that can send the user/agent into a loop: show says not found, add says conflict, etc. I’d make this a specific recovery message: “This hostname is already registered outside the selected app. Select the owning app, remove it there, or contact support.” We don’t need list/transfer/reassign in this PR, just a better dead-end.

2 smaller nits:

  • renderAppDomainShow tones the failure row as error only when failureReason exists, but formatDomainFailure can show a failureCategory without a reason. If failureCategory || failureReason is present, the row should render as an error.
  • can we make retry output a bit more informative? app domain retry currently prints hostname/status only. Since retry is part of the recovery path, it would be useful to include DNS records and/or the same failure/fix fields when present, similar to show. Not blocking, but it would make the command feel less like “now run show to understand what happened.”

luanvdw
luanvdw previously approved these changes May 27, 2026
Copy link
Copy Markdown
Member

@luanvdw luanvdw left a comment

Choose a reason for hiding this comment

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

Lessgo! 🚀

@luanvdw luanvdw merged commit 36a42ca into main May 27, 2026
4 checks passed
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