Skip to content

Commit 6c41548

Browse files
The host runs Composer 0.26.0: one config file, no prisma-composer binary (8.0.0-rc.20) (#330)
Slice 3 of the one-config-file project ([prisma/orm#30536](prisma/orm#30536)). Composer 0.26.0 published the merged config ([prisma/composer#328](prisma/composer#328)) and dropped the `prisma-composer` binary ([prisma/composer#331](prisma/composer#331)); this PR makes the host carry it. Merging publishes `prisma@8.0.0-rc.20`. From a Composer project outside any workspace, with this branch's `prisma` and Composer 0.26.0 from the registry: ``` $ prisma dev module.ts # with prisma-composer.config.ts left beside prisma.config.ts CLI.CONFIG_SECTION_INVALID The 'composer' section of .../prisma.config.ts is invalid. CONFIG.FILE_RETIRED .../prisma-composer.config.ts is no longer read. Composer reads its configuration only from the `composer` section of prisma.config.ts. ... $ prisma --version 8.0.0-rc.20 ``` ## The decision `@prisma/cli` and `prisma` pin `@prisma/composer-cli` and `@prisma/composer` at 0.26.0 and the version advances to 8.0.0-rc.20, so `prisma@latest` runs Composer's family with the `composer` section of `prisma.config.ts` as its configuration. The automatic pin-bump workflow did not fire (Composer's publish could not notify this repository), so this PR carries the bump. ## What the bump changes in the host - **Tests.** The config fixture that held `composer: { configPath }` now proves the retirement: `dev --config` against it fails with the engine's `CLI.CONFIG_SECTION_INVALID` headline and Composer's `CONFIG.FIELD_RETIRED` diagnostic, exit 2, on every platform, since validation now fails before the handler runs. A second fixture holds a valid section built with `defineConfig as composer` from `@prisma/composer/config` and proves the handler runs against it. - **Conformance.** The composer-cli engine-pin exception in `scripts/conformance.ts` is removed, as its own note said this bump would do. The suite reports nothing. - **The shipped skill.** `skills/prisma-platform-core-concepts/SKILL.md` no longer says `prisma-composer.config.ts` is mandatory or that `dev` fails with `CONFIG.FILE_MISSING`. It describes the `composer` section and the three retirement codes in the same terms as Composer's own skill, with the fix for each. - **Isolation.** `composer-isolation.test.ts` passes unchanged: mounting the 0.26.0 family still loads neither Alchemy nor `effect` on an unrelated command. ## Verification - Build, typecheck, lint, cli tests (1027), cli-engine tests (1025), `test:scripts`, `check:skill-packaging`, `manifest-pins`, `composer-isolation`, and `check:conformance` with zero failing and zero allowed. - Manual QA against the published 0.26.0 in a project outside the workspace, recorded in the project folder: `--version`, `deploy --help`, `dev --help` exit 0 and list neither `destroy` nor `log`; the retired file gives `CONFIG.FILE_RETIRED`; the retired field gives `CONFIG.FIELD_RETIRED`; an `effect` forced to 4.0.0-rc.118 gives `CLI.CONFIG_UNREADABLE` naming the missing module while `--version` still exits 0. - `prisma dev` to ready still needs `alchemy` as a direct dependency in a plain pnpm project; that is a Composer defect fixed in [prisma/composer#332](prisma/composer#332), not a host matter, and will ship in Composer's next release. ## Not in this PR - New commands. `destroy` and `log` remain operations on `@prisma/composer/control`; their command-line form is a separate grammar project. - The prisma/web pages, which land in their own PR after this release is on `latest`. Agent: columbo-17 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
1 parent 5be86dd commit 6c41548

14 files changed

Lines changed: 165 additions & 140 deletions

File tree

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "prisma-cli",
3-
"version": "8.0.0-rc.19",
3+
"version": "8.0.0-rc.20",
44
"private": true,
55
"engines": {
66
"node": ">=24"

‎packages/cli-conformance/package.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@repo/cli-conformance",
33
"private": true,
4-
"version": "8.0.0-rc.19",
4+
"version": "8.0.0-rc.20",
55
"description": "Reusable conformance checks for the engine's consumers: import purity over built output, config-section validators that never throw, and verification of the tarballs a registry would receive. Depends on no package it checks.",
66
"type": "module",
77
"exports": {
@@ -24,7 +24,7 @@
2424
"test": "pnpm run typecheck && vitest run"
2525
},
2626
"devDependencies": {
27-
"@repo/tsconfig": "workspace:8.0.0-rc.19",
27+
"@repo/tsconfig": "workspace:8.0.0-rc.20",
2828
"@types/node": "^22.19.19",
2929
"es-module-lexer": "^2.1.0",
3030
"tsx": "^4.22.4",

‎packages/cli-engine/package.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@
5959
},
6060
"devDependencies": {
6161
"@prisma/management-api-sdk": "1.80.0",
62-
"@repo/cli-conformance": "workspace:8.0.0-rc.19",
63-
"@repo/tsconfig": "workspace:8.0.0-rc.19",
62+
"@repo/cli-conformance": "workspace:8.0.0-rc.20",
63+
"@repo/tsconfig": "workspace:8.0.0-rc.20",
6464
"@types/node": "^22.19.19",
6565
"ci-info": "^4.3.1",
6666
"tsdown": "^0.21.10",

‎packages/cli-telemetry/package.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@repo/cli-telemetry",
33
"private": true,
4-
"version": "8.0.0-rc.19",
4+
"version": "8.0.0-rc.20",
55
"description": "CLI telemetry child sender: the detached subprocess the engine hands a composed payload to, its system probes, and the POST",
66
"type": "module",
77
"sideEffects": [
@@ -35,7 +35,7 @@
3535
"@vercel/detect-agent": "^1.2.3"
3636
},
3737
"devDependencies": {
38-
"@repo/tsconfig": "workspace:8.0.0-rc.19",
38+
"@repo/tsconfig": "workspace:8.0.0-rc.20",
3939
"@types/node": "^22.19.19",
4040
"tsdown": "^0.21.10",
4141
"typescript": "^6.0.3",

‎packages/cli/package.json‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@prisma/cli",
3-
"version": "8.0.0-rc.19",
3+
"version": "8.0.0-rc.20",
44
"description": "Command-line interface for the Prisma Developer Platform.",
55
"type": "module",
66
"bin": {
@@ -50,7 +50,7 @@
5050
"dependencies": {
5151
"@manypkg/tools": "^2.1.2",
5252
"@prisma/cli-engine": "workspace:0.6.2",
53-
"@prisma/composer-cli": "0.25.0",
53+
"@prisma/composer-cli": "0.26.0",
5454
"@prisma/compute-sdk": "0.43.0",
5555
"@prisma/management-api-sdk": "1.80.0",
5656
"@prisma/orm-toolchain": "8.0.0-rc.14",
@@ -62,11 +62,11 @@
6262
"open": "^11.0.0"
6363
},
6464
"devDependencies": {
65-
"@prisma/composer": "0.25.0",
65+
"@prisma/composer": "0.26.0",
6666
"@prisma/credentials-store": "^7.8.0",
67-
"@repo/cli-conformance": "workspace:8.0.0-rc.19",
68-
"@repo/cli-telemetry": "workspace:8.0.0-rc.19",
69-
"@repo/tsconfig": "workspace:8.0.0-rc.19",
67+
"@repo/cli-conformance": "workspace:8.0.0-rc.20",
68+
"@repo/cli-telemetry": "workspace:8.0.0-rc.20",
69+
"@repo/tsconfig": "workspace:8.0.0-rc.20",
7070
"@types/node": "^22.19.19",
7171
"@types/cross-spawn": "^6.0.6",
7272
"tsdown": "^0.21.10",

‎packages/cli/scripts/conformance.ts‎

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,6 @@ async function tarball(): Promise<readonly Finding[]> {
110110
enginePackage: "@prisma/cli-engine",
111111
familyPackages: ["@prisma/composer-cli", "@prisma/orm-toolchain"],
112112
exceptions: [
113-
{
114-
familyPackage: "@prisma/composer-cli",
115-
familyPin: "0.6.1",
116-
shellPin: "0.6.2",
117-
reason: "engine 0.6.2 must publish before composer-cli can peer it",
118-
removeWhen:
119-
"composer-cli releases peering 0.6.2 and the follow-up bump PR pins that release",
120-
},
121113
{
122114
familyPackage: "@prisma/orm-toolchain",
123115
familyPin: "0.6.1",

‎packages/cli/tests/bin.test.ts‎

Lines changed: 65 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,20 @@ const MISSING_PRISMA_CONFIG_PATH = join(
3434
"missing-prisma.config.ts",
3535
);
3636

37-
/** A prisma.config.ts whose only section is composer's. */
38-
const COMPOSER_SECTION_CONFIG_PATH = join(
37+
/** A composer section that still carries the retired `configPath`. */
38+
const COMPOSER_CONFIG_PATH_CONFIG_PATH = join(
3939
dirname(fileURLToPath(import.meta.url)),
4040
"fixtures",
4141
"config",
42-
"composer-section.config.ts",
42+
"composer-config-path.config.ts",
43+
);
44+
45+
/** A composer section built with `@prisma/composer/config`. */
46+
const COMPOSER_VALID_CONFIG_PATH = join(
47+
dirname(fileURLToPath(import.meta.url)),
48+
"fixtures",
49+
"config",
50+
"composer-valid.config.ts",
4351
);
4452

4553
const SEMVER_PREFIX = /^\d+\.\d+\.\d+/;
@@ -492,7 +500,10 @@ describe("buildCli", () => {
492500
* stdout is not a TTY here, so the stream is JSON, and JSON escapes
493501
* every separator in a Windows path — no path the CLI printed is a
494502
* substring of the stream that carried it. */
495-
function resultError(stdoutText: string): Diagnostic {
503+
function resultFailure(stdoutText: string): {
504+
readonly error: Diagnostic;
505+
readonly diagnostics: readonly Diagnostic[];
506+
} {
496507
const frames = stdoutText
497508
.split("\n")
498509
.filter((line) => line !== "")
@@ -501,81 +512,74 @@ describe("buildCli", () => {
501512
if (last?.kind !== "result" || last.envelope.ok) {
502513
throw new Error(`expected a failed result frame, got: ${stdoutText}`);
503514
}
504-
return last.envelope.error;
515+
return {
516+
error: last.envelope.error,
517+
diagnostics: last.envelope.diagnostics,
518+
};
505519
}
506520

507-
/** Composer's `dev` through the real bin, against the fixture whose
508-
* composer section names a config file that is not there. */
509-
async function runComposerDev(): Promise<{
521+
/** Composer's `dev` through the real bin, reading the given config. */
522+
async function runComposerDev(configPath: string): Promise<{
510523
readonly exitCode: number;
511524
readonly error: Diagnostic;
525+
readonly diagnostics: readonly Diagnostic[];
512526
}> {
513527
const proc = makeProcess({
514-
argv: [
515-
"node",
516-
"bin.js",
517-
"dev",
518-
"--config",
519-
COMPOSER_SECTION_CONFIG_PATH,
520-
"src/service.ts",
521-
],
528+
argv: ["node", "bin.js", "dev", "--config", configPath, "src/service.ts"],
522529
});
523530

524531
const exitCode = await main(proc);
525-
return { exitCode, error: resultError(proc.stdoutText) };
532+
return { exitCode, ...resultFailure(proc.stdoutText) };
526533
}
527534

528535
/**
529536
* The mount's config wiring, end to end: the section name composer's
530-
* family declares, read by the bin's real disk loader, reaching
531-
* composer's own handler as the path it acts on.
532-
*
533-
* Every platform but Windows. `dev` is the only composer command
534-
* that reaches config discovery without credentials — `deploy` stops
535-
* at the credential check — and it refuses Windows before it reads
536-
* the section it was handed, so no shipped command can show the
537-
* section arriving there. The test after this one pins what Windows
538-
* can still show.
537+
* family declares, read by the bin's real disk loader and checked by
538+
* composer's own validator before any handler runs, so every
539+
* platform sees the same refusal.
539540
*/
540-
it.skipIf(process.platform === "win32")(
541-
"hands the composer section of prisma.config.ts to the composer family",
542-
async () => {
543-
const { exitCode, error } = await runComposerDev();
544-
545-
expect(exitCode).toBe(2);
546-
expect(error.code).toBe("CONFIG.FILE_MISSING");
547-
// Composer resolves the section's relative path against the
548-
// prisma.config.ts that declared it, not against the cwd.
549-
expect(error.where?.path).toBe(
550-
join(
551-
dirname(COMPOSER_SECTION_CONFIG_PATH),
552-
"named-by-the-section.config.ts",
553-
),
554-
);
555-
expect(error.why).toContain("there is no walk to fall back on");
556-
},
557-
);
541+
it("refuses a composer section that still names a config file", async () => {
542+
const { exitCode, error, diagnostics } = await runComposerDev(
543+
COMPOSER_CONFIG_PATH_CONFIG_PATH,
544+
);
545+
546+
expect(exitCode).toBe(2);
547+
expect(error).toMatchObject({
548+
code: "CLI.CONFIG_SECTION_INVALID",
549+
summary: `The 'composer' section of ${COMPOSER_CONFIG_PATH_CONFIG_PATH} is invalid.`,
550+
});
551+
expect(diagnostics).toEqual([
552+
expect.objectContaining({
553+
code: "CONFIG.FIELD_RETIRED",
554+
severity: "error",
555+
meta: { field: "configPath" },
556+
where: { path: COMPOSER_CONFIG_PATH_CONFIG_PATH },
557+
}),
558+
]);
559+
});
558560

559561
/**
560-
* What Windows still shows: the bin evaluated the config file, the
561-
* engine accepted its `composer` section, and the command reached
562-
* composer's own operation — which then refuses the platform. A
563-
* mis-wired section would fail here as a config diagnostic instead.
564-
* What it does not show is the section's path reaching composer's
565-
* config discovery, since the refusal comes first.
566-
*
567-
* When composer supports Windows this test fails, and the pair
568-
* collapses back into the one above.
562+
* `dev --help` never evaluates the config, so a valid section shows
563+
* only on a run that validates it: composer's validator accepts the
564+
* section and the handler runs. Its first step imports the entry the
565+
* host passed, which does not exist; on Windows the handler refuses
566+
* the platform before that.
569567
*/
570-
it.runIf(process.platform === "win32")(
571-
"on Windows, composer's dev refuses the platform before it reads the section",
572-
async () => {
573-
const { exitCode, error } = await runComposerDev();
568+
it("hands a valid composer section to composer's dev", async () => {
569+
const { exitCode, error } = await runComposerDev(
570+
COMPOSER_VALID_CONFIG_PATH,
571+
);
574572

575-
expect(exitCode).toBe(2);
576-
expect(error.code).toBe("DEV.PLATFORM_UNSUPPORTED");
577-
},
578-
);
573+
expect(exitCode).toBe(2);
574+
expect(error).toMatchObject(
575+
process.platform === "win32"
576+
? { code: "DEV.PLATFORM_UNSUPPORTED" }
577+
: {
578+
code: "COMPOSE.ENTRY_UNLOADABLE",
579+
summary: expect.stringContaining(join("src", "service.ts")),
580+
},
581+
);
582+
});
579583

580584
it("runs --version through the real tree, printing the version with exit 0", async () => {
581585
const proc = makeProcess({

packages/cli/tests/fixtures/config/composer-section.config.ts renamed to packages/cli/tests/fixtures/config/composer-config-path.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ import { definePrismaConfig } from "@prisma/cli-engine";
44
// appearing in one of this repository's directories above these
55
// fixtures can never join a test's chain.
66
export default definePrismaConfig({
7-
composer: { configPath: "./named-by-the-section.config.ts" },
7+
composer: { configPath: "./prisma-composer.config.ts" },
88
parent: false,
99
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { definePrismaConfig } from "@prisma/cli-engine";
2+
import { defineConfig as composer } from "@prisma/composer/config";
3+
import { nodeBuild } from "@prisma/composer/node/control";
4+
5+
const build = nodeBuild();
6+
7+
export default definePrismaConfig({
8+
composer: composer({
9+
extensions: [build],
10+
state: {
11+
extension: build.id,
12+
create: () => {
13+
throw new Error("no command in these tests reaches the state store");
14+
},
15+
},
16+
}),
17+
parent: false,
18+
});

‎packages/compute/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
"test": "vitest run"
4343
},
4444
"devDependencies": {
45-
"@repo/tsconfig": "workspace:8.0.0-rc.19",
45+
"@repo/tsconfig": "workspace:8.0.0-rc.20",
4646
"@types/node": "^22.19.19",
4747
"tsdown": "^0.21.10",
4848
"typescript": "^6.0.3",

0 commit comments

Comments
 (0)