diff --git a/.changeset/clever-bears-roll.md b/.changeset/clever-bears-roll.md new file mode 100644 index 00000000000..88580901737 --- /dev/null +++ b/.changeset/clever-bears-roll.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +Fixed an error being printed to the console when the Prisma CLI exited with a non-zero exit code when running `keystone-next prisma` diff --git a/packages-next/keystone/src/scripts/prisma.ts b/packages-next/keystone/src/scripts/prisma.ts index d33d2c8d8bf..34b3d5bd383 100644 --- a/packages-next/keystone/src/scripts/prisma.ts +++ b/packages-next/keystone/src/scripts/prisma.ts @@ -3,7 +3,7 @@ import { createSystem } from '../lib/createSystem'; import { generateNodeModulesArtifacts, validateCommittedArtifacts } from '../artifacts'; import { requireSource } from '../lib/requireSource'; import { initConfig } from '../lib/initConfig'; -import { getConfigPath } from './utils'; +import { ExitError, getConfigPath } from './utils'; export async function prisma(cwd: string, args: string[]) { const config = initConfig(requireSource(getConfigPath(cwd)).default); @@ -13,12 +13,16 @@ export async function prisma(cwd: string, args: string[]) { await validateCommittedArtifacts(graphQLSchema, keystone, cwd); await generateNodeModulesArtifacts(graphQLSchema, keystone, config, cwd); - await execa('node', [require.resolve('prisma'), ...args], { + const result = await execa('node', [require.resolve('prisma'), ...args], { cwd, stdio: 'inherit', + reject: false, env: { ...process.env, DATABASE_URL: config.db.url, }, }); + if (result.exitCode !== 0) { + throw new ExitError(result.exitCode); + } } diff --git a/packages-next/keystone/src/scripts/tests/artifacts.test.ts b/packages-next/keystone/src/scripts/tests/artifacts.test.ts index 4bd7b8cd3f2..f1dced84dab 100644 --- a/packages-next/keystone/src/scripts/tests/artifacts.test.ts +++ b/packages-next/keystone/src/scripts/tests/artifacts.test.ts @@ -1,8 +1,14 @@ -import fs from 'fs-extra'; import { text } from '@keystone-next/fields'; import { config, list } from '../../schema'; import { ExitError } from '../utils'; -import { getFiles, recordConsole, runCommand, symlinkKeystoneDeps, testdir } from './utils'; +import { + getFiles, + recordConsole, + runCommand, + schemas, + symlinkKeystoneDeps, + testdir, +} from './utils'; const basicKeystoneConfig = { kind: 'config' as const, @@ -18,11 +24,6 @@ const basicKeystoneConfig = { }), }; -const schemas = { - 'schema.graphql': fs.readFileSync(`${__dirname}/fixtures/basic-project/schema.graphql`, 'utf8'), - 'schema.prisma': fs.readFileSync(`${__dirname}/fixtures/basic-project/schema.prisma`, 'utf8'), -}; - describe.each(['postinstall', 'build', 'prisma migrate status'])('%s', command => { test('logs an error and exits with 1 when the schemas do not exist and the terminal is non-interactive', async () => { const tmp = await testdir({ diff --git a/packages-next/keystone/src/scripts/tests/prisma.test.ts b/packages-next/keystone/src/scripts/tests/prisma.test.ts new file mode 100644 index 00000000000..7539644ec4f --- /dev/null +++ b/packages-next/keystone/src/scripts/tests/prisma.test.ts @@ -0,0 +1,85 @@ +import execa from 'execa'; +import stripAnsi from 'strip-ansi'; +import { basicKeystoneConfig, cliBinPath, schemas, symlinkKeystoneDeps, testdir } from './utils'; + +// testing erroring when the schemas are not up to date is in artifacts.test.ts + +test('keystone-next prisma exits with the same code as the prisma child process exits with', async () => { + const tmp = await testdir({ + ...symlinkKeystoneDeps, + ...schemas, + 'keystone.js': basicKeystoneConfig, + }); + const result = await execa('node', [cliBinPath, 'prisma', 'bad-thing'], { + reject: false, + all: true, + cwd: tmp, + }); + expect(result.exitCode).toBe(1); + expect(stripAnsi(result.all!)).toMatchInlineSnapshot(` + " + ! Unknown command \\"bad-thing\\" + + ◭ Prisma is a modern DB toolkit to query, migrate and model your database (https://prisma.io) + + Usage + + $ prisma [command] + + Commands + + init Setup Prisma for your app + generate Generate artifacts (e.g. Prisma Client) + db Manage your database schema and lifecycle + migrate Migrate your database + studio Browse your data with Prisma Studio + format Format your schema + + Flags + + --preview-feature Run Preview Prisma commands + + Examples + + Setup a new Prisma project + $ prisma init + + Generate artifacts (e.g. Prisma Client) + $ prisma generate + + Browse your data + $ prisma studio + + Create migrations from your Prisma schema, apply them to the database, generate artifacts (e.g. Prisma Client) + $ prisma migrate dev + + Pull the schema from an existing database, updating the Prisma schema + $ prisma db pull + + Push the Prisma schema state to the database + $ prisma db push --preview-feature + " + `); +}); + +test('keystone-next prisma uses the db url in the keystone config', async () => { + const tmp = await testdir({ + ...symlinkKeystoneDeps, + ...schemas, + 'keystone.js': basicKeystoneConfig, + }); + const result = await execa('node', [cliBinPath, 'prisma', 'migrate', 'status'], { + reject: false, + all: true, + cwd: tmp, + }); + expect(result.exitCode).toBe(0); + expect(stripAnsi(result.all!)).toMatchInlineSnapshot(` + "Prisma schema loaded from schema.prisma + Datasource \\"sqlite\\": SQLite database \\"app.db\\" at \\"file:./app.db\\" + + Database connection error: + + P1003: SQLite database file doesn't exist" + `); +}); diff --git a/packages-next/keystone/src/scripts/tests/utils.tsx b/packages-next/keystone/src/scripts/tests/utils.tsx index 83f7df67bd6..9760f87b94c 100644 --- a/packages-next/keystone/src/scripts/tests/utils.tsx +++ b/packages-next/keystone/src/scripts/tests/utils.tsx @@ -13,6 +13,34 @@ import { IntrospectionEngine, uriToCredentials } from '@prisma/sdk'; import { cli } from '../cli'; import { mockPrompts } from '../../lib/prompts'; +export const cliBinPath = require.resolve('@keystone-next/keystone/bin/cli.js'); + +export const js = outdent; +export const ts = outdent; +export const tsx = outdent; +export const graphql = outdent; + +export const basicKeystoneConfig = js` + import { config, list } from "@keystone-next/keystone/schema"; + import { text } from "@keystone-next/fields"; + + export default config({ + db: { provider: "sqlite", url: "file:./app.db" }, + lists: { + Todo: list({ + fields: { + title: text(), + }, + }), + }, + }); + `; + +export const schemas = { + 'schema.graphql': fs.readFileSync(`${__dirname}/fixtures/basic-project/schema.graphql`, 'utf8'), + 'schema.prisma': fs.readFileSync(`${__dirname}/fixtures/basic-project/schema.prisma`, 'utf8'), +}; + export function recordConsole(promptResponses?: Record) { let oldConsole = { ...console }; let contents = ''; @@ -83,11 +111,6 @@ export function recordConsole(promptResponses?: Record let f = fixturez(__dirname); -export const js = outdent; -export const ts = outdent; -export const tsx = outdent; -export const graphql = outdent; - export const symlinkKeystoneDeps = Object.fromEntries( [ '@keystone-next/keystone',