feat(orchestrator): add support for Docker Compose project deployments - #32
feat(orchestrator): add support for Docker Compose project deployments#32Lftobs wants to merge 15 commits into
Conversation
merge to main
merge to main
chore: merge to main
project deployments - Update database schema to store compose-specific metadata - Enhance Caddy dynamic ingress to route traffic to specific services - Extend project/domain APIs to support service target configuration - Refactor documentation landing page and UI components
📝 WalkthroughWalkthroughThe pull request adds Docker Compose project configuration, validation, deployment orchestration, service-specific domain routing, database provisioning recovery, a multi-step project creation page, session refresh handling, and a redesigned documentation landing page. ChangesCompose platform
Domain service routing
Database provisioning recovery
Session refresh
Documentation refresh
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant CreateProjectPage
participant ProjectsAPI
participant ComposeOrchestrator
participant Caddy
User->>CreateProjectPage: Configure Compose services
CreateProjectPage->>ProjectsAPI: Create project and deployment
ProjectsAPI->>ComposeOrchestrator: Build and deploy Compose stack
ComposeOrchestrator->>Caddy: Generate and reload service routes
Caddy-->>CreateProjectPage: Return deployed runtime URL
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 17
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/api/src/utils/domain-verifier.ts (1)
127-155: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winResolve the fallback port before generating custom blocks.
The loop formats
customBlocksbefore thePORTenvironment variable can updateport. If a domain hastargetServicebut notargetPort, its custom block usesconfig.appInternalPortwhile the primary block can usePORT.Read and validate
PORTbefore the domain loop, or defer custom-block formatting until after port resolution. Add a regression test for a target service withouttargetPort.🤖 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 `@apps/api/src/utils/domain-verifier.ts` around lines 127 - 155, The domain loop currently builds custom blocks before the PORT environment variable can update the fallback port. In the domain-verification flow around listEnvironmentVariablesForDeploy and customBlocks generation, resolve and validate PORT before iterating verified domains, or defer block formatting until afterward, so targetService entries without targetPort use the resolved port consistently with the primary block. Add a regression test covering a target service with no targetPort.
🧹 Nitpick comments (3)
apps/web/src/components/project/settings/ProjectSettingsTab.tsx (1)
143-143: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRemove the nonessential source comment.
The JSX structure already identifies this section.
As per coding guidelines,
**/*.{ts,tsx,js,jsx}files must have no comments in source code unless absolutely necessary.🤖 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 `@apps/web/src/components/project/settings/ProjectSettingsTab.tsx` at line 143, Remove the nonessential JSX comment `{/* Build Strategy */}` from the project settings component, leaving the surrounding JSX structure and behavior unchanged.Source: Coding guidelines
apps/web/src/routes/CreateProjectPage.tsx (1)
44-96: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRemove the new section comments.
The state grouping and JSX hierarchy already identify these sections.
As per coding guidelines,
**/*.{ts,tsx,js,jsx}files must have no comments in source code unless absolutely necessary.🤖 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 `@apps/web/src/routes/CreateProjectPage.tsx` around lines 44 - 96, Remove the section comments around the state declarations in the component, including “Form State,” “Git Settings,” “ZIP Settings,” “Build & Runtime Options (Railpack),” “Docker Compose Settings,” and “Environment Variables State & Tabs.” Leave the existing state declarations and JSX hierarchy unchanged.Source: Coding guidelines
apps/api/src/orchestrator/compose.ts (1)
46-94: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRemove comments that restate parser control flow.
These comments only describe the adjacent conditions and regexes. Use clear helper names when context needs explanation.
As per coding guidelines,
**/*.{ts,tsx,js,jsx}: “No comments in source code unless absolutely necessary.”🤖 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 `@apps/api/src/orchestrator/compose.ts` around lines 46 - 94, Remove the redundant control-flow comments in the parser block around the services, top-level block, service declaration, ports block, inline port syntax, and port-item handling; preserve the existing parsing logic unchanged and rely on the conditions, regexes, and helper names for context.Source: Coding guidelines
🤖 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 `@apps/api/src/api/domains/index.ts`:
- Around line 33-38: Update addToCaddyRoute and both domain-verification call
sites so verified domains use their persisted Domain targetService and
targetPort values when generating Caddy routing. Generate a dedicated proxy
block for targeted domains instead of always appending to the primary Caddy
block, while preserving existing routing for domains without targets.
In `@apps/api/src/databases/manager.ts`:
- Around line 67-78: Update the provisioning flow after the readiness loop to
throw a timeout error instead of resolving normally after updateDatabaseStatus
records the database as failed. Ensure the existing catch handling captures and
propagates this error while preserving the failed status update.
In `@apps/api/src/orchestrator/compose.ts`:
- Around line 223-263: Propagate the deployment controller’s abort signal
through buildWithCompose and deployWithCompose into spawnComposeCommand,
extending its options as needed. In spawnComposeCommand, listen for signal
abortion and terminate the spawned Compose child process, while preserving
normal completion and error handling.
- Around line 11-17: Update findComposeFilePath to resolve and realpath the
workspace and sourceDir-derived candidate directory, rejecting any candidate
outside the resolved workspace, including paths escaping through ../ segments.
Use the validated candidate directory when locating docker-compose.yml or
docker-compose.yaml and ensure the same validated directory is used as the
deployment cwd.
- Around line 41-96: Replace the regex-based Compose parsing in
parseComposeTarget and parseAllComposeServices with normalized Compose data from
a structured YAML parser or Docker Compose output. Implement one shared
service-extraction function used by both callers, handling host-bound mappings
such as 127.0.0.1:8080:80 and long-form ports while selecting the container
target port so servicePorts is populated instead of falling back to 3000.
In `@apps/api/src/orchestrator/pipeline.ts`:
- Around line 575-700: Extract the compose-specific branch from the deployment
orchestration around deployWithCompose into a dedicated, feature-grouped Compose
deployment module. Move stack replacement, network attachment, service/container
resolution, Caddy route generation and reload, and runtime URL/name assignment
there, exposing a narrow result contract containing the runtime container name
and live URL; update the parent orchestration to call this module while
preserving the existing non-compose path and behavior.
- Around line 412-427: Update the Compose deployment and rollback flow around
buildWithCompose, rollbackTo, and deployContainer so Compose rollback does not
attempt to start the unavailable imageTag. Either persist or recreate the prior
Compose source revision and restore it through the Compose deployment path,
including its services and Caddy routes; otherwise reject rollback requests for
Compose deployments before invoking single-container rollback logic.
In `@apps/api/src/utils/validate.ts`:
- Around line 27-31: Reject non-number and non-decimal-string values before
conversion in validate.ts's port validation, preserving the existing 1–65535
integer rule. Add boolean and array failure assertions in
apps/api/src/utils/__tests__/validate.test.ts lines 22-27. In
apps/api/src/api/projects/index.ts lines 22-26, detect composePort by presence
rather than truthiness, reuse the strict port parser, and treat only null as an
explicit clear operation.
In `@apps/docs/src/components/Hero.astro`:
- Around line 10-13: Update the Hero component’s props and defaults so accepted
values are not ignored: either render tag, titleNormal, and titleItalic in the
markup around the hardcoded title and commented tag usage, or remove these props
and their default values from the Props definition and component setup. Keep the
chosen approach consistent with the component’s rendered output.
In `@apps/docs/src/components/HowItWorks.astro`:
- Around line 44-47: Update the descriptive text in the “Instant Auto Routing”
section to say the internal Caddy engine reloads dynamic routes “with zero
downtime,” preserving the existing claim and surrounding content.
In `@apps/docs/src/pages/index.astro`:
- Around line 203-204: Replace the inline style on the “dequel” span in the page
markup with equivalent static Tailwind utility classes for font weight, font
size, letter spacing, and muted text color. Keep the rendered appearance
unchanged and remove the style attribute.
In `@apps/docs/src/styles/global.css`:
- Around line 895-917: Remove the quotation marks around the single-word Play
font family in the affected .cf-pill-btn-white and .cf-pill-btn-glass
declarations, preserving the existing sans-serif fallback.
In `@apps/web/src/components/project/domains/DomainsTab.tsx`:
- Around line 495-522: Refactor DomainsTab into feature-local components so the
file is under 500 lines: extract the add-domain dialog and domain-list UI into
dedicated components within the domains feature folder, while keeping domain
state and API mutations in a focused container or hook used by DomainsTab.
Preserve the existing compose-specific fields, behavior, and component
interactions.
In `@apps/web/src/components/project/settings/ProjectSettingsTab.tsx`:
- Around line 47-58: Update the composeServices parsing flow in
ProjectSettingsTab to validate and normalize every parsed service row before
calling setComposeServicesList. Require each row to be a non-null object with
string id, serviceName, port, and subdomain fields; if any row fails validation,
use the existing default service entry instead.
- Around line 83-96: Only include composeService, composePort, and
composeServices in the updateProjectMutation payload within
ProjectSettingsTab.tsx when buildType === "compose"; omit them for Railpack
builds. Apply the same conditional payload handling in CreateProjectPage.tsx at
lines 243-261, while preserving the existing Compose values and validation
behavior for Compose builds.
In `@apps/web/src/routes/CreateProjectPage.tsx`:
- Around line 263-297: Reorder the submission flow so the staged environment
variables and managed database are created before the deployment request. Move
the `api.createDeployment` block below the `stagedEnvs` and `provisionDb`
handling in the surrounding submit function, while preserving the existing
status updates and payloads.
- Around line 72-76: Update the step-four and sidebar summary displays in
CreateProjectPage to derive the primary service and port from
composeServicesList[0] instead of the stale composeService and composePort
state. Reuse the first entry’s serviceName and port values, preserving the
existing Auto-detect fallback when they are empty, and remove the duplicate
state only if it is no longer used elsewhere.
---
Outside diff comments:
In `@apps/api/src/utils/domain-verifier.ts`:
- Around line 127-155: The domain loop currently builds custom blocks before the
PORT environment variable can update the fallback port. In the
domain-verification flow around listEnvironmentVariablesForDeploy and
customBlocks generation, resolve and validate PORT before iterating verified
domains, or defer block formatting until afterward, so targetService entries
without targetPort use the resolved port consistently with the primary block.
Add a regression test covering a target service with no targetPort.
---
Nitpick comments:
In `@apps/api/src/orchestrator/compose.ts`:
- Around line 46-94: Remove the redundant control-flow comments in the parser
block around the services, top-level block, service declaration, ports block,
inline port syntax, and port-item handling; preserve the existing parsing logic
unchanged and rely on the conditions, regexes, and helper names for context.
In `@apps/web/src/components/project/settings/ProjectSettingsTab.tsx`:
- Line 143: Remove the nonessential JSX comment `{/* Build Strategy */}` from
the project settings component, leaving the surrounding JSX structure and
behavior unchanged.
In `@apps/web/src/routes/CreateProjectPage.tsx`:
- Around line 44-96: Remove the section comments around the state declarations
in the component, including “Form State,” “Git Settings,” “ZIP Settings,” “Build
& Runtime Options (Railpack),” “Docker Compose Settings,” and “Environment
Variables State & Tabs.” Leave the existing state declarations and JSX hierarchy
unchanged.
🪄 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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 6bd325b6-a68e-4470-aad9-4021eb7def87
📒 Files selected for processing (39)
apps/api/src/api/domains/index.tsapps/api/src/api/projects/index.tsapps/api/src/databases/manager.tsapps/api/src/db/migrations/0004_early_sunfire.sqlapps/api/src/db/migrations/0005_famous_grandmaster.sqlapps/api/src/db/migrations/0006_cheerful_vance_astro.sqlapps/api/src/db/migrations/meta/0004_snapshot.jsonapps/api/src/db/migrations/meta/0005_snapshot.jsonapps/api/src/db/migrations/meta/0006_snapshot.jsonapps/api/src/db/migrations/meta/_journal.jsonapps/api/src/db/repo/domains.tsapps/api/src/db/repo/projects.tsapps/api/src/db/schema.tsapps/api/src/orchestrator/__tests__/compose.test.tsapps/api/src/orchestrator/compose.tsapps/api/src/orchestrator/pipeline.tsapps/api/src/types.tsapps/api/src/utils/__tests__/domain-verifier.test.tsapps/api/src/utils/__tests__/validate.test.tsapps/api/src/utils/domain-verifier.tsapps/api/src/utils/validate.tsapps/docs/.astro/astro/content.d.tsapps/docs/.astro/settings.jsonapps/docs/src/components/CTA.astroapps/docs/src/components/Comparison.astroapps/docs/src/components/Features.astroapps/docs/src/components/Hero.astroapps/docs/src/components/HowItWorks.astroapps/docs/src/components/Stats.astroapps/docs/src/components/TerminalDemo.astroapps/docs/src/pages/index.astroapps/docs/src/styles/global.cssapps/web/src/api/client.tsapps/web/src/components/project/domains/DomainsTab.tsxapps/web/src/components/project/settings/ProjectSettingsTab.tsxapps/web/src/routes/CreateProjectPage.tsxapps/web/src/routes/Dashboard.tsxapps/web/src/routes/index.tsxapps/web/src/types/index.ts
| const domain = await createDomain({ | ||
| projectId: params.id, | ||
| domain: body.domain, | ||
| type: body.type ?? "custom", | ||
| targetService: body.targetService || null, | ||
| targetPort, |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Preserve target routing for domains verified after deployment.
This route persists targetService and targetPort, but the verification flow calls addToCaddyRoute without either value. addToCaddyRoute only appends the domain to the primary Caddy block. A target domain added after deployment therefore routes to the default container and port until a later redeploy regenerates the snippet.
Update addToCaddyRoute and both verification call sites to generate a dedicated proxy block from the persisted Domain, or regenerate the project snippet from persisted domain records.
🤖 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 `@apps/api/src/api/domains/index.ts` around lines 33 - 38, Update
addToCaddyRoute and both domain-verification call sites so verified domains use
their persisted Domain targetService and targetPort values when generating Caddy
routing. Generate a dedicated proxy block for targeted domains instead of always
appending to the primary Caddy block, while preserving existing routing for
domains without targets.
| for (let i = 0; i < 30; i++) { | ||
| try { | ||
| const status = await run(dockerBin, ['inspect', '-f', '{{.State.Status}}', containerName]); | ||
| if (status.trim() === 'running') { | ||
| await updateDatabaseStatus(dbRecord.id, 'running', containerName); | ||
| return; | ||
| } | ||
| } catch {} | ||
| await new Promise(r => setTimeout(r, 2000)); | ||
| } | ||
|
|
||
| await updateDatabaseStatus(dbRecord.id, 'failed', containerName); | ||
| await updateDatabaseStatus(dbRecord.id, 'failed', containerName); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Fail the provisioning operation after the readiness timeout.
At Line 78, the function records failed and then resolves normally. Callers can treat the provisioning operation as successful and continue with a database that never reached running.
Throw a timeout error here. The existing catch block will record the failed status, log the error, and propagate the failure.
Proposed fix
- await updateDatabaseStatus(dbRecord.id, 'failed', containerName);
+ throw new Error(`Database ${dbRecord.id} did not reach running state before the readiness timeout`);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| for (let i = 0; i < 30; i++) { | |
| try { | |
| const status = await run(dockerBin, ['inspect', '-f', '{{.State.Status}}', containerName]); | |
| if (status.trim() === 'running') { | |
| await updateDatabaseStatus(dbRecord.id, 'running', containerName); | |
| return; | |
| } | |
| } catch {} | |
| await new Promise(r => setTimeout(r, 2000)); | |
| } | |
| await updateDatabaseStatus(dbRecord.id, 'failed', containerName); | |
| await updateDatabaseStatus(dbRecord.id, 'failed', containerName); | |
| for (let i = 0; i < 30; i++) { | |
| try { | |
| const status = await run(dockerBin, ['inspect', '-f', '{{.State.Status}}', containerName]); | |
| if (status.trim() === 'running') { | |
| await updateDatabaseStatus(dbRecord.id, 'running', containerName); | |
| return; | |
| } | |
| } catch {} | |
| await new Promise(r => setTimeout(r, 2000)); | |
| } | |
| throw new Error(`Database ${dbRecord.id} did not reach running state before the readiness timeout`); |
🧰 Tools
🪛 ast-grep (0.45.0)
[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { spawn } from 'node:child_process';
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(detect-child-process-typescript)
🤖 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 `@apps/api/src/databases/manager.ts` around lines 67 - 78, Update the
provisioning flow after the readiness loop to throw a timeout error instead of
resolving normally after updateDatabaseStatus records the database as failed.
Ensure the existing catch handling captures and propagates this error while
preserving the failed status update.
| export const findComposeFilePath = (workspacePath: string, sourceDir?: string | null): string | null => { | ||
| const base = sourceDir ? join(workspacePath, sourceDir.replace(/^\//, "")) : workspacePath; | ||
| const ymlPath = join(base, "docker-compose.yml"); | ||
| if (existsSync(ymlPath)) return ymlPath; | ||
| const yamlPath = join(base, "docker-compose.yaml"); | ||
| if (existsSync(yamlPath)) return yamlPath; | ||
| return null; |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Block traversal outside the deployment workspace.
sourceDir reaches this function from the project API. Removing only the first / leaves ../ segments intact. join() can then select a Compose file and working directory outside workspacePath.
Resolve and realpath the workspace and candidate directory. Reject the candidate when it is outside the workspace. Use the validated directory for both the Compose file and cwd.
🤖 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 `@apps/api/src/orchestrator/compose.ts` around lines 11 - 17, Update
findComposeFilePath to resolve and realpath the workspace and sourceDir-derived
candidate directory, rejecting any candidate outside the resolved workspace,
including paths escaping through ../ segments. Use the validated candidate
directory when locating docker-compose.yml or docker-compose.yaml and ensure the
same validated directory is used as the deployment cwd.
| for (let i = 0; i < lines.length; i++) { | ||
| const line = lines[i]; | ||
| const trimmed = line.trim(); | ||
| if (!trimmed || trimmed.startsWith("#")) continue; | ||
|
|
||
| // Check if entering services block | ||
| if (line.match(/^services:/)) { | ||
| inServicesBlock = true; | ||
| continue; | ||
| } | ||
|
|
||
| // Top level block exit | ||
| if (line.match(/^[a-zA-Z0-9_-]+:/) && !line.startsWith("services:")) { | ||
| inServicesBlock = false; | ||
| currentService = ""; | ||
| } | ||
|
|
||
| if (!inServicesBlock) continue; | ||
|
|
||
| // Service declaration under services: (2 spaces indentation) | ||
| const serviceMatch = line.match(/^ ([a-zA-Z0-9_-]+):/); | ||
| if (serviceMatch) { | ||
| currentService = serviceMatch[1]; | ||
| servicesList.push(currentService); | ||
| inPortsBlock = false; | ||
| continue; | ||
| } | ||
|
|
||
| if (currentService) { | ||
| // Check if entering ports block | ||
| if (line.match(/^\s+ports:/)) { | ||
| inPortsBlock = true; | ||
| // Inline array syntax: ports: ["8080:80"] or ports: [3000] | ||
| const inlineMatch = trimmed.match(/ports:\s*\[\s*["']?(\d+)(?::(\d+))?["']?\s*\]/i); | ||
| if (inlineMatch) { | ||
| const target = inlineMatch[2] || inlineMatch[1]; | ||
| servicePorts[currentService] = Number(target); | ||
| inPortsBlock = false; | ||
| } | ||
| continue; | ||
| } | ||
|
|
||
| // Port item under ports block | ||
| if (inPortsBlock && line.match(/^\s+-\s*/)) { | ||
| const portMatch = trimmed.match(/-\s*["']?(\d+)(?::(\d+))?["']?/); | ||
| if (portMatch) { | ||
| const targetPort = portMatch[2] || portMatch[1]; | ||
| if (!servicePorts[currentService]) { | ||
| servicePorts[currentService] = Number(targetPort); | ||
| } | ||
| } | ||
| } else if (line.match(/^\s+[a-zA-Z0-9_-]+:/)) { | ||
| inPortsBlock = false; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Replace the regex-based Compose parser.
The parser accepts only limited short port syntax. Valid mappings such as "127.0.0.1:8080:80" and long-form ports entries leave servicePorts unset. The deployment then routes Caddy to the fallback port 3000.
Parse normalized Compose data with a structured parser or Docker Compose output. Share one service-extraction function between parseComposeTarget and parseAllComposeServices.
Also applies to: 154-203
🤖 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 `@apps/api/src/orchestrator/compose.ts` around lines 41 - 96, Replace the
regex-based Compose parsing in parseComposeTarget and parseAllComposeServices
with normalized Compose data from a structured YAML parser or Docker Compose
output. Implement one shared service-extraction function used by both callers,
handling host-bound mappings such as 127.0.0.1:8080:80 and long-form ports while
selecting the container target port so servicePorts is populated instead of
falling back to 3000.
| const spawnComposeCommand = ( | ||
| args: string[], | ||
| cwd: string, | ||
| envVars?: Record<string, string>, | ||
| onLog?: (line: string) => Promise<void>, | ||
| ): Promise<{ code: number; stdout: string; stderr: string }> => { | ||
| return new Promise((resolve, reject) => { | ||
| const child = spawn(dockerBin, ["compose", ...args], { | ||
| cwd, | ||
| env: { ...process.env, ...(envVars || {}) }, | ||
| stdio: ["ignore", "pipe", "pipe"], | ||
| }); | ||
|
|
||
| let stdout = ""; | ||
| let stderr = ""; | ||
|
|
||
| child.stdout.on("data", (chunk) => { | ||
| const str = String(chunk); | ||
| stdout += str; | ||
| if (onLog) { | ||
| for (const line of str.split("\n").map((l) => l.trim()).filter(Boolean)) { | ||
| void onLog(line); | ||
| } | ||
| } | ||
| }); | ||
|
|
||
| child.stderr.on("data", (chunk) => { | ||
| const str = String(chunk); | ||
| stderr += str; | ||
| if (onLog) { | ||
| for (const line of str.split("\n").map((l) => l.trim()).filter(Boolean)) { | ||
| void onLog(line); | ||
| } | ||
| } | ||
| }); | ||
|
|
||
| child.on("error", reject); | ||
| child.on("close", (code) => { | ||
| resolve({ code: code ?? 1, stdout: stdout.trim(), stderr: stderr.trim() }); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Terminate Compose builds when deployment cancellation occurs.
cancelDeployment aborts its controller, but this process does not receive an abort signal. A canceled Compose build continues to use Docker and host resources until it exits.
Pass the controller signal through buildWithCompose to spawnComposeCommand. Stop the child process when that signal aborts. Apply the same mechanism to deployWithCompose.
🤖 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 `@apps/api/src/orchestrator/compose.ts` around lines 223 - 263, Propagate the
deployment controller’s abort signal through buildWithCompose and
deployWithCompose into spawnComposeCommand, extending its options as needed. In
spawnComposeCommand, listen for signal abortion and terminate the spawned
Compose child process, while preserving normal completion and error handling.
time - Add `finished_at` column to deployments table - Implement status-based timestamping for deployment completion - Update runtime reconciliation to skip non-existent containers - Fix Ko-fi popup mounting in dashboard sidebar - Update docker-compose configuration for local builds
customization - Add `project_type`, `buildCommand`, and `startCommand` fields to projects. - Implement dynamic `railpack.json` generation for better build/runtime compatibility. - Add `ProjectSettingsTab` to the dashboard for managing build settings. - Update Caddy reverse proxy to correctly pass the Host header to upstream containers.
project deployments - Update database schema to store compose-specific metadata - Enhance Caddy dynamic ingress to route traffic to specific services - Extend project/domain APIs to support service target configuration - Refactor documentation landing page and UI components
027e32d to
5b37f3a
Compare
deployment support - Refactor compose service parsing to support long-form port syntax. - Extract compose deployment logic into dedicated module. - Add validation to block rollbacks for compose deployments. - Add error handling for database provisioning timeouts. - Include `yaml` package to improve parsing reliability.
…l into feat/managed-db-and-compose
Description
Type of Change
How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce.
bun testinapps/api/)Checklist
bun testinapps/api/and all tests passbun run sync-versions)Screenshots (if applicable)
Additional Context
Add any other context about the PR here (e.g., migration notes, deployment considerations, rollback strategy).
Summary by CodeRabbit
New Features
Bug Fixes
Documentation