Skip to content

Conversation

myftija
Copy link
Member

@myftija myftija commented Sep 24, 2025

This PR enables canceling deployments via the dashboard or the API. This
feature is especially useful for deployments created by the build server, where
the user does not otherwise have control on the deployment process.

Copy link

changeset-bot bot commented Sep 24, 2025

⚠️ No Changeset found

Latest commit: 4507835

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link
Contributor

coderabbitai bot commented Sep 24, 2025

Walkthrough

Adds end-to-end deployment cancellation support: DB migration and Prisma schema add canceledAt and canceledReason to WorkerDeployment. API/schema: new CancelDeploymentRequestBody zod schema, a POST route api.v1.deployments.$deploymentId.cancel, and a resources action to cancel by projectId/deploymentShortCode. Service: DeploymentService.cancelDeployment added and FINAL_DEPLOYMENT_STATUSES exported/extended (includes TIMED_OUT). Presenter: deployment payload now includes installedAt, canceledAt, canceledReason. UI: CANCELED added to deploymentStatuses; deployment views render canceled/installed fields; new Cancel dialog wired in routes; RollbackDeploymentDialog file removed.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The PR description explains the high-level intent but does not follow the repository's required template: it is missing the "Closes #" line, the checklist, the Testing section with steps performed, the Changelog entry, and the Screenshots section, so it is incomplete relative to the template. Please update the PR description to match the repository template by adding "Closes #" if applicable, completing the checklist items, describing the exact testing steps and results, providing a short changelog entry, and including screenshots or noting none; this will make the PR reviewable and traceable.
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 (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title "feat: enable canceling deployments" is concise, focused, and accurately reflects the primary change in the diff (adding cancel endpoints, UI actions, service logic, and DB fields to enable canceling deployments), so it clearly communicates the main purpose to reviewers scanning history.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch enable-cancelling-deployments

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.

Base automatically changed from installing-status-for-deployments to main September 24, 2025 08:27
@myftija myftija force-pushed the enable-cancelling-deployments branch from 12ee260 to 209242f Compare September 24, 2025 08: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: 5

🧹 Nitpick comments (10)
apps/webapp/app/components/runs/v3/DeploymentStatus.tsx (1)

131-141: Outdated/misleading comment (and typo) above statuses

The comment contradicts the array (CANCELED is included) and “ommited” is misspelled.

Apply this diff:

-// PENDING and CANCELED are not used so are ommited from the UI
+// Full list of deployment statuses used by the UI (including PENDING and CANCELED)
internal-packages/database/prisma/migrations/20250923192901_add_canceled_at_to_deployments/migration.sql (1)

1-2: Migration looks good

Optional: consider a follow-up partial index on status (non-final) if you routinely query/update “active” deployments.

apps/webapp/app/v3/services/failDeployment.server.ts (1)

8-13: Make FINAL_DEPLOYMENT_STATUSES readonly at type level

Prevents accidental mutation and keeps narrow literal types.

Apply this diff:

-export const FINAL_DEPLOYMENT_STATUSES: WorkerDeploymentStatus[] = [
-  "CANCELED",
-  "DEPLOYED",
-  "FAILED",
-  "TIMED_OUT",
-];
+export const FINAL_DEPLOYMENT_STATUSES =
+  ["CANCELED", "DEPLOYED", "FAILED", "TIMED_OUT"] as const satisfies ReadonlyArray<WorkerDeploymentStatus>;
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments.$deploymentParam/route.tsx (1)

171-176: Fix spelling: “Cancellation reason”

Minor UI text polish.

Apply this diff:

-                  <Property.Label>Cancelation reason</Property.Label>
+                  <Property.Label>Cancellation reason</Property.Label>
packages/core/src/v3/schemas/api.ts (1)

388-393: Trim and disallow whitespace-only reasons

Avoids accepting strings that are effectively empty.

Apply this diff:

-export const CancelDeploymentRequestBody = z.object({
-  reason: z.string().max(200, "Reason must be less than 200 characters").optional(),
-});
+export const CancelDeploymentRequestBody = z.object({
+  reason: z
+    .string()
+    .trim()
+    .min(1, "Reason cannot be empty")
+    .max(200, "Reason must be less than 200 characters")
+    .optional(),
+});
apps/webapp/app/routes/api.v1.deployments.$deploymentId.cancel.ts (1)

12-15: Return 405 with Allow header

Include the Allow header for better client behavior.

Apply this diff:

-  if (request.method.toUpperCase() !== "POST") {
-    return json({ error: "Method Not Allowed" }, { status: 405 });
-  }
+  if (request.method.toUpperCase() !== "POST") {
+    return json({ error: "Method Not Allowed" }, { status: 405, headers: { Allow: "POST" } });
+  }
apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts (1)

11-13: Rename schema for clarity.

promoteSchema is used by a cancel route. Consider renaming to cancelSchema to avoid confusion.

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route.tsx (3)

416-418: Avoid duplicating final-status lists in UI.

Hard-coding final statuses risks drift from server truth. Consider a shared UI constant or deriving from a single source used across the app.


528-535: Use the formAction variable to avoid divergence.

Minor: the action string is duplicated; prefer the formAction variable used for isLoading.

-        <Form
-          action={`/resources/${projectId}/deployments/${deploymentShortCode}/rollback`}
-          method="post"
-        >
+        <Form action={formAction} method="post">

570-577: Same here: reuse formAction for promote dialog.

-        <Form
-          action={`/resources/${projectId}/deployments/${deploymentShortCode}/promote`}
-          method="post"
-        >
+        <Form action={formAction} method="post">
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc94d12 and 209242f.

📒 Files selected for processing (12)
  • apps/webapp/app/components/runs/v3/DeploymentStatus.tsx (1 hunks)
  • apps/webapp/app/components/runs/v3/RollbackDeploymentDialog.tsx (0 hunks)
  • apps/webapp/app/presenters/v3/DeploymentPresenter.server.ts (2 hunks)
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments.$deploymentParam/route.tsx (2 hunks)
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route.tsx (7 hunks)
  • apps/webapp/app/routes/api.v1.deployments.$deploymentId.cancel.ts (1 hunks)
  • apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts (1 hunks)
  • apps/webapp/app/v3/services/deployment.server.ts (2 hunks)
  • apps/webapp/app/v3/services/failDeployment.server.ts (1 hunks)
  • internal-packages/database/prisma/migrations/20250923192901_add_canceled_at_to_deployments/migration.sql (1 hunks)
  • internal-packages/database/prisma/schema.prisma (1 hunks)
  • packages/core/src/v3/schemas/api.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/webapp/app/components/runs/v3/RollbackDeploymentDialog.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Always prefer using isomorphic code like fetch, ReadableStream, etc. instead of Node.js specific code
For TypeScript, we usually use types over interfaces
Avoid enums
No default exports, use function declarations

Files:

  • packages/core/src/v3/schemas/api.ts
  • apps/webapp/app/components/runs/v3/DeploymentStatus.tsx
  • apps/webapp/app/presenters/v3/DeploymentPresenter.server.ts
  • apps/webapp/app/v3/services/deployment.server.ts
  • apps/webapp/app/routes/api.v1.deployments.$deploymentId.cancel.ts
  • apps/webapp/app/v3/services/failDeployment.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments.$deploymentParam/route.tsx
  • apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route.tsx
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

We use zod a lot in packages/core and in the webapp

Files:

  • packages/core/src/v3/schemas/api.ts
  • apps/webapp/app/components/runs/v3/DeploymentStatus.tsx
  • apps/webapp/app/presenters/v3/DeploymentPresenter.server.ts
  • apps/webapp/app/v3/services/deployment.server.ts
  • apps/webapp/app/routes/api.v1.deployments.$deploymentId.cancel.ts
  • apps/webapp/app/v3/services/failDeployment.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments.$deploymentParam/route.tsx
  • apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route.tsx
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

When importing from @trigger.dev/core in the webapp, never import the root package path; always use one of the documented subpath exports from @trigger.dev/core’s package.json

Files:

  • apps/webapp/app/components/runs/v3/DeploymentStatus.tsx
  • apps/webapp/app/presenters/v3/DeploymentPresenter.server.ts
  • apps/webapp/app/v3/services/deployment.server.ts
  • apps/webapp/app/routes/api.v1.deployments.$deploymentId.cancel.ts
  • apps/webapp/app/v3/services/failDeployment.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments.$deploymentParam/route.tsx
  • apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route.tsx
{apps/webapp/app/**/*.server.{ts,tsx},apps/webapp/app/routes/**/*.ts}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access environment variables only via the env export from app/env.server.ts; do not reference process.env directly

Files:

  • apps/webapp/app/presenters/v3/DeploymentPresenter.server.ts
  • apps/webapp/app/v3/services/deployment.server.ts
  • apps/webapp/app/routes/api.v1.deployments.$deploymentId.cancel.ts
  • apps/webapp/app/v3/services/failDeployment.server.ts
  • apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts
apps/webapp/app/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Modules intended for test consumption under apps/webapp/app/**/*.ts must not read environment variables; accept configuration via options instead

Files:

  • apps/webapp/app/presenters/v3/DeploymentPresenter.server.ts
  • apps/webapp/app/v3/services/deployment.server.ts
  • apps/webapp/app/routes/api.v1.deployments.$deploymentId.cancel.ts
  • apps/webapp/app/v3/services/failDeployment.server.ts
  • apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts
🧬 Code graph analysis (5)
apps/webapp/app/v3/services/deployment.server.ts (2)
apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV4.server.ts (1)
  • deployment (182-200)
apps/webapp/app/v3/services/failDeployment.server.ts (1)
  • FINAL_DEPLOYMENT_STATUSES (8-13)
apps/webapp/app/routes/api.v1.deployments.$deploymentId.cancel.ts (3)
apps/webapp/app/services/apiAuth.server.ts (1)
  • authenticateRequest (379-441)
packages/core/src/v3/schemas/api.ts (2)
  • CancelDeploymentRequestBody (388-390)
  • CancelDeploymentRequestBody (392-392)
apps/webapp/app/v3/services/deployment.server.ts (1)
  • DeploymentService (11-222)
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments.$deploymentParam/route.tsx (1)
apps/webapp/app/components/primitives/DateTime.tsx (1)
  • DateTimeAccurate (196-242)
apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts (3)
apps/webapp/app/services/session.server.ts (1)
  • requireUserId (25-35)
apps/webapp/app/v3/services/deployment.server.ts (1)
  • DeploymentService (11-222)
apps/webapp/app/models/message.server.ts (2)
  • redirectWithErrorMessage (181-198)
  • redirectWithSuccessMessage (162-179)
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route.tsx (3)
apps/webapp/app/components/primitives/Dialog.tsx (6)
  • Dialog (113-113)
  • DialogTrigger (114-114)
  • DialogContent (115-115)
  • DialogHeader (116-116)
  • DialogDescription (119-119)
  • DialogFooter (117-117)
apps/webapp/app/components/primitives/Buttons.tsx (1)
  • Button (296-331)
apps/webapp/app/components/primitives/Spinner.tsx (1)
  • SpinnerWhite (76-78)
⏰ 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). (23)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (7)
apps/webapp/app/components/runs/v3/DeploymentStatus.tsx (1)

140-141: CANCELED added to statuses — LGTM

This aligns the list with the rest of the UI logic and schemas.

internal-packages/database/prisma/schema.prisma (1)

1775-1777: New fields on WorkerDeployment — LGTM

Types match the migration and downstream usage.

apps/webapp/app/v3/services/failDeployment.server.ts (1)

4-6: Type‑only imports — nice cleanup

Keeps runtime lean.

apps/webapp/app/routes/api.v1.deployments.$deploymentId.cancel.ts (1)

8-10: Verify identifier semantics: friendlyId vs database id

The service expects a friendlyId (findFirst by friendlyId), but the route param is named deploymentId. Confirm that clients supply the friendly ID (e.g., deploy_…) and that docs reflect this. Otherwise, either rename the route param to deploymentFriendlyId or update the service to accept id as well.

Would you like me to update the route/docs, or adjust the service to accept either id or friendlyId and return 404/409 appropriately on race?

Also applies to: 34-36, 46-50

apps/webapp/app/presenters/v3/DeploymentPresenter.server.ts (2)

106-109: Good: selecting new fields (installedAt/canceledAt/canceledReason).

Selection aligns with the new columns and keeps the presenter authoritative for UI needs.


153-158: Good: exposing installedAt/canceledAt/canceledReason in payload.

Matches the DB selection and enables UI rendering without extra queries.

apps/webapp/app/v3/services/deployment.server.ts (1)

104-105: Good: set installedAt at transition to BUILDING.

This timestamp placement is appropriate and consistent with the deployment lifecycle.

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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 209242f and 8e85316.

📒 Files selected for processing (1)
  • apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Always prefer using isomorphic code like fetch, ReadableStream, etc. instead of Node.js specific code
For TypeScript, we usually use types over interfaces
Avoid enums
No default exports, use function declarations

Files:

  • apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

We use zod a lot in packages/core and in the webapp

Files:

  • apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

When importing from @trigger.dev/core in the webapp, never import the root package path; always use one of the documented subpath exports from @trigger.dev/core’s package.json

Files:

  • apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts
{apps/webapp/app/**/*.server.{ts,tsx},apps/webapp/app/routes/**/*.ts}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access environment variables only via the env export from app/env.server.ts; do not reference process.env directly

Files:

  • apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts
apps/webapp/app/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Modules intended for test consumption under apps/webapp/app/**/*.ts must not read environment variables; accept configuration via options instead

Files:

  • apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts
🧬 Code graph analysis (1)
apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts (3)
apps/webapp/app/services/session.server.ts (1)
  • requireUserId (25-35)
apps/webapp/app/v3/services/deployment.server.ts (1)
  • DeploymentService (11-222)
apps/webapp/app/models/message.server.ts (2)
  • redirectWithErrorMessage (181-198)
  • redirectWithSuccessMessage (162-179)
⏰ 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). (1)
  • GitHub Check: units / webapp / 📊 Merge Reports
🔇 Additional comments (6)
apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts (6)

86-93: Fix log message: it's a cancel route, not promote.

The logger message incorrectly says "Failed to promote deployment" even though this is the cancel route.

Apply this diff to correct the log message:

-    logger.error(
-      `Failed to promote deployment: ${result.error.type}`,
+    logger.error(
+      `Failed to cancel deployment: ${result.error.type}`,

104-109: Correct user message for non-cancellable deployments.

The error case for deployment_cannot_be_cancelled incorrectly returns "Deployment not found", which is misleading to users.

Apply this diff to provide the correct error message:

       case "deployment_cannot_be_cancelled":
         return redirectWithErrorMessage(
           submission.value.redirectUrl,
           request,
-          "Deployment not found"
+          "Deployment cannot be canceled"
         );

31-54: LGTM - Proper project membership verification.

The project membership verification correctly ensures only authorized users can cancel deployments by checking organization membership through the userId.


56-76: LGTM - Efficient deployment lookup using composite key.

The deployment lookup uses the efficient projectId_shortCode composite unique constraint and properly handles the not-found case.


79-83: LGTM - Service integration follows established patterns.

The deployment service integration uses the Result pattern consistently with proper error chaining, following the established patterns seen in other deployment operations.


121-126: LGTM - Clear success feedback.

The success message clearly indicates the deployment was canceled and includes the deployment short code for user reference.

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 (5)
apps/webapp/app/routes/api.v1.deployments.$deploymentId.progress.ts (1)

37-38: Optional: log malformed JSON to aid diagnostics.

Swallowing parse errors and treating the body as {} is fine here. Consider logging at debug to trace bad clients.

Apply this diff:

-  const [, rawBody] = await tryCatch(request.json());
+  const [parseErr, rawBody] = await tryCatch(request.json());
+  if (parseErr) {
+    logger.debug("Invalid JSON in progress request body; treating as empty object", {
+      url: request.url,
+    });
+  }
apps/webapp/app/routes/api.v1.deployments.$deploymentId.cancel.ts (1)

37-39: Optional: add debug log on JSON parse failure.

Helps trace clients sending malformed JSON without changing behavior.

-  const [, rawBody] = await tryCatch(request.json());
+  const [parseErr, rawBody] = await tryCatch(request.json());
+  if (parseErr) {
+    logger.debug("Invalid JSON in cancel request body; treating as empty object", {
+      url: request.url,
+    });
+  }
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route.tsx (3)

416-418: Avoid duplicating final status lists in UI.

Hardcoding finalStatuses in the client risks drift from server truth. Centralize in a shared module (e.g., a client-shared constants file) and import here.

Example:

  • Create a shared finalDeploymentStatuses export in a client-available module and replace this array with that import.

528-543: Use the computed formAction for consistency and to prevent drift.

The isLoading check relies on formAction, but the Form uses a string literal. Use the variable.

-        <Form
-          action={`/resources/${projectId}/deployments/${deploymentShortCode}/rollback`}
-          method="post"
-        >
+        <Form action={formAction} method="post">

570-585: Same here: align Form action with formAction variable.

Prevents mismatches if the path changes.

-        <Form
-          action={`/resources/${projectId}/deployments/${deploymentShortCode}/promote`}
-          method="post"
-        >
+        <Form action={formAction} method="post">
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8e85316 and 4507835.

📒 Files selected for processing (5)
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route.tsx (7 hunks)
  • apps/webapp/app/routes/api.v1.deployments.$deploymentId.cancel.ts (1 hunks)
  • apps/webapp/app/routes/api.v1.deployments.$deploymentId.progress.ts (2 hunks)
  • apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts (1 hunks)
  • apps/webapp/app/v3/services/deployment.server.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Always prefer using isomorphic code like fetch, ReadableStream, etc. instead of Node.js specific code
For TypeScript, we usually use types over interfaces
Avoid enums
No default exports, use function declarations

Files:

  • apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts
  • apps/webapp/app/routes/api.v1.deployments.$deploymentId.cancel.ts
  • apps/webapp/app/routes/api.v1.deployments.$deploymentId.progress.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route.tsx
  • apps/webapp/app/v3/services/deployment.server.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

We use zod a lot in packages/core and in the webapp

Files:

  • apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts
  • apps/webapp/app/routes/api.v1.deployments.$deploymentId.cancel.ts
  • apps/webapp/app/routes/api.v1.deployments.$deploymentId.progress.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route.tsx
  • apps/webapp/app/v3/services/deployment.server.ts
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

When importing from @trigger.dev/core in the webapp, never import the root package path; always use one of the documented subpath exports from @trigger.dev/core’s package.json

Files:

  • apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts
  • apps/webapp/app/routes/api.v1.deployments.$deploymentId.cancel.ts
  • apps/webapp/app/routes/api.v1.deployments.$deploymentId.progress.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route.tsx
  • apps/webapp/app/v3/services/deployment.server.ts
{apps/webapp/app/**/*.server.{ts,tsx},apps/webapp/app/routes/**/*.ts}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access environment variables only via the env export from app/env.server.ts; do not reference process.env directly

Files:

  • apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts
  • apps/webapp/app/routes/api.v1.deployments.$deploymentId.cancel.ts
  • apps/webapp/app/routes/api.v1.deployments.$deploymentId.progress.ts
  • apps/webapp/app/v3/services/deployment.server.ts
apps/webapp/app/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Modules intended for test consumption under apps/webapp/app/**/*.ts must not read environment variables; accept configuration via options instead

Files:

  • apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts
  • apps/webapp/app/routes/api.v1.deployments.$deploymentId.cancel.ts
  • apps/webapp/app/routes/api.v1.deployments.$deploymentId.progress.ts
  • apps/webapp/app/v3/services/deployment.server.ts
🧬 Code graph analysis (5)
apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts (3)
apps/webapp/app/services/session.server.ts (1)
  • requireUserId (25-35)
apps/webapp/app/v3/services/deployment.server.ts (1)
  • DeploymentService (11-234)
apps/webapp/app/models/message.server.ts (2)
  • redirectWithErrorMessage (181-198)
  • redirectWithSuccessMessage (162-179)
apps/webapp/app/routes/api.v1.deployments.$deploymentId.cancel.ts (5)
apps/webapp/app/routes/api.v1.deployments.$deploymentId.progress.ts (1)
  • action (12-76)
apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts (1)
  • action (20-133)
apps/webapp/app/services/apiAuth.server.ts (1)
  • authenticateRequest (379-441)
packages/core/src/v3/schemas/api.ts (2)
  • CancelDeploymentRequestBody (388-390)
  • CancelDeploymentRequestBody (392-392)
apps/webapp/app/v3/services/deployment.server.ts (1)
  • DeploymentService (11-234)
apps/webapp/app/routes/api.v1.deployments.$deploymentId.progress.ts (1)
packages/core/src/v3/schemas/api.ts (2)
  • ProgressDeploymentRequestBody (380-384)
  • ProgressDeploymentRequestBody (386-386)
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route.tsx (3)
apps/webapp/app/components/primitives/Dialog.tsx (6)
  • Dialog (113-113)
  • DialogTrigger (114-114)
  • DialogContent (115-115)
  • DialogHeader (116-116)
  • DialogDescription (119-119)
  • DialogFooter (117-117)
apps/webapp/app/components/primitives/Buttons.tsx (1)
  • Button (296-331)
apps/webapp/app/components/primitives/Spinner.tsx (1)
  • SpinnerWhite (76-78)
apps/webapp/app/v3/services/deployment.server.ts (3)
apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV4.server.ts (1)
  • deployment (182-200)
apps/webapp/app/v3/services/failDeployment.server.ts (1)
  • FINAL_DEPLOYMENT_STATUSES (8-13)
apps/webapp/app/v3/services/timeoutDeployment.server.ts (1)
  • TimeoutDeploymentService (8-69)
⏰ 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). (23)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (13)
apps/webapp/app/routes/api.v1.deployments.$deploymentId.progress.ts (1)

2-2: Good use of guarded JSON parsing via tryCatch and subpath import.

Importing tryCatch from @trigger.dev/core/v3 aligns with our subpath guideline and avoids throwing on empty/invalid JSON.

apps/webapp/app/routes/api.v1.deployments.$deploymentId.cancel.ts (3)

37-39: Guarded JSON parse implemented correctly.

Using tryCatch to avoid request.json() throws and validating with zod keeps the route robust when the body is empty/invalid.


46-49: Correct mapping from API body to service input.

Passing canceledReason from body.data.reason matches the schema and service.


55-69: Error mapping looks solid and consistent with other routes.

Correct statuses, including ignoring timeout dequeue failures.

apps/webapp/app/v3/services/deployment.server.ts (4)

94-105: Installed timestamp set during BUILDING transition.

Setting installedAt when moving to BUILDING is coherent with exposing install milestones.


185-191: Final-state guard prevents canceling completed deployments.

Correct use of FINAL_DEPLOYMENT_STATUSES with a clear error path.


196-221: Concurrency-safe cancel write with proper verification.

Using updateMany with a status guard and checking result.count avoids TOCTOU issues.


222-233: Timeout cleanup after cancel.

Dequeueing the timeout job prevents post-cancel transitions; correct to surface a distinct error so callers can decide to ignore.

apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.cancel.ts (3)

11-13: Schema naming matches route intent.

cancelSchema is clear and exported; usage updated accordingly.


85-94: Accurate logging context for cancel failures.

Message and conditional cause logging look good.


95-125: Error-to-UX mapping is precise.

Good distinction for non-cancelable vs not found; ignoring dequeue failures as success is pragmatic.

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route.tsx (2)

597-621: Cancel dialog wiring looks correct.

Correct formAction usage, loading indicator, and danger styling.


433-444: Action labels streamlined.

“Rollback” and “Promote” labels are concise and consistent with menu context.

Also applies to: 454-465

@myftija myftija merged commit 700a6ea into main Sep 24, 2025
31 checks passed
@myftija myftija deleted the enable-cancelling-deployments branch September 24, 2025 09:14
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