@@ -2,10 +2,21 @@ import { type PrismaClient, type PrismaClientOrTransaction } from "@trigger.dev/
22import slug from "slug" ;
33import { prisma } from "~/db.server" ;
44import { createApiKeyForEnv , createPkApiKeyForEnv } from "~/models/api-key.server" ;
5- import { type CreateBranchOptions } from "~/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.branches/route" ;
65import { isValidGitBranchName , sanitizeBranchName } from "@trigger.dev/core/v3/utils/gitBranch" ;
76import { logger } from "./logger.server" ;
87import { getCurrentPlan , getLimit } from "./platform.v3.server" ;
8+ import { GitMeta } from "@trigger.dev/core/v3" ;
9+ import { z } from "zod" ;
10+ import invariant from "tiny-invariant" ;
11+
12+ export const CreateBranchOptions = z . object ( {
13+ projectId : z . string ( ) ,
14+ env : z . enum ( [ "preview" , "development" ] ) ,
15+ branchName : z . string ( ) . min ( 1 ) ,
16+ git : GitMeta . optional ( ) ,
17+ } ) ;
18+
19+ type CreateBranchOptions = z . infer < typeof CreateBranchOptions > ;
920
1021export class UpsertBranchService {
1122 #prismaClient: PrismaClient ;
@@ -22,8 +33,12 @@ export class UpsertBranchService {
2233 orgFilter :
2334 | { type : "userMembership" ; userId : string }
2435 | { type : "orgId" ; organizationId : string } ,
25- { parentEnvironmentId , branchName, git } : CreateBranchOptions
36+ { projectId , env , branchName, git } : CreateBranchOptions
2637 ) {
38+
39+
40+ const parentEnvSlug = env === "preview" ? "preview" : "dev" ;
41+
2742 const sanitizedBranchName = sanitizeBranchName ( branchName ) ;
2843 if ( ! sanitizedBranchName ) {
2944 return {
@@ -42,16 +57,17 @@ export class UpsertBranchService {
4257 try {
4358 const parentEnvironment = await this . #prismaClient. runtimeEnvironment . findFirst ( {
4459 where : {
45- id : parentEnvironmentId ,
60+ projectId,
61+ slug : parentEnvSlug ,
4662 organization :
4763 orgFilter . type === "userMembership"
4864 ? {
49- members : {
50- some : {
51- userId : orgFilter . userId ,
52- } ,
65+ members : {
66+ some : {
67+ userId : orgFilter . userId ,
5368 } ,
54- }
69+ } ,
70+ }
5571 : { id : orgFilter . organizationId } ,
5672 } ,
5773 include : {
@@ -72,6 +88,7 @@ export class UpsertBranchService {
7288 } ) ;
7389
7490 if ( ! parentEnvironment ) {
91+ invariant ( env === "preview" , "No default dev runtime environment setup" ) ;
7592 return {
7693 success : false as const ,
7794 error : "You don't have preview branches setup. Go to the dashboard to enable them." ,
@@ -81,16 +98,12 @@ export class UpsertBranchService {
8198 if ( ! parentEnvironment . isBranchableEnvironment ) {
8299 return {
83100 success : false as const ,
84- error : " Your preview environment is not branchable" ,
101+ error : ` Your ${ env } environment is not branchable` ,
85102 } ;
86103 }
87104
88105 const limits = await checkBranchLimit (
89- this . #prismaClient,
90- parentEnvironment . organization . id ,
91- parentEnvironment . project . id ,
92- sanitizedBranchName
93- ) ;
106+ { prisma : this . #prismaClient, organizationId : parentEnvironment . organization . id , projectId : parentEnvironment . project . id , newBranchName : sanitizedBranchName } ) ;
94107
95108 if ( limits . isAtLimit ) {
96109 return {
@@ -159,11 +172,11 @@ export class UpsertBranchService {
159172}
160173
161174export async function checkBranchLimit (
162- prisma : PrismaClientOrTransaction ,
163- organizationId : string ,
164- projectId : string ,
165- newBranchName ?: string
166- ) {
175+ { prisma, organizationId , projectId , env , newBranchName } :
176+ { prisma : PrismaClientOrTransaction ; organizationId : string ; projectId : string ; env : "preview" | "development" ; newBranchName ?: string ; } ) {
177+
178+
179+
167180 const usedEnvs = await prisma . runtimeEnvironment . findMany ( {
168181 where : {
169182 projectId,
@@ -177,7 +190,9 @@ export async function checkBranchLimit(
177190 const count = newBranchName
178191 ? usedEnvs . filter ( ( env ) => env . branchName !== newBranchName ) . length
179192 : usedEnvs . length ;
180- const baseLimit = await getLimit ( organizationId , "branches" , 100_000_000 ) ;
193+
194+ const limitName = env === "preview" ? "branches" : "branchesDev" ;
195+ const baseLimit = await getLimit ( organizationId , limitName , 100_000_000 ) ;
181196 const currentPlan = await getCurrentPlan ( organizationId ) ;
182197 const purchasedBranches = currentPlan ?. v3Subscription ?. addOns ?. branches ?. purchased ?? 0 ;
183198 const limit = baseLimit + purchasedBranches ;
0 commit comments