@@ -134,7 +134,8 @@ export async function runBranchDatabaseSchemaSetup(options: {
134134 directUrl : string | null ;
135135} ) : Promise < BranchDatabaseSchemaSetupResult > {
136136 const schemaPath = path . relative ( options . context . runtime . cwd , options . schema . path ) || defaultSchemaSourcePath ( options . schema ) ;
137- const commands = buildSchemaSetupCommands ( options . schema , schemaPath , options . databaseUrl ) ;
137+ const prisma = await resolvePrismaInvocation ( options . context . runtime . cwd ) ;
138+ const commands = buildSchemaSetupCommands ( options . schema , schemaPath , options . databaseUrl , prisma ) ;
138139
139140 for ( const command of commands ) {
140141 await runPrismaCommand ( {
@@ -411,21 +412,92 @@ async function readTextFileIfSmall(filePath: string, signal: AbortSignal): Promi
411412 return readFile ( filePath , { encoding : "utf8" , signal } ) ;
412413}
413414
414- function buildSchemaSetupCommands ( schema : BranchDatabaseSchema , schemaPath : string , databaseUrl : string ) : Array < {
415+ // Last resort for repos that ship a schema with no Prisma packages
416+ // installed at all. Pinned to the 6.x line: Prisma 7 rejects the classic
417+ // `url = env(...)` datasource form (P1012), which is exactly the schema
418+ // shape such repos have. Bump deliberately, never to `latest`.
419+ const FALLBACK_PRISMA_CLI_VERSION = "6.19.3" ;
420+
421+ interface PrismaInvocation {
422+ argsPrefix : string [ ] ;
423+ displayPrefix : string ;
424+ }
425+
426+ /**
427+ * Picks how `prisma` CLI commands are invoked for schema setup. Projects
428+ * with the CLI installed run their own binary (version-exact). Projects
429+ * without it fall back to a versioned `npx prisma@<x>` pinned to the
430+ * installed `@prisma/client` — never bare `npx prisma`, which resolves to
431+ * latest and can be a major version ahead of the project's schema.
432+ */
433+ async function resolvePrismaInvocation ( cwd : string ) : Promise < PrismaInvocation > {
434+ if ( await localPrismaBinExists ( cwd ) ) {
435+ return {
436+ argsPrefix : [ "--no-install" , "prisma" ] ,
437+ displayPrefix : "npx --no-install prisma" ,
438+ } ;
439+ }
440+
441+ const clientVersion = await readInstalledPrismaClientVersion ( cwd ) ;
442+ const pinned = clientVersion ?? FALLBACK_PRISMA_CLI_VERSION ;
443+ return {
444+ argsPrefix : [ "--yes" , `prisma@${ pinned } ` ] ,
445+ displayPrefix : `npx prisma@${ pinned } ` ,
446+ } ;
447+ }
448+
449+ /** npm/pnpm name the local CLI shim `prisma` on POSIX and `prisma.cmd`/`prisma.ps1` on Windows. */
450+ async function localPrismaBinExists ( cwd : string ) : Promise < boolean > {
451+ const binDir = path . join ( cwd , "node_modules" , ".bin" ) ;
452+ const checks = await Promise . all (
453+ [ "prisma" , "prisma.cmd" , "prisma.ps1" ] . map ( ( name ) =>
454+ fileExists ( path . join ( binDir , name ) ) ,
455+ ) ,
456+ ) ;
457+ return checks . some ( Boolean ) ;
458+ }
459+
460+ async function fileExists ( filePath : string ) : Promise < boolean > {
461+ try {
462+ await access ( filePath ) ;
463+ return true ;
464+ } catch {
465+ return false ;
466+ }
467+ }
468+
469+ async function readInstalledPrismaClientVersion ( cwd : string ) : Promise < string | null > {
470+ try {
471+ const raw = await readFile (
472+ path . join ( cwd , "node_modules" , "@prisma" , "client" , "package.json" ) ,
473+ { encoding : "utf8" } ,
474+ ) ;
475+ const parsed : unknown = JSON . parse ( raw ) ;
476+ if ( typeof parsed !== "object" || parsed === null ) {
477+ return null ;
478+ }
479+ const version = ( parsed as { version ?: unknown } ) . version ;
480+ return typeof version === "string" && version . length > 0 ? version : null ;
481+ } catch {
482+ return null ;
483+ }
484+ }
485+
486+ function buildSchemaSetupCommands ( schema : BranchDatabaseSchema , schemaPath : string , databaseUrl : string , prisma : PrismaInvocation ) : Array < {
415487 args : string [ ] ;
416488 displayCommand : string ;
417489} > {
418490 if ( schema . command === "migrate-deploy" ) {
419491 return [ {
420- args : [ "--no-install" , " prisma" , "migrate" , "deploy" , "--schema" , schemaPath ] ,
421- displayCommand : "npx --no-install prisma migrate deploy" ,
492+ args : [ ... prisma . argsPrefix , "migrate" , "deploy" , "--schema" , schemaPath ] ,
493+ displayCommand : ` ${ prisma . displayPrefix } migrate deploy` ,
422494 } ] ;
423495 }
424496
425497 if ( schema . command === "db-push" ) {
426498 return [ {
427- args : [ "--no-install" , " prisma" , "db" , "push" , "--schema" , schemaPath ] ,
428- displayCommand : "npx --no-install prisma db push" ,
499+ args : [ ... prisma . argsPrefix , "db" , "push" , "--schema" , schemaPath ] ,
500+ displayCommand : ` ${ prisma . displayPrefix } db push` ,
429501 } ] ;
430502 }
431503
0 commit comments