Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions .github/workflows/error-reference-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Error Reference Check

# The published error-reference page must list every structured error code the
# product (prisma/prisma main) can emit — each emitted error links to
# /docs/orm/next/reference/error-reference#<CODE>. This check fails if any
# known code is missing from the page, even if the sync workflow breaks.
#
# Runs on pushes to main, on PRs that touch the page or its tooling, and on a
# daily schedule so drift introduced upstream is flagged without blocking
# unrelated PRs.

on:
push:
branches: [main]
pull_request:
paths:
- apps/docs/content/docs/orm/next/reference/error-reference.mdx
- apps/docs/scripts/generate-error-reference.mjs
- .github/workflows/error-reference-check.yml
- .github/workflows/sync-error-reference-docs.yml
schedule:
- cron: "30 6 * * *"
workflow_dispatch:

permissions:
contents: read

Comment thread
coderabbitai[bot] marked this conversation as resolved.
jobs:
verify:
name: Verify error-reference completeness
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false

- name: Checkout prisma/prisma (main)
uses: actions/checkout@v4
with:
repository: prisma/prisma
ref: main
path: prisma-src
persist-credentials: false

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"

- name: Verify page lists every known error code
run: node prisma-src/scripts/list-error-codes.mjs --root prisma-src --verify apps/docs/content/docs/orm/next/reference/error-reference.mdx
74 changes: 74 additions & 0 deletions .github/workflows/sync-error-reference-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: Sync Error Reference Docs

on:
repository_dispatch:
types: [error-reference-updated]
schedule:
- cron: "0 6 * * *"
workflow_dispatch:

concurrency:
group: sync-error-reference-docs
cancel-in-progress: false

permissions:
contents: read

jobs:
sync:
name: Sync Error Reference Documentation
runs-on: ubuntu-latest
steps:
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false

- name: Checkout prisma/prisma (main)
uses: actions/checkout@v4
with:
repository: prisma/prisma
ref: main
path: prisma-src
Comment thread
coderabbitai[bot] marked this conversation as resolved.
persist-credentials: false

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"

- name: Generate error reference page
working-directory: apps/docs
run: node ./scripts/generate-error-reference.mjs --source ../../prisma-src/docs/reference/error-reference.md

- name: Verify page lists every known error code
run: node prisma-src/scripts/list-error-codes.mjs --root prisma-src --verify apps/docs/content/docs/orm/next/reference/error-reference.mdx

- name: Check for changes
id: changes
run: |
if [[ -z "$(git status --porcelain --untracked-files=all -- apps/docs/content/docs/orm/next/reference/error-reference.mdx)" ]]; then
echo "changed=false" >> $GITHUB_OUTPUT
echo "No changes detected"
else
echo "changed=true" >> $GITHUB_OUTPUT
echo "Changes detected:"
git status --short -- apps/docs/content/docs/orm/next/reference/error-reference.mdx
fi

- name: Commit and push
if: steps.changes.outputs.changed == 'true'
env:
BOT_TOKEN: ${{ secrets.BOT_TOKEN_DOCS_COMMIT }}
TARGET_REPO: ${{ github.repository }}
TARGET_REF: ${{ github.ref_name }}
run: |
git config user.email "prismabots@gmail.com"
git config user.name "Prismo"
git add apps/docs/content/docs/orm/next/reference/error-reference.mdx
git commit -m "chore(docs): sync Prisma Next error reference"
git push "https://x-access-token:${BOT_TOKEN}@github.com/${TARGET_REPO}.git" "HEAD:${TARGET_REF}"

- name: Trigger Vercel deploy
if: steps.changes.outputs.changed == 'true'
run: curl --fail -X POST "${{ secrets.VERCEL_DEPLOY_HOOK_URL }}"
1,043 changes: 1,043 additions & 0 deletions apps/docs/content/docs/orm/next/reference/error-reference.mdx

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion apps/docs/content/docs/orm/next/reference/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"sql-query-builder",
"pipeline-builder",
"raw-queries",
"transactions-and-runtime"
"transactions-and-runtime",
"error-reference"
]
}
6 changes: 2 additions & 4 deletions apps/docs/cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -439,8 +439,6 @@
"pattern": "/videoId=\"[A-Za-z0-9_-]{6,}\"/g"
}
],
"ignoreRegExpList": [
"mdxVideoIdAttribute"
],
"ignorePaths": []
"ignoreRegExpList": ["mdxVideoIdAttribute"],
"ignorePaths": ["content/docs/orm/next/reference/error-reference.mdx"]
}
1 change: 1 addition & 0 deletions apps/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"fetch-openapi": "tsx ./scripts/fetch-openapi.ts",
"generate:management-api-docs": "pnpm run fetch-openapi && tsx ./scripts/generate-docs.ts && pnpm run generate:postman-collection && fumadocs-mdx",
"generate:postman-collection": "tsx ./scripts/generate-postman-collection.ts",
"generate:error-reference": "node ./scripts/generate-error-reference.mjs && fumadocs-mdx",
"build": "pnpm run fetch-openapi && next build",
"start": "next start --port 3001",
"dev": "next dev --port 3001",
Expand Down
117 changes: 117 additions & 0 deletions apps/docs/scripts/generate-error-reference.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Generates content/docs/orm/next/reference/error-reference.mdx from the
// canonical docs/reference/error-reference.md in prisma/prisma (main branch).
//
// Usage:
// node scripts/generate-error-reference.mjs [--source <path-to-error-reference.md>]
//
// Without --source, the file is fetched from raw.githubusercontent.com.
//
// Every Prisma Next error carries a docsUrl of the form
// https://docs.prisma.io/docs/orm/next/reference/error-reference#<CODE>
// so each `### NAMESPACE.SUBCODE` heading gets an explicit anchor equal to the
// raw code text (uppercase, with the dot) via Fumadocs' `[#custom-id]` syntax.

import { readFileSync, writeFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";

const SOURCE_URL =
"https://raw.githubusercontent.com/prisma/prisma/main/docs/reference/error-reference.md";
const GITHUB_BLOB_BASE = "https://github.com/prisma/prisma/blob/main/docs/reference/";
const OUTPUT = join(
dirname(fileURLToPath(import.meta.url)),
"../content/docs/orm/next/reference/error-reference.mdx",
);
const CODE_HEADING = /^### ([A-Z0-9_]+\.[A-Z0-9_.]+)$/;

async function loadSource() {
const flagIndex = process.argv.indexOf("--source");
if (flagIndex !== -1) {
const path = process.argv[flagIndex + 1];
if (!path) throw new Error("--source requires a path");
return readFileSync(path, "utf8");
}
const response = await fetch(SOURCE_URL);
if (!response.ok) {
throw new Error(`Failed to fetch ${SOURCE_URL}: ${response.status}`);
}
return response.text();
}

function assertMdxSafe(markdown) {
// The page is plain markdown compiled as MDX. Braces and JSX-like tags
// outside code spans/fences would change meaning or break the build, so
// refuse them here where the failure is attributable to the source file.
const withoutCode = markdown.replace(/```[\s\S]*?```/g, "").replace(/`[^`\n]*`/g, "");
const hostile = withoutCode.match(/[{}]|<[A-Za-z/]/);
if (hostile) {
throw new Error(
`Source contains MDX-unsafe text outside code spans (found ${JSON.stringify(hostile[0])}). ` +
"Escape it in prisma/prisma docs/reference/error-reference.md or teach this generator to handle it.",
);
}
}

function transform(markdown) {
assertMdxSafe(markdown);

let body = markdown.replace(/^# Error reference\s*\n/, "");

// The source intro describes itself from the prisma/prisma repo's point of
// view ("canonical source", its own CI check). Reworded for readers of the
// hosted page; if upstream rewrites the sentence the original is kept.
body = body.replace(
/It is the canonical source for the hosted reference at[\s\S]*?missing from this page\./,
"Each code anchors as `#<CODE>` — the exact fragment every emitted error carries in its " +
"`docsUrl`. This page is generated from the canonical reference in the `prisma/prisma` " +
"repository, whose CI requires every code in production source to be documented before it ships.",
);
Comment thread
coderabbitai[bot] marked this conversation as resolved.

// Repo-relative links point at files that only exist in prisma/prisma.
body = body.replace(/\]\((\.\.?\/[^)]+)\)/g, (_, target) => {
const url = new URL(target, `${GITHUB_BLOB_BASE}error-reference.md`);
return `](${url.href})`;
});

const codes = [];
body = body.replace(/^### .+$/gm, (heading) => {
const match = heading.match(CODE_HEADING);
if (!match) {
throw new Error(
`Unexpected heading shape: ${JSON.stringify(heading)}. ` +
"Anchors are only generated for `### NAMESPACE.SUBCODE` headings.",
);
}
codes.push(match[1]);
return `${heading} [#${match[1]}]`;
});

if (codes.length === 0) {
throw new Error("No error-code headings found — refusing to write an empty page.");
}
const duplicates = codes.filter((code, i) => codes.indexOf(code) !== i);
if (duplicates.length > 0) {
throw new Error(`Duplicate error codes in source: ${duplicates.join(", ")}`);
}

const frontmatter = `---
title: Error reference
description: Every structured error code Prisma Next can emit, by namespace, with the condition that raises it.
url: /orm/next/reference/error-reference
metaTitle: Prisma Next error reference
metaDescription: Every structured error code Prisma Next can emit, by namespace, with the condition that raises it.
badge: early-access
---

{/* Generated by scripts/generate-error-reference.mjs from
https://github.com/prisma/prisma/blob/main/docs/reference/error-reference.md
Do not edit by hand — changes are overwritten by the sync workflow. */}

`;

return { mdx: frontmatter + body, codeCount: codes.length };
}

const { mdx, codeCount } = transform(await loadSource());
writeFileSync(OUTPUT, mdx);
console.log(`Wrote ${OUTPUT} with ${codeCount} error codes.`);
15 changes: 15 additions & 0 deletions apps/docs/tests/error-reference-anchors.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { expect, test } from "@playwright/test";

// Every Prisma Next error carries a docsUrl like
// https://docs.prisma.io/docs/orm/next/reference/error-reference#CONTRACT.IDENTIFIER_INVALID
// The fragment is the raw code — uppercase, with the dot — so the heading ids
// must be the raw code text, not a slugified form.
test("error-reference anchors use raw error codes", async ({ page }) => {
await page.goto("/docs/orm/next/reference/error-reference#CONTRACT.IDENTIFIER_INVALID");

const heading = page.locator('h3[id="CONTRACT.IDENTIFIER_INVALID"]');
await expect(heading).toHaveText("CONTRACT.IDENTIFIER_INVALID");
await expect(heading).toBeInViewport();

expect(await page.locator('h3[id*="."]').count()).toBeGreaterThan(200);
});
Loading