Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@
}
}
},
"overrides": [
{
"includes": ["packages/worker/test/**"],
"linter": {
"rules": {
"suspicious": {
"noExplicitAny": "off"
}
}
}
}
],
"javascript": {
"formatter": {
"quoteStyle": "double"
Expand Down
24 changes: 24 additions & 0 deletions packages/worker/src/deployments/env-vars.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { decrypt, envVars } from "@shipyard/shared";
import { eq } from "drizzle-orm";
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
import type { Env } from "../config/env.js";

type DB = PostgresJsDatabase<Record<string, unknown>>;

export async function fetchDecryptedEnvVars(db: DB, env: Env, appId: string) {
const rows = await db.select().from(envVars).where(eq(envVars.appId, appId));

const masterKey = env.ENCRYPTION_KEY;
const result: Record<string, string> = {};

for (const row of rows as {
key: string;
value: string;
isSecret: boolean;
}[]) {
const val = row.isSecret ? decrypt(row.value, masterKey) : row.value;
result[row.key] = val;
}

return result;
}
61 changes: 61 additions & 0 deletions packages/worker/src/deployments/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import fs from "node:fs";
import path from "node:path";
import { buildJobs, deploymentLogs } from "@shipyard/shared";
import { and, eq } from "drizzle-orm";
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
import type { Env } from "../config/env.js";

type DB = PostgresJsDatabase<Record<string, unknown>>;

export const TWO_GB = 2 * 1024 * 1024 * 1024;

export function createWorkspace(env: Env, deploymentId: string): string {
const ws = path.join(env.BUILD_WORKSPACE_DIR, deploymentId);
fs.mkdirSync(ws, { recursive: true });
return ws;
}

export async function createBuildJobRow(
db: DB,
deploymentId: string,
stepName: string,
) {
await db.insert(buildJobs).values({
deploymentId,
step: stepName,
status: "running",
startedAt: new Date(),
});
}

export async function finalizeBuildJobRow(
db: DB,
deploymentId: string,
stepName: string,
ok: boolean,
attempts: number,
) {
await db
.update(buildJobs)
.set({
status: ok ? "success" : "failed",
finishedAt: new Date(),
attempts,
})
.where(
and(
eq(buildJobs.deploymentId, deploymentId),
eq(buildJobs.step, stepName),
eq(buildJobs.status, "running"),
),
);
}

export async function insertStructuredEvent(
db: DB,
deploymentId: string,
step: string,
content: string,
) {
await db.insert(deploymentLogs).values({ deploymentId, step, content });
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,19 @@ import {
organizationMembers,
users,
} from "@shipyard/shared";
import type { App } from "@shipyard/shared/schema";
import { asc, eq } from "drizzle-orm";
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";

type DB = PostgresJsDatabase<Record<string, unknown>>;

import type { Env } from "../config/env.js";
import { deployDockerfile } from "./deploy-dockerfile.js";
import { deployBuildPack } from "./deploy-static.js";
import type { DockerRunner } from "./docker/docker-runner.js";
import type { DockerRunner } from "../infrastructure/docker/docker-runner.js";
import { deployDockerfile } from "./strategies/dockerfile.js";
import { deployBuildPack } from "./strategies/static.js";

export interface OrchestratorDeps {
db: unknown;
db: DB;
env: Env;
logger: {
info: (obj: Record<string, unknown>, msg?: string) => void;
Expand All @@ -34,13 +39,8 @@ export interface OrchestratorDeps {
export class DeploymentOrchestrator {
constructor(private deps: OrchestratorDeps) {}

// biome-ignore lint/suspicious/noExplicitAny: Drizzle query builder type too complex to abstract
private get db() {
return this.deps.db as any;
}

private async fetchDeploymentContext(deploymentId: string) {
const rows = await this.db
const rows = await this.deps.db
.select({
deployment: deployments,
app: apps,
Expand All @@ -65,8 +65,7 @@ export class DeploymentOrchestrator {

async process(deploymentId: string): Promise<void> {
const ctx = await this.fetchDeploymentContext(deploymentId);
// biome-ignore lint/suspicious/noExplicitAny: DB query result shape known at runtime
const app: Record<string, any> = ctx.app;
const app: App = ctx.app;
const userId: string = ctx.userId;
const githubAccessToken: string | null = ctx.githubAccessToken;

Expand All @@ -80,7 +79,7 @@ export class DeploymentOrchestrator {
deploymentId,
app,
githubAccessToken,
this.db,
this.deps.db,
this.deps.env,
this.deps.logger,
this.deps.runner,
Expand All @@ -94,7 +93,7 @@ export class DeploymentOrchestrator {
app,
userId,
githubAccessToken,
this.db,
this.deps.db,
this.deps.env,
this.deps.logger,
this.deps.runner,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { db } from "../config/db.js";
import { getEnv } from "../config/env.js";
import { logger } from "../config/logger.js";
import { upsertFileRoute, upsertProxyRoute } from "./caddy/client.js";
import { DockerRunner } from "./docker/docker-runner.js";
import { DeploymentOrchestrator } from "./orchestrator.js";
import {
upsertFileRoute,
upsertProxyRoute,
} from "../infrastructure/caddy/client.js";
import { DockerRunner } from "../infrastructure/docker/docker-runner.js";
import { DeploymentOrchestrator } from "./pipeline.js";

export async function processDeployment(deploymentId: string): Promise<void> {
const orchestrator = new DeploymentOrchestrator({
Expand Down
89 changes: 0 additions & 89 deletions packages/worker/src/deployments/shared.ts

This file was deleted.

4 changes: 2 additions & 2 deletions packages/worker/src/deployments/steps/build-step.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { App } from "@shipyard/shared/schema";
import type { DockerRunner } from "../docker/docker-runner.js";
import type { DockerRunner } from "../../infrastructure/docker/docker-runner.js";
import type { LogBuffer } from "../../infrastructure/log-buffer.js";
import { classifyError } from "../errors/classify-error.js";
import type { LogBuffer } from "../logs/log-buffer.js";
import type { StepResult } from "./clone-step.js";

/**
Expand Down
6 changes: 3 additions & 3 deletions packages/worker/src/deployments/steps/clone-step.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { StepError } from "@shipyard/shared";
import type { App } from "@shipyard/shared/schema";
import type { DockerRunner } from "../docker/docker-runner.js";
import type { DockerRunner } from "../../infrastructure/docker/docker-runner.js";
import type { LogBuffer } from "../../infrastructure/log-buffer.js";
import { RetryExhaustedError, withRetry } from "../../infrastructure/retry.js";
import { classifyError } from "../errors/classify-error.js";
import type { LogBuffer } from "../logs/log-buffer.js";
import { RetryExhaustedError, withRetry } from "../utils/retry.js";

/** Result returned by a build step — ok or classified error. */
export type StepResult = {
Expand Down
6 changes: 3 additions & 3 deletions packages/worker/src/deployments/steps/install-step.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { StepError } from "@shipyard/shared";
import type { App } from "@shipyard/shared/schema";
import type { DockerRunner } from "../docker/docker-runner.js";
import type { DockerRunner } from "../../infrastructure/docker/docker-runner.js";
import type { LogBuffer } from "../../infrastructure/log-buffer.js";
import { RetryExhaustedError, withRetry } from "../../infrastructure/retry.js";
import { classifyError } from "../errors/classify-error.js";
import type { LogBuffer } from "../logs/log-buffer.js";
import { RetryExhaustedError, withRetry } from "../utils/retry.js";
import type { StepResult } from "./clone-step.js";

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/worker/src/deployments/steps/verify-step.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from "node:fs";
import path from "node:path";
import { getEnv } from "../../config/env.js";
import type { LogBuffer } from "../logs/log-buffer.js";
import type { LogBuffer } from "../../infrastructure/log-buffer.js";
import type { StepResult } from "./clone-step.js";

/** Filenames to exclude from output file count. */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import fs from "node:fs";
import path from "node:path";
import { apps, deployments, domains } from "@shipyard/shared";
import type { App } from "@shipyard/shared/schema";
import { and, eq } from "drizzle-orm";
import type { DockerRunner } from "./docker/docker-runner.js";
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
import type { Env } from "../../config/env.js";
import type { DockerRunner } from "../../infrastructure/docker/docker-runner.js";
import { fetchDecryptedEnvVars } from "../env-vars.js";

type DB = PostgresJsDatabase<Record<string, unknown>>;

import {
createBuildJobRow,
createWorkspace,
fetchDecryptedEnvVars,
finalizeBuildJobRow,
insertStructuredEvent,
} from "./shared.js";
} from "../events.js";

const PORT_CONFLICT_RETRIES = 3;
const PORT_CONFLICT_BACKOFF_MS = 2000;
Expand Down Expand Up @@ -45,13 +51,10 @@ async function runLongLivedWithRetry(

export async function deployDockerfile(
deploymentId: string,
// biome-ignore lint/suspicious/noExplicitAny: DB query result shape known at runtime
app: Record<string, any>,
app: App,
githubAccessToken: string | null,
// biome-ignore lint/suspicious/noExplicitAny: Drizzle query builder type too complex to abstract
db: any,
// biome-ignore lint/suspicious/noExplicitAny: runtime shape matches Env
env: any,
db: DB,
env: Env,
logger: {
info: (obj: Record<string, unknown>, msg?: string) => void;
warn: (obj: Record<string, unknown>, msg?: string) => void;
Expand Down
Loading
Loading