Fix broken cloud deploys by using depot ephemeral registry, skip the registry proxy (#1637)
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"trigger.dev": patch
|
||||
"@trigger.dev/core": patch
|
||||
---
|
||||
|
||||
Fix broken cloud deploys by using depot ephemeral registry
|
||||
@@ -147,7 +147,10 @@ const EnvironmentSchema = z.object({
|
||||
CONTAINER_REGISTRY_ORIGIN: z.string().optional(),
|
||||
CONTAINER_REGISTRY_USERNAME: z.string().optional(),
|
||||
CONTAINER_REGISTRY_PASSWORD: z.string().optional(),
|
||||
ENABLE_REGISTRY_PROXY: z.string().optional(),
|
||||
DEPLOY_REGISTRY_HOST: z.string().optional(),
|
||||
DEPLOY_REGISTRY_USERNAME: z.string().optional(),
|
||||
DEPLOY_REGISTRY_PASSWORD: z.string().optional(),
|
||||
DEPLOY_REGISTRY_NAMESPACE: z.string().default("trigger"),
|
||||
DEPLOY_TIMEOUT_MS: z.coerce
|
||||
.number()
|
||||
|
||||
+24
-13
@@ -1,9 +1,10 @@
|
||||
import { ActionFunctionArgs, json } from "@remix-run/server-runtime";
|
||||
import { StartDeploymentIndexingRequestBody } from "@trigger.dev/core/v3";
|
||||
import { FinalizeDeploymentRequestBody } from "@trigger.dev/core/v3";
|
||||
import { z } from "zod";
|
||||
import { authenticateApiRequest } from "~/services/apiAuth.server";
|
||||
import { logger } from "~/services/logger.server";
|
||||
import { StartDeploymentIndexing } from "~/v3/services/startDeploymentIndexing.server";
|
||||
import { ServiceValidationError } from "~/v3/services/baseService.server";
|
||||
import { FinalizeDeploymentV2Service } from "~/v3/services/finalizeDeploymentV2";
|
||||
|
||||
const ParamsSchema = z.object({
|
||||
deploymentId: z.string(),
|
||||
@@ -34,21 +35,31 @@ export async function action({ request, params }: ActionFunctionArgs) {
|
||||
const { deploymentId } = parsedParams.data;
|
||||
|
||||
const rawBody = await request.json();
|
||||
const body = StartDeploymentIndexingRequestBody.safeParse(rawBody);
|
||||
const body = FinalizeDeploymentRequestBody.safeParse(rawBody);
|
||||
|
||||
if (!body.success) {
|
||||
return json({ error: "Invalid body", issues: body.error.issues }, { status: 400 });
|
||||
}
|
||||
|
||||
const service = new StartDeploymentIndexing();
|
||||
try {
|
||||
const service = new FinalizeDeploymentV2Service();
|
||||
await service.call(authenticatedEnv, deploymentId, body.data);
|
||||
|
||||
const deployment = await service.call(authenticatedEnv, deploymentId, body.data);
|
||||
|
||||
return json(
|
||||
{
|
||||
id: deployment.friendlyId,
|
||||
contentHash: deployment.contentHash,
|
||||
},
|
||||
{ status: 200 }
|
||||
);
|
||||
return json(
|
||||
{
|
||||
id: deploymentId,
|
||||
},
|
||||
{ status: 200 }
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof ServiceValidationError) {
|
||||
return json({ error: error.message }, { status: 400 });
|
||||
} else if (error instanceof Error) {
|
||||
logger.error("Error finalizing deployment", { error: error.message });
|
||||
return json({ error: `Internal server error: ${error.message}` }, { status: 500 });
|
||||
} else {
|
||||
logger.error("Error finalizing deployment", { error: String(error) });
|
||||
return json({ error: "Internal server error" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -435,6 +435,11 @@ function initializeProxy() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!env.ENABLE_REGISTRY_PROXY || env.ENABLE_REGISTRY_PROXY === "false") {
|
||||
logger.info("Registry proxy is disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
return new RegistryProxy({
|
||||
origin: env.CONTAINER_REGISTRY_ORIGIN,
|
||||
auth: {
|
||||
|
||||
@@ -16,7 +16,7 @@ export class FinalizeDeploymentService extends BaseService {
|
||||
id: string,
|
||||
body: FinalizeDeploymentRequestBody
|
||||
) {
|
||||
const deployment = await this._prisma.workerDeployment.findUnique({
|
||||
const deployment = await this._prisma.workerDeployment.findFirst({
|
||||
where: {
|
||||
friendlyId: id,
|
||||
environmentId: authenticatedEnv.id,
|
||||
@@ -48,6 +48,12 @@ export class FinalizeDeploymentService extends BaseService {
|
||||
throw new ServiceValidationError("Worker deployment is not in DEPLOYING status");
|
||||
}
|
||||
|
||||
let imageReference = body.imageReference;
|
||||
|
||||
if (registryProxy && body.selfHosted !== true && body.skipRegistryProxy !== true) {
|
||||
imageReference = registryProxy.rewriteImageReference(body.imageReference);
|
||||
}
|
||||
|
||||
// Link the deployment with the background worker
|
||||
const finalizedDeployment = await this._prisma.workerDeployment.update({
|
||||
where: {
|
||||
@@ -56,10 +62,7 @@ export class FinalizeDeploymentService extends BaseService {
|
||||
data: {
|
||||
status: "DEPLOYED",
|
||||
deployedAt: new Date(),
|
||||
imageReference:
|
||||
registryProxy && body.selfHosted !== true
|
||||
? registryProxy.rewriteImageReference(body.imageReference)
|
||||
: body.imageReference,
|
||||
imageReference: imageReference,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,259 @@
|
||||
import { ExternalBuildData, FinalizeDeploymentRequestBody } from "@trigger.dev/core/v3/schemas";
|
||||
import { AuthenticatedEnvironment } from "~/services/apiAuth.server";
|
||||
import { logger } from "~/services/logger.server";
|
||||
import { BaseService, ServiceValidationError } from "./baseService.server";
|
||||
import { join } from "node:path";
|
||||
import { tmpdir } from "node:os";
|
||||
import { mkdtemp, writeFile } from "node:fs/promises";
|
||||
import { env } from "~/env.server";
|
||||
import { depot as execDepot } from "@depot/cli";
|
||||
import { FinalizeDeploymentService } from "./finalizeDeployment.server";
|
||||
|
||||
export class FinalizeDeploymentV2Service extends BaseService {
|
||||
public async call(
|
||||
authenticatedEnv: AuthenticatedEnvironment,
|
||||
id: string,
|
||||
body: FinalizeDeploymentRequestBody
|
||||
) {
|
||||
// if it's self hosted, lets just use the v1 finalize deployment service
|
||||
if (body.selfHosted) {
|
||||
const finalizeService = new FinalizeDeploymentService();
|
||||
|
||||
return finalizeService.call(authenticatedEnv, id, body);
|
||||
}
|
||||
|
||||
const deployment = await this._prisma.workerDeployment.findFirst({
|
||||
where: {
|
||||
friendlyId: id,
|
||||
environmentId: authenticatedEnv.id,
|
||||
},
|
||||
include: {
|
||||
environment: true,
|
||||
worker: {
|
||||
include: {
|
||||
tasks: true,
|
||||
project: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!deployment) {
|
||||
logger.error("Worker deployment not found", { id });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!deployment.worker) {
|
||||
logger.error("Worker deployment does not have a worker", { id });
|
||||
throw new ServiceValidationError("Worker deployment does not have a worker");
|
||||
}
|
||||
|
||||
if (deployment.status !== "DEPLOYING") {
|
||||
logger.error("Worker deployment is not in DEPLOYING status", { id });
|
||||
throw new ServiceValidationError("Worker deployment is not in DEPLOYING status");
|
||||
}
|
||||
|
||||
const externalBuildData = deployment.externalBuildData
|
||||
? ExternalBuildData.safeParse(deployment.externalBuildData)
|
||||
: undefined;
|
||||
|
||||
if (!externalBuildData) {
|
||||
throw new ServiceValidationError("External build data is missing");
|
||||
}
|
||||
|
||||
if (!externalBuildData.success) {
|
||||
throw new ServiceValidationError("External build data is invalid");
|
||||
}
|
||||
|
||||
if (
|
||||
!env.DEPLOY_REGISTRY_HOST ||
|
||||
!env.DEPLOY_REGISTRY_USERNAME ||
|
||||
!env.DEPLOY_REGISTRY_PASSWORD
|
||||
) {
|
||||
throw new ServiceValidationError("Missing deployment registry credentials");
|
||||
}
|
||||
|
||||
if (!env.DEPOT_TOKEN) {
|
||||
throw new ServiceValidationError("Missing depot token");
|
||||
}
|
||||
|
||||
const pushResult = await executePushToRegistry({
|
||||
depot: {
|
||||
buildId: externalBuildData.data.buildId,
|
||||
orgToken: env.DEPOT_TOKEN,
|
||||
projectId: externalBuildData.data.projectId,
|
||||
},
|
||||
registry: {
|
||||
host: env.DEPLOY_REGISTRY_HOST,
|
||||
namespace: env.DEPLOY_REGISTRY_NAMESPACE,
|
||||
username: env.DEPLOY_REGISTRY_USERNAME,
|
||||
password: env.DEPLOY_REGISTRY_PASSWORD,
|
||||
},
|
||||
deployment: {
|
||||
version: deployment.version,
|
||||
environmentSlug: deployment.environment.slug,
|
||||
projectExternalRef: deployment.worker.project.externalRef,
|
||||
},
|
||||
});
|
||||
|
||||
if (!pushResult.ok) {
|
||||
throw new ServiceValidationError(pushResult.error);
|
||||
}
|
||||
|
||||
const finalizeService = new FinalizeDeploymentService();
|
||||
|
||||
const finalizedDeployment = await finalizeService.call(authenticatedEnv, id, {
|
||||
imageReference: pushResult.image,
|
||||
skipRegistryProxy: true,
|
||||
});
|
||||
|
||||
return finalizedDeployment;
|
||||
}
|
||||
}
|
||||
|
||||
type ExecutePushToRegistryOptions = {
|
||||
depot: {
|
||||
buildId: string;
|
||||
orgToken: string;
|
||||
projectId: string;
|
||||
};
|
||||
registry: {
|
||||
host: string;
|
||||
namespace: string;
|
||||
username: string;
|
||||
password: string;
|
||||
};
|
||||
deployment: {
|
||||
version: string;
|
||||
environmentSlug: string;
|
||||
projectExternalRef: string;
|
||||
};
|
||||
};
|
||||
|
||||
type ExecutePushResult =
|
||||
| {
|
||||
ok: true;
|
||||
image: string;
|
||||
logs: string;
|
||||
}
|
||||
| {
|
||||
ok: false;
|
||||
error: string;
|
||||
logs: string;
|
||||
};
|
||||
|
||||
async function executePushToRegistry({
|
||||
depot,
|
||||
registry,
|
||||
deployment,
|
||||
}: ExecutePushToRegistryOptions): Promise<ExecutePushResult> {
|
||||
// Step 1: We need to "login" to the digital ocean registry
|
||||
const configDir = await ensureLoggedIntoDockerRegistry(registry.host, {
|
||||
username: registry.username,
|
||||
password: registry.password,
|
||||
});
|
||||
|
||||
const imageTag = `${registry.host}/${registry.namespace}/${deployment.projectExternalRef}:${deployment.version}.${deployment.environmentSlug}`;
|
||||
|
||||
// Step 2: We need to run the depot push command
|
||||
// DEPOT_TOKEN="<org token>" DEPOT_PROJECT_ID="<project id>" depot push <build id> -t registry.digitalocean.com/trigger-failover/proj_bzhdaqhlymtuhlrcgbqy:20250124.54.prod
|
||||
// Step 4: Build and push the image
|
||||
const childProcess = execDepot(["push", depot.buildId, "-t", imageTag, "--progress", "plain"], {
|
||||
env: {
|
||||
NODE_ENV: process.env.NODE_ENV,
|
||||
DEPOT_TOKEN: depot.orgToken,
|
||||
DEPOT_PROJECT_ID: depot.projectId,
|
||||
DEPOT_NO_SUMMARY_LINK: "1",
|
||||
DEPOT_NO_UPDATE_NOTIFIER: "1",
|
||||
DOCKER_CONFIG: configDir,
|
||||
},
|
||||
});
|
||||
|
||||
const errors: string[] = [];
|
||||
|
||||
try {
|
||||
const processCode = await new Promise<number | null>((res, rej) => {
|
||||
// For some reason everything is output on stderr, not stdout
|
||||
childProcess.stderr?.on("data", (data: Buffer) => {
|
||||
const text = data.toString();
|
||||
|
||||
// Emitted data chunks can contain multiple lines. Remove empty lines.
|
||||
const lines = text.split("\n").filter(Boolean);
|
||||
|
||||
errors.push(...lines);
|
||||
logger.debug(text, {
|
||||
imageTag,
|
||||
deployment,
|
||||
});
|
||||
});
|
||||
|
||||
childProcess.on("error", (e) => rej(e));
|
||||
childProcess.on("close", (code) => res(code));
|
||||
});
|
||||
|
||||
const logs = extractLogs(errors);
|
||||
|
||||
if (processCode !== 0) {
|
||||
return {
|
||||
ok: false as const,
|
||||
error: `Error pushing image`,
|
||||
logs,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
ok: true as const,
|
||||
image: imageTag,
|
||||
logs,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
ok: false as const,
|
||||
error: e instanceof Error ? e.message : JSON.stringify(e),
|
||||
logs: extractLogs(errors),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function ensureLoggedIntoDockerRegistry(
|
||||
registryHost: string,
|
||||
auth: { username: string; password: string }
|
||||
) {
|
||||
const tmpDir = await createTempDir();
|
||||
// Read the current docker config
|
||||
const dockerConfigPath = join(tmpDir, "config.json");
|
||||
|
||||
await writeJSONFile(dockerConfigPath, {
|
||||
auths: {
|
||||
[registryHost]: {
|
||||
auth: Buffer.from(`${auth.username}:${auth.password}`).toString("base64"),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
logger.debug(`Writing docker config to ${dockerConfigPath}`);
|
||||
|
||||
return tmpDir;
|
||||
}
|
||||
|
||||
// Create a temporary directory within the OS's temp directory
|
||||
async function createTempDir(): Promise<string> {
|
||||
// Generate a unique temp directory path
|
||||
const tempDirPath: string = join(tmpdir(), "trigger-");
|
||||
|
||||
// Create the temp directory synchronously and return the path
|
||||
const directory = await mkdtemp(tempDirPath);
|
||||
|
||||
return directory;
|
||||
}
|
||||
|
||||
async function writeJSONFile(path: string, json: any, pretty = false) {
|
||||
await writeFile(path, JSON.stringify(json, undefined, pretty ? 2 : undefined), "utf8");
|
||||
}
|
||||
|
||||
function extractLogs(outputs: string[]) {
|
||||
// Remove empty lines
|
||||
const cleanedOutputs = outputs.map((line) => line.trim()).filter((line) => line !== "");
|
||||
|
||||
return cleanedOutputs.map((line) => line.trim()).join("\n");
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import { StartDeploymentIndexingRequestBody } from "@trigger.dev/core/v3";
|
||||
import { AuthenticatedEnvironment } from "~/services/apiAuth.server";
|
||||
import { registryProxy } from "../registryProxy.server";
|
||||
import { BaseService } from "./baseService.server";
|
||||
import { IndexDeploymentService } from "./indexDeployment.server";
|
||||
|
||||
export class StartDeploymentIndexing extends BaseService {
|
||||
public async call(
|
||||
environment: AuthenticatedEnvironment,
|
||||
deploymentId: string,
|
||||
body: StartDeploymentIndexingRequestBody
|
||||
) {
|
||||
const deployment = await this._prisma.workerDeployment.update({
|
||||
where: {
|
||||
friendlyId: deploymentId,
|
||||
},
|
||||
data: {
|
||||
imageReference:
|
||||
registryProxy && body.selfHosted !== true
|
||||
? registryProxy.rewriteImageReference(body.imageReference)
|
||||
: body.imageReference,
|
||||
status: "DEPLOYING",
|
||||
builtAt: new Date(),
|
||||
},
|
||||
});
|
||||
|
||||
await IndexDeploymentService.enqueue(deployment.id);
|
||||
|
||||
return deployment;
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,7 @@
|
||||
"@conform-to/react": "^0.6.1",
|
||||
"@conform-to/zod": "^0.6.1",
|
||||
"@depot/sdk-node": "^1.0.0",
|
||||
"@depot/cli": "0.0.1-cli.2.80.0",
|
||||
"@electric-sql/react": "^0.3.5",
|
||||
"@headlessui/react": "^1.7.8",
|
||||
"@heroicons/react": "^2.0.12",
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@clack/prompts": "^0.7.0",
|
||||
"@depot/cli": "0.0.1-cli.2.73.0",
|
||||
"@depot/cli": "0.0.1-cli.2.80.0",
|
||||
"@opentelemetry/api": "1.9.0",
|
||||
"@opentelemetry/api-logs": "0.52.1",
|
||||
"@opentelemetry/exporter-logs-otlp-http": "0.52.1",
|
||||
|
||||
@@ -254,7 +254,7 @@ export class CliApiClient {
|
||||
|
||||
return wrapZodFetch(
|
||||
FailDeploymentResponseBody,
|
||||
`${this.apiURL}/api/v1/deployments/${id}/finalize`,
|
||||
`${this.apiURL}/api/v2/deployments/${id}/finalize`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { intro, outro } from "@clack/prompts";
|
||||
import { prepareDeploymentError } from "@trigger.dev/core/v3";
|
||||
import { ResolvedConfig } from "@trigger.dev/core/v3/build";
|
||||
import { BuildManifest, InitializeDeploymentResponseBody } from "@trigger.dev/core/v3/schemas";
|
||||
import { InitializeDeploymentResponseBody } from "@trigger.dev/core/v3/schemas";
|
||||
import { Command, Option as CommandOption } from "commander";
|
||||
import { writeFile } from "node:fs/promises";
|
||||
import { join, relative, resolve } from "node:path";
|
||||
import { readPackageJSON, writePackageJSON } from "pkg-types";
|
||||
import { resolve } from "node:path";
|
||||
import { x } from "tinyexec";
|
||||
import { z } from "zod";
|
||||
import { CliApiClient } from "../apiClient.js";
|
||||
import { buildWorker } from "../build/buildWorker.js";
|
||||
import { resolveAlwaysExternal } from "../build/externals.js";
|
||||
import {
|
||||
CommonCommandOptions,
|
||||
commonOptions,
|
||||
@@ -17,7 +16,7 @@ import {
|
||||
wrapCommandAction,
|
||||
} from "../cli/common.js";
|
||||
import { loadConfig } from "../config.js";
|
||||
import { buildImage, generateContainerfile } from "../deploy/buildImage.js";
|
||||
import { buildImage } from "../deploy/buildImage.js";
|
||||
import {
|
||||
checkLogsForErrors,
|
||||
checkLogsForWarnings,
|
||||
@@ -25,10 +24,8 @@ import {
|
||||
printWarnings,
|
||||
saveLogs,
|
||||
} from "../deploy/logs.js";
|
||||
import { buildManifestToJSON } from "../utilities/buildManifest.js";
|
||||
import { chalkError, cliLink, isLinksSupported, prettyError } from "../utilities/cliOutput.js";
|
||||
import { loadDotEnvVars } from "../utilities/dotEnv.js";
|
||||
import { writeJSONFile } from "../utilities/fileSystem.js";
|
||||
import { printStandloneInitialBanner } from "../utilities/initialBanner.js";
|
||||
import { logger } from "../utilities/logger.js";
|
||||
import { getProjectClient } from "../utilities/session.js";
|
||||
@@ -36,8 +33,6 @@ import { getTmpDir } from "../utilities/tempDirectories.js";
|
||||
import { spinner } from "../utilities/windows.js";
|
||||
import { login } from "./login.js";
|
||||
import { updateTriggerPackages } from "./update.js";
|
||||
import { resolveAlwaysExternal } from "../build/externals.js";
|
||||
import { x } from "tinyexec";
|
||||
|
||||
const DeployCommandOptions = CommonCommandOptions.extend({
|
||||
dryRun: z.boolean().default(false),
|
||||
@@ -429,7 +424,7 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
|
||||
? `${selfHostedRegistryHost ? `${selfHostedRegistryHost}/` : ""}${buildResult.image}${
|
||||
buildResult.digest ? `@${buildResult.digest}` : ""
|
||||
}`
|
||||
: `${registryHost}/${buildResult.image}${buildResult.digest ? `@${buildResult.digest}` : ""}`;
|
||||
: `${buildResult.image}${buildResult.digest ? `@${buildResult.digest}` : ""}`;
|
||||
|
||||
const finalizeResponse = await projectClient.client.finalizeDeployment(deployment.id, {
|
||||
imageReference,
|
||||
@@ -459,104 +454,6 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
|
||||
);
|
||||
}
|
||||
|
||||
function rewriteBuildManifestPaths(
|
||||
buildManifest: BuildManifest,
|
||||
destinationDir: string
|
||||
): BuildManifest {
|
||||
return {
|
||||
...buildManifest,
|
||||
files: buildManifest.files.map((file) => ({
|
||||
...file,
|
||||
entry: cleanEntryPath(file.entry),
|
||||
out: rewriteOutputPath(destinationDir, file.out),
|
||||
})),
|
||||
outputPath: rewriteOutputPath(destinationDir, buildManifest.outputPath),
|
||||
configPath: rewriteOutputPath(destinationDir, buildManifest.configPath),
|
||||
runControllerEntryPoint: buildManifest.runControllerEntryPoint
|
||||
? rewriteOutputPath(destinationDir, buildManifest.runControllerEntryPoint)
|
||||
: undefined,
|
||||
runWorkerEntryPoint: rewriteOutputPath(destinationDir, buildManifest.runWorkerEntryPoint),
|
||||
indexControllerEntryPoint: buildManifest.indexControllerEntryPoint
|
||||
? rewriteOutputPath(destinationDir, buildManifest.indexControllerEntryPoint)
|
||||
: undefined,
|
||||
indexWorkerEntryPoint: rewriteOutputPath(destinationDir, buildManifest.indexWorkerEntryPoint),
|
||||
loaderEntryPoint: buildManifest.loaderEntryPoint
|
||||
? rewriteOutputPath(destinationDir, buildManifest.loaderEntryPoint)
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
async function writeProjectFiles(
|
||||
buildManifest: BuildManifest,
|
||||
resolvedConfig: ResolvedConfig,
|
||||
outputPath: string
|
||||
) {
|
||||
// Step 1. Read the package.json file
|
||||
const packageJson = await readProjectPackageJson(resolvedConfig.packageJsonPath);
|
||||
|
||||
if (!packageJson) {
|
||||
throw new Error("Could not read the package.json file");
|
||||
}
|
||||
|
||||
const dependencies =
|
||||
buildManifest.externals?.reduce(
|
||||
(acc, external) => {
|
||||
acc[external.name] = external.version;
|
||||
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, string>
|
||||
) ?? {};
|
||||
|
||||
// Step 3: Write the resolved dependencies to the package.json file
|
||||
await writePackageJSON(join(outputPath, "package.json"), {
|
||||
...packageJson,
|
||||
name: packageJson.name ?? "trigger-project",
|
||||
dependencies: {
|
||||
...dependencies,
|
||||
},
|
||||
trustedDependencies: Object.keys(dependencies),
|
||||
devDependencies: {},
|
||||
peerDependencies: {},
|
||||
scripts: {},
|
||||
});
|
||||
|
||||
await writeJSONFile(join(outputPath, "build.json"), buildManifestToJSON(buildManifest));
|
||||
await writeContainerfile(outputPath, buildManifest);
|
||||
}
|
||||
|
||||
async function readProjectPackageJson(packageJsonPath: string) {
|
||||
const packageJson = await readPackageJSON(packageJsonPath);
|
||||
|
||||
return packageJson;
|
||||
}
|
||||
|
||||
// Remove any query parameters from the entry path
|
||||
// For example, src/trigger/ai.ts?sentryProxyModule=true -> src/trigger/ai.ts
|
||||
function cleanEntryPath(entry: string): string {
|
||||
return entry.split("?")[0]!;
|
||||
}
|
||||
|
||||
function rewriteOutputPath(destinationDir: string, filePath: string) {
|
||||
return `/app/${relative(destinationDir, filePath)}`;
|
||||
}
|
||||
|
||||
async function writeContainerfile(outputPath: string, buildManifest: BuildManifest) {
|
||||
if (!buildManifest.runControllerEntryPoint || !buildManifest.indexControllerEntryPoint) {
|
||||
throw new Error("Something went wrong with the build. Aborting deployment. [code 7789]");
|
||||
}
|
||||
|
||||
const containerfile = await generateContainerfile({
|
||||
runtime: buildManifest.runtime,
|
||||
entrypoint: buildManifest.runControllerEntryPoint,
|
||||
build: buildManifest.build,
|
||||
image: buildManifest.image,
|
||||
indexScript: buildManifest.indexControllerEntryPoint,
|
||||
});
|
||||
|
||||
await writeFile(join(outputPath, "Containerfile"), containerfile);
|
||||
}
|
||||
|
||||
export async function syncEnvVarsWithServer(
|
||||
apiClient: CliApiClient,
|
||||
projectRef: string,
|
||||
|
||||
@@ -194,10 +194,8 @@ async function depotBuildImage(options: DepotBuildImageOptions): Promise<BuildIm
|
||||
...(options.extraCACerts ? ["--build-arg", `NODE_EXTRA_CA_CERTS=${options.extraCACerts}`] : []),
|
||||
"--progress",
|
||||
"plain",
|
||||
"-t",
|
||||
`${options.registryHost}/${options.imageTag}`,
|
||||
".",
|
||||
"--push",
|
||||
"--save",
|
||||
options.loadImage ? "--load" : undefined,
|
||||
].filter(Boolean) as string[];
|
||||
|
||||
@@ -249,7 +247,7 @@ async function depotBuildImage(options: DepotBuildImageOptions): Promise<BuildIm
|
||||
|
||||
return {
|
||||
ok: true as const,
|
||||
image: options.imageTag,
|
||||
image: `registry.depot.dev/${options.buildProjectId}:${options.buildId}`,
|
||||
logs,
|
||||
digest,
|
||||
};
|
||||
|
||||
@@ -222,6 +222,7 @@ export type StartDeploymentIndexingResponseBody = z.infer<
|
||||
export const FinalizeDeploymentRequestBody = z.object({
|
||||
imageReference: z.string(),
|
||||
selfHosted: z.boolean().optional(),
|
||||
skipRegistryProxy: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export type FinalizeDeploymentRequestBody = z.infer<typeof FinalizeDeploymentRequestBody>;
|
||||
|
||||
Generated
+34
-31
@@ -228,6 +228,9 @@ importers:
|
||||
'@conform-to/zod':
|
||||
specifier: ^0.6.1
|
||||
version: 0.6.1(@conform-to/dom@0.6.1)(zod@3.23.8)
|
||||
'@depot/cli':
|
||||
specifier: 0.0.1-cli.2.80.0
|
||||
version: 0.0.1-cli.2.80.0
|
||||
'@depot/sdk-node':
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0
|
||||
@@ -1070,8 +1073,8 @@ importers:
|
||||
specifier: ^0.7.0
|
||||
version: 0.7.0
|
||||
'@depot/cli':
|
||||
specifier: 0.0.1-cli.2.73.0
|
||||
version: 0.0.1-cli.2.73.0
|
||||
specifier: 0.0.1-cli.2.80.0
|
||||
version: 0.0.1-cli.2.80.0
|
||||
'@opentelemetry/api':
|
||||
specifier: 1.9.0
|
||||
version: 1.9.0
|
||||
@@ -5477,8 +5480,8 @@ packages:
|
||||
dependencies:
|
||||
'@jridgewell/trace-mapping': 0.3.9
|
||||
|
||||
/@depot/cli-darwin-arm64@0.0.1-cli.2.73.0:
|
||||
resolution: {integrity: sha512-nXG6loMJxbfWnKoVvTvrw19GAX3TxsgUy2mnb7sKv06VjUeMvsvBueXAW4lxO5Cf89oim9b0/Agnj/B3IVD2Kg==}
|
||||
/@depot/cli-darwin-arm64@0.0.1-cli.2.80.0:
|
||||
resolution: {integrity: sha512-H7tQ0zWXVmdYXGFvt3d/v5fmquMlMM1I9JC8C2yiBZ9En9a20hzSbKoiym92RtcfqjKQFvhXL0DT6vQmJ8bgQA==}
|
||||
engines: {node: '>=14'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
@@ -5486,8 +5489,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@depot/cli-darwin-x64@0.0.1-cli.2.73.0:
|
||||
resolution: {integrity: sha512-AqkNIIOuzh/8hmwTwu1FIY5Lvez7h4/STO3oPjaalLajV+ZfHgV2xpmbtTwxPmgLVFPaE2e77wzvpRWuFarWwQ==}
|
||||
/@depot/cli-darwin-x64@0.0.1-cli.2.80.0:
|
||||
resolution: {integrity: sha512-3RDyybnCC2YSvbJCkHxXBYbKR7adUO7U00O9DHreX8EyS2E/C3kQgET+rFXR+iDdeG0h+h+At2rDng7AxvUhDw==}
|
||||
engines: {node: '>=14'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
@@ -5495,8 +5498,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@depot/cli-linux-arm64@0.0.1-cli.2.73.0:
|
||||
resolution: {integrity: sha512-Rfiil6MAO/SkAK27vaEA1IOPOJq8DgCvm09sfasrXFvpldDYa700Hx7c+V1uuBYfIckVh2S/i7AQjGg535MDjg==}
|
||||
/@depot/cli-linux-arm64@0.0.1-cli.2.80.0:
|
||||
resolution: {integrity: sha512-Fc1+Guqdsl2WM+b+76FirRjjRvEoYZX0MI4uuIQF9c9gwp6UZSZ5o3U7lAUpdkclVMKXSAW5bsIpgcOfUiJX3w==}
|
||||
engines: {node: '>=14'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
@@ -5504,8 +5507,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@depot/cli-linux-arm@0.0.1-cli.2.73.0:
|
||||
resolution: {integrity: sha512-/HspMwaVYYPErg372Bk4x7Gno7n8VuaLqaGm39wbZEb9C4S9YAP7r7T0wSywrUZBzJBxX7f+GoHbBic0IQoraQ==}
|
||||
/@depot/cli-linux-arm@0.0.1-cli.2.80.0:
|
||||
resolution: {integrity: sha512-95kjKwKxP6RKkAhJoPlO6g3drEYpFWy9AC7QfvQMHDRnI3HXgbxA/BSTp4R3C4TTfp5JUPShVf8Js/NAcrUpUQ==}
|
||||
engines: {node: '>=14'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
@@ -5513,8 +5516,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@depot/cli-linux-ia32@0.0.1-cli.2.73.0:
|
||||
resolution: {integrity: sha512-1GHDaNe6KXYjHWNoUrd2GutnseyYt3yrUKmRYKAR+/AU3BW/eQGcRAp50bSu9nntIaL+ByugkR+LjwKJIqRzmg==}
|
||||
/@depot/cli-linux-ia32@0.0.1-cli.2.80.0:
|
||||
resolution: {integrity: sha512-2KoyIoYqnyIuynPN+mWbugoOB2APiNNvFLKERWOwPa0KYLSfcENT3sYxDW8tDuIw2dftHlmZN73uvXrGFeMcDQ==}
|
||||
engines: {node: '>=14'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
@@ -5522,8 +5525,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@depot/cli-linux-x64@0.0.1-cli.2.73.0:
|
||||
resolution: {integrity: sha512-CY4IwXT5l2btXbjCYl+85tfF/viz6zdyaWjiu7MUuxxAM+s9bMYl7HKBITHdflx9Z/dRfDGFX8tM1i2AsKBcqA==}
|
||||
/@depot/cli-linux-x64@0.0.1-cli.2.80.0:
|
||||
resolution: {integrity: sha512-B8xDlXFxhYHD2tUk0jUv7SKipLfWwJVlY7ZhDQixyQzatibXakahdqpvZJgE6FLZJd3lgFIEAVsKURZHa1l57A==}
|
||||
engines: {node: '>=14'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
@@ -5531,8 +5534,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@depot/cli-win32-arm64@0.0.1-cli.2.73.0:
|
||||
resolution: {integrity: sha512-mslCCUzlK53aYstJH6//mPOVTWa8vU2IemBGLFsntgB1f/0fqDdfAskyfu+RVx/ZNqjr2Ih2jtdlfyOA3XKZdw==}
|
||||
/@depot/cli-win32-arm64@0.0.1-cli.2.80.0:
|
||||
resolution: {integrity: sha512-CPJX691MKEhnKZX25xS+opWESgPQ73HKkEwkAvvVqdBzahndcHoqAeIxYLv2hoCqrDlkH3YCF+DJleLiEP3blA==}
|
||||
engines: {node: '>=14'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
@@ -5540,8 +5543,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@depot/cli-win32-ia32@0.0.1-cli.2.73.0:
|
||||
resolution: {integrity: sha512-/xsLWyIO7tAHTkFTFO0j9Csc78WnoENeEWROeUWsvAizFX6GF6Toir1xRZbM28yRRlGsOG+KWsFwULyEJkI1Wg==}
|
||||
/@depot/cli-win32-ia32@0.0.1-cli.2.80.0:
|
||||
resolution: {integrity: sha512-6eewZ1zPEyNL3zcCwC01s3rZNMqMGVu1iv/EPywj3/uk4CNyUBaTlZ3StQ1BLFHPQnU0vk29yOzA5ZEuRLSyxA==}
|
||||
engines: {node: '>=14'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
@@ -5549,8 +5552,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@depot/cli-win32-x64@0.0.1-cli.2.73.0:
|
||||
resolution: {integrity: sha512-iC8FpHij2yrO1hNQPuRYgreYsyvXgC6xaBdBpfM5x7C7Uf+vOg4k5ERToj0WCfvRhkja+uguQdw2V3il6IhNeA==}
|
||||
/@depot/cli-win32-x64@0.0.1-cli.2.80.0:
|
||||
resolution: {integrity: sha512-9CRcc7D0/x4UrBkDuc35WVPMQG5gKMD1JckGLEl6VREE0Ppdny6n+hunQ8prwVc8aqzKG134XCC2U4DUjYg18A==}
|
||||
engines: {node: '>=14'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@@ -5558,21 +5561,21 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@depot/cli@0.0.1-cli.2.73.0:
|
||||
resolution: {integrity: sha512-pu5SKOj95jzCPG5H5SZvAN6Z+h4ACcjs6shv7S1lXqSGxNBVTvq7LlTiBFGpLcLo+EkSfbEjAdlNBdh1LRqrKA==}
|
||||
/@depot/cli@0.0.1-cli.2.80.0:
|
||||
resolution: {integrity: sha512-KvmOiQdpbamFziqnzzgqBm6RjfGhLJimBBYEOVriTxCPtVJuBIFm34xZllM36OQzPZIWpWBP+2/UnOyRG5smUg==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
optionalDependencies:
|
||||
'@depot/cli-darwin-arm64': 0.0.1-cli.2.73.0
|
||||
'@depot/cli-darwin-x64': 0.0.1-cli.2.73.0
|
||||
'@depot/cli-linux-arm': 0.0.1-cli.2.73.0
|
||||
'@depot/cli-linux-arm64': 0.0.1-cli.2.73.0
|
||||
'@depot/cli-linux-ia32': 0.0.1-cli.2.73.0
|
||||
'@depot/cli-linux-x64': 0.0.1-cli.2.73.0
|
||||
'@depot/cli-win32-arm64': 0.0.1-cli.2.73.0
|
||||
'@depot/cli-win32-ia32': 0.0.1-cli.2.73.0
|
||||
'@depot/cli-win32-x64': 0.0.1-cli.2.73.0
|
||||
'@depot/cli-darwin-arm64': 0.0.1-cli.2.80.0
|
||||
'@depot/cli-darwin-x64': 0.0.1-cli.2.80.0
|
||||
'@depot/cli-linux-arm': 0.0.1-cli.2.80.0
|
||||
'@depot/cli-linux-arm64': 0.0.1-cli.2.80.0
|
||||
'@depot/cli-linux-ia32': 0.0.1-cli.2.80.0
|
||||
'@depot/cli-linux-x64': 0.0.1-cli.2.80.0
|
||||
'@depot/cli-win32-arm64': 0.0.1-cli.2.80.0
|
||||
'@depot/cli-win32-ia32': 0.0.1-cli.2.80.0
|
||||
'@depot/cli-win32-x64': 0.0.1-cli.2.80.0
|
||||
dev: false
|
||||
|
||||
/@depot/sdk-node@1.0.0:
|
||||
|
||||
Reference in New Issue
Block a user