diff --git a/apps/webapp/app/presenters/v3/DeploymentListPresenter.server.ts b/apps/webapp/app/presenters/v3/DeploymentListPresenter.server.ts index 9b7f204bd70..0b55ced0f0c 100644 --- a/apps/webapp/app/presenters/v3/DeploymentListPresenter.server.ts +++ b/apps/webapp/app/presenters/v3/DeploymentListPresenter.server.ts @@ -14,6 +14,7 @@ import { VercelProjectIntegrationDataSchema, buildVercelDeploymentUrl, } from "~/v3/vercel/vercelProjectIntegrationSchema"; +import { isBillingConfigured } from "~/services/platform.v3.server"; import { resolveRedeploySource } from "~/v3/redeploy"; const pageSize = 20; @@ -225,13 +226,15 @@ LIMIT ${pageSize} OFFSET ${pageSize * (page - 1)};`; currentPage: page, totalPages: Math.ceil(totalCount / pageSize), hasVercelIntegration, - connectedGithubRepository: project.connectedGithubRepository ?? undefined, - environmentGitHubBranch, + connectedGithubRepository: isBillingConfigured() + ? (project.connectedGithubRepository ?? undefined) + : undefined, + environmentGitHubBranch: isBillingConfigured() ? environmentGitHubBranch : undefined, deployments: deployments.map((deployment, index) => { const label = labeledDeployments.find( (labeledDeployment) => labeledDeployment.deploymentId === deployment.id ); - const redeploySource = resolveRedeploySource(deployment); + const redeploySource = isBillingConfigured() ? resolveRedeploySource(deployment) : null; let vercelDeploymentUrl: string | null = null; if ( diff --git a/apps/webapp/app/presenters/v3/GitHubSettingsPresenter.server.ts b/apps/webapp/app/presenters/v3/GitHubSettingsPresenter.server.ts index 162e44f8a88..c29fd45d005 100644 --- a/apps/webapp/app/presenters/v3/GitHubSettingsPresenter.server.ts +++ b/apps/webapp/app/presenters/v3/GitHubSettingsPresenter.server.ts @@ -1,6 +1,7 @@ import { type PrismaClient } from "@trigger.dev/database"; import { fromPromise, ok, ResultAsync } from "neverthrow"; import { env } from "~/env.server"; +import { isBillingConfigured } from "~/services/platform.v3.server"; import { BranchTrackingConfigSchema } from "~/v3/github"; import { BasePresenter } from "./basePresenter.server"; @@ -11,7 +12,7 @@ type GitHubSettingsOptions = { export class GitHubSettingsPresenter extends BasePresenter { public call({ projectId, organizationId }: GitHubSettingsOptions) { - const githubAppEnabled = env.GITHUB_APP_ENABLED === "1"; + const githubAppEnabled = env.GITHUB_APP_ENABLED === "1" && isBillingConfigured(); if (!githubAppEnabled) { return ok({ diff --git a/apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.github.tsx b/apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.github.tsx index 5ce57aa0472..a53100b13ed 100644 --- a/apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.github.tsx +++ b/apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.github.tsx @@ -71,7 +71,7 @@ import { findEnvironmentBySlug } from "~/models/runtimeEnvironment.server"; import { env } from "~/env.server"; import { GitHubSettingsPresenter } from "~/presenters/v3/GitHubSettingsPresenter.server"; import { logger } from "~/services/logger.server"; -import { triggerInitialDeployment } from "~/services/platform.v3.server"; +import { isBillingConfigured, triggerInitialDeployment } from "~/services/platform.v3.server"; import { marketplaceInitialDeploymentOptions } from "~/v3/services/marketplaceInitialDeploymentOptions.server"; import { ProjectSettingsService } from "~/services/projectSettings.server"; import { rbac } from "~/services/rbac.server"; @@ -241,6 +241,13 @@ export const action = dashboardAction( throw new Response("Not Found", { status: 404 }); } + if (env.GITHUB_APP_ENABLED !== "1" || !isBillingConfigured()) { + return json( + { ok: false, error: "Native GitHub deployments are not available on self-hosted instances." }, + { status: 403 } + ); + } + const formData = await request.formData(); const submission = parseWithZod(formData, { schema: GitHubActionSchema }); diff --git a/apps/webapp/app/services/platform.v3.server.ts b/apps/webapp/app/services/platform.v3.server.ts index 716777c7845..cf274f8d93f 100644 --- a/apps/webapp/app/services/platform.v3.server.ts +++ b/apps/webapp/app/services/platform.v3.server.ts @@ -1178,7 +1178,7 @@ export async function enqueueBuild( fromBundle?: boolean; } ) { - if (!client) return undefined; + if (!client) throw new Error("Platform client not configured"); const result = await client.enqueueBuild(projectId, { deploymentId, artifactKey, options }); if (!result.success) { recordPlatformFailure("enqueueBuild", "no_success"); diff --git a/apps/webapp/app/v3/services/initializeDeployment.server.ts b/apps/webapp/app/v3/services/initializeDeployment.server.ts index 0727c7fa652..33b3bd3ed07 100644 --- a/apps/webapp/app/v3/services/initializeDeployment.server.ts +++ b/apps/webapp/app/v3/services/initializeDeployment.server.ts @@ -18,6 +18,7 @@ import { resolveDeployBaseImages } from "../deployBaseImages.server"; import { getDeploymentImageRef } from "../getDeploymentImageRef.server"; import { tryCatch } from "@trigger.dev/core"; import { getRegistryConfig } from "../registryConfig.server"; +import { isBillingConfigured } from "~/services/platform.v3.server"; import { DeploymentService } from "./deployment.server"; import { recordDeploymentInitialized } from "./recordDeploymentFinished.server"; import { buildEnvVarsEnvelope } from "./initializeDeployment/buildEnvVarsEnvelope.server"; @@ -149,6 +150,13 @@ export class InitializeDeploymentService extends BaseService { throw new ServiceValidationError("UNMANAGED deployments are not supported"); } + if (payload.isNativeBuild && !isBillingConfigured()) { + throw new ServiceValidationError( + "Native builds are not supported on self-hosted instances. Deploy with the CLI or GitHub Actions instead.", + 400 + ); + } + const requiredBaseImages = resolveDeployBaseImages(runtime, { base: env.DEPLOY_BASE_IMAGES, buildBase: env.DEPLOY_BUILD_BASE_IMAGES,